1 /* xscreensaver, Copyright (c) 2001-2018 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 unsigned long *pixels; /* ignored - unfreed */
321 Pixmap logo = xscreensaver_logo (screen, visual, drawable, cmap,
322 BlackPixelOfScreen (screen),
323 &pixels, &npixels, &mask, True);
324 draw_colorbars (screen, visual, drawable, cmap, 0, 0, 0, 0, logo, mask);
325 XFreePixmap (DisplayOfScreen (screen), logo);
326 XFreePixmap (DisplayOfScreen (screen), mask);
330 /* Scales an XImage, modifying it in place.
331 This doesn't do dithering or smoothing, so it might have artifacts.
332 If out of memory, returns False, and the XImage will have been
335 #if !defined(USE_EXTERNAL_SCREEN_GRABBER) || defined(HAVE_JPEGLIB)
337 scale_ximage (Screen *screen, Visual *visual,
338 XImage *ximage, int new_width, int new_height)
340 Display *dpy = DisplayOfScreen (screen);
341 int depth = visual_depth (screen, visual);
343 double xscale, yscale;
345 XImage *ximage2 = XCreateImage (dpy, visual, depth,
347 new_width, new_height, 8, 0);
348 ximage2->data = (char *) calloc (ximage2->height, ximage2->bytes_per_line);
352 fprintf (stderr, "%s: out of memory scaling %dx%d image to %dx%d\n",
354 ximage->width, ximage->height,
355 ximage2->width, ximage2->height);
356 if (ximage->data) free (ximage->data);
357 if (ximage2->data) free (ximage2->data);
360 XDestroyImage (ximage);
361 XDestroyImage (ximage2);
365 /* Brute force scaling... */
366 xscale = (double) ximage->width / ximage2->width;
367 yscale = (double) ximage->height / ximage2->height;
368 for (y = 0; y < ximage2->height; y++)
369 for (x = 0; x < ximage2->width; x++)
370 XPutPixel (ximage2, x, y,
371 XGetPixel (ximage, x * xscale, y * yscale));
376 (*ximage) = (*ximage2);
379 XDestroyImage (ximage2);
383 #endif /* !USE_EXTERNAL_SCREEN_GRABBER || HAVE_JPEGLIB */
386 #ifdef HAVE_GDK_PIXBUF
388 /* Reads the given image file and renders it on the Drawable, using GDK.
389 Returns False if it fails.
392 read_file_gdk (Screen *screen, Window window, Drawable drawable,
393 const char *filename, Bool verbose_p,
394 XRectangle *geom_ret)
397 Display *dpy = DisplayOfScreen (screen);
398 unsigned int win_width, win_height, win_depth;
401 # endif /* HAVE_GTK2 */
403 /* Find the size of the Drawable. */
408 XGetGeometry (dpy, drawable,
409 &root, &x, &y, &win_width, &win_height, &bw, &win_depth);
412 gdk_pixbuf_xlib_init_with_depth (dpy, screen_number (screen), win_depth);
414 # if !GLIB_CHECK_VERSION(2, 36 ,0)
417 # else /* !HAVE_GTK2 */
418 xlib_rgb_init (dpy, screen);
419 # endif /* !HAVE_GTK2 */
421 pb = gdk_pixbuf_new_from_file (filename
424 # endif /* HAVE_GTK2 */
429 fprintf (stderr, "%s: unable to load \"%s\"\n", progname, filename);
431 if (gerr && gerr->message && *gerr->message)
432 fprintf (stderr, "%s: reason: %s\n", progname, gerr->message);
433 # endif /* HAVE_GTK2 */
438 int w = gdk_pixbuf_get_width (pb);
439 int h = gdk_pixbuf_get_height (pb);
440 int srcx, srcy, destx, desty, w2, h2;
443 # ifdef HAVE_GDK_PIXBUF_APPLY_EMBEDDED_ORIENTATION
447 pb = gdk_pixbuf_apply_embedded_orientation (opb);
448 g_object_unref (opb);
449 w = gdk_pixbuf_get_width (pb);
450 h = gdk_pixbuf_get_height (pb);
451 if (verbose_p && (w != ow || h != oh))
452 fprintf (stderr, "%s: rotated %dx%d to %dx%d\n",
453 progname, ow, oh, w, h);
457 compute_image_scaling (w, h, win_width, win_height, verbose_p,
458 &srcx, &srcy, &destx, &desty, &w2, &h2);
459 if (w != w2 || h != h2)
461 GdkPixbuf *pb2 = gdk_pixbuf_scale_simple (pb, w2, h2,
462 GDK_INTERP_BILINEAR);
471 fprintf (stderr, "%s: out of memory when scaling?\n", progname);
474 /* If we're rendering onto the root window (and it's not the
475 xscreensaver pseudo-root) then put the image in the window's
476 background. Otherwise, just paint the image onto the window.
478 bg_p = (window == drawable && root_window_p (screen, window));
484 drawable = XCreatePixmap (dpy, window,
485 win_width, win_height, win_depth);
486 gcv.foreground = BlackPixelOfScreen (screen);
487 gc = XCreateGC (dpy, drawable, GCForeground, &gcv);
488 XFillRectangle (dpy, drawable, gc, 0, 0, win_width, win_height);
492 clear_drawable (screen, drawable);
494 /* #### Note that this always uses the default colormap! Morons!
495 Owen says that in Gnome 2.0, I should try using
496 gdk_pixbuf_render_pixmap_and_mask_for_colormap() instead.
499 if (srcx > 0) w -= srcx;
500 if (srcy > 0) h -= srcy;
501 gdk_pixbuf_xlib_render_to_drawable_alpha (pb, drawable,
502 srcx, srcy, destx, desty,
504 GDK_PIXBUF_ALPHA_FULL, 127,
505 XLIB_RGB_DITHER_NORMAL,
509 XSetWindowBackgroundPixmap (dpy, window, drawable);
510 XClearWindow (dpy, window);
518 geom_ret->height = h;
526 #endif /* HAVE_GDK_PIXBUF */
532 /* Allocates a colormap that makes a PseudoColor or DirectColor
533 visual behave like a TrueColor visual of the same depth.
535 #### Duplicated in utils/grabscreen.c
538 allocate_cubic_colormap (Screen *screen, Visual *visual, Colormap cmap,
541 Display *dpy = DisplayOfScreen (screen);
542 int nr, ng, nb, cells;
548 depth = visual_depth (screen, visual);
552 case 8: nr = 3; ng = 3; nb = 2; cells = 256; break;
553 case 12: nr = 4; ng = 4; nb = 4; cells = 4096; break;
554 default: abort(); break;
557 memset(colors, 0, sizeof(colors));
558 for (r = 0; r < (1 << nr); r++)
559 for (g = 0; g < (1 << ng); g++)
560 for (b = 0; b < (1 << nb); b++)
562 i = (r | (g << nr) | (b << (nr + ng)));
564 colors[i].flags = DoRed|DoGreen|DoBlue;
567 colors[i].red = ((r << 13) | (r << 10) | (r << 7) |
568 (r << 4) | (r << 1));
569 colors[i].green = ((g << 13) | (g << 10) | (g << 7) |
570 (g << 4) | (g << 1));
571 colors[i].blue = ((b << 14) | (b << 12) | (b << 10) |
572 (b << 8) | (b << 6) | (b << 4) |
577 colors[i].red = (r << 12) | (r << 8) | (r << 4) | r;
578 colors[i].green = (g << 12) | (g << 8) | (g << 4) | g;
579 colors[i].blue = (b << 12) | (b << 8) | (b << 4) | b;
586 int interleave = cells / 8; /* skip around, rather than allocating in
587 order, so that we get better coverage if
588 we can't allocated all of them. */
589 for (j = 0; j < interleave; j++)
590 for (i = 0; i < cells; i += interleave)
591 if (XAllocColor (dpy, cmap, &colors[i + j]))
595 fprintf (stderr, "%s: allocated %d of %d colors for cubic map\n",
596 progname, allocated, cells);
600 /* Find the pixel index that is closest to the given color
601 (using linear distance in RGB space -- which is far from the best way.)
603 #### Duplicated in utils/grabscreen.c
606 find_closest_pixel (XColor *colors, int ncolors,
607 unsigned long r, unsigned long g, unsigned long b)
609 unsigned long distance = ~0;
614 for (i = 0; i < ncolors; i++)
619 rd = r - colors[i].red;
620 gd = g - colors[i].green;
621 bd = b - colors[i].blue;
622 if (rd < 0) rd = -rd;
623 if (gd < 0) gd = -gd;
624 if (bd < 0) bd = -bd;
625 d = (rd << 1) + (gd << 2) + bd;
640 /* Given an XImage with 8-bit or 12-bit RGB data, convert it to be
641 displayable with the given X colormap. The farther from a perfect
642 color cube the contents of the colormap are, the lossier the
643 transformation will be. No dithering is done.
645 #### Duplicated in utils/grabscreen.c
648 remap_image (Screen *screen, Colormap cmap, XImage *image, Bool verbose_p)
650 Display *dpy = DisplayOfScreen (screen);
651 unsigned long map[4097];
656 if (image->depth == 8)
658 else if (image->depth == 12)
663 memset(map, -1, sizeof(*map));
664 memset(colors, -1, sizeof(*colors));
666 for (i = 0; i < cells; i++)
668 XQueryColors (dpy, cmap, colors, cells);
671 fprintf(stderr, "%s: building color cube for %d bit image\n",
672 progname, image->depth);
674 for (i = 0; i < cells; i++)
676 unsigned short r, g, b;
680 /* "RRR GGG BB" In an 8 bit map. Convert that to
681 "RRR RRR RR" "GGG GGG GG" "BB BB BB BB" to give
687 r = ((r << 13) | (r << 10) | (r << 7) | (r << 4) | (r << 1));
688 g = ((g << 13) | (g << 10) | (g << 7) | (g << 4) | (g << 1));
689 b = ((b << 14) | (b << 12) | (b << 10) | (b << 8) |
690 (b << 6) | (b << 4) | (b << 2) | b);
694 /* "RRRR GGGG BBBB" In a 12 bit map. Convert that to
695 "RRRR RRRR" "GGGG GGGG" "BBBB BBBB" to give an even
698 g = (i & 0x0F0) >> 4;
699 b = (i & 0xF00) >> 8;
701 r = (r << 12) | (r << 8) | (r << 4) | r;
702 g = (g << 12) | (g << 8) | (g << 4) | g;
703 b = (b << 12) | (b << 8) | (b << 4) | b;
706 map[i] = find_closest_pixel (colors, cells, r, g, b);
710 fprintf(stderr, "%s: remapping colors in %d bit image\n",
711 progname, image->depth);
713 for (y = 0; y < image->height; y++)
714 for (x = 0; x < image->width; x++)
716 unsigned long pixel = XGetPixel(image, x, y);
717 if (pixel >= cells) abort();
718 XPutPixel(image, x, y, map[pixel]);
723 /* If the file has a PPM (P6) on it, read it and return an XImage.
724 Otherwise, rewind the fd back to the beginning, and return 0.
727 maybe_read_ppm (Screen *screen, Visual *visual,
728 const char *filename, FILE *in, Bool verbose_p)
730 Display *dpy = DisplayOfScreen (screen);
731 int depth = visual_depth (screen, visual);
737 int x, y, w, h, maxval;
740 if (fstat (fileno (in), &st))
744 buf = (char *) malloc (bufsiz + 1);
747 fprintf (stderr, "%s: out of memory loading %d byte PPM file %s\n",
748 progname, bufsiz, filename);
752 if (! (s = fgets (buf, bufsiz, in))) /* line 1 */
755 if (!strncmp (buf, "\107\111", 2))
757 fprintf (stderr, "%s: %s: sorry, GIF files not supported"
758 " when compiled with JPEGlib instead of GDK_Pixbuf.\n",
762 else if (!strncmp (buf, "\211\120", 2))
764 fprintf (stderr, "%s: %s: sorry, PNG files not supported"
765 " when compiled with JPEGlib instead of GDK_Pixbuf.\n",
770 if (strncmp (s, "P6", 2))
773 if (! (s = fgets (buf, bufsiz, in))) /* line 2 */
775 if (2 != sscanf (s, " %d %d %c", &w, &h, &dummy))
777 fprintf (stderr, "%s: %s: invalid PPM (line 2)\n", progname, filename);
781 if (! (s = fgets (buf, bufsiz, in))) /* line 3 */
783 if (1 != sscanf (s, " %d %c", &maxval, &dummy))
785 fprintf (stderr, "%s: %s: invalid PPM (line 3)\n", progname, filename);
790 fprintf (stderr, "%s: %s: unparsable PPM: maxval is %d\n",
791 progname, filename, maxval);
795 ximage = XCreateImage (dpy, visual, depth, ZPixmap, 0, 0,
798 ximage->data = (char *) calloc (ximage->height, ximage->bytes_per_line);
799 if (!ximage || !ximage->data)
801 fprintf (stderr, "%s: out of memory loading %dx%d PPM file %s\n",
802 progname, ximage->width, ximage->height, filename);
808 while ((i = fread (s, 1, j, in)) > 0)
812 for (y = 0; y < ximage->height; y++)
813 for (x = 0; x < ximage->width; x++)
815 unsigned char r = buf[i++];
816 unsigned char g = buf[i++];
817 unsigned char b = buf[i++];
821 pixel = (r << 16) | (g << 8) | b;
823 pixel = ((r >> 5) | ((g >> 5) << 3) | ((b >> 6) << 6));
824 else if (depth == 12)
825 pixel = ((r >> 4) | ((g >> 4) << 4) | ((b >> 4) << 8));
826 else if (depth == 16 || depth == 15)
827 pixel = (((r >> 3) << 10) | ((g >> 3) << 5) | ((b >> 3)));
831 XPutPixel (ximage, x, y, pixel);
839 if (ximage && ximage->data)
844 if (ximage) XDestroyImage (ximage);
845 fseek (in, 0, SEEK_SET);
851 struct jpeg_error_mgr pub; /* this is what passes for subclassing in C */
852 const char *filename;
857 } getimg_jpg_error_mgr;
861 jpg_output_message (j_common_ptr cinfo)
863 getimg_jpg_error_mgr *err = (getimg_jpg_error_mgr *) cinfo->err;
864 char buf[JMSG_LENGTH_MAX];
865 cinfo->err->format_message (cinfo, buf);
866 fprintf (stderr, "%s: %s: %s\n", progname, err->filename, buf);
871 jpg_error_exit (j_common_ptr cinfo)
873 getimg_jpg_error_mgr *err = (getimg_jpg_error_mgr *) cinfo->err;
874 cinfo->err->output_message (cinfo);
875 colorbars (err->screen, err->visual, err->drawable, err->cmap);
876 XSync (DisplayOfScreen (err->screen), False);
881 /* Reads a JPEG file, returns an RGB XImage of it.
884 read_jpeg_ximage (Screen *screen, Visual *visual, Drawable drawable,
885 Colormap cmap, const char *filename, Bool verbose_p)
887 Display *dpy = DisplayOfScreen (screen);
888 int depth = visual_depth (screen, visual);
892 struct jpeg_decompress_struct cinfo;
893 getimg_jpg_error_mgr jerr;
894 JSAMPARRAY scanbuf = 0;
897 jerr.filename = filename;
898 jerr.screen = screen;
899 jerr.visual = visual;
900 jerr.drawable = drawable;
903 if (! (depth >= 15 || depth == 12 || depth == 8))
905 fprintf (stderr, "%s: unsupported depth: %d\n", progname, depth);
909 in = fopen (filename, "rb");
912 fprintf (stderr, "%s: %s: unreadable\n", progname, filename);
916 /* Check to see if it's a PPM, and if so, read that instead of using
917 the JPEG library. Yeah, this is all modular and stuff.
919 if ((ximage = maybe_read_ppm (screen, visual, filename, in, verbose_p)))
925 cinfo.err = jpeg_std_error (&jerr.pub);
926 jerr.pub.output_message = jpg_output_message;
927 jerr.pub.error_exit = jpg_error_exit;
929 jpeg_create_decompress (&cinfo);
930 jpeg_stdio_src (&cinfo, in);
931 jpeg_read_header (&cinfo, TRUE);
933 /* set some decode parameters */
934 cinfo.out_color_space = JCS_RGB;
935 cinfo.quantize_colors = FALSE;
937 jpeg_start_decompress (&cinfo);
939 ximage = XCreateImage (dpy, visual, depth, ZPixmap, 0, 0,
940 cinfo.output_width, cinfo.output_height,
943 ximage->data = (char *) calloc (ximage->height, ximage->bytes_per_line);
945 if (ximage && ximage->data)
946 scanbuf = (*cinfo.mem->alloc_sarray) ((j_common_ptr) &cinfo, JPOOL_IMAGE,
947 cinfo.rec_outbuf_height *
949 cinfo.output_components,
951 if (!ximage || !ximage->data || !scanbuf)
953 fprintf (stderr, "%s: out of memory loading %dx%d file %s\n",
954 progname, ximage->width, ximage->height, filename);
959 while (cinfo.output_scanline < cinfo.output_height)
961 int n = jpeg_read_scanlines (&cinfo, scanbuf, 1);
963 for (i = 0; i < n; i++)
966 for (x = 0; x < ximage->width; x++)
968 int j = x * cinfo.output_components;
969 unsigned char r = scanbuf[i][j];
970 unsigned char g = scanbuf[i][j+1];
971 unsigned char b = scanbuf[i][j+2];
975 pixel = (r << 16) | (g << 8) | b;
977 pixel = ((r >> 5) | ((g >> 5) << 3) | ((b >> 6) << 6));
978 else if (depth == 12)
979 pixel = ((r >> 4) | ((g >> 4) << 4) | ((b >> 4) << 8));
980 else if (depth == 15)
981 /* Gah! I don't understand why these are in the other
983 pixel = (((r >> 3) << 10) | ((g >> 3) << 5) | ((b >> 3)));
984 else if (depth == 16)
985 pixel = (((r >> 3) << 11) | ((g >> 2) << 5) | ((b >> 3)));
989 XPutPixel (ximage, x, y, pixel);
995 if (cinfo.output_scanline < cinfo.output_height)
996 /* don't goto FAIL -- we might have viewable partial data. */
997 jpeg_abort_decompress (&cinfo);
999 jpeg_finish_decompress (&cinfo);
1001 jpeg_destroy_decompress (&cinfo);
1008 if (in) fclose (in);
1009 if (ximage && ximage->data)
1011 free (ximage->data);
1014 if (ximage) XDestroyImage (ximage);
1015 if (scanbuf) free (scanbuf);
1020 /* Reads the given image file and renders it on the Drawable, using JPEG lib.
1021 Returns False if it fails.
1024 read_file_jpeglib (Screen *screen, Window window, Drawable drawable,
1025 const char *filename, Bool verbose_p,
1026 XRectangle *geom_ret)
1028 Display *dpy = DisplayOfScreen (screen);
1033 unsigned int win_width, win_height, win_depth;
1034 int srcx, srcy, destx, desty, w2, h2;
1036 /* Find the size of the Drawable, and the Visual/Colormap of the Window. */
1041 XWindowAttributes xgwa;
1042 XGetWindowAttributes (dpy, window, &xgwa);
1043 visual = xgwa.visual;
1044 cmap = xgwa.colormap;
1045 XGetGeometry (dpy, drawable,
1046 &root, &x, &y, &win_width, &win_height, &bw, &win_depth);
1049 /* Make sure we're not on some weirdo visual...
1051 class = visual_class (screen, visual);
1052 depth = visual_depth (screen, visual);
1053 if ((class == PseudoColor || class == DirectColor) &&
1054 (depth != 8 && depth != 12))
1056 fprintf (stderr, "%s: Pseudo/DirectColor depth %d unsupported\n",
1063 ximage = read_jpeg_ximage (screen, visual, drawable, cmap,
1064 filename, verbose_p);
1065 if (!ximage) return False;
1067 /* Scale it, if necessary...
1069 compute_image_scaling (ximage->width, ximage->height,
1070 win_width, win_height, verbose_p,
1071 &srcx, &srcy, &destx, &desty, &w2, &h2);
1072 if (ximage->width != w2 || ximage->height != h2)
1073 if (! scale_ximage (screen, visual, ximage, w2, h2))
1076 /* Allocate a colormap, if we need to...
1078 if (class == PseudoColor || class == DirectColor)
1080 allocate_cubic_colormap (screen, visual, cmap, verbose_p);
1081 remap_image (screen, cmap, ximage, verbose_p);
1084 /* Finally, put the resized image on the window.
1090 /* If we're rendering onto the root window (and it's not the xscreensaver
1091 pseudo-root) then put the image in the window's background. Otherwise,
1092 just paint the image onto the window.
1094 if (window == drawable && root_window_p (screen, window))
1096 Pixmap bg = XCreatePixmap (dpy, window,
1097 win_width, win_height, win_depth);
1098 gcv.foreground = BlackPixelOfScreen (screen);
1099 gc = XCreateGC (dpy, drawable, GCForeground, &gcv);
1100 XFillRectangle (dpy, bg, gc, 0, 0, win_width, win_height);
1101 XPutImage (dpy, bg, gc, ximage,
1102 srcx, srcy, destx, desty, ximage->width, ximage->height);
1103 XSetWindowBackgroundPixmap (dpy, window, bg);
1104 XClearWindow (dpy, window);
1108 gc = XCreateGC (dpy, drawable, 0, &gcv);
1109 clear_drawable (screen, drawable);
1110 XPutImage (dpy, drawable, gc, ximage,
1111 srcx, srcy, destx, desty, ximage->width, ximage->height);
1119 geom_ret->x = destx;
1120 geom_ret->y = desty;
1121 geom_ret->width = ximage->width;
1122 geom_ret->height = ximage->height;
1125 free (ximage->data);
1127 XDestroyImage (ximage);
1132 #endif /* HAVE_JPEGLIB */
1135 /* Reads the given image file and renders it on the Drawable.
1136 Returns False if it fails.
1139 display_file (Screen *screen, Window window, Drawable drawable,
1140 const char *filename, Bool verbose_p,
1141 XRectangle *geom_ret)
1144 fprintf (stderr, "%s: loading \"%s\"\n", progname, filename);
1146 # if defined(HAVE_GDK_PIXBUF)
1147 if (read_file_gdk (screen, window, drawable, filename, verbose_p, geom_ret))
1149 # elif defined(HAVE_JPEGLIB)
1150 if (read_file_jpeglib (screen, window, drawable, filename, verbose_p,
1153 # else /* !(HAVE_GDK_PIXBUF || HAVE_JPEGLIB) */
1154 /* shouldn't get here if we have no image-loading methods available. */
1156 # endif /* !(HAVE_GDK_PIXBUF || HAVE_JPEGLIB) */
1162 /* Invokes a sub-process and returns its output (presumably, a file to
1163 load.) Free the string when done. 'grab_type' controls which program
1164 to run. Returned pathname may be relative to 'directory', or absolute.
1167 get_filename_1 (Screen *screen, const char *directory, grab_type type,
1170 Display *dpy = DisplayOfScreen (screen);
1181 av[ac++] = GETIMAGE_FILE_PROGRAM;
1183 av[ac++] = "--verbose";
1184 av[ac++] = "--name";
1185 av[ac++] = (char *) directory;
1189 av[ac++] = GETIMAGE_VIDEO_PROGRAM;
1191 av[ac++] = "--verbose";
1192 av[ac++] = "--name";
1195 # ifdef USE_EXTERNAL_SCREEN_GRABBER
1197 av[ac++] = GETIMAGE_SCREEN_PROGRAM;
1199 av[ac++] = "--verbose";
1200 av[ac++] = "--name";
1212 fprintf (stderr, "%s: executing:", progname);
1213 for (i = 0; i < ac; i++)
1214 fprintf (stderr, " %s", av[i]);
1215 fprintf (stderr, "\n");
1220 sprintf (buf, "%s: error creating pipe", progname);
1228 switch ((int) (forked = fork ()))
1232 sprintf (buf, "%s: couldn't fork", progname);
1240 close (in); /* don't need this one */
1241 close (ConnectionNumber (dpy)); /* close display fd */
1243 if (dup2 (out, stdout_fd) < 0) /* pipe stdout */
1245 sprintf (buf, "%s: could not dup() a new stdout", progname);
1246 exit (-1); /* exits fork */
1249 execvp (av[0], av); /* shouldn't return. */
1250 exit (-1); /* exits fork */
1256 int wait_status = 0;
1257 FILE *f = fdopen (in, "r");
1261 close (out); /* don't need this one */
1263 if (! fgets (buf, sizeof(buf)-1, f))
1267 /* Wait for the child to die. */
1268 waitpid (-1, &wait_status, 0);
1271 while (L && buf[L-1] == '\n')
1281 /* Program returned path relative to directory. Prepend dir
1282 to buf so that we can properly stat it. */
1283 strcpy (buf, directory);
1284 if (directory[strlen(directory)-1] != '/')
1291 fprintf (stderr, "%s: file does not exist: \"%s\"\n",
1305 /* Returns a pathname to an image file. Free the string when you're done.
1308 get_filename (Screen *screen, const char *directory, Bool verbose_p)
1310 return get_filename_1 (screen, directory, GRAB_FILE, verbose_p);
1314 /* Grabs a video frame to a file, and returns a pathname to that file.
1315 Delete that file when you are done with it (and free the string.)
1318 get_video_filename (Screen *screen, Bool verbose_p)
1320 return get_filename_1 (screen, 0, GRAB_VIDEO, verbose_p);
1323 /* Grabs a desktop image to a file, and returns a pathname to that file.
1324 Delete that file when you are done with it (and free the string.)
1326 # ifdef USE_EXTERNAL_SCREEN_GRABBER
1328 get_desktop_filename (Screen *screen, Bool verbose_p)
1330 return get_filename_1 (screen, 0, GRAB_DESK, verbose_p);
1332 #endif /* USE_EXTERNAL_SCREEN_GRABBER */
1335 /* Grabs a video frame, and renders it on the Drawable.
1336 Returns False if it fails;
1339 display_video (Screen *screen, Window window, Drawable drawable,
1340 Bool verbose_p, XRectangle *geom_ret)
1342 char *filename = get_video_filename (screen, verbose_p);
1348 fprintf (stderr, "%s: video grab failed.\n", progname);
1352 status = display_file (screen, window, drawable, filename, verbose_p,
1355 if (unlink (filename))
1358 sprintf (buf, "%s: rm %.100s", progname, filename);
1362 fprintf (stderr, "%s: rm %s\n", progname, filename);
1364 if (filename) free (filename);
1369 /* Grabs a desktop screen shot onto the window and the drawable.
1370 If the window and drawable are not the same size, the image in
1371 the drawable is scaled to fit.
1372 Returns False if it fails.
1375 display_desktop (Screen *screen, Window window, Drawable drawable,
1376 Bool verbose_p, XRectangle *geom_ret)
1378 # ifdef USE_EXTERNAL_SCREEN_GRABBER
1380 Display *dpy = DisplayOfScreen (screen);
1381 Bool top_p = top_level_window_p (screen, window);
1388 fprintf (stderr, "%s: unmapping 0x%lx.\n", progname,
1389 (unsigned long) window);
1390 XUnmapWindow (dpy, window);
1394 filename = get_desktop_filename (screen, verbose_p);
1399 fprintf (stderr, "%s: mapping 0x%lx.\n", progname,
1400 (unsigned long) window);
1401 XMapRaised (dpy, window);
1408 fprintf (stderr, "%s: desktop grab failed.\n", progname);
1412 status = display_file (screen, window, drawable, filename, verbose_p,
1415 if (unlink (filename))
1418 sprintf (buf, "%s: rm %.100s", progname, filename);
1422 fprintf (stderr, "%s: rm %s\n", progname, filename);
1424 if (filename) free (filename);
1427 # else /* !USE_EXTERNAL_SCREEN_GRABBER */
1429 Display *dpy = DisplayOfScreen (screen);
1431 XWindowAttributes xgwa;
1434 unsigned int pw, ph, pbw, pd;
1435 int srcx, srcy, destx, desty, w2, h2;
1439 fprintf (stderr, "%s: grabbing desktop image\n", progname);
1440 grabscreen_verbose();
1443 XGetWindowAttributes (dpy, window, &xgwa);
1444 XGetGeometry (dpy, drawable, &root, &px, &py, &pw, &ph, &pbw, &pd);
1446 grab_screen_image_internal (screen, window);
1448 compute_image_scaling (xgwa.width, xgwa.height,
1450 &srcx, &srcy, &destx, &desty, &w2, &h2);
1452 if (pw == w2 && ph == h2) /* it fits -- just copy server-side pixmaps */
1454 GC gc = XCreateGC (dpy, drawable, 0, &gcv);
1455 XCopyArea (dpy, window, drawable, gc,
1456 0, 0, xgwa.width, xgwa.height, 0, 0);
1459 else /* size mismatch -- must scale client-side images to fit drawable */
1463 XErrorHandler old_handler;
1466 old_handler = XSetErrorHandler (ignore_badmatch_ehandler);
1467 error_handler_hit_p = False;
1469 /* This can return BadMatch if the window is not fully on screen.
1470 Trap that error and return color bars in that case.
1471 (Note that this only happens with XGetImage, not with XCopyArea:
1472 yet another totally gratuitous inconsistency in X, thanks.)
1474 ximage = XGetImage (dpy, window, 0, 0, xgwa.width, xgwa.height,
1478 XSetErrorHandler (old_handler);
1481 if (error_handler_hit_p)
1485 fprintf (stderr, "%s: BadMatch reading window 0x%x contents!\n",
1486 progname, (unsigned int) window);
1490 !scale_ximage (xgwa.screen, xgwa.visual, ximage, w2, h2))
1493 gc = XCreateGC (dpy, drawable, 0, &gcv);
1494 clear_drawable (screen, drawable);
1495 XPutImage (dpy, drawable, gc, ximage,
1496 srcx, srcy, destx, desty, ximage->width, ximage->height);
1497 XDestroyImage (ximage);
1503 geom_ret->x = destx;
1504 geom_ret->y = desty;
1505 geom_ret->width = w2;
1506 geom_ret->height = h2;
1512 # endif /* !USE_EXTERNAL_SCREEN_GRABBER */
1516 /* Whether the given Drawable is unreasonably small.
1519 drawable_miniscule_p (Display *dpy, Drawable drawable)
1523 unsigned int bw, d, w = 0, h = 0;
1524 XGetGeometry (dpy, drawable, &root, &xx, &yy, &w, &h, &bw, &d);
1525 return (w < 32 || h < 30);
1529 /* Grabs an image (from a file, video, or the desktop) and renders it on
1530 the Drawable. If `file' is specified, always use that file. Otherwise,
1531 select randomly, based on the other arguments.
1534 get_image (Screen *screen,
1535 Window window, Drawable drawable,
1543 Display *dpy = DisplayOfScreen (screen);
1544 grab_type which = GRAB_BARS;
1546 const char *file_prop = 0;
1548 XRectangle geom = { 0, 0, 0, 0 };
1550 if (! drawable_window_p (dpy, window))
1552 fprintf (stderr, "%s: 0x%lx is a pixmap, not a window!\n",
1553 progname, (unsigned long) window);
1557 /* Make sure the Screen and the Window correspond. */
1559 XWindowAttributes xgwa;
1560 XGetWindowAttributes (dpy, window, &xgwa);
1561 screen = xgwa.screen;
1564 if (file && stat (file, &st))
1566 fprintf (stderr, "%s: file \"%s\" does not exist\n", progname, file);
1572 fprintf (stderr, "%s: grabDesktopImages: %s\n",
1573 progname, desk_p ? "True" : "False");
1574 fprintf (stderr, "%s: grabVideoFrames: %s\n",
1575 progname, video_p ? "True" : "False");
1576 fprintf (stderr, "%s: chooseRandomImages: %s\n",
1577 progname, image_p ? "True" : "False");
1578 fprintf (stderr, "%s: imageDirectory: %s\n",
1579 progname, (file ? file : dir ? dir : ""));
1582 # if !(defined(HAVE_GDK_PIXBUF) || defined(HAVE_JPEGLIB))
1583 image_p = False; /* can't load images from files... */
1584 # ifdef USE_EXTERNAL_SCREEN_GRABBER
1585 desk_p = False; /* ...or from desktops grabbed to files. */
1591 "%s: image file loading not available at compile-time\n",
1593 fprintf (stderr, "%s: can't load \"%s\"\n", progname, file);
1596 # endif /* !(HAVE_GDK_PIXBUF || HAVE_JPEGLIB) */
1604 else if (!dir || !*dir)
1606 if (verbose_p && image_p)
1608 "%s: no imageDirectory: turning off chooseRandomImages.\n",
1613 /* If the target drawable is really small, no good can come of that.
1614 Always do colorbars in that case.
1616 if (drawable_miniscule_p (dpy, drawable))
1624 # error Error! This file definitely needs vroot.h!
1627 /* We can grab desktop images (using the normal X11 method) if:
1628 - the window is the real root window;
1629 - the window is a toplevel window.
1630 We cannot grab desktop images that way if:
1631 - the window is a non-top-level window.
1633 Under X11 on MacOS, desktops are just like loaded image files.
1634 Under Cocoa on MacOS, this code is not used at all.
1636 # ifndef USE_EXTERNAL_SCREEN_GRABBER
1639 if (!top_level_window_p (screen, window))
1644 "%s: 0x%x not top-level: turning off grabDesktopImages.\n",
1645 progname, (unsigned int) window);
1648 # endif /* !USE_EXTERNAL_SCREEN_GRABBER */
1650 if (! (desk_p || video_p || image_p))
1656 /* Loop until we get one that's permitted.
1657 If files or video are permitted, do them more often
1660 D+V+I: 10% + 45% + 45%.
1666 n = (random() % 100);
1667 if (++i > 300) abort();
1668 else if (desk_p && n < 10) which = GRAB_DESK; /* 10% */
1669 else if (video_p && n < 55) which = GRAB_VIDEO; /* 45% */
1670 else if (image_p) which = GRAB_FILE; /* 45% */
1675 /* If we're to search a directory to find an image file, do so now.
1677 if (which == GRAB_FILE && !file)
1679 file = get_filename (screen, dir, verbose_p);
1684 fprintf (stderr, "%s: no image files found.\n", progname);
1688 /* Now actually render something.
1694 XWindowAttributes xgwa;
1697 fprintf (stderr, "%s: drawing colorbars.\n", progname);
1698 XGetWindowAttributes (dpy, window, &xgwa);
1699 colorbars (screen, xgwa.visual, drawable, xgwa.colormap);
1701 if (! file_prop) file_prop = "";
1707 if (! display_desktop (screen, window, drawable, verbose_p, &geom))
1709 file_prop = "desktop";
1713 if (*file && *file != '/') /* pathname is relative to dir. */
1715 if (absfile) free (absfile);
1716 absfile = malloc (strlen(dir) + strlen(file) + 10);
1717 strcpy (absfile, dir);
1718 if (dir[strlen(dir)-1] != '/')
1719 strcat (absfile, "/");
1720 strcat (absfile, file);
1722 if (! display_file (screen, window, drawable,
1723 (absfile ? absfile : file),
1730 if (! display_video (screen, window, drawable, verbose_p, &geom))
1732 file_prop = "video";
1741 Atom a = XInternAtom (dpy, XA_XSCREENSAVER_IMAGE_FILENAME, False);
1742 if (file_prop && *file_prop)
1744 char *f2 = strdup (file_prop);
1746 /* Take the extension off of the file name. */
1747 /* Duplicated in utils/grabclient.c. */
1748 char *slash = strrchr (f2, '/');
1749 char *dot = strrchr ((slash ? slash : f2), '.');
1751 /* Replace slashes with newlines */
1752 /* while ((dot = strchr(f2, '/'))) *dot = '\n'; */
1753 /* Replace slashes with spaces */
1754 /* while ((dot = strchr(f2, '/'))) *dot = ' '; */
1756 XChangeProperty (dpy, window, a, XA_STRING, 8, PropModeReplace,
1757 (unsigned char *) f2, strlen(f2));
1761 XDeleteProperty (dpy, window, a);
1763 a = XInternAtom (dpy, XA_XSCREENSAVER_IMAGE_GEOMETRY, False);
1767 sprintf (gstr, "%dx%d+%d+%d", geom.width, geom.height, geom.x, geom.y);
1768 XChangeProperty (dpy, window, a, XA_STRING, 8, PropModeReplace,
1769 (unsigned char *) gstr, strlen (gstr));
1772 XDeleteProperty (dpy, window, a);
1775 if (absfile) free (absfile);
1782 mapper (XrmDatabase *db, XrmBindingList bindings, XrmQuarkList quarks,
1783 XrmRepresentation *type, XrmValue *value, XPointer closure)
1786 for (i = 0; quarks[i]; i++)
1788 if (bindings[i] == XrmBindTightly)
1789 fprintf (stderr, (i == 0 ? "" : "."));
1790 else if (bindings[i] == XrmBindLoosely)
1791 fprintf (stderr, "*");
1793 fprintf (stderr, " ??? ");
1794 fprintf(stderr, "%s", XrmQuarkToString (quarks[i]));
1797 fprintf (stderr, ": %s\n", (char *) value->addr);
1804 #define USAGE "usage: %s [ -options... ] window-id [pixmap-id]\n" \
1808 " %s puts an image on the given window or pixmap.\n" \
1810 " It is used by those xscreensaver demos that operate on images.\n" \
1811 " The image may be a file loaded from disk, a frame grabbed from\n" \
1812 " the system's video camera, or a screenshot of the desktop,\n" \
1813 " depending on command-line options or the ~/.xscreensaver file.\n" \
1815 " Options include:\n" \
1817 " -display host:dpy.screen which display to use\n" \
1818 " -root draw to the root window\n" \
1819 " -verbose print diagnostics\n" \
1820 " -images / -no-images whether to allow image file loading\n" \
1821 " -video / -no-video whether to allow video grabs\n" \
1822 " -desktop / -no-desktop whether to allow desktop screen grabs\n"\
1823 " -directory <path> where to find image files to load\n" \
1824 " -file <filename> load this image file\n" \
1826 " The XScreenSaver Control Panel (xscreensaver-demo) lets you set the\n"\
1827 " defaults for these options in your ~/.xscreensaver file.\n" \
1831 main (int argc, char **argv)
1833 saver_preferences P;
1837 char *oprogname = progname;
1841 Window window = (Window) 0;
1842 Drawable drawable = (Drawable) 0;
1843 const char *window_str = 0;
1844 const char *drawable_str = 0;
1849 s = strrchr (progname, '/');
1850 if (s) progname = s+1;
1851 oprogname = progname;
1853 /* half-assed way of avoiding buffer-overrun attacks. */
1854 if (strlen (progname) >= 100) progname[100] = 0;
1857 # error Error! This file definitely needs vroot.h!
1860 /* Get the version number, for error messages. */
1862 char *v = (char *) strdup(strchr(screensaver_id, ' '));
1863 char *s1, *s2, *s3, *s4;
1864 s1 = (char *) strchr(v, ' '); s1++;
1865 s2 = (char *) strchr(s1, ' ');
1866 s3 = (char *) strchr(v, '('); s3++;
1867 s4 = (char *) strchr(s3, ')');
1870 sprintf (version, "Part of XScreenSaver %s -- %s.", s1, s3);
1874 /* We must read exactly the same resources as xscreensaver.
1875 That means we must have both the same progclass *and* progname,
1876 at least as far as the resource database is concerned. So,
1877 put "xscreensaver" in argv[0] while initializing Xt.
1879 progname = argv[0] = "xscreensaver";
1881 /* allow one dash or two. */
1882 for (i = 1; i < argc; i++)
1883 if (argv[i][0] == '-' && argv[i][1] == '-') argv[i]++;
1885 toplevel = XtAppInitialize (&app, progclass, 0, 0, &argc, argv,
1887 dpy = XtDisplay (toplevel);
1888 screen = XtScreen (toplevel);
1889 db = XtDatabase (dpy);
1890 XtGetApplicationNameAndClass (dpy, &s, &progclass);
1891 XSetErrorHandler (x_ehandler);
1894 /* Randomize -- only need to do this here because this program
1895 doesn't use the `screenhack.h' or `lockmore.h' APIs. */
1896 # undef ya_rand_init
1899 memset (&P, 0, sizeof(P));
1901 load_init_file (dpy, &P);
1903 progname = argv[0] = oprogname;
1905 for (i = 1; i < argc; i++)
1910 /* Have to re-process these, or else the .xscreensaver file
1911 has priority over the command line...
1913 if (!strcmp (argv[i], "-v") || !strcmp (argv[i], "-verbose"))
1915 else if (!strcmp (argv[i], "-desktop")) P.grab_desktop_p = True;
1916 else if (!strcmp (argv[i], "-no-desktop")) P.grab_desktop_p = False;
1917 else if (!strcmp (argv[i], "-video")) P.grab_video_p = True;
1918 else if (!strcmp (argv[i], "-no-video")) P.grab_video_p = False;
1919 else if (!strcmp (argv[i], "-images")) P.random_image_p = True;
1920 else if (!strcmp (argv[i], "-no-images")) P.random_image_p = False;
1921 else if (!strcmp (argv[i], "-file")) file = argv[++i];
1922 else if (!strcmp (argv[i], "-directory") || !strcmp (argv[i], "-dir"))
1923 P.image_directory = argv[++i];
1924 else if (!strcmp (argv[i], "-root") || !strcmp (argv[i], "root"))
1928 fprintf (stderr, "%s: both %s and %s specified?\n",
1929 progname, argv[i], window_str);
1932 window_str = argv[i];
1933 window = VirtualRootWindowOfScreen (screen);
1935 else if ((1 == sscanf (argv[i], " 0x%lx %c", &w, &dummy) ||
1936 1 == sscanf (argv[i], " %lu %c", &w, &dummy)) &&
1941 fprintf (stderr, "%s: both %s and %s specified?\n",
1942 progname, drawable_str, argv[i]);
1947 drawable_str = argv[i];
1948 drawable = (Drawable) w;
1952 window_str = argv[i];
1953 window = (Window) w;
1958 if (argv[i][0] == '-')
1959 fprintf (stderr, "\n%s: unknown option \"%s\"\n",
1962 fprintf (stderr, "\n%s: unparsable window/pixmap ID: \"%s\"\n",
1966 __extension__ /* don't warn about "string length is greater than
1967 the length ISO C89 compilers are required to
1968 support" in the usage string... */
1970 fprintf (stderr, USAGE, progname, version, progname);
1977 fprintf (stderr, "\n%s: no window ID specified!\n", progname);
1983 if (P.verbose_p) /* Print out all the resources we can see. */
1985 XrmName name = { 0 };
1986 XrmClass class = { 0 };
1988 XrmEnumerateDatabase (db, &name, &class, XrmEnumAllLevels, mapper,
1989 (XtPointer) &count);
1993 if (!window) abort();
1994 if (!drawable) drawable = window;
1996 get_image (screen, window, drawable, P.verbose_p,
1997 P.grab_desktop_p, P.grab_video_p, P.random_image_p,
1998 P.image_directory, file);