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);
316 colorbars (Screen *screen, Visual *visual, Drawable drawable, Colormap cmap)
319 Pixmap logo = xscreensaver_logo (screen, visual, drawable, cmap,
320 BlackPixelOfScreen (screen),
322 draw_colorbars (screen, visual, drawable, cmap, 0, 0, 0, 0, logo, mask);
323 XFreePixmap (DisplayOfScreen (screen), logo);
324 XFreePixmap (DisplayOfScreen (screen), mask);
328 /* Scales an XImage, modifying it in place.
329 This doesn't do dithering or smoothing, so it might have artifacts.
330 If out of memory, returns False, and the XImage will have been
333 #if !defined(USE_EXTERNAL_SCREEN_GRABBER) || defined(HAVE_JPEGLIB)
335 scale_ximage (Screen *screen, Visual *visual,
336 XImage *ximage, int new_width, int new_height)
338 Display *dpy = DisplayOfScreen (screen);
339 int depth = visual_depth (screen, visual);
341 double xscale, yscale;
343 XImage *ximage2 = XCreateImage (dpy, visual, depth,
345 new_width, new_height, 8, 0);
346 ximage2->data = (char *) calloc (ximage2->height, ximage2->bytes_per_line);
350 fprintf (stderr, "%s: out of memory scaling %dx%d image to %dx%d\n",
352 ximage->width, ximage->height,
353 ximage2->width, ximage2->height);
354 if (ximage->data) free (ximage->data);
355 if (ximage2->data) free (ximage2->data);
358 XDestroyImage (ximage);
359 XDestroyImage (ximage2);
363 /* Brute force scaling... */
364 xscale = (double) ximage->width / ximage2->width;
365 yscale = (double) ximage->height / ximage2->height;
366 for (y = 0; y < ximage2->height; y++)
367 for (x = 0; x < ximage2->width; x++)
368 XPutPixel (ximage2, x, y,
369 XGetPixel (ximage, x * xscale, y * yscale));
374 (*ximage) = (*ximage2);
377 XDestroyImage (ximage2);
381 #endif /* !USE_EXTERNAL_SCREEN_GRABBER || HAVE_JPEGLIB */
384 #ifdef HAVE_GDK_PIXBUF
386 /* Reads the given image file and renders it on the Drawable, using GDK.
387 Returns False if it fails.
390 read_file_gdk (Screen *screen, Window window, Drawable drawable,
391 const char *filename, Bool verbose_p,
392 XRectangle *geom_ret)
395 Display *dpy = DisplayOfScreen (screen);
396 unsigned int win_width, win_height, win_depth;
399 # endif /* HAVE_GTK2 */
401 /* Find the size of the Drawable. */
406 XGetGeometry (dpy, drawable,
407 &root, &x, &y, &win_width, &win_height, &bw, &win_depth);
410 gdk_pixbuf_xlib_init_with_depth (dpy, screen_number (screen), win_depth);
412 # if !GLIB_CHECK_VERSION(2, 36 ,0)
415 # else /* !HAVE_GTK2 */
416 xlib_rgb_init (dpy, screen);
417 # endif /* !HAVE_GTK2 */
419 pb = gdk_pixbuf_new_from_file (filename
422 # endif /* HAVE_GTK2 */
427 fprintf (stderr, "%s: unable to load \"%s\"\n", progname, filename);
429 if (gerr && gerr->message && *gerr->message)
430 fprintf (stderr, "%s: reason: %s\n", progname, gerr->message);
431 # endif /* HAVE_GTK2 */
436 int w = gdk_pixbuf_get_width (pb);
437 int h = gdk_pixbuf_get_height (pb);
438 int srcx, srcy, destx, desty, w2, h2;
441 # ifdef HAVE_GDK_PIXBUF_APPLY_EMBEDDED_ORIENTATION
445 pb = gdk_pixbuf_apply_embedded_orientation (opb);
446 g_object_unref (opb);
447 w = gdk_pixbuf_get_width (pb);
448 h = gdk_pixbuf_get_height (pb);
449 if (verbose_p && (w != ow || h != oh))
450 fprintf (stderr, "%s: rotated %dx%d to %dx%d\n",
451 progname, ow, oh, w, h);
455 compute_image_scaling (w, h, win_width, win_height, verbose_p,
456 &srcx, &srcy, &destx, &desty, &w2, &h2);
457 if (w != w2 || h != h2)
459 GdkPixbuf *pb2 = gdk_pixbuf_scale_simple (pb, w2, h2,
460 GDK_INTERP_BILINEAR);
469 fprintf (stderr, "%s: out of memory when scaling?\n", progname);
472 /* If we're rendering onto the root window (and it's not the
473 xscreensaver pseudo-root) then put the image in the window's
474 background. Otherwise, just paint the image onto the window.
476 bg_p = (window == drawable && root_window_p (screen, window));
482 drawable = XCreatePixmap (dpy, window,
483 win_width, win_height, win_depth);
484 gcv.foreground = BlackPixelOfScreen (screen);
485 gc = XCreateGC (dpy, drawable, GCForeground, &gcv);
486 XFillRectangle (dpy, drawable, gc, 0, 0, win_width, win_height);
490 clear_drawable (screen, drawable);
492 /* #### Note that this always uses the default colormap! Morons!
493 Owen says that in Gnome 2.0, I should try using
494 gdk_pixbuf_render_pixmap_and_mask_for_colormap() instead.
497 if (srcx > 0) w -= srcx;
498 if (srcy > 0) h -= srcy;
499 gdk_pixbuf_xlib_render_to_drawable_alpha (pb, drawable,
500 srcx, srcy, destx, desty,
502 GDK_PIXBUF_ALPHA_FULL, 127,
503 XLIB_RGB_DITHER_NORMAL,
507 XSetWindowBackgroundPixmap (dpy, window, drawable);
508 XClearWindow (dpy, window);
516 geom_ret->height = h;
524 #endif /* HAVE_GDK_PIXBUF */
530 /* Allocates a colormap that makes a PseudoColor or DirectColor
531 visual behave like a TrueColor visual of the same depth.
533 #### Duplicated in utils/grabscreen.c
536 allocate_cubic_colormap (Screen *screen, Visual *visual, Colormap cmap,
539 Display *dpy = DisplayOfScreen (screen);
540 int nr, ng, nb, cells;
546 depth = visual_depth (screen, visual);
550 case 8: nr = 3; ng = 3; nb = 2; cells = 256; break;
551 case 12: nr = 4; ng = 4; nb = 4; cells = 4096; break;
552 default: abort(); break;
555 memset(colors, 0, sizeof(colors));
556 for (r = 0; r < (1 << nr); r++)
557 for (g = 0; g < (1 << ng); g++)
558 for (b = 0; b < (1 << nb); b++)
560 i = (r | (g << nr) | (b << (nr + ng)));
562 colors[i].flags = DoRed|DoGreen|DoBlue;
565 colors[i].red = ((r << 13) | (r << 10) | (r << 7) |
566 (r << 4) | (r << 1));
567 colors[i].green = ((g << 13) | (g << 10) | (g << 7) |
568 (g << 4) | (g << 1));
569 colors[i].blue = ((b << 14) | (b << 12) | (b << 10) |
570 (b << 8) | (b << 6) | (b << 4) |
575 colors[i].red = (r << 12) | (r << 8) | (r << 4) | r;
576 colors[i].green = (g << 12) | (g << 8) | (g << 4) | g;
577 colors[i].blue = (b << 12) | (b << 8) | (b << 4) | b;
584 int interleave = cells / 8; /* skip around, rather than allocating in
585 order, so that we get better coverage if
586 we can't allocated all of them. */
587 for (j = 0; j < interleave; j++)
588 for (i = 0; i < cells; i += interleave)
589 if (XAllocColor (dpy, cmap, &colors[i + j]))
593 fprintf (stderr, "%s: allocated %d of %d colors for cubic map\n",
594 progname, allocated, cells);
598 /* Find the pixel index that is closest to the given color
599 (using linear distance in RGB space -- which is far from the best way.)
601 #### Duplicated in utils/grabscreen.c
604 find_closest_pixel (XColor *colors, int ncolors,
605 unsigned long r, unsigned long g, unsigned long b)
607 unsigned long distance = ~0;
612 for (i = 0; i < ncolors; i++)
617 rd = r - colors[i].red;
618 gd = g - colors[i].green;
619 bd = b - colors[i].blue;
620 if (rd < 0) rd = -rd;
621 if (gd < 0) gd = -gd;
622 if (bd < 0) bd = -bd;
623 d = (rd << 1) + (gd << 2) + bd;
638 /* Given an XImage with 8-bit or 12-bit RGB data, convert it to be
639 displayable with the given X colormap. The farther from a perfect
640 color cube the contents of the colormap are, the lossier the
641 transformation will be. No dithering is done.
643 #### Duplicated in utils/grabscreen.c
646 remap_image (Screen *screen, Colormap cmap, XImage *image, Bool verbose_p)
648 Display *dpy = DisplayOfScreen (screen);
649 unsigned long map[4097];
654 if (image->depth == 8)
656 else if (image->depth == 12)
661 memset(map, -1, sizeof(*map));
662 memset(colors, -1, sizeof(*colors));
664 for (i = 0; i < cells; i++)
666 XQueryColors (dpy, cmap, colors, cells);
669 fprintf(stderr, "%s: building color cube for %d bit image\n",
670 progname, image->depth);
672 for (i = 0; i < cells; i++)
674 unsigned short r, g, b;
678 /* "RRR GGG BB" In an 8 bit map. Convert that to
679 "RRR RRR RR" "GGG GGG GG" "BB BB BB BB" to give
685 r = ((r << 13) | (r << 10) | (r << 7) | (r << 4) | (r << 1));
686 g = ((g << 13) | (g << 10) | (g << 7) | (g << 4) | (g << 1));
687 b = ((b << 14) | (b << 12) | (b << 10) | (b << 8) |
688 (b << 6) | (b << 4) | (b << 2) | b);
692 /* "RRRR GGGG BBBB" In a 12 bit map. Convert that to
693 "RRRR RRRR" "GGGG GGGG" "BBBB BBBB" to give an even
696 g = (i & 0x0F0) >> 4;
697 b = (i & 0xF00) >> 8;
699 r = (r << 12) | (r << 8) | (r << 4) | r;
700 g = (g << 12) | (g << 8) | (g << 4) | g;
701 b = (b << 12) | (b << 8) | (b << 4) | b;
704 map[i] = find_closest_pixel (colors, cells, r, g, b);
708 fprintf(stderr, "%s: remapping colors in %d bit image\n",
709 progname, image->depth);
711 for (y = 0; y < image->height; y++)
712 for (x = 0; x < image->width; x++)
714 unsigned long pixel = XGetPixel(image, x, y);
715 if (pixel >= cells) abort();
716 XPutPixel(image, x, y, map[pixel]);
721 /* If the file has a PPM (P6) on it, read it and return an XImage.
722 Otherwise, rewind the fd back to the beginning, and return 0.
725 maybe_read_ppm (Screen *screen, Visual *visual,
726 const char *filename, FILE *in, Bool verbose_p)
728 Display *dpy = DisplayOfScreen (screen);
729 int depth = visual_depth (screen, visual);
735 int x, y, w, h, maxval;
738 if (fstat (fileno (in), &st))
742 buf = (char *) malloc (bufsiz + 1);
745 fprintf (stderr, "%s: out of memory loading %d byte PPM file %s\n",
746 progname, bufsiz, filename);
750 if (! (s = fgets (buf, bufsiz, in))) /* line 1 */
753 if (!strncmp (buf, "\107\111", 2))
755 fprintf (stderr, "%s: %s: sorry, GIF files not supported"
756 " when compiled with JPEGlib instead of GDK_Pixbuf.\n",
760 else if (!strncmp (buf, "\211\120", 2))
762 fprintf (stderr, "%s: %s: sorry, PNG files not supported"
763 " when compiled with JPEGlib instead of GDK_Pixbuf.\n",
768 if (strncmp (s, "P6", 2))
771 if (! (s = fgets (buf, bufsiz, in))) /* line 2 */
773 if (2 != sscanf (s, " %d %d %c", &w, &h, &dummy))
775 fprintf (stderr, "%s: %s: invalid PPM (line 2)\n", progname, filename);
779 if (! (s = fgets (buf, bufsiz, in))) /* line 3 */
781 if (1 != sscanf (s, " %d %c", &maxval, &dummy))
783 fprintf (stderr, "%s: %s: invalid PPM (line 3)\n", progname, filename);
788 fprintf (stderr, "%s: %s: unparsable PPM: maxval is %d\n",
789 progname, filename, maxval);
793 ximage = XCreateImage (dpy, visual, depth, ZPixmap, 0, 0,
796 ximage->data = (char *) calloc (ximage->height, ximage->bytes_per_line);
797 if (!ximage || !ximage->data)
799 fprintf (stderr, "%s: out of memory loading %dx%d PPM file %s\n",
800 progname, ximage->width, ximage->height, filename);
806 while ((i = fread (s, 1, j, in)) > 0)
810 for (y = 0; y < ximage->height; y++)
811 for (x = 0; x < ximage->width; x++)
813 unsigned char r = buf[i++];
814 unsigned char g = buf[i++];
815 unsigned char b = buf[i++];
819 pixel = (r << 16) | (g << 8) | b;
821 pixel = ((r >> 5) | ((g >> 5) << 3) | ((b >> 6) << 6));
822 else if (depth == 12)
823 pixel = ((r >> 4) | ((g >> 4) << 4) | ((b >> 4) << 8));
824 else if (depth == 16 || depth == 15)
825 pixel = (((r >> 3) << 10) | ((g >> 3) << 5) | ((b >> 3)));
829 XPutPixel (ximage, x, y, pixel);
837 if (ximage && ximage->data)
842 if (ximage) XDestroyImage (ximage);
843 fseek (in, 0, SEEK_SET);
849 struct jpeg_error_mgr pub; /* this is what passes for subclassing in C */
850 const char *filename;
855 } getimg_jpg_error_mgr;
859 jpg_output_message (j_common_ptr cinfo)
861 getimg_jpg_error_mgr *err = (getimg_jpg_error_mgr *) cinfo->err;
862 char buf[JMSG_LENGTH_MAX];
863 cinfo->err->format_message (cinfo, buf);
864 fprintf (stderr, "%s: %s: %s\n", progname, err->filename, buf);
869 jpg_error_exit (j_common_ptr cinfo)
871 getimg_jpg_error_mgr *err = (getimg_jpg_error_mgr *) cinfo->err;
872 cinfo->err->output_message (cinfo);
873 colorbars (err->screen, err->visual, err->drawable, err->cmap);
874 XSync (DisplayOfScreen (err->screen), False);
879 /* Reads a JPEG file, returns an RGB XImage of it.
882 read_jpeg_ximage (Screen *screen, Visual *visual, Drawable drawable,
883 Colormap cmap, const char *filename, Bool verbose_p)
885 Display *dpy = DisplayOfScreen (screen);
886 int depth = visual_depth (screen, visual);
890 struct jpeg_decompress_struct cinfo;
891 getimg_jpg_error_mgr jerr;
892 JSAMPARRAY scanbuf = 0;
895 jerr.filename = filename;
896 jerr.screen = screen;
897 jerr.visual = visual;
898 jerr.drawable = drawable;
901 if (! (depth >= 15 || depth == 12 || depth == 8))
903 fprintf (stderr, "%s: unsupported depth: %d\n", progname, depth);
907 in = fopen (filename, "rb");
910 fprintf (stderr, "%s: %s: unreadable\n", progname, filename);
914 /* Check to see if it's a PPM, and if so, read that instead of using
915 the JPEG library. Yeah, this is all modular and stuff.
917 if ((ximage = maybe_read_ppm (screen, visual, filename, in, verbose_p)))
923 cinfo.err = jpeg_std_error (&jerr.pub);
924 jerr.pub.output_message = jpg_output_message;
925 jerr.pub.error_exit = jpg_error_exit;
927 jpeg_create_decompress (&cinfo);
928 jpeg_stdio_src (&cinfo, in);
929 jpeg_read_header (&cinfo, TRUE);
931 /* set some decode parameters */
932 cinfo.out_color_space = JCS_RGB;
933 cinfo.quantize_colors = FALSE;
935 jpeg_start_decompress (&cinfo);
937 ximage = XCreateImage (dpy, visual, depth, ZPixmap, 0, 0,
938 cinfo.output_width, cinfo.output_height,
941 ximage->data = (char *) calloc (ximage->height, ximage->bytes_per_line);
943 if (ximage && ximage->data)
944 scanbuf = (*cinfo.mem->alloc_sarray) ((j_common_ptr) &cinfo, JPOOL_IMAGE,
945 cinfo.rec_outbuf_height *
947 cinfo.output_components,
949 if (!ximage || !ximage->data || !scanbuf)
951 fprintf (stderr, "%s: out of memory loading %dx%d file %s\n",
952 progname, ximage->width, ximage->height, filename);
957 while (cinfo.output_scanline < cinfo.output_height)
959 int n = jpeg_read_scanlines (&cinfo, scanbuf, 1);
961 for (i = 0; i < n; i++)
964 for (x = 0; x < ximage->width; x++)
966 int j = x * cinfo.output_components;
967 unsigned char r = scanbuf[i][j];
968 unsigned char g = scanbuf[i][j+1];
969 unsigned char b = scanbuf[i][j+2];
973 pixel = (r << 16) | (g << 8) | b;
975 pixel = ((r >> 5) | ((g >> 5) << 3) | ((b >> 6) << 6));
976 else if (depth == 12)
977 pixel = ((r >> 4) | ((g >> 4) << 4) | ((b >> 4) << 8));
978 else if (depth == 15)
979 /* Gah! I don't understand why these are in the other
981 pixel = (((r >> 3) << 10) | ((g >> 3) << 5) | ((b >> 3)));
982 else if (depth == 16)
983 pixel = (((r >> 3) << 11) | ((g >> 2) << 5) | ((b >> 3)));
987 XPutPixel (ximage, x, y, pixel);
993 if (cinfo.output_scanline < cinfo.output_height)
994 /* don't goto FAIL -- we might have viewable partial data. */
995 jpeg_abort_decompress (&cinfo);
997 jpeg_finish_decompress (&cinfo);
999 jpeg_destroy_decompress (&cinfo);
1006 if (in) fclose (in);
1007 if (ximage && ximage->data)
1009 free (ximage->data);
1012 if (ximage) XDestroyImage (ximage);
1013 if (scanbuf) free (scanbuf);
1018 /* Reads the given image file and renders it on the Drawable, using JPEG lib.
1019 Returns False if it fails.
1022 read_file_jpeglib (Screen *screen, Window window, Drawable drawable,
1023 const char *filename, Bool verbose_p,
1024 XRectangle *geom_ret)
1026 Display *dpy = DisplayOfScreen (screen);
1031 unsigned int win_width, win_height, win_depth;
1032 int srcx, srcy, destx, desty, w2, h2;
1034 /* Find the size of the Drawable, and the Visual/Colormap of the Window. */
1039 XWindowAttributes xgwa;
1040 XGetWindowAttributes (dpy, window, &xgwa);
1041 visual = xgwa.visual;
1042 cmap = xgwa.colormap;
1043 XGetGeometry (dpy, drawable,
1044 &root, &x, &y, &win_width, &win_height, &bw, &win_depth);
1047 /* Make sure we're not on some weirdo visual...
1049 class = visual_class (screen, visual);
1050 depth = visual_depth (screen, visual);
1051 if ((class == PseudoColor || class == DirectColor) &&
1052 (depth != 8 && depth != 12))
1054 fprintf (stderr, "%s: Pseudo/DirectColor depth %d unsupported\n",
1061 ximage = read_jpeg_ximage (screen, visual, drawable, cmap,
1062 filename, verbose_p);
1063 if (!ximage) return False;
1065 /* Scale it, if necessary...
1067 compute_image_scaling (ximage->width, ximage->height,
1068 win_width, win_height, verbose_p,
1069 &srcx, &srcy, &destx, &desty, &w2, &h2);
1070 if (ximage->width != w2 || ximage->height != h2)
1071 if (! scale_ximage (screen, visual, ximage, w2, h2))
1074 /* Allocate a colormap, if we need to...
1076 if (class == PseudoColor || class == DirectColor)
1078 allocate_cubic_colormap (screen, visual, cmap, verbose_p);
1079 remap_image (screen, cmap, ximage, verbose_p);
1082 /* Finally, put the resized image on the window.
1088 /* If we're rendering onto the root window (and it's not the xscreensaver
1089 pseudo-root) then put the image in the window's background. Otherwise,
1090 just paint the image onto the window.
1092 if (window == drawable && root_window_p (screen, window))
1094 Pixmap bg = XCreatePixmap (dpy, window,
1095 win_width, win_height, win_depth);
1096 gcv.foreground = BlackPixelOfScreen (screen);
1097 gc = XCreateGC (dpy, drawable, GCForeground, &gcv);
1098 XFillRectangle (dpy, bg, gc, 0, 0, win_width, win_height);
1099 XPutImage (dpy, bg, gc, ximage,
1100 srcx, srcy, destx, desty, ximage->width, ximage->height);
1101 XSetWindowBackgroundPixmap (dpy, window, bg);
1102 XClearWindow (dpy, window);
1106 gc = XCreateGC (dpy, drawable, 0, &gcv);
1107 clear_drawable (screen, drawable);
1108 XPutImage (dpy, drawable, gc, ximage,
1109 srcx, srcy, destx, desty, ximage->width, ximage->height);
1117 geom_ret->x = destx;
1118 geom_ret->y = desty;
1119 geom_ret->width = ximage->width;
1120 geom_ret->height = ximage->height;
1123 free (ximage->data);
1125 XDestroyImage (ximage);
1130 #endif /* HAVE_JPEGLIB */
1133 /* Reads the given image file and renders it on the Drawable.
1134 Returns False if it fails.
1137 display_file (Screen *screen, Window window, Drawable drawable,
1138 const char *filename, Bool verbose_p,
1139 XRectangle *geom_ret)
1142 fprintf (stderr, "%s: loading \"%s\"\n", progname, filename);
1144 # if defined(HAVE_GDK_PIXBUF)
1145 if (read_file_gdk (screen, window, drawable, filename, verbose_p, geom_ret))
1147 # elif defined(HAVE_JPEGLIB)
1148 if (read_file_jpeglib (screen, window, drawable, filename, verbose_p,
1151 # else /* !(HAVE_GDK_PIXBUF || HAVE_JPEGLIB) */
1152 /* shouldn't get here if we have no image-loading methods available. */
1154 # endif /* !(HAVE_GDK_PIXBUF || HAVE_JPEGLIB) */
1160 /* Invokes a sub-process and returns its output (presumably, a file to
1161 load.) Free the string when done. 'grab_type' controls which program
1162 to run. Returned pathname may be relative to 'directory', or absolute.
1165 get_filename_1 (Screen *screen, const char *directory, grab_type type,
1168 Display *dpy = DisplayOfScreen (screen);
1179 av[ac++] = GETIMAGE_FILE_PROGRAM;
1181 av[ac++] = "--verbose";
1182 av[ac++] = "--name";
1183 av[ac++] = (char *) directory;
1187 av[ac++] = GETIMAGE_VIDEO_PROGRAM;
1189 av[ac++] = "--verbose";
1190 av[ac++] = "--name";
1193 # ifdef USE_EXTERNAL_SCREEN_GRABBER
1195 av[ac++] = GETIMAGE_SCREEN_PROGRAM;
1197 av[ac++] = "--verbose";
1198 av[ac++] = "--name";
1210 fprintf (stderr, "%s: executing:", progname);
1211 for (i = 0; i < ac; i++)
1212 fprintf (stderr, " %s", av[i]);
1213 fprintf (stderr, "\n");
1218 sprintf (buf, "%s: error creating pipe", progname);
1226 switch ((int) (forked = fork ()))
1230 sprintf (buf, "%s: couldn't fork", progname);
1238 close (in); /* don't need this one */
1239 close (ConnectionNumber (dpy)); /* close display fd */
1241 if (dup2 (out, stdout_fd) < 0) /* pipe stdout */
1243 sprintf (buf, "%s: could not dup() a new stdout", progname);
1244 exit (-1); /* exits fork */
1247 execvp (av[0], av); /* shouldn't return. */
1248 exit (-1); /* exits fork */
1254 int wait_status = 0;
1255 FILE *f = fdopen (in, "r");
1259 close (out); /* don't need this one */
1261 if (! fgets (buf, sizeof(buf)-1, f))
1265 /* Wait for the child to die. */
1266 waitpid (-1, &wait_status, 0);
1269 while (L && buf[L-1] == '\n')
1279 /* Program returned path relative to directory. Prepend dir
1280 to buf so that we can properly stat it. */
1281 strcpy (buf, directory);
1282 if (directory[strlen(directory)-1] != '/')
1289 fprintf (stderr, "%s: file does not exist: \"%s\"\n",
1303 /* Returns a pathname to an image file. Free the string when you're done.
1306 get_filename (Screen *screen, const char *directory, Bool verbose_p)
1308 return get_filename_1 (screen, directory, GRAB_FILE, verbose_p);
1312 /* Grabs a video frame to a file, and returns a pathname to that file.
1313 Delete that file when you are done with it (and free the string.)
1316 get_video_filename (Screen *screen, Bool verbose_p)
1318 return get_filename_1 (screen, 0, GRAB_VIDEO, verbose_p);
1321 /* Grabs a desktop image to a file, and returns a pathname to that file.
1322 Delete that file when you are done with it (and free the string.)
1324 # ifdef USE_EXTERNAL_SCREEN_GRABBER
1326 get_desktop_filename (Screen *screen, Bool verbose_p)
1328 return get_filename_1 (screen, 0, GRAB_DESK, verbose_p);
1330 #endif /* USE_EXTERNAL_SCREEN_GRABBER */
1333 /* Grabs a video frame, and renders it on the Drawable.
1334 Returns False if it fails;
1337 display_video (Screen *screen, Window window, Drawable drawable,
1338 Bool verbose_p, XRectangle *geom_ret)
1340 char *filename = get_video_filename (screen, verbose_p);
1346 fprintf (stderr, "%s: video grab failed.\n", progname);
1350 status = display_file (screen, window, drawable, filename, verbose_p,
1353 if (unlink (filename))
1356 sprintf (buf, "%s: rm %.100s", progname, filename);
1360 fprintf (stderr, "%s: rm %s\n", progname, filename);
1362 if (filename) free (filename);
1367 /* Grabs a desktop screen shot onto the window and the drawable.
1368 If the window and drawable are not the same size, the image in
1369 the drawable is scaled to fit.
1370 Returns False if it fails.
1373 display_desktop (Screen *screen, Window window, Drawable drawable,
1374 Bool verbose_p, XRectangle *geom_ret)
1376 # ifdef USE_EXTERNAL_SCREEN_GRABBER
1378 Display *dpy = DisplayOfScreen (screen);
1379 Bool top_p = top_level_window_p (screen, window);
1386 fprintf (stderr, "%s: unmapping 0x%lx.\n", progname,
1387 (unsigned long) window);
1388 XUnmapWindow (dpy, window);
1392 filename = get_desktop_filename (screen, verbose_p);
1397 fprintf (stderr, "%s: mapping 0x%lx.\n", progname,
1398 (unsigned long) window);
1399 XMapRaised (dpy, window);
1406 fprintf (stderr, "%s: desktop grab failed.\n", progname);
1410 status = display_file (screen, window, drawable, filename, verbose_p,
1413 if (unlink (filename))
1416 sprintf (buf, "%s: rm %.100s", progname, filename);
1420 fprintf (stderr, "%s: rm %s\n", progname, filename);
1422 if (filename) free (filename);
1425 # else /* !USE_EXTERNAL_SCREEN_GRABBER */
1427 Display *dpy = DisplayOfScreen (screen);
1429 XWindowAttributes xgwa;
1432 unsigned int pw, ph, pbw, pd;
1433 int srcx, srcy, destx, desty, w2, h2;
1437 fprintf (stderr, "%s: grabbing desktop image\n", progname);
1438 grabscreen_verbose();
1441 XGetWindowAttributes (dpy, window, &xgwa);
1442 XGetGeometry (dpy, drawable, &root, &px, &py, &pw, &ph, &pbw, &pd);
1444 grab_screen_image_internal (screen, window);
1446 compute_image_scaling (xgwa.width, xgwa.height,
1448 &srcx, &srcy, &destx, &desty, &w2, &h2);
1450 if (pw == w2 && ph == h2) /* it fits -- just copy server-side pixmaps */
1452 GC gc = XCreateGC (dpy, drawable, 0, &gcv);
1453 XCopyArea (dpy, window, drawable, gc,
1454 0, 0, xgwa.width, xgwa.height, 0, 0);
1457 else /* size mismatch -- must scale client-side images to fit drawable */
1461 XErrorHandler old_handler;
1464 old_handler = XSetErrorHandler (ignore_badmatch_ehandler);
1465 error_handler_hit_p = False;
1467 /* This can return BadMatch if the window is not fully on screen.
1468 Trap that error and return color bars in that case.
1469 (Note that this only happens with XGetImage, not with XCopyArea:
1470 yet another totally gratuitous inconsistency in X, thanks.)
1472 ximage = XGetImage (dpy, window, 0, 0, xgwa.width, xgwa.height,
1476 XSetErrorHandler (old_handler);
1479 if (error_handler_hit_p)
1483 fprintf (stderr, "%s: BadMatch reading window 0x%x contents!\n",
1484 progname, (unsigned int) window);
1488 !scale_ximage (xgwa.screen, xgwa.visual, ximage, w2, h2))
1491 gc = XCreateGC (dpy, drawable, 0, &gcv);
1492 clear_drawable (screen, drawable);
1493 XPutImage (dpy, drawable, gc, ximage,
1494 srcx, srcy, destx, desty, ximage->width, ximage->height);
1495 XDestroyImage (ximage);
1501 geom_ret->x = destx;
1502 geom_ret->y = desty;
1503 geom_ret->width = w2;
1504 geom_ret->height = h2;
1510 # endif /* !USE_EXTERNAL_SCREEN_GRABBER */
1514 /* Whether the given Drawable is unreasonably small.
1517 drawable_miniscule_p (Display *dpy, Drawable drawable)
1521 unsigned int bw, d, w = 0, h = 0;
1522 XGetGeometry (dpy, drawable, &root, &xx, &yy, &w, &h, &bw, &d);
1523 return (w < 32 || h < 30);
1527 /* Grabs an image (from a file, video, or the desktop) and renders it on
1528 the Drawable. If `file' is specified, always use that file. Otherwise,
1529 select randomly, based on the other arguments.
1532 get_image (Screen *screen,
1533 Window window, Drawable drawable,
1541 Display *dpy = DisplayOfScreen (screen);
1542 grab_type which = GRAB_BARS;
1544 const char *file_prop = 0;
1546 XRectangle geom = { 0, 0, 0, 0 };
1548 if (! drawable_window_p (dpy, window))
1550 fprintf (stderr, "%s: 0x%lx is a pixmap, not a window!\n",
1551 progname, (unsigned long) window);
1555 /* Make sure the Screen and the Window correspond. */
1557 XWindowAttributes xgwa;
1558 XGetWindowAttributes (dpy, window, &xgwa);
1559 screen = xgwa.screen;
1562 if (file && stat (file, &st))
1564 fprintf (stderr, "%s: file \"%s\" does not exist\n", progname, file);
1570 fprintf (stderr, "%s: grabDesktopImages: %s\n",
1571 progname, desk_p ? "True" : "False");
1572 fprintf (stderr, "%s: grabVideoFrames: %s\n",
1573 progname, video_p ? "True" : "False");
1574 fprintf (stderr, "%s: chooseRandomImages: %s\n",
1575 progname, image_p ? "True" : "False");
1576 fprintf (stderr, "%s: imageDirectory: %s\n",
1577 progname, (file ? file : dir ? dir : ""));
1580 # if !(defined(HAVE_GDK_PIXBUF) || defined(HAVE_JPEGLIB))
1581 image_p = False; /* can't load images from files... */
1582 # ifdef USE_EXTERNAL_SCREEN_GRABBER
1583 desk_p = False; /* ...or from desktops grabbed to files. */
1589 "%s: image file loading not available at compile-time\n",
1591 fprintf (stderr, "%s: can't load \"%s\"\n", progname, file);
1594 # endif /* !(HAVE_GDK_PIXBUF || HAVE_JPEGLIB) */
1602 else if (!dir || !*dir)
1604 if (verbose_p && image_p)
1606 "%s: no imageDirectory: turning off chooseRandomImages.\n",
1611 /* If the target drawable is really small, no good can come of that.
1612 Always do colorbars in that case.
1614 if (drawable_miniscule_p (dpy, drawable))
1622 # error Error! This file definitely needs vroot.h!
1625 /* We can grab desktop images (using the normal X11 method) if:
1626 - the window is the real root window;
1627 - the window is a toplevel window.
1628 We cannot grab desktop images that way if:
1629 - the window is a non-top-level window.
1631 Under X11 on MacOS, desktops are just like loaded image files.
1632 Under Cocoa on MacOS, this code is not used at all.
1634 # ifndef USE_EXTERNAL_SCREEN_GRABBER
1637 if (!top_level_window_p (screen, window))
1642 "%s: 0x%x not top-level: turning off grabDesktopImages.\n",
1643 progname, (unsigned int) window);
1646 # endif /* !USE_EXTERNAL_SCREEN_GRABBER */
1648 if (! (desk_p || video_p || image_p))
1654 /* Loop until we get one that's permitted.
1655 If files or video are permitted, do them more often
1658 D+V+I: 10% + 45% + 45%.
1664 n = (random() % 100);
1665 if (++i > 300) abort();
1666 else if (desk_p && n < 10) which = GRAB_DESK; /* 10% */
1667 else if (video_p && n < 55) which = GRAB_VIDEO; /* 45% */
1668 else if (image_p) which = GRAB_FILE; /* 45% */
1673 /* If we're to search a directory to find an image file, do so now.
1675 if (which == GRAB_FILE && !file)
1677 file = get_filename (screen, dir, verbose_p);
1682 fprintf (stderr, "%s: no image files found.\n", progname);
1686 /* Now actually render something.
1692 XWindowAttributes xgwa;
1695 fprintf (stderr, "%s: drawing colorbars.\n", progname);
1696 XGetWindowAttributes (dpy, window, &xgwa);
1697 colorbars (screen, xgwa.visual, drawable, xgwa.colormap);
1699 if (! file_prop) file_prop = "";
1705 if (! display_desktop (screen, window, drawable, verbose_p, &geom))
1707 file_prop = "desktop";
1711 if (*file && *file != '/') /* pathname is relative to dir. */
1713 if (absfile) free (absfile);
1714 absfile = malloc (strlen(dir) + strlen(file) + 10);
1715 strcpy (absfile, dir);
1716 if (dir[strlen(dir)-1] != '/')
1717 strcat (absfile, "/");
1718 strcat (absfile, file);
1720 if (! display_file (screen, window, drawable,
1721 (absfile ? absfile : file),
1728 if (! display_video (screen, window, drawable, verbose_p, &geom))
1730 file_prop = "video";
1739 Atom a = XInternAtom (dpy, XA_XSCREENSAVER_IMAGE_FILENAME, False);
1740 if (file_prop && *file_prop)
1742 char *f2 = strdup (file_prop);
1744 /* Take the extension off of the file name. */
1745 /* Duplicated in utils/grabclient.c. */
1746 char *slash = strrchr (f2, '/');
1747 char *dot = strrchr ((slash ? slash : f2), '.');
1749 /* Replace slashes with newlines */
1750 /* while ((dot = strchr(f2, '/'))) *dot = '\n'; */
1751 /* Replace slashes with spaces */
1752 /* while ((dot = strchr(f2, '/'))) *dot = ' '; */
1754 XChangeProperty (dpy, window, a, XA_STRING, 8, PropModeReplace,
1755 (unsigned char *) f2, strlen(f2));
1759 XDeleteProperty (dpy, window, a);
1761 a = XInternAtom (dpy, XA_XSCREENSAVER_IMAGE_GEOMETRY, False);
1765 sprintf (gstr, "%dx%d+%d+%d", geom.width, geom.height, geom.x, geom.y);
1766 XChangeProperty (dpy, window, a, XA_STRING, 8, PropModeReplace,
1767 (unsigned char *) gstr, strlen (gstr));
1770 XDeleteProperty (dpy, window, a);
1773 if (absfile) free (absfile);
1780 mapper (XrmDatabase *db, XrmBindingList bindings, XrmQuarkList quarks,
1781 XrmRepresentation *type, XrmValue *value, XPointer closure)
1784 for (i = 0; quarks[i]; i++)
1786 if (bindings[i] == XrmBindTightly)
1787 fprintf (stderr, (i == 0 ? "" : "."));
1788 else if (bindings[i] == XrmBindLoosely)
1789 fprintf (stderr, "*");
1791 fprintf (stderr, " ??? ");
1792 fprintf(stderr, "%s", XrmQuarkToString (quarks[i]));
1795 fprintf (stderr, ": %s\n", (char *) value->addr);
1802 #define USAGE "usage: %s [ -options... ] window-id [pixmap-id]\n" \
1806 " %s puts an image on the given window or pixmap.\n" \
1808 " It is used by those xscreensaver demos that operate on images.\n" \
1809 " The image may be a file loaded from disk, a frame grabbed from\n" \
1810 " the system's video camera, or a screenshot of the desktop,\n" \
1811 " depending on command-line options or the ~/.xscreensaver file.\n" \
1813 " Options include:\n" \
1815 " -display host:dpy.screen which display to use\n" \
1816 " -root draw to the root window\n" \
1817 " -verbose print diagnostics\n" \
1818 " -images / -no-images whether to allow image file loading\n" \
1819 " -video / -no-video whether to allow video grabs\n" \
1820 " -desktop / -no-desktop whether to allow desktop screen grabs\n"\
1821 " -directory <path> where to find image files to load\n" \
1822 " -file <filename> load this image file\n" \
1824 " The XScreenSaver Control Panel (xscreensaver-demo) lets you set the\n"\
1825 " defaults for these options in your ~/.xscreensaver file.\n" \
1829 main (int argc, char **argv)
1831 saver_preferences P;
1835 char *oprogname = progname;
1839 Window window = (Window) 0;
1840 Drawable drawable = (Drawable) 0;
1841 const char *window_str = 0;
1842 const char *drawable_str = 0;
1847 s = strrchr (progname, '/');
1848 if (s) progname = s+1;
1849 oprogname = progname;
1851 /* half-assed way of avoiding buffer-overrun attacks. */
1852 if (strlen (progname) >= 100) progname[100] = 0;
1855 # error Error! This file definitely needs vroot.h!
1858 /* Get the version number, for error messages. */
1860 char *v = (char *) strdup(strchr(screensaver_id, ' '));
1861 char *s1, *s2, *s3, *s4;
1862 s1 = (char *) strchr(v, ' '); s1++;
1863 s2 = (char *) strchr(s1, ' ');
1864 s3 = (char *) strchr(v, '('); s3++;
1865 s4 = (char *) strchr(s3, ')');
1868 sprintf (version, "Part of XScreenSaver %s -- %s.", s1, s3);
1872 /* We must read exactly the same resources as xscreensaver.
1873 That means we must have both the same progclass *and* progname,
1874 at least as far as the resource database is concerned. So,
1875 put "xscreensaver" in argv[0] while initializing Xt.
1877 progname = argv[0] = "xscreensaver";
1879 /* allow one dash or two. */
1880 for (i = 1; i < argc; i++)
1881 if (argv[i][0] == '-' && argv[i][1] == '-') argv[i]++;
1883 toplevel = XtAppInitialize (&app, progclass, 0, 0, &argc, argv,
1885 dpy = XtDisplay (toplevel);
1886 screen = XtScreen (toplevel);
1887 db = XtDatabase (dpy);
1888 XtGetApplicationNameAndClass (dpy, &s, &progclass);
1889 XSetErrorHandler (x_ehandler);
1892 /* Randomize -- only need to do this here because this program
1893 doesn't use the `screenhack.h' or `lockmore.h' APIs. */
1894 # undef ya_rand_init
1897 memset (&P, 0, sizeof(P));
1899 load_init_file (dpy, &P);
1901 progname = argv[0] = oprogname;
1903 for (i = 1; i < argc; i++)
1908 /* Have to re-process these, or else the .xscreensaver file
1909 has priority over the command line...
1911 if (!strcmp (argv[i], "-v") || !strcmp (argv[i], "-verbose"))
1913 else if (!strcmp (argv[i], "-desktop")) P.grab_desktop_p = True;
1914 else if (!strcmp (argv[i], "-no-desktop")) P.grab_desktop_p = False;
1915 else if (!strcmp (argv[i], "-video")) P.grab_video_p = True;
1916 else if (!strcmp (argv[i], "-no-video")) P.grab_video_p = False;
1917 else if (!strcmp (argv[i], "-images")) P.random_image_p = True;
1918 else if (!strcmp (argv[i], "-no-images")) P.random_image_p = False;
1919 else if (!strcmp (argv[i], "-file")) file = argv[++i];
1920 else if (!strcmp (argv[i], "-directory") || !strcmp (argv[i], "-dir"))
1921 P.image_directory = argv[++i];
1922 else if (!strcmp (argv[i], "-root") || !strcmp (argv[i], "root"))
1926 fprintf (stderr, "%s: both %s and %s specified?\n",
1927 progname, argv[i], window_str);
1930 window_str = argv[i];
1931 window = VirtualRootWindowOfScreen (screen);
1933 else if ((1 == sscanf (argv[i], " 0x%lx %c", &w, &dummy) ||
1934 1 == sscanf (argv[i], " %lu %c", &w, &dummy)) &&
1939 fprintf (stderr, "%s: both %s and %s specified?\n",
1940 progname, drawable_str, argv[i]);
1945 drawable_str = argv[i];
1946 drawable = (Drawable) w;
1950 window_str = argv[i];
1951 window = (Window) w;
1956 if (argv[i][0] == '-')
1957 fprintf (stderr, "\n%s: unknown option \"%s\"\n",
1960 fprintf (stderr, "\n%s: unparsable window/pixmap ID: \"%s\"\n",
1964 __extension__ /* don't warn about "string length is greater than
1965 the length ISO C89 compilers are required to
1966 support" in the usage string... */
1968 fprintf (stderr, USAGE, progname, version, progname);
1975 fprintf (stderr, "\n%s: no window ID specified!\n", progname);
1981 if (P.verbose_p) /* Print out all the resources we can see. */
1983 XrmName name = { 0 };
1984 XrmClass class = { 0 };
1986 XrmEnumerateDatabase (db, &name, &class, XrmEnumAllLevels, mapper,
1987 (XtPointer) &count);
1991 if (!window) abort();
1992 if (!drawable) drawable = window;
1994 get_image (screen, window, drawable, P.verbose_p,
1995 P.grab_desktop_p, P.grab_video_p, P.random_image_p,
1996 P.image_directory, file);