1 /* xscreensaver, Copyright (c) 2001-2016 by Jamie Zawinski <jwz@jwz.org>
3 * Permission to use, copy, modify, distribute, and sell this software and its
4 * documentation for any purpose is hereby granted without fee, provided that
5 * the above copyright notice appear in all copies and that both that
6 * copyright notice and this permission notice appear in supporting
7 * documentation. No representations are made about the suitability of this
8 * software for any purpose. It is provided "as is" without express or
12 /* xscreensaver-getimage -- helper program that puts a random image
13 onto the given window or pixmap. That image is either a screen-grab,
14 a file loaded from disk, or a frame grabbed from the system's video
20 #include <X11/Intrinsic.h>
26 #ifdef HAVE_SYS_WAIT_H
27 # include <sys/wait.h> /* for waitpid() and associated macros */
32 # include <X11/Xmu/Error.h>
34 # include <Xmu/Error.h>
41 #include "grabscreen.h"
42 #include "resources.h"
43 #include "colorbars.h"
49 #ifndef _XSCREENSAVER_VROOT_H_
50 # error Error! You have an old version of vroot.h! Check -I args.
51 #endif /* _XSCREENSAVER_VROOT_H_ */
53 #ifdef HAVE_GDK_PIXBUF
56 # include <gdk-pixbuf-xlib/gdk-pixbuf-xlib.h>
57 # else /* !HAVE_GTK2 */
58 # include <gdk-pixbuf/gdk-pixbuf-xlib.h>
59 # endif /* !HAVE_GTK2 */
60 #endif /* HAVE_GDK_PIXBUF */
63 # undef HAVE_GDK_PIXBUF
69 /* On MacOS under X11, the usual X11 mechanism of getting a screen shot
70 doesn't work, and we need to use an external program. This is only
71 used when running under X11 on MacOS. If it's a Cocoa build, this
72 path is not taken, and OSX/grabclient-osx.m is used instead.
74 # define USE_EXTERNAL_SCREEN_GRABBER
79 __extension__ /* shut up about "string length is greater than the length
80 ISO C89 compilers are required to support" when including
84 static char *defaults[] = {
85 #include "../driver/XScreenSaver_ad.h"
92 char *progclass = "XScreenSaver";
96 extern void grabscreen_verbose (void);
99 GRAB_DESK, GRAB_VIDEO, GRAB_FILE, GRAB_BARS
103 #define GETIMAGE_VIDEO_PROGRAM "xscreensaver-getimage-video"
104 #define GETIMAGE_FILE_PROGRAM "xscreensaver-getimage-file"
105 #define GETIMAGE_SCREEN_PROGRAM "xscreensaver-getimage-desktop"
107 extern const char *blurb (void);
117 x_ehandler (Display *dpy, XErrorEvent *error)
119 if (error->error_code == BadWindow || error->error_code == BadDrawable)
121 fprintf (stderr, "%s: target %s 0x%lx unexpectedly deleted\n", progname,
122 (error->error_code == BadWindow ? "window" : "pixmap"),
123 (unsigned long) error->resourceid);
127 fprintf (stderr, "\nX error in %s:\n", progname);
128 XmuPrintDefaultErrorMessage (dpy, error, stderr);
135 static Bool error_handler_hit_p = False;
138 ignore_all_errors_ehandler (Display *dpy, XErrorEvent *error)
140 error_handler_hit_p = True;
144 #ifndef USE_EXTERNAL_SCREEN_GRABBER
146 ignore_badmatch_ehandler (Display *dpy, XErrorEvent *error)
148 if (error->error_code == BadMatch)
149 return ignore_all_errors_ehandler (dpy, error);
151 return x_ehandler (dpy, error);
153 #endif /* ! USE_EXTERNAL_SCREEN_GRABBER */
156 /* Returns True if the given Drawable is a Window; False if it's a Pixmap.
159 drawable_window_p (Display *dpy, Drawable d)
161 XErrorHandler old_handler;
162 XWindowAttributes xgwa;
165 old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
166 error_handler_hit_p = False;
167 XGetWindowAttributes (dpy, d, &xgwa);
169 XSetErrorHandler (old_handler);
172 if (!error_handler_hit_p)
173 return True; /* It's a Window. */
175 return False; /* It's a Pixmap, or an invalid ID. */
179 /* Returns true if the window is the root window, or a virtual root window,
180 but *not* the xscreensaver window. That is, if it's a "real" desktop
181 root window of some kind.
184 root_window_p (Screen *screen, Window window)
186 Display *dpy = DisplayOfScreen (screen);
189 unsigned long nitems, bytesafter;
190 unsigned char *version;
192 if (window != RootWindowOfScreen (screen))
195 if (XGetWindowProperty (dpy, window,
196 XInternAtom (dpy, "_SCREENSAVER_VERSION", False),
197 0, 1, False, XA_STRING,
198 &type, &format, &nitems, &bytesafter,
208 /* Clear the window or pixmap to black, or its background color.
211 clear_drawable (Screen *screen, Drawable drawable)
213 Display *dpy = DisplayOfScreen (screen);
218 unsigned int w, h, bw, d;
219 XGetGeometry (dpy, drawable, &root, &x, &y, &w, &h, &bw, &d);
221 /* The window might have no-op background of None, so to clear it,
222 draw a black rectangle first, then do XClearWindow (in case the
223 actual background color is non-black...) */
225 /* #### really we should allocate "black" instead, but I'm lazy... */
226 gcv.foreground = BlackPixelOfScreen (screen);
227 gc = XCreateGC (dpy, drawable, GCForeground, &gcv);
228 XFillRectangle (dpy, drawable, gc, 0, 0, w, h);
230 if (drawable_window_p (dpy, drawable))
231 XClearWindow (dpy, (Window) drawable);
236 /* Figure out what kind of scaling/positioning we ought to do to display
237 a src-sized image in a dest-sized window/pixmap. Returns the width
238 and height to which the image should be scaled, and the position where
239 it should be displayed to center it.
242 compute_image_scaling (int src_w, int src_h,
243 int dest_w, int dest_h,
245 int *scaled_from_x_ret, int *scaled_from_y_ret,
246 int *scaled_to_x_ret, int *scaled_to_y_ret,
247 int *scaled_w_ret, int *scaled_h_ret)
249 int srcx, srcy, destx, desty;
251 Bool exact_fit_p = ((src_w == dest_w && src_h <= dest_h) ||
252 (src_h == dest_h && src_w <= dest_w));
254 if (!exact_fit_p) /* scale the image up or down */
256 float rw = (float) dest_w / src_w;
257 float rh = (float) dest_h / src_h;
258 float r = (rw < rh ? rw : rh);
261 /* If the window is a goofy aspect ratio, take a middle slice of
262 the image instead. */
263 if (dest_w > dest_h * 5 || dest_h > dest_w * 5)
265 double r2 = (dest_w > dest_h
266 ? dest_w / (double) dest_h
267 : dest_h / (double) dest_w);
270 fprintf (stderr, "%s: weird aspect: scaling by %.1f\n",
279 /* this optimization breaks things */
280 if (pct < 95 || pct > 105) /* don't scale if it's close */
284 fprintf (stderr, "%s: scaling image by %d%% (%dx%d -> %dx%d)\n",
285 progname, pct, src_w, src_h, tw, th);
291 /* Center the image on the window/pixmap. */
294 destx = (dest_w - src_w) / 2;
295 desty = (dest_h - src_h) / 2;
296 if (destx < 0) srcx = -destx, destx = 0;
297 if (desty < 0) srcy = -desty, desty = 0;
299 /* if (dest_w < src_w) src_w = dest_w;
300 if (dest_h < src_h) src_h = dest_h; */
302 *scaled_w_ret = src_w;
303 *scaled_h_ret = src_h;
304 *scaled_from_x_ret = srcx;
305 *scaled_from_y_ret = srcy;
306 *scaled_to_x_ret = destx;
307 *scaled_to_y_ret = desty;
310 fprintf (stderr, "%s: displaying %dx%d+%d+%d image at %d,%d in %dx%d.\n",
311 progname, src_w, src_h, srcx, srcy, destx, desty, dest_w, dest_h);
315 /* Scales an XImage, modifying it in place.
316 This doesn't do dithering or smoothing, so it might have artifacts.
317 If out of memory, returns False, and the XImage will have been
320 #if !defined(USE_EXTERNAL_SCREEN_GRABBER) || defined(HAVE_JPEGLIB)
322 scale_ximage (Screen *screen, Visual *visual,
323 XImage *ximage, int new_width, int new_height)
325 Display *dpy = DisplayOfScreen (screen);
326 int depth = visual_depth (screen, visual);
328 double xscale, yscale;
330 XImage *ximage2 = XCreateImage (dpy, visual, depth,
332 new_width, new_height, 8, 0);
333 ximage2->data = (char *) calloc (ximage2->height, ximage2->bytes_per_line);
337 fprintf (stderr, "%s: out of memory scaling %dx%d image to %dx%d\n",
339 ximage->width, ximage->height,
340 ximage2->width, ximage2->height);
341 if (ximage->data) free (ximage->data);
342 if (ximage2->data) free (ximage2->data);
345 XDestroyImage (ximage);
346 XDestroyImage (ximage2);
350 /* Brute force scaling... */
351 xscale = (double) ximage->width / ximage2->width;
352 yscale = (double) ximage->height / ximage2->height;
353 for (y = 0; y < ximage2->height; y++)
354 for (x = 0; x < ximage2->width; x++)
355 XPutPixel (ximage2, x, y,
356 XGetPixel (ximage, x * xscale, y * yscale));
361 (*ximage) = (*ximage2);
364 XDestroyImage (ximage2);
368 #endif /* !USE_EXTERNAL_SCREEN_GRABBER || HAVE_JPEGLIB */
371 #ifdef HAVE_GDK_PIXBUF
373 /* Reads the given image file and renders it on the Drawable, using GDK.
374 Returns False if it fails.
377 read_file_gdk (Screen *screen, Window window, Drawable drawable,
378 const char *filename, Bool verbose_p,
379 XRectangle *geom_ret)
382 Display *dpy = DisplayOfScreen (screen);
383 unsigned int win_width, win_height, win_depth;
386 # endif /* HAVE_GTK2 */
388 /* Find the size of the Drawable. */
393 XGetGeometry (dpy, drawable,
394 &root, &x, &y, &win_width, &win_height, &bw, &win_depth);
397 gdk_pixbuf_xlib_init_with_depth (dpy, screen_number (screen), win_depth);
399 # if !GLIB_CHECK_VERSION(2, 36 ,0)
402 # else /* !HAVE_GTK2 */
403 xlib_rgb_init (dpy, screen);
404 # endif /* !HAVE_GTK2 */
406 pb = gdk_pixbuf_new_from_file (filename
409 # endif /* HAVE_GTK2 */
414 fprintf (stderr, "%s: unable to load \"%s\"\n", progname, filename);
416 if (gerr && gerr->message && *gerr->message)
417 fprintf (stderr, "%s: reason: %s\n", progname, gerr->message);
418 # endif /* HAVE_GTK2 */
423 int w = gdk_pixbuf_get_width (pb);
424 int h = gdk_pixbuf_get_height (pb);
425 int srcx, srcy, destx, desty, w2, h2;
428 # ifdef HAVE_GDK_PIXBUF_APPLY_EMBEDDED_ORIENTATION
432 pb = gdk_pixbuf_apply_embedded_orientation (opb);
433 g_object_unref (opb);
434 w = gdk_pixbuf_get_width (pb);
435 h = gdk_pixbuf_get_height (pb);
436 if (verbose_p && (w != ow || h != oh))
437 fprintf (stderr, "%s: rotated %dx%d to %dx%d\n",
438 progname, ow, oh, w, h);
442 compute_image_scaling (w, h, win_width, win_height, verbose_p,
443 &srcx, &srcy, &destx, &desty, &w2, &h2);
444 if (w != w2 || h != h2)
446 GdkPixbuf *pb2 = gdk_pixbuf_scale_simple (pb, w2, h2,
447 GDK_INTERP_BILINEAR);
456 fprintf (stderr, "%s: out of memory when scaling?\n", progname);
459 /* If we're rendering onto the root window (and it's not the
460 xscreensaver pseudo-root) then put the image in the window's
461 background. Otherwise, just paint the image onto the window.
463 bg_p = (window == drawable && root_window_p (screen, window));
469 drawable = XCreatePixmap (dpy, window,
470 win_width, win_height, win_depth);
471 gcv.foreground = BlackPixelOfScreen (screen);
472 gc = XCreateGC (dpy, drawable, GCForeground, &gcv);
473 XFillRectangle (dpy, drawable, gc, 0, 0, win_width, win_height);
477 clear_drawable (screen, drawable);
479 /* #### Note that this always uses the default colormap! Morons!
480 Owen says that in Gnome 2.0, I should try using
481 gdk_pixbuf_render_pixmap_and_mask_for_colormap() instead.
484 if (srcx > 0) w -= srcx;
485 if (srcy > 0) h -= srcy;
486 gdk_pixbuf_xlib_render_to_drawable_alpha (pb, drawable,
487 srcx, srcy, destx, desty,
489 GDK_PIXBUF_ALPHA_FULL, 127,
490 XLIB_RGB_DITHER_NORMAL,
494 XSetWindowBackgroundPixmap (dpy, window, drawable);
495 XClearWindow (dpy, window);
503 geom_ret->height = h;
511 #endif /* HAVE_GDK_PIXBUF */
517 /* Allocates a colormap that makes a PseudoColor or DirectColor
518 visual behave like a TrueColor visual of the same depth.
520 #### Duplicated in utils/grabscreen.c
523 allocate_cubic_colormap (Screen *screen, Visual *visual, Colormap cmap,
526 Display *dpy = DisplayOfScreen (screen);
527 int nr, ng, nb, cells;
533 depth = visual_depth (screen, visual);
537 case 8: nr = 3; ng = 3; nb = 2; cells = 256; break;
538 case 12: nr = 4; ng = 4; nb = 4; cells = 4096; break;
539 default: abort(); break;
542 memset(colors, 0, sizeof(colors));
543 for (r = 0; r < (1 << nr); r++)
544 for (g = 0; g < (1 << ng); g++)
545 for (b = 0; b < (1 << nb); b++)
547 i = (r | (g << nr) | (b << (nr + ng)));
549 colors[i].flags = DoRed|DoGreen|DoBlue;
552 colors[i].red = ((r << 13) | (r << 10) | (r << 7) |
553 (r << 4) | (r << 1));
554 colors[i].green = ((g << 13) | (g << 10) | (g << 7) |
555 (g << 4) | (g << 1));
556 colors[i].blue = ((b << 14) | (b << 12) | (b << 10) |
557 (b << 8) | (b << 6) | (b << 4) |
562 colors[i].red = (r << 12) | (r << 8) | (r << 4) | r;
563 colors[i].green = (g << 12) | (g << 8) | (g << 4) | g;
564 colors[i].blue = (b << 12) | (b << 8) | (b << 4) | b;
571 int interleave = cells / 8; /* skip around, rather than allocating in
572 order, so that we get better coverage if
573 we can't allocated all of them. */
574 for (j = 0; j < interleave; j++)
575 for (i = 0; i < cells; i += interleave)
576 if (XAllocColor (dpy, cmap, &colors[i + j]))
580 fprintf (stderr, "%s: allocated %d of %d colors for cubic map\n",
581 progname, allocated, cells);
585 /* Find the pixel index that is closest to the given color
586 (using linear distance in RGB space -- which is far from the best way.)
588 #### Duplicated in utils/grabscreen.c
591 find_closest_pixel (XColor *colors, int ncolors,
592 unsigned long r, unsigned long g, unsigned long b)
594 unsigned long distance = ~0;
599 for (i = 0; i < ncolors; i++)
604 rd = r - colors[i].red;
605 gd = g - colors[i].green;
606 bd = b - colors[i].blue;
607 if (rd < 0) rd = -rd;
608 if (gd < 0) gd = -gd;
609 if (bd < 0) bd = -bd;
610 d = (rd << 1) + (gd << 2) + bd;
625 /* Given an XImage with 8-bit or 12-bit RGB data, convert it to be
626 displayable with the given X colormap. The farther from a perfect
627 color cube the contents of the colormap are, the lossier the
628 transformation will be. No dithering is done.
630 #### Duplicated in utils/grabscreen.c
633 remap_image (Screen *screen, Colormap cmap, XImage *image, Bool verbose_p)
635 Display *dpy = DisplayOfScreen (screen);
636 unsigned long map[4097];
641 if (image->depth == 8)
643 else if (image->depth == 12)
648 memset(map, -1, sizeof(*map));
649 memset(colors, -1, sizeof(*colors));
651 for (i = 0; i < cells; i++)
653 XQueryColors (dpy, cmap, colors, cells);
656 fprintf(stderr, "%s: building color cube for %d bit image\n",
657 progname, image->depth);
659 for (i = 0; i < cells; i++)
661 unsigned short r, g, b;
665 /* "RRR GGG BB" In an 8 bit map. Convert that to
666 "RRR RRR RR" "GGG GGG GG" "BB BB BB BB" to give
672 r = ((r << 13) | (r << 10) | (r << 7) | (r << 4) | (r << 1));
673 g = ((g << 13) | (g << 10) | (g << 7) | (g << 4) | (g << 1));
674 b = ((b << 14) | (b << 12) | (b << 10) | (b << 8) |
675 (b << 6) | (b << 4) | (b << 2) | b);
679 /* "RRRR GGGG BBBB" In a 12 bit map. Convert that to
680 "RRRR RRRR" "GGGG GGGG" "BBBB BBBB" to give an even
683 g = (i & 0x0F0) >> 4;
684 b = (i & 0xF00) >> 8;
686 r = (r << 12) | (r << 8) | (r << 4) | r;
687 g = (g << 12) | (g << 8) | (g << 4) | g;
688 b = (b << 12) | (b << 8) | (b << 4) | b;
691 map[i] = find_closest_pixel (colors, cells, r, g, b);
695 fprintf(stderr, "%s: remapping colors in %d bit image\n",
696 progname, image->depth);
698 for (y = 0; y < image->height; y++)
699 for (x = 0; x < image->width; x++)
701 unsigned long pixel = XGetPixel(image, x, y);
702 if (pixel >= cells) abort();
703 XPutPixel(image, x, y, map[pixel]);
708 /* If the file has a PPM (P6) on it, read it and return an XImage.
709 Otherwise, rewind the fd back to the beginning, and return 0.
712 maybe_read_ppm (Screen *screen, Visual *visual,
713 const char *filename, FILE *in, Bool verbose_p)
715 Display *dpy = DisplayOfScreen (screen);
716 int depth = visual_depth (screen, visual);
722 int x, y, w, h, maxval;
725 if (fstat (fileno (in), &st))
729 buf = (char *) malloc (bufsiz + 1);
732 fprintf (stderr, "%s: out of memory loading %d byte PPM file %s\n",
733 progname, bufsiz, filename);
737 if (! (s = fgets (buf, bufsiz, in))) /* line 1 */
740 if (!strncmp (buf, "\107\111", 2))
742 fprintf (stderr, "%s: %s: sorry, GIF files not supported"
743 " when compiled with JPEGlib instead of GDK_Pixbuf.\n",
747 else if (!strncmp (buf, "\211\120", 2))
749 fprintf (stderr, "%s: %s: sorry, PNG files not supported"
750 " when compiled with JPEGlib instead of GDK_Pixbuf.\n",
755 if (strncmp (s, "P6", 2))
758 if (! (s = fgets (buf, bufsiz, in))) /* line 2 */
760 if (2 != sscanf (s, " %d %d %c", &w, &h, &dummy))
762 fprintf (stderr, "%s: %s: invalid PPM (line 2)\n", progname, filename);
766 if (! (s = fgets (buf, bufsiz, in))) /* line 3 */
768 if (1 != sscanf (s, " %d %c", &maxval, &dummy))
770 fprintf (stderr, "%s: %s: invalid PPM (line 3)\n", progname, filename);
775 fprintf (stderr, "%s: %s: unparsable PPM: maxval is %d\n",
776 progname, filename, maxval);
780 ximage = XCreateImage (dpy, visual, depth, ZPixmap, 0, 0,
783 ximage->data = (char *) calloc (ximage->height, ximage->bytes_per_line);
784 if (!ximage || !ximage->data)
786 fprintf (stderr, "%s: out of memory loading %dx%d PPM file %s\n",
787 progname, ximage->width, ximage->height, filename);
793 while ((i = fread (s, 1, j, in)) > 0)
797 for (y = 0; y < ximage->height; y++)
798 for (x = 0; x < ximage->width; x++)
800 unsigned char r = buf[i++];
801 unsigned char g = buf[i++];
802 unsigned char b = buf[i++];
806 pixel = (r << 16) | (g << 8) | b;
808 pixel = ((r >> 5) | ((g >> 5) << 3) | ((b >> 6) << 6));
809 else if (depth == 12)
810 pixel = ((r >> 4) | ((g >> 4) << 4) | ((b >> 4) << 8));
811 else if (depth == 16 || depth == 15)
812 pixel = (((r >> 3) << 10) | ((g >> 3) << 5) | ((b >> 3)));
816 XPutPixel (ximage, x, y, pixel);
824 if (ximage && ximage->data)
829 if (ximage) XDestroyImage (ximage);
830 fseek (in, 0, SEEK_SET);
836 struct jpeg_error_mgr pub; /* this is what passes for subclassing in C */
837 const char *filename;
842 } getimg_jpg_error_mgr;
846 jpg_output_message (j_common_ptr cinfo)
848 getimg_jpg_error_mgr *err = (getimg_jpg_error_mgr *) cinfo->err;
849 char buf[JMSG_LENGTH_MAX];
850 cinfo->err->format_message (cinfo, buf);
851 fprintf (stderr, "%s: %s: %s\n", progname, err->filename, buf);
856 jpg_error_exit (j_common_ptr cinfo)
858 getimg_jpg_error_mgr *err = (getimg_jpg_error_mgr *) cinfo->err;
859 cinfo->err->output_message (cinfo);
860 draw_colorbars (err->screen, err->visual, err->drawable, err->cmap,
862 XSync (DisplayOfScreen (err->screen), False);
867 /* Reads a JPEG file, returns an RGB XImage of it.
870 read_jpeg_ximage (Screen *screen, Visual *visual, Drawable drawable,
871 Colormap cmap, const char *filename, Bool verbose_p)
873 Display *dpy = DisplayOfScreen (screen);
874 int depth = visual_depth (screen, visual);
878 struct jpeg_decompress_struct cinfo;
879 getimg_jpg_error_mgr jerr;
880 JSAMPARRAY scanbuf = 0;
883 jerr.filename = filename;
884 jerr.screen = screen;
885 jerr.visual = visual;
886 jerr.drawable = drawable;
889 if (! (depth >= 15 || depth == 12 || depth == 8))
891 fprintf (stderr, "%s: unsupported depth: %d\n", progname, depth);
895 in = fopen (filename, "rb");
898 fprintf (stderr, "%s: %s: unreadable\n", progname, filename);
902 /* Check to see if it's a PPM, and if so, read that instead of using
903 the JPEG library. Yeah, this is all modular and stuff.
905 if ((ximage = maybe_read_ppm (screen, visual, filename, in, verbose_p)))
911 cinfo.err = jpeg_std_error (&jerr.pub);
912 jerr.pub.output_message = jpg_output_message;
913 jerr.pub.error_exit = jpg_error_exit;
915 jpeg_create_decompress (&cinfo);
916 jpeg_stdio_src (&cinfo, in);
917 jpeg_read_header (&cinfo, TRUE);
919 /* set some decode parameters */
920 cinfo.out_color_space = JCS_RGB;
921 cinfo.quantize_colors = FALSE;
923 jpeg_start_decompress (&cinfo);
925 ximage = XCreateImage (dpy, visual, depth, ZPixmap, 0, 0,
926 cinfo.output_width, cinfo.output_height,
929 ximage->data = (char *) calloc (ximage->height, ximage->bytes_per_line);
931 if (ximage && ximage->data)
932 scanbuf = (*cinfo.mem->alloc_sarray) ((j_common_ptr) &cinfo, JPOOL_IMAGE,
933 cinfo.rec_outbuf_height *
935 cinfo.output_components,
937 if (!ximage || !ximage->data || !scanbuf)
939 fprintf (stderr, "%s: out of memory loading %dx%d file %s\n",
940 progname, ximage->width, ximage->height, filename);
945 while (cinfo.output_scanline < cinfo.output_height)
947 int n = jpeg_read_scanlines (&cinfo, scanbuf, 1);
949 for (i = 0; i < n; i++)
952 for (x = 0; x < ximage->width; x++)
954 int j = x * cinfo.output_components;
955 unsigned char r = scanbuf[i][j];
956 unsigned char g = scanbuf[i][j+1];
957 unsigned char b = scanbuf[i][j+2];
961 pixel = (r << 16) | (g << 8) | b;
963 pixel = ((r >> 5) | ((g >> 5) << 3) | ((b >> 6) << 6));
964 else if (depth == 12)
965 pixel = ((r >> 4) | ((g >> 4) << 4) | ((b >> 4) << 8));
966 else if (depth == 15)
967 /* Gah! I don't understand why these are in the other
969 pixel = (((r >> 3) << 10) | ((g >> 3) << 5) | ((b >> 3)));
970 else if (depth == 16)
971 pixel = (((r >> 3) << 11) | ((g >> 2) << 5) | ((b >> 3)));
975 XPutPixel (ximage, x, y, pixel);
981 if (cinfo.output_scanline < cinfo.output_height)
982 /* don't goto FAIL -- we might have viewable partial data. */
983 jpeg_abort_decompress (&cinfo);
985 jpeg_finish_decompress (&cinfo);
987 jpeg_destroy_decompress (&cinfo);
995 if (ximage && ximage->data)
1000 if (ximage) XDestroyImage (ximage);
1001 if (scanbuf) free (scanbuf);
1006 /* Reads the given image file and renders it on the Drawable, using JPEG lib.
1007 Returns False if it fails.
1010 read_file_jpeglib (Screen *screen, Window window, Drawable drawable,
1011 const char *filename, Bool verbose_p,
1012 XRectangle *geom_ret)
1014 Display *dpy = DisplayOfScreen (screen);
1019 unsigned int win_width, win_height, win_depth;
1020 int srcx, srcy, destx, desty, w2, h2;
1022 /* Find the size of the Drawable, and the Visual/Colormap of the Window. */
1027 XWindowAttributes xgwa;
1028 XGetWindowAttributes (dpy, window, &xgwa);
1029 visual = xgwa.visual;
1030 cmap = xgwa.colormap;
1031 XGetGeometry (dpy, drawable,
1032 &root, &x, &y, &win_width, &win_height, &bw, &win_depth);
1035 /* Make sure we're not on some weirdo visual...
1037 class = visual_class (screen, visual);
1038 depth = visual_depth (screen, visual);
1039 if ((class == PseudoColor || class == DirectColor) &&
1040 (depth != 8 && depth != 12))
1042 fprintf (stderr, "%s: Pseudo/DirectColor depth %d unsupported\n",
1049 ximage = read_jpeg_ximage (screen, visual, drawable, cmap,
1050 filename, verbose_p);
1051 if (!ximage) return False;
1053 /* Scale it, if necessary...
1055 compute_image_scaling (ximage->width, ximage->height,
1056 win_width, win_height, verbose_p,
1057 &srcx, &srcy, &destx, &desty, &w2, &h2);
1058 if (ximage->width != w2 || ximage->height != h2)
1059 if (! scale_ximage (screen, visual, ximage, w2, h2))
1062 /* Allocate a colormap, if we need to...
1064 if (class == PseudoColor || class == DirectColor)
1066 allocate_cubic_colormap (screen, visual, cmap, verbose_p);
1067 remap_image (screen, cmap, ximage, verbose_p);
1070 /* Finally, put the resized image on the window.
1076 /* If we're rendering onto the root window (and it's not the xscreensaver
1077 pseudo-root) then put the image in the window's background. Otherwise,
1078 just paint the image onto the window.
1080 if (window == drawable && root_window_p (screen, window))
1082 Pixmap bg = XCreatePixmap (dpy, window,
1083 win_width, win_height, win_depth);
1084 gcv.foreground = BlackPixelOfScreen (screen);
1085 gc = XCreateGC (dpy, drawable, GCForeground, &gcv);
1086 XFillRectangle (dpy, bg, gc, 0, 0, win_width, win_height);
1087 XPutImage (dpy, bg, gc, ximage,
1088 srcx, srcy, destx, desty, ximage->width, ximage->height);
1089 XSetWindowBackgroundPixmap (dpy, window, bg);
1090 XClearWindow (dpy, window);
1094 gc = XCreateGC (dpy, drawable, 0, &gcv);
1095 clear_drawable (screen, drawable);
1096 XPutImage (dpy, drawable, gc, ximage,
1097 srcx, srcy, destx, desty, ximage->width, ximage->height);
1105 geom_ret->x = destx;
1106 geom_ret->y = desty;
1107 geom_ret->width = ximage->width;
1108 geom_ret->height = ximage->height;
1111 free (ximage->data);
1113 XDestroyImage (ximage);
1118 #endif /* HAVE_JPEGLIB */
1121 /* Reads the given image file and renders it on the Drawable.
1122 Returns False if it fails.
1125 display_file (Screen *screen, Window window, Drawable drawable,
1126 const char *filename, Bool verbose_p,
1127 XRectangle *geom_ret)
1130 fprintf (stderr, "%s: loading \"%s\"\n", progname, filename);
1132 # if defined(HAVE_GDK_PIXBUF)
1133 if (read_file_gdk (screen, window, drawable, filename, verbose_p, geom_ret))
1135 # elif defined(HAVE_JPEGLIB)
1136 if (read_file_jpeglib (screen, window, drawable, filename, verbose_p,
1139 # else /* !(HAVE_GDK_PIXBUF || HAVE_JPEGLIB) */
1140 /* shouldn't get here if we have no image-loading methods available. */
1142 # endif /* !(HAVE_GDK_PIXBUF || HAVE_JPEGLIB) */
1148 /* Invokes a sub-process and returns its output (presumably, a file to
1149 load.) Free the string when done. 'grab_type' controls which program
1150 to run. Returned pathname may be relative to 'directory', or absolute.
1153 get_filename_1 (Screen *screen, const char *directory, grab_type type,
1156 Display *dpy = DisplayOfScreen (screen);
1167 av[ac++] = GETIMAGE_FILE_PROGRAM;
1169 av[ac++] = "--verbose";
1170 av[ac++] = "--name";
1171 av[ac++] = (char *) directory;
1175 av[ac++] = GETIMAGE_VIDEO_PROGRAM;
1177 av[ac++] = "--verbose";
1178 av[ac++] = "--name";
1181 # ifdef USE_EXTERNAL_SCREEN_GRABBER
1183 av[ac++] = GETIMAGE_SCREEN_PROGRAM;
1185 av[ac++] = "--verbose";
1186 av[ac++] = "--name";
1198 fprintf (stderr, "%s: executing:", progname);
1199 for (i = 0; i < ac; i++)
1200 fprintf (stderr, " %s", av[i]);
1201 fprintf (stderr, "\n");
1206 sprintf (buf, "%s: error creating pipe", progname);
1214 switch ((int) (forked = fork ()))
1218 sprintf (buf, "%s: couldn't fork", progname);
1226 close (in); /* don't need this one */
1227 close (ConnectionNumber (dpy)); /* close display fd */
1229 if (dup2 (out, stdout_fd) < 0) /* pipe stdout */
1231 sprintf (buf, "%s: could not dup() a new stdout", progname);
1232 exit (-1); /* exits fork */
1235 execvp (av[0], av); /* shouldn't return. */
1236 exit (-1); /* exits fork */
1242 int wait_status = 0;
1243 FILE *f = fdopen (in, "r");
1247 close (out); /* don't need this one */
1249 if (! fgets (buf, sizeof(buf)-1, f))
1253 /* Wait for the child to die. */
1254 waitpid (-1, &wait_status, 0);
1257 while (L && buf[L-1] == '\n')
1267 /* Program returned path relative to directory. Prepend dir
1268 to buf so that we can properly stat it. */
1269 strcpy (buf, directory);
1270 if (directory[strlen(directory)-1] != '/')
1277 fprintf (stderr, "%s: file does not exist: \"%s\"\n",
1291 /* Returns a pathname to an image file. Free the string when you're done.
1294 get_filename (Screen *screen, const char *directory, Bool verbose_p)
1296 return get_filename_1 (screen, directory, GRAB_FILE, verbose_p);
1300 /* Grabs a video frame to a file, and returns a pathname to that file.
1301 Delete that file when you are done with it (and free the string.)
1304 get_video_filename (Screen *screen, Bool verbose_p)
1306 return get_filename_1 (screen, 0, GRAB_VIDEO, verbose_p);
1309 /* Grabs a desktop image to a file, and returns a pathname to that file.
1310 Delete that file when you are done with it (and free the string.)
1312 # ifdef USE_EXTERNAL_SCREEN_GRABBER
1314 get_desktop_filename (Screen *screen, Bool verbose_p)
1316 return get_filename_1 (screen, 0, GRAB_DESK, verbose_p);
1318 #endif /* USE_EXTERNAL_SCREEN_GRABBER */
1321 /* Grabs a video frame, and renders it on the Drawable.
1322 Returns False if it fails;
1325 display_video (Screen *screen, Window window, Drawable drawable,
1326 Bool verbose_p, XRectangle *geom_ret)
1328 char *filename = get_video_filename (screen, verbose_p);
1334 fprintf (stderr, "%s: video grab failed.\n", progname);
1338 status = display_file (screen, window, drawable, filename, verbose_p,
1341 if (unlink (filename))
1344 sprintf (buf, "%s: rm %.100s", progname, filename);
1348 fprintf (stderr, "%s: rm %s\n", progname, filename);
1350 if (filename) free (filename);
1355 /* Grabs a desktop screen shot onto the window and the drawable.
1356 If the window and drawable are not the same size, the image in
1357 the drawable is scaled to fit.
1358 Returns False if it fails.
1361 display_desktop (Screen *screen, Window window, Drawable drawable,
1362 Bool verbose_p, XRectangle *geom_ret)
1364 # ifdef USE_EXTERNAL_SCREEN_GRABBER
1366 Display *dpy = DisplayOfScreen (screen);
1367 Bool top_p = top_level_window_p (screen, window);
1374 fprintf (stderr, "%s: unmapping 0x%lx.\n", progname,
1375 (unsigned long) window);
1376 XUnmapWindow (dpy, window);
1380 filename = get_desktop_filename (screen, verbose_p);
1385 fprintf (stderr, "%s: mapping 0x%lx.\n", progname,
1386 (unsigned long) window);
1387 XMapRaised (dpy, window);
1394 fprintf (stderr, "%s: desktop grab failed.\n", progname);
1398 status = display_file (screen, window, drawable, filename, verbose_p,
1401 if (unlink (filename))
1404 sprintf (buf, "%s: rm %.100s", progname, filename);
1408 fprintf (stderr, "%s: rm %s\n", progname, filename);
1410 if (filename) free (filename);
1413 # else /* !USE_EXTERNAL_SCREEN_GRABBER */
1415 Display *dpy = DisplayOfScreen (screen);
1417 XWindowAttributes xgwa;
1420 unsigned int pw, ph, pbw, pd;
1421 int srcx, srcy, destx, desty, w2, h2;
1425 fprintf (stderr, "%s: grabbing desktop image\n", progname);
1426 grabscreen_verbose();
1429 XGetWindowAttributes (dpy, window, &xgwa);
1430 XGetGeometry (dpy, drawable, &root, &px, &py, &pw, &ph, &pbw, &pd);
1432 grab_screen_image_internal (screen, window);
1434 compute_image_scaling (xgwa.width, xgwa.height,
1436 &srcx, &srcy, &destx, &desty, &w2, &h2);
1438 if (pw == w2 && ph == h2) /* it fits -- just copy server-side pixmaps */
1440 GC gc = XCreateGC (dpy, drawable, 0, &gcv);
1441 XCopyArea (dpy, window, drawable, gc,
1442 0, 0, xgwa.width, xgwa.height, 0, 0);
1445 else /* size mismatch -- must scale client-side images to fit drawable */
1449 XErrorHandler old_handler;
1452 old_handler = XSetErrorHandler (ignore_badmatch_ehandler);
1453 error_handler_hit_p = False;
1455 /* This can return BadMatch if the window is not fully on screen.
1456 Trap that error and return color bars in that case.
1457 (Note that this only happens with XGetImage, not with XCopyArea:
1458 yet another totally gratuitous inconsistency in X, thanks.)
1460 ximage = XGetImage (dpy, window, 0, 0, xgwa.width, xgwa.height,
1464 XSetErrorHandler (old_handler);
1467 if (error_handler_hit_p)
1471 fprintf (stderr, "%s: BadMatch reading window 0x%x contents!\n",
1472 progname, (unsigned int) window);
1476 !scale_ximage (xgwa.screen, xgwa.visual, ximage, w2, h2))
1479 gc = XCreateGC (dpy, drawable, 0, &gcv);
1480 clear_drawable (screen, drawable);
1481 XPutImage (dpy, drawable, gc, ximage,
1482 srcx, srcy, destx, desty, ximage->width, ximage->height);
1483 XDestroyImage (ximage);
1489 geom_ret->x = destx;
1490 geom_ret->y = desty;
1491 geom_ret->width = w2;
1492 geom_ret->height = h2;
1498 # endif /* !USE_EXTERNAL_SCREEN_GRABBER */
1502 /* Whether the given Drawable is unreasonably small.
1505 drawable_miniscule_p (Display *dpy, Drawable drawable)
1509 unsigned int bw, d, w = 0, h = 0;
1510 XGetGeometry (dpy, drawable, &root, &xx, &yy, &w, &h, &bw, &d);
1511 return (w < 32 || h < 30);
1515 /* Grabs an image (from a file, video, or the desktop) and renders it on
1516 the Drawable. If `file' is specified, always use that file. Otherwise,
1517 select randomly, based on the other arguments.
1520 get_image (Screen *screen,
1521 Window window, Drawable drawable,
1529 Display *dpy = DisplayOfScreen (screen);
1530 grab_type which = GRAB_BARS;
1532 const char *file_prop = 0;
1534 XRectangle geom = { 0, 0, 0, 0 };
1536 if (! drawable_window_p (dpy, window))
1538 fprintf (stderr, "%s: 0x%lx is a pixmap, not a window!\n",
1539 progname, (unsigned long) window);
1543 /* Make sure the Screen and the Window correspond. */
1545 XWindowAttributes xgwa;
1546 XGetWindowAttributes (dpy, window, &xgwa);
1547 screen = xgwa.screen;
1550 if (file && stat (file, &st))
1552 fprintf (stderr, "%s: file \"%s\" does not exist\n", progname, file);
1558 fprintf (stderr, "%s: grabDesktopImages: %s\n",
1559 progname, desk_p ? "True" : "False");
1560 fprintf (stderr, "%s: grabVideoFrames: %s\n",
1561 progname, video_p ? "True" : "False");
1562 fprintf (stderr, "%s: chooseRandomImages: %s\n",
1563 progname, image_p ? "True" : "False");
1564 fprintf (stderr, "%s: imageDirectory: %s\n",
1565 progname, (file ? file : dir ? dir : ""));
1568 # if !(defined(HAVE_GDK_PIXBUF) || defined(HAVE_JPEGLIB))
1569 image_p = False; /* can't load images from files... */
1570 # ifdef USE_EXTERNAL_SCREEN_GRABBER
1571 desk_p = False; /* ...or from desktops grabbed to files. */
1577 "%s: image file loading not available at compile-time\n",
1579 fprintf (stderr, "%s: can't load \"%s\"\n", progname, file);
1582 # endif /* !(HAVE_GDK_PIXBUF || HAVE_JPEGLIB) */
1590 else if (!dir || !*dir)
1592 if (verbose_p && image_p)
1594 "%s: no imageDirectory: turning off chooseRandomImages.\n",
1599 /* If the target drawable is really small, no good can come of that.
1600 Always do colorbars in that case.
1602 if (drawable_miniscule_p (dpy, drawable))
1610 # error Error! This file definitely needs vroot.h!
1613 /* We can grab desktop images (using the normal X11 method) if:
1614 - the window is the real root window;
1615 - the window is a toplevel window.
1616 We cannot grab desktop images that way if:
1617 - the window is a non-top-level window.
1619 Under X11 on MacOS, desktops are just like loaded image files.
1620 Under Cocoa on MacOS, this code is not used at all.
1622 # ifndef USE_EXTERNAL_SCREEN_GRABBER
1625 if (!top_level_window_p (screen, window))
1630 "%s: 0x%x not top-level: turning off grabDesktopImages.\n",
1631 progname, (unsigned int) window);
1634 # endif /* !USE_EXTERNAL_SCREEN_GRABBER */
1636 if (! (desk_p || video_p || image_p))
1642 /* Loop until we get one that's permitted.
1643 If files or video are permitted, do them more often
1646 D+V+I: 10% + 45% + 45%.
1652 n = (random() % 100);
1653 if (++i > 300) abort();
1654 else if (desk_p && n < 10) which = GRAB_DESK; /* 10% */
1655 else if (video_p && n < 55) which = GRAB_VIDEO; /* 45% */
1656 else if (image_p) which = GRAB_FILE; /* 45% */
1661 /* If we're to search a directory to find an image file, do so now.
1663 if (which == GRAB_FILE && !file)
1665 file = get_filename (screen, dir, verbose_p);
1670 fprintf (stderr, "%s: no image files found.\n", progname);
1674 /* Now actually render something.
1680 XWindowAttributes xgwa;
1683 fprintf (stderr, "%s: drawing colorbars.\n", progname);
1684 XGetWindowAttributes (dpy, window, &xgwa);
1685 draw_colorbars (screen, xgwa.visual, drawable, xgwa.colormap,
1688 if (! file_prop) file_prop = "";
1694 if (! display_desktop (screen, window, drawable, verbose_p, &geom))
1696 file_prop = "desktop";
1700 if (*file && *file != '/') /* pathname is relative to dir. */
1702 if (absfile) free (absfile);
1703 absfile = malloc (strlen(dir) + strlen(file) + 10);
1704 strcpy (absfile, dir);
1705 if (dir[strlen(dir)-1] != '/')
1706 strcat (absfile, "/");
1707 strcat (absfile, file);
1709 if (! display_file (screen, window, drawable,
1710 (absfile ? absfile : file),
1717 if (! display_video (screen, window, drawable, verbose_p, &geom))
1719 file_prop = "video";
1728 Atom a = XInternAtom (dpy, XA_XSCREENSAVER_IMAGE_FILENAME, False);
1729 if (file_prop && *file_prop)
1731 char *f2 = strdup (file_prop);
1733 /* Take the extension off of the file name. */
1734 /* Duplicated in utils/grabclient.c. */
1735 char *slash = strrchr (f2, '/');
1736 char *dot = strrchr ((slash ? slash : f2), '.');
1738 /* Replace slashes with newlines */
1739 /* while ((dot = strchr(f2, '/'))) *dot = '\n'; */
1740 /* Replace slashes with spaces */
1741 /* while ((dot = strchr(f2, '/'))) *dot = ' '; */
1743 XChangeProperty (dpy, window, a, XA_STRING, 8, PropModeReplace,
1744 (unsigned char *) f2, strlen(f2));
1748 XDeleteProperty (dpy, window, a);
1750 a = XInternAtom (dpy, XA_XSCREENSAVER_IMAGE_GEOMETRY, False);
1754 sprintf (gstr, "%dx%d+%d+%d", geom.width, geom.height, geom.x, geom.y);
1755 XChangeProperty (dpy, window, a, XA_STRING, 8, PropModeReplace,
1756 (unsigned char *) gstr, strlen (gstr));
1759 XDeleteProperty (dpy, window, a);
1762 if (absfile) free (absfile);
1769 mapper (XrmDatabase *db, XrmBindingList bindings, XrmQuarkList quarks,
1770 XrmRepresentation *type, XrmValue *value, XPointer closure)
1773 for (i = 0; quarks[i]; i++)
1775 if (bindings[i] == XrmBindTightly)
1776 fprintf (stderr, (i == 0 ? "" : "."));
1777 else if (bindings[i] == XrmBindLoosely)
1778 fprintf (stderr, "*");
1780 fprintf (stderr, " ??? ");
1781 fprintf(stderr, "%s", XrmQuarkToString (quarks[i]));
1784 fprintf (stderr, ": %s\n", (char *) value->addr);
1791 #define USAGE "usage: %s [ -options... ] window-id [pixmap-id]\n" \
1795 " %s puts an image on the given window or pixmap.\n" \
1797 " It is used by those xscreensaver demos that operate on images.\n" \
1798 " The image may be a file loaded from disk, a frame grabbed from\n" \
1799 " the system's video camera, or a screenshot of the desktop,\n" \
1800 " depending on command-line options or the ~/.xscreensaver file.\n" \
1802 " Options include:\n" \
1804 " -display host:dpy.screen which display to use\n" \
1805 " -root draw to the root window\n" \
1806 " -verbose print diagnostics\n" \
1807 " -images / -no-images whether to allow image file loading\n" \
1808 " -video / -no-video whether to allow video grabs\n" \
1809 " -desktop / -no-desktop whether to allow desktop screen grabs\n"\
1810 " -directory <path> where to find image files to load\n" \
1811 " -file <filename> load this image file\n" \
1813 " The XScreenSaver Control Panel (xscreensaver-demo) lets you set the\n"\
1814 " defaults for these options in your ~/.xscreensaver file.\n" \
1818 main (int argc, char **argv)
1820 saver_preferences P;
1824 char *oprogname = progname;
1828 Window window = (Window) 0;
1829 Drawable drawable = (Drawable) 0;
1830 const char *window_str = 0;
1831 const char *drawable_str = 0;
1836 s = strrchr (progname, '/');
1837 if (s) progname = s+1;
1838 oprogname = progname;
1840 /* half-assed way of avoiding buffer-overrun attacks. */
1841 if (strlen (progname) >= 100) progname[100] = 0;
1844 # error Error! This file definitely needs vroot.h!
1847 /* Get the version number, for error messages. */
1849 char *v = (char *) strdup(strchr(screensaver_id, ' '));
1850 char *s1, *s2, *s3, *s4;
1851 s1 = (char *) strchr(v, ' '); s1++;
1852 s2 = (char *) strchr(s1, ' ');
1853 s3 = (char *) strchr(v, '('); s3++;
1854 s4 = (char *) strchr(s3, ')');
1857 sprintf (version, "Part of XScreenSaver %s -- %s.", s1, s3);
1861 /* We must read exactly the same resources as xscreensaver.
1862 That means we must have both the same progclass *and* progname,
1863 at least as far as the resource database is concerned. So,
1864 put "xscreensaver" in argv[0] while initializing Xt.
1866 progname = argv[0] = "xscreensaver";
1868 /* allow one dash or two. */
1869 for (i = 1; i < argc; i++)
1870 if (argv[i][0] == '-' && argv[i][1] == '-') argv[i]++;
1872 toplevel = XtAppInitialize (&app, progclass, 0, 0, &argc, argv,
1874 dpy = XtDisplay (toplevel);
1875 screen = XtScreen (toplevel);
1876 db = XtDatabase (dpy);
1877 XtGetApplicationNameAndClass (dpy, &s, &progclass);
1878 XSetErrorHandler (x_ehandler);
1881 /* Randomize -- only need to do this here because this program
1882 doesn't use the `screenhack.h' or `lockmore.h' APIs. */
1883 # undef ya_rand_init
1886 memset (&P, 0, sizeof(P));
1888 load_init_file (dpy, &P);
1890 progname = argv[0] = oprogname;
1892 for (i = 1; i < argc; i++)
1897 /* Have to re-process these, or else the .xscreensaver file
1898 has priority over the command line...
1900 if (!strcmp (argv[i], "-v") || !strcmp (argv[i], "-verbose"))
1902 else if (!strcmp (argv[i], "-desktop")) P.grab_desktop_p = True;
1903 else if (!strcmp (argv[i], "-no-desktop")) P.grab_desktop_p = False;
1904 else if (!strcmp (argv[i], "-video")) P.grab_video_p = True;
1905 else if (!strcmp (argv[i], "-no-video")) P.grab_video_p = False;
1906 else if (!strcmp (argv[i], "-images")) P.random_image_p = True;
1907 else if (!strcmp (argv[i], "-no-images")) P.random_image_p = False;
1908 else if (!strcmp (argv[i], "-file")) file = argv[++i];
1909 else if (!strcmp (argv[i], "-directory") || !strcmp (argv[i], "-dir"))
1910 P.image_directory = argv[++i];
1911 else if (!strcmp (argv[i], "-root") || !strcmp (argv[i], "root"))
1915 fprintf (stderr, "%s: both %s and %s specified?\n",
1916 progname, argv[i], window_str);
1919 window_str = argv[i];
1920 window = VirtualRootWindowOfScreen (screen);
1922 else if ((1 == sscanf (argv[i], " 0x%lx %c", &w, &dummy) ||
1923 1 == sscanf (argv[i], " %lu %c", &w, &dummy)) &&
1928 fprintf (stderr, "%s: both %s and %s specified?\n",
1929 progname, drawable_str, argv[i]);
1934 drawable_str = argv[i];
1935 drawable = (Drawable) w;
1939 window_str = argv[i];
1940 window = (Window) w;
1945 if (argv[i][0] == '-')
1946 fprintf (stderr, "\n%s: unknown option \"%s\"\n",
1949 fprintf (stderr, "\n%s: unparsable window/pixmap ID: \"%s\"\n",
1953 __extension__ /* don't warn about "string length is greater than
1954 the length ISO C89 compilers are required to
1955 support" in the usage string... */
1957 fprintf (stderr, USAGE, progname, version, progname);
1964 fprintf (stderr, "\n%s: no window ID specified!\n", progname);
1970 if (P.verbose_p) /* Print out all the resources we can see. */
1972 XrmName name = { 0 };
1973 XrmClass class = { 0 };
1975 XrmEnumerateDatabase (db, &name, &class, XrmEnumAllLevels, mapper,
1976 (XtPointer) &count);
1980 if (!window) abort();
1981 if (!drawable) drawable = window;
1983 get_image (screen, window, drawable, P.verbose_p,
1984 P.grab_desktop_p, P.grab_video_p, P.random_image_p,
1985 P.image_directory, file);