1 /* xscreensaver, Copyright (c) 2001, 2002, 2003 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 __extension__ /* shut up about "string length is greater than the length
70 ISO C89 compilers are required to support" when including
74 static char *defaults[] = {
75 #include "../driver/XScreenSaver_ad.h"
82 char *progclass = "XScreenSaver";
86 extern void grabscreen_verbose (void);
89 #define GETIMAGE_VIDEO_PROGRAM "xscreensaver-getimage-video"
90 #define GETIMAGE_FILE_PROGRAM "xscreensaver-getimage-file"
100 x_ehandler (Display *dpy, XErrorEvent *error)
102 if (error->error_code == BadWindow || error->error_code == BadDrawable)
104 fprintf (stderr, "%s: target %s 0x%lx unexpectedly deleted\n", progname,
105 (error->error_code == BadWindow ? "window" : "pixmap"),
106 (unsigned long) error->resourceid);
110 fprintf (stderr, "\nX error in %s:\n", progname);
111 XmuPrintDefaultErrorMessage (dpy, error, stderr);
118 static Bool error_handler_hit_p = False;
121 ignore_all_errors_ehandler (Display *dpy, XErrorEvent *error)
123 error_handler_hit_p = True;
128 /* Returns True if the given Drawable is a Window; False if it's a Pixmap.
131 drawable_window_p (Display *dpy, Drawable d)
133 XErrorHandler old_handler;
134 XWindowAttributes xgwa;
137 old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
138 error_handler_hit_p = False;
139 XGetWindowAttributes (dpy, d, &xgwa);
141 XSetErrorHandler (old_handler);
144 if (!error_handler_hit_p)
145 return True; /* It's a Window. */
147 return False; /* It's a Pixmap, or an invalid ID. */
151 /* Returns true if the window is the root window, or a virtual root window,
152 but *not* the xscreensaver window. That is, if it's a "real" desktop
153 root window of some kind.
156 root_window_p (Screen *screen, Window window)
158 Display *dpy = DisplayOfScreen (screen);
161 unsigned long nitems, bytesafter;
164 if (window != RootWindowOfScreen (screen))
167 if (XGetWindowProperty (dpy, window,
168 XInternAtom (dpy, "_SCREENSAVER_VERSION", False),
169 0, 1, False, XA_STRING,
170 &type, &format, &nitems, &bytesafter,
171 (unsigned char **) &version)
180 /* Clear the window or pixmap to black, or its background color.
183 clear_drawable (Screen *screen, Drawable drawable)
185 Display *dpy = DisplayOfScreen (screen);
190 unsigned int w, h, bw, d;
191 XGetGeometry (dpy, drawable, &root, &x, &y, &w, &h, &bw, &d);
193 /* The window might have no-op background of None, so to clear it,
194 draw a black rectangle first, then do XClearWindow (in case the
195 actual background color is non-black...) */
197 /* #### really we should allocate "black" instead, but I'm lazy... */
198 gcv.foreground = BlackPixelOfScreen (screen);
199 gc = XCreateGC (dpy, drawable, GCForeground, &gcv);
200 XFillRectangle (dpy, drawable, gc, 0, 0, w, h);
202 if (drawable_window_p (dpy, drawable))
203 XClearWindow (dpy, (Window) drawable);
208 /* Figure out what kind of scaling/positioning we ought to do to display
209 a src-sized image in a dest-sized window/pixmap. Returns the width
210 and height to which the image should be scaled, and the position where
211 it should be displayed to center it.
214 compute_image_scaling (int src_w, int src_h,
215 int dest_w, int dest_h,
217 int *scaled_from_x_ret, int *scaled_from_y_ret,
218 int *scaled_to_x_ret, int *scaled_to_y_ret,
219 int *scaled_w_ret, int *scaled_h_ret)
221 int srcx, srcy, destx, desty;
223 Bool exact_fit_p = ((src_w == dest_w && src_h <= dest_h) ||
224 (src_h == dest_h && src_w <= dest_w));
226 if (!exact_fit_p) /* scale the image up or down */
228 float rw = (float) dest_w / src_w;
229 float rh = (float) dest_h / src_h;
230 float r = (rw < rh ? rw : rh);
236 /* this optimization breaks things */
237 if (pct < 95 || pct > 105) /* don't scale if it's close */
241 fprintf (stderr, "%s: scaling image by %d%% (%dx%d -> %dx%d)\n",
242 progname, pct, src_w, src_h, tw, th);
248 /* Center the image on the window/pixmap. */
251 destx = (dest_w - src_w) / 2;
252 desty = (dest_h - src_h) / 2;
253 if (destx < 0) srcx = -destx, destx = 0;
254 if (desty < 0) srcy = -desty, desty = 0;
256 if (dest_w < src_w) src_w = dest_w;
257 if (dest_h < src_h) src_h = dest_h;
259 *scaled_w_ret = src_w;
260 *scaled_h_ret = src_h;
261 *scaled_from_x_ret = srcx;
262 *scaled_from_y_ret = srcy;
263 *scaled_to_x_ret = destx;
264 *scaled_to_y_ret = desty;
267 fprintf (stderr, "%s: displaying %dx%d image at %d,%d.\n",
268 progname, src_w, src_h, destx, desty);
272 #ifdef HAVE_GDK_PIXBUF
274 /* Reads the given image file and renders it on the Drawable, using GDK.
275 Returns False if it fails.
278 read_file_gdk (Screen *screen, Window window, Drawable drawable,
279 const char *filename, Bool verbose_p)
282 Display *dpy = DisplayOfScreen (screen);
283 unsigned int win_width, win_height, win_depth;
286 # endif /* HAVE_GTK2 */
288 /* Find the size of the Drawable. */
293 XGetGeometry (dpy, drawable,
294 &root, &x, &y, &win_width, &win_height, &bw, &win_depth);
297 gdk_pixbuf_xlib_init (dpy, screen_number (screen));
300 # else /* !HAVE_GTK2 */
301 xlib_rgb_init (dpy, screen);
302 # endif /* !HAVE_GTK2 */
304 pb = gdk_pixbuf_new_from_file (filename
307 # endif /* HAVE_GTK2 */
312 fprintf (stderr, "%s: unable to load \"%s\"\n", progname, filename);
314 if (gerr && gerr->message && *gerr->message)
315 fprintf (stderr, "%s: reason: %s\n", progname, gerr->message);
316 # endif /* HAVE_GTK2 */
321 int w = gdk_pixbuf_get_width (pb);
322 int h = gdk_pixbuf_get_height (pb);
323 int srcx, srcy, destx, desty, w2, h2;
326 compute_image_scaling (w, h, win_width, win_height, verbose_p,
327 &srcx, &srcy, &destx, &desty, &w2, &h2);
328 if (w != w2 || h != h2)
330 GdkPixbuf *pb2 = gdk_pixbuf_scale_simple (pb, w2, h2,
331 GDK_INTERP_BILINEAR);
334 gdk_pixbuf_unref (pb);
340 fprintf (stderr, "%s: out of memory when scaling?\n", progname);
343 /* If we're rendering onto the root window (and it's not the
344 xscreensaver pseudo-root) then put the image in the window's
345 background. Otherwise, just paint the image onto the window.
347 bg_p = (window == drawable && root_window_p (screen, window));
353 drawable = XCreatePixmap (dpy, window,
354 win_width, win_height, win_depth);
355 gcv.foreground = BlackPixelOfScreen (screen);
356 gc = XCreateGC (dpy, drawable, GCForeground, &gcv);
357 XFillRectangle (dpy, drawable, gc, 0, 0, win_width, win_height);
361 clear_drawable (screen, drawable);
363 /* #### Note that this always uses the default colormap! Morons!
364 Owen says that in Gnome 2.0, I should try using
365 gdk_pixbuf_render_pixmap_and_mask_for_colormap() instead.
368 gdk_pixbuf_xlib_render_to_drawable_alpha (pb, drawable,
369 srcx, srcy, destx, desty,
371 GDK_PIXBUF_ALPHA_FULL, 127,
372 XLIB_RGB_DITHER_NORMAL,
376 XSetWindowBackgroundPixmap (dpy, window, drawable);
377 XClearWindow (dpy, window);
385 #endif /* HAVE_GDK_PIXBUF */
391 /* Allocates a colormap that makes a PseudoColor or DirectColor
392 visual behave like a TrueColor visual of the same depth.
395 allocate_cubic_colormap (Screen *screen, Visual *visual, Colormap cmap,
398 Display *dpy = DisplayOfScreen (screen);
399 int nr, ng, nb, cells;
405 depth = visual_depth (screen, visual);
409 case 8: nr = 3; ng = 3; nb = 2; cells = 256; break;
410 case 12: nr = 4; ng = 4; nb = 4; cells = 4096; break;
411 default: abort(); break;
414 memset(colors, 0, sizeof(colors));
415 for (r = 0; r < (1 << nr); r++)
416 for (g = 0; g < (1 << ng); g++)
417 for (b = 0; b < (1 << nb); b++)
419 i = (r | (g << nr) | (b << (nr + ng)));
421 colors[i].flags = DoRed|DoGreen|DoBlue;
424 colors[i].red = ((r << 13) | (r << 10) | (r << 7) |
425 (r << 4) | (r << 1));
426 colors[i].green = ((g << 13) | (g << 10) | (g << 7) |
427 (g << 4) | (g << 1));
428 colors[i].blue = ((b << 14) | (b << 12) | (b << 10) |
429 (b << 8) | (b << 6) | (b << 4) |
434 colors[i].red = (r << 12) | (r << 8) | (r << 4) | r;
435 colors[i].green = (g << 12) | (g << 8) | (g << 4) | g;
436 colors[i].blue = (b << 12) | (b << 8) | (b << 4) | b;
443 int interleave = cells / 8; /* skip around, rather than allocating in
444 order, so that we get better coverage if
445 we can't allocated all of them. */
446 for (j = 0; j < interleave; j++)
447 for (i = 0; i < cells; i += interleave)
448 if (XAllocColor (dpy, cmap, &colors[i + j]))
452 fprintf (stderr, "%s: allocated %d of %d colors for cubic map\n",
453 progname, allocated, cells);
457 /* Find the pixel index that is closest to the given color
458 (using linear distance in RGB space -- which is far from the best way.)
461 find_closest_pixel (XColor *colors, int ncolors,
462 unsigned long r, unsigned long g, unsigned long b)
464 unsigned long distance = ~0;
469 for (i = 0; i < ncolors; i++)
474 rd = r - colors[i].red;
475 gd = g - colors[i].green;
476 bd = b - colors[i].blue;
477 if (rd < 0) rd = -rd;
478 if (gd < 0) gd = -gd;
479 if (bd < 0) bd = -bd;
480 d = (rd << 1) + (gd << 2) + bd;
495 /* Given an XImage with 8-bit or 12-bit RGB data, convert it to be
496 displayable with the given X colormap. The farther from a perfect
497 color cube the contents of the colormap are, the lossier the
498 transformation will be. No dithering is done.
501 remap_image (Screen *screen, Colormap cmap, XImage *image, Bool verbose_p)
503 Display *dpy = DisplayOfScreen (screen);
504 unsigned long map[4097];
509 if (image->depth == 8)
511 else if (image->depth == 12)
516 memset(map, -1, sizeof(*map));
517 memset(colors, -1, sizeof(*colors));
519 for (i = 0; i < cells; i++)
521 XQueryColors (dpy, cmap, colors, cells);
524 fprintf(stderr, "%s: building color cube for %d bit image\n",
525 progname, image->depth);
527 for (i = 0; i < cells; i++)
529 unsigned short r, g, b;
533 /* "RRR GGG BB" In an 8 bit map. Convert that to
534 "RRR RRR RR" "GGG GGG GG" "BB BB BB BB" to give
540 r = ((r << 13) | (r << 10) | (r << 7) | (r << 4) | (r << 1));
541 g = ((g << 13) | (g << 10) | (g << 7) | (g << 4) | (g << 1));
542 b = ((b << 14) | (b << 12) | (b << 10) | (b << 8) |
543 (b << 6) | (b << 4) | (b << 2) | b);
547 /* "RRRR GGGG BBBB" In a 12 bit map. Convert that to
548 "RRRR RRRR" "GGGG GGGG" "BBBB BBBB" to give an even
551 g = (i & 0x0F0) >> 4;
552 b = (i & 0xF00) >> 8;
554 r = (r << 12) | (r << 8) | (r << 4) | r;
555 g = (g << 12) | (g << 8) | (g << 4) | g;
556 b = (b << 12) | (b << 8) | (b << 4) | b;
559 map[i] = find_closest_pixel (colors, cells, r, g, b);
563 fprintf(stderr, "%s: remapping colors in %d bit image\n",
564 progname, image->depth);
566 for (y = 0; y < image->height; y++)
567 for (x = 0; x < image->width; x++)
569 unsigned long pixel = XGetPixel(image, x, y);
570 if (pixel >= cells) abort();
571 XPutPixel(image, x, y, map[pixel]);
576 /* If the file has a PPM (P6) on it, read it and return an XImage.
577 Otherwise, rewind the fd back to the beginning, and return 0.
580 maybe_read_ppm (Screen *screen, Visual *visual,
581 const char *filename, FILE *in, Bool verbose_p)
583 Display *dpy = DisplayOfScreen (screen);
584 int depth = visual_depth (screen, visual);
590 int x, y, w, h, maxval;
593 if (fstat (fileno (in), &st))
597 buf = (char *) malloc (bufsiz + 1);
600 fprintf (stderr, "%s: out of memory loading %d byte PPM file %s\n",
601 progname, bufsiz, filename);
605 if (! (s = fgets (buf, bufsiz, in))) /* line 1 */
608 if (!strncmp (buf, "\107\111", 2))
610 fprintf (stderr, "%s: %s: sorry, GIF files not supported"
611 " when compiled with JPEGlib instead of GDK_Pixbuf.\n",
615 else if (!strncmp (buf, "\211\120", 2))
617 fprintf (stderr, "%s: %s: sorry, PNG files not supported"
618 " when compiled with JPEGlib instead of GDK_Pixbuf.\n",
623 if (strncmp (s, "P6", 2))
626 if (! (s = fgets (buf, bufsiz, in))) /* line 2 */
628 if (2 != sscanf (s, " %d %d %c", &w, &h, &dummy))
630 fprintf (stderr, "%s: %s: invalid PPM (line 2)\n", progname, filename);
634 if (! (s = fgets (buf, bufsiz, in))) /* line 3 */
636 if (1 != sscanf (s, " %d %c", &maxval, &dummy))
638 fprintf (stderr, "%s: %s: invalid PPM (line 3)\n", progname, filename);
643 fprintf (stderr, "%s: %s: unparsable PPM: maxval is %d\n",
644 progname, filename, maxval);
648 ximage = XCreateImage (dpy, visual, depth, ZPixmap, 0, 0,
651 ximage->data = (char *) calloc (ximage->height, ximage->bytes_per_line);
652 if (!ximage || !ximage->data)
654 fprintf (stderr, "%s: out of memory loading %dx%d PPM file %s\n",
655 progname, ximage->width, ximage->height, filename);
661 while ((i = fread (s, 1, j, in)) > 0)
665 for (y = 0; y < ximage->height; y++)
666 for (x = 0; x < ximage->width; x++)
668 unsigned char r = buf[i++];
669 unsigned char g = buf[i++];
670 unsigned char b = buf[i++];
674 pixel = (r << 16) | (g << 8) | b;
676 pixel = ((r >> 5) | ((g >> 5) << 3) | ((b >> 6) << 6));
677 else if (depth == 12)
678 pixel = ((r >> 4) | ((g >> 4) << 4) | ((b >> 4) << 8));
679 else if (depth == 16 || depth == 15)
680 pixel = (((r >> 3) << 10) | ((g >> 3) << 5) | ((b >> 3)));
684 XPutPixel (ximage, x, y, pixel);
692 if (ximage && ximage->data)
697 if (ximage) XDestroyImage (ximage);
698 fseek (in, 0, SEEK_SET);
704 struct jpeg_error_mgr pub; /* this is what passes for subclassing in C */
705 const char *filename;
710 } getimg_jpg_error_mgr;
714 jpg_output_message (j_common_ptr cinfo)
716 getimg_jpg_error_mgr *err = (getimg_jpg_error_mgr *) cinfo->err;
717 char buf[JMSG_LENGTH_MAX];
718 cinfo->err->format_message (cinfo, buf);
719 fprintf (stderr, "%s: %s: %s\n", progname, err->filename, buf);
724 jpg_error_exit (j_common_ptr cinfo)
726 getimg_jpg_error_mgr *err = (getimg_jpg_error_mgr *) cinfo->err;
727 cinfo->err->output_message (cinfo);
728 draw_colorbars (err->screen, err->visual, err->drawable, err->cmap,
730 XSync (DisplayOfScreen (err->screen), False);
735 /* Reads a JPEG file, returns an RGB XImage of it.
738 read_jpeg_ximage (Screen *screen, Visual *visual, Drawable drawable,
739 Colormap cmap, const char *filename, Bool verbose_p)
741 Display *dpy = DisplayOfScreen (screen);
742 int depth = visual_depth (screen, visual);
746 struct jpeg_decompress_struct cinfo;
747 getimg_jpg_error_mgr jerr;
748 JSAMPARRAY scanbuf = 0;
751 jerr.filename = filename;
752 jerr.screen = screen;
753 jerr.visual = visual;
754 jerr.drawable = drawable;
757 if (! (depth >= 15 || depth == 12 || depth == 8))
759 fprintf (stderr, "%s: unsupported depth: %d\n", progname, depth);
763 in = fopen (filename, "rb");
766 fprintf (stderr, "%s: %s: unreadable\n", progname, filename);
770 /* Check to see if it's a PPM, and if so, read that instead of using
771 the JPEG library. Yeah, this is all modular and stuff.
773 if ((ximage = maybe_read_ppm (screen, visual, filename, in, verbose_p)))
779 cinfo.err = jpeg_std_error (&jerr.pub);
780 jerr.pub.output_message = jpg_output_message;
781 jerr.pub.error_exit = jpg_error_exit;
783 jpeg_create_decompress (&cinfo);
784 jpeg_stdio_src (&cinfo, in);
785 jpeg_read_header (&cinfo, TRUE);
787 /* set some decode parameters */
788 cinfo.out_color_space = JCS_RGB;
789 cinfo.quantize_colors = FALSE;
791 jpeg_start_decompress (&cinfo);
793 ximage = XCreateImage (dpy, visual, depth, ZPixmap, 0, 0,
794 cinfo.output_width, cinfo.output_height,
797 ximage->data = (char *) calloc (ximage->height, ximage->bytes_per_line);
799 if (ximage && ximage->data)
800 scanbuf = (*cinfo.mem->alloc_sarray) ((j_common_ptr) &cinfo, JPOOL_IMAGE,
801 cinfo.rec_outbuf_height *
803 cinfo.output_components,
805 if (!ximage || !ximage->data || !scanbuf)
807 fprintf (stderr, "%s: out of memory loading %dx%d file %s\n",
808 progname, ximage->width, ximage->height, filename);
813 while (cinfo.output_scanline < cinfo.output_height)
815 int n = jpeg_read_scanlines (&cinfo, scanbuf, 1);
817 for (i = 0; i < n; i++)
820 for (x = 0; x < ximage->width; x++)
822 int j = x * cinfo.num_components;
823 unsigned char r = scanbuf[i][j];
824 unsigned char g = scanbuf[i][j+1];
825 unsigned char b = scanbuf[i][j+2];
829 pixel = (r << 16) | (g << 8) | b;
831 pixel = ((r >> 5) | ((g >> 5) << 3) | ((b >> 6) << 6));
832 else if (depth == 12)
833 pixel = ((r >> 4) | ((g >> 4) << 4) | ((b >> 4) << 8));
834 else if (depth == 16 || depth == 15)
835 /* Gah! I don't understand why these are in the other
837 pixel = (((r >> 3) << 10) | ((g >> 3) << 5) | ((b >> 3)));
841 XPutPixel (ximage, x, y, pixel);
847 if (cinfo.output_scanline < cinfo.output_height)
848 /* don't goto FAIL -- we might have viewable partial data. */
849 jpeg_abort_decompress (&cinfo);
851 jpeg_finish_decompress (&cinfo);
853 jpeg_destroy_decompress (&cinfo);
861 if (ximage && ximage->data)
866 if (ximage) XDestroyImage (ximage);
867 if (scanbuf) free (scanbuf);
872 /* Scales an XImage, modifying it in place.
873 If out of memory, returns False, and the XImage will have been
877 scale_ximage (Screen *screen, Visual *visual,
878 XImage *ximage, int new_width, int new_height)
880 Display *dpy = DisplayOfScreen (screen);
881 int depth = visual_depth (screen, visual);
883 double xscale, yscale;
885 XImage *ximage2 = XCreateImage (dpy, visual, depth,
887 new_width, new_height, 8, 0);
888 ximage2->data = (char *) calloc (ximage2->height, ximage2->bytes_per_line);
892 fprintf (stderr, "%s: out of memory scaling %dx%d image to %dx%d\n",
894 ximage->width, ximage->height,
895 ximage2->width, ximage2->height);
896 if (ximage->data) free (ximage->data);
897 if (ximage2->data) free (ximage2->data);
900 XDestroyImage (ximage);
901 XDestroyImage (ximage2);
905 /* Brute force scaling... */
906 xscale = (double) ximage->width / ximage2->width;
907 yscale = (double) ximage->height / ximage2->height;
908 for (y = 0; y < ximage2->height; y++)
909 for (x = 0; x < ximage2->width; x++)
910 XPutPixel (ximage2, x, y,
911 XGetPixel (ximage, x * xscale, y * yscale));
916 (*ximage) = (*ximage2);
919 XDestroyImage (ximage2);
925 /* Reads the given image file and renders it on the Drawable, using JPEG lib.
926 Returns False if it fails.
929 read_file_jpeglib (Screen *screen, Window window, Drawable drawable,
930 const char *filename, Bool verbose_p)
932 Display *dpy = DisplayOfScreen (screen);
937 unsigned int win_width, win_height, win_depth;
938 int srcx, srcy, destx, desty, w2, h2;
940 /* Find the size of the Drawable, and the Visual/Colormap of the Window. */
945 XWindowAttributes xgwa;
946 XGetWindowAttributes (dpy, window, &xgwa);
947 visual = xgwa.visual;
948 cmap = xgwa.colormap;
949 XGetGeometry (dpy, drawable,
950 &root, &x, &y, &win_width, &win_height, &bw, &win_depth);
953 /* Make sure we're not on some weirdo visual...
955 class = visual_class (screen, visual);
956 depth = visual_depth (screen, visual);
957 if ((class == PseudoColor || class == DirectColor) &&
958 (depth != 8 && depth != 12))
960 fprintf (stderr, "%s: Pseudo/DirectColor depth %d unsupported\n",
967 ximage = read_jpeg_ximage (screen, visual, drawable, cmap,
968 filename, verbose_p);
969 if (!ximage) return False;
971 /* Scale it, if necessary...
973 compute_image_scaling (ximage->width, ximage->height,
974 win_width, win_height, verbose_p,
975 &srcx, &srcy, &destx, &desty, &w2, &h2);
976 if (ximage->width != w2 || ximage->height != h2)
977 if (! scale_ximage (screen, visual, ximage, w2, h2))
980 /* Allocate a colormap, if we need to...
982 if (class == PseudoColor || class == DirectColor)
984 allocate_cubic_colormap (screen, visual, cmap, verbose_p);
985 remap_image (screen, cmap, ximage, verbose_p);
988 /* Finally, put the resized image on the window.
994 /* If we're rendering onto the root window (and it's not the xscreensaver
995 pseudo-root) then put the image in the window's background. Otherwise,
996 just paint the image onto the window.
998 if (window == drawable && root_window_p (screen, window))
1000 Pixmap bg = XCreatePixmap (dpy, window,
1001 win_width, win_height, win_depth);
1002 gcv.foreground = BlackPixelOfScreen (screen);
1003 gc = XCreateGC (dpy, drawable, GCForeground, &gcv);
1004 XFillRectangle (dpy, bg, gc, 0, 0, win_width, win_height);
1005 XPutImage (dpy, bg, gc, ximage,
1006 srcx, srcy, destx, desty, ximage->width, ximage->height);
1007 XSetWindowBackgroundPixmap (dpy, window, bg);
1008 XClearWindow (dpy, window);
1012 gc = XCreateGC (dpy, drawable, 0, &gcv);
1013 clear_drawable (screen, drawable);
1014 XPutImage (dpy, drawable, gc, ximage,
1015 srcx, srcy, destx, desty, ximage->width, ximage->height);
1021 free (ximage->data);
1023 XDestroyImage (ximage);
1028 #endif /* HAVE_JPEGLIB */
1031 /* Reads the given image file and renders it on the Drawable.
1032 Returns False if it fails.
1035 display_file (Screen *screen, Window window, Drawable drawable,
1036 const char *filename, Bool verbose_p)
1039 fprintf (stderr, "%s: loading \"%s\"\n", progname, filename);
1041 # if defined(HAVE_GDK_PIXBUF)
1042 if (read_file_gdk (screen, window, drawable, filename, verbose_p))
1044 # elif defined(HAVE_JPEGLIB)
1045 if (read_file_jpeglib (screen, window, drawable, filename, verbose_p))
1047 # else /* !(HAVE_GDK_PIXBUF || HAVE_JPEGLIB) */
1048 /* shouldn't get here if we have no image-loading methods available. */
1050 # endif /* !(HAVE_GDK_PIXBUF || HAVE_JPEGLIB) */
1056 /* Invokes a sub-process and returns its output (presumably, a file to
1057 load.) Free the string when done. video_p controls which program
1061 get_filename_1 (Screen *screen, const char *directory, Bool video_p,
1064 Display *dpy = DisplayOfScreen (screen);
1074 av[ac++] = GETIMAGE_FILE_PROGRAM;
1076 av[ac++] = "--verbose";
1077 av[ac++] = "--name";
1078 av[ac++] = (char *) directory;
1082 av[ac++] = GETIMAGE_VIDEO_PROGRAM;
1084 av[ac++] = "--verbose";
1085 av[ac++] = "--name";
1092 fprintf (stderr, "%s: executing:", progname);
1093 for (i = 0; i < ac; i++)
1094 fprintf (stderr, " %s", av[i]);
1095 fprintf (stderr, "\n");
1100 sprintf (buf, "%s: error creating pipe", progname);
1108 switch ((int) (forked = fork ()))
1112 sprintf (buf, "%s: couldn't fork", progname);
1120 close (in); /* don't need this one */
1121 close (ConnectionNumber (dpy)); /* close display fd */
1123 if (dup2 (out, stdout_fd) < 0) /* pipe stdout */
1125 sprintf (buf, "%s: could not dup() a new stdout", progname);
1126 exit (-1); /* exits fork */
1129 execvp (av[0], av); /* shouldn't return. */
1130 exit (-1); /* exits fork */
1136 int wait_status = 0;
1137 FILE *f = fdopen (in, "r");
1140 close (out); /* don't need this one */
1142 fgets (buf, sizeof(buf)-1, f);
1145 /* Wait for the child to die. */
1146 waitpid (-1, &wait_status, 0);
1149 while (L && buf[L-1] == '\n')
1156 fprintf (stderr, "%s: file does not exist: \"%s\"\n",
1161 return strdup (buf);
1169 /* Returns a pathname to an image file. Free the string when you're done.
1172 get_filename (Screen *screen, const char *directory, Bool verbose_p)
1174 return get_filename_1 (screen, directory, False, verbose_p);
1178 /* Grabs a video frame to a file, and returns a pathname to that file.
1179 Delete that file when you are done with it (and free the string.)
1182 get_video_filename (Screen *screen, Bool verbose_p)
1184 return get_filename_1 (screen, 0, True, verbose_p);
1188 /* Grabs a video frame, and renders it on the Drawable.
1189 Returns False if it fails;
1192 display_video (Screen *screen, Window window, Drawable drawable,
1195 char *filename = get_video_filename (screen, verbose_p);
1201 fprintf (stderr, "%s: video grab failed.\n", progname);
1205 status = display_file (screen, window, drawable, filename, verbose_p);
1207 if (unlink (filename))
1210 sprintf (buf, "%s: rm %.100s", progname, filename);
1214 fprintf (stderr, "%s: rm %s\n", progname, filename);
1216 if (filename) free (filename);
1221 /* Grabs an image (from a file, video, or the desktop) and renders it on
1222 the Drawable. If `file' is specified, always use that file. Otherwise,
1223 select randomly, based on the other arguments.
1226 get_image (Screen *screen,
1227 Window window, Drawable drawable,
1235 Display *dpy = DisplayOfScreen (screen);
1236 enum { do_desk, do_video, do_image, do_bars } which = do_bars;
1240 if (! drawable_window_p (dpy, window))
1242 fprintf (stderr, "%s: 0x%lx is a pixmap, not a window!\n",
1243 progname, (unsigned long) window);
1247 /* Make sure the Screen and the Window correspond. */
1249 XWindowAttributes xgwa;
1250 XGetWindowAttributes (dpy, window, &xgwa);
1251 screen = xgwa.screen;
1254 if (file && stat (file, &st))
1256 fprintf (stderr, "%s: file \"%s\" does not exist\n", progname, file);
1262 fprintf (stderr, "%s: grabDesktopImages: %s\n",
1263 progname, desk_p ? "True" : "False");
1264 fprintf (stderr, "%s: grabVideoFrames: %s\n",
1265 progname, video_p ? "True" : "False");
1266 fprintf (stderr, "%s: chooseRandomImages: %s\n",
1267 progname, image_p ? "True" : "False");
1268 fprintf (stderr, "%s: imageDirectory: %s\n",
1269 progname, (file ? file : dir ? dir : ""));
1272 # if !(defined(HAVE_GDK_PIXBUF) || defined(HAVE_JPEGLIB))
1273 image_p = False; /* can't load images from files... */
1277 "%s: image file loading not available at compile-time\n",
1279 fprintf (stderr, "%s: can't load \"%s\"\n", progname, file);
1282 # endif /* !(HAVE_GDK_PIXBUF || HAVE_JPEGLIB) */
1293 if (verbose_p && image_p)
1295 "%s: no imageDirectory: turning off chooseRandomImages.\n",
1302 # error Error! This file definitely needs vroot.h!
1305 /* We can grab desktop images if:
1306 - the window is the real root window;
1307 - the window is a toplevel window.
1308 We cannot grab desktop images if:
1309 - the window is a non-top-level window.
1313 if (!top_level_window_p (screen, window))
1318 "%s: 0x%x not top-level: turning off grabDesktopImages.\n",
1319 progname, (unsigned int) window);
1324 if (desk_p) count++;
1325 if (video_p) count++;
1326 if (image_p) count++;
1333 while (1) /* loop until we get one that's permitted */
1335 which = (random() % 3);
1336 if (which == do_desk && desk_p) break;
1337 if (which == do_video && video_p) break;
1338 if (which == do_image && image_p) break;
1339 if (++i > 200) abort();
1344 /* If we're to search a directory to find an image file, do so now.
1346 if (which == do_image && !file)
1348 file = get_filename (screen, dir, verbose_p);
1353 fprintf (stderr, "%s: no image files found.\n", progname);
1357 /* Now actually render something.
1359 if (which == do_bars)
1361 XWindowAttributes xgwa;
1364 fprintf (stderr, "%s: drawing colorbars.\n", progname);
1365 XGetWindowAttributes (dpy, window, &xgwa);
1366 draw_colorbars (screen, xgwa.visual, drawable, xgwa.colormap,
1370 else if (which == do_desk)
1374 XWindowAttributes xgwa;
1378 fprintf (stderr, "%s: grabbing desktop image\n", progname);
1379 grabscreen_verbose();
1381 gc = XCreateGC (dpy, drawable, 0, &gcv);
1382 XGetWindowAttributes (dpy, window, &xgwa);
1383 grab_screen_image (screen, window);
1384 XCopyArea (dpy, window, drawable, gc,
1385 0, 0, xgwa.width, xgwa.height, 0, 0);
1389 else if (which == do_image)
1391 if (! display_file (screen, window, drawable, file, verbose_p))
1394 else if (which == do_video)
1396 if (! display_video (screen, window, drawable, verbose_p))
1406 mapper (XrmDatabase *db, XrmBindingList bindings, XrmQuarkList quarks,
1407 XrmRepresentation *type, XrmValue *value, XPointer closure)
1410 for (i = 0; quarks[i]; i++)
1412 if (bindings[i] == XrmBindTightly)
1413 fprintf (stderr, (i == 0 ? "" : "."));
1414 else if (bindings[i] == XrmBindLoosely)
1415 fprintf (stderr, "*");
1417 fprintf (stderr, " ??? ");
1418 fprintf(stderr, "%s", XrmQuarkToString (quarks[i]));
1421 fprintf (stderr, ": %s\n", (char *) value->addr);
1428 #define USAGE "usage: %s [ -options... ] window-id [pixmap-id]\n" \
1432 " %s puts an image on the given window or pixmap.\n" \
1434 " It is used by those xscreensaver demos that operate on images.\n" \
1435 " The image may be a file loaded from disk, a frame grabbed from\n" \
1436 " the system's video camera, or a screenshot of the desktop,\n" \
1437 " depending on command-line options or the ~/.xscreensaver file.\n" \
1439 " Options include:\n" \
1441 " -display host:dpy.screen which display to use\n" \
1442 " -root draw to the root window\n" \
1443 " -verbose print diagnostics\n" \
1444 " -images / -no-images whether to allow image file loading\n" \
1445 " -video / -no-video whether to allow video grabs\n" \
1446 " -desktop / -no-desktop whether to allow desktop screen grabs\n"\
1447 " -directory <path> where to find image files to load\n" \
1448 " -file <filename> load this image file\n" \
1450 " The XScreenSaver Control Panel (xscreensaver-demo) lets you set the\n"\
1451 " defaults for these options in your ~/.xscreensaver file.\n" \
1455 main (int argc, char **argv)
1457 saver_preferences P;
1461 char *oprogname = progname;
1465 Window window = (Window) 0;
1466 Drawable drawable = (Drawable) 0;
1467 const char *window_str = 0;
1468 const char *drawable_str = 0;
1473 s = strrchr (progname, '/');
1474 if (s) progname = s+1;
1475 oprogname = progname;
1477 /* half-assed way of avoiding buffer-overrun attacks. */
1478 if (strlen (progname) >= 100) progname[100] = 0;
1481 # error Error! This file definitely needs vroot.h!
1484 /* Get the version number, for error messages. */
1486 char *v = (char *) strdup(strchr(screensaver_id, ' '));
1487 char *s1, *s2, *s3, *s4;
1488 s1 = (char *) strchr(v, ' '); s1++;
1489 s2 = (char *) strchr(s1, ' ');
1490 s3 = (char *) strchr(v, '('); s3++;
1491 s4 = (char *) strchr(s3, ')');
1494 sprintf (version, "Part of XScreenSaver %s -- %s.", s1, s3);
1498 /* We must read exactly the same resources as xscreensaver.
1499 That means we must have both the same progclass *and* progname,
1500 at least as far as the resource database is concerned. So,
1501 put "xscreensaver" in argv[0] while initializing Xt.
1503 progname = argv[0] = "xscreensaver";
1505 /* allow one dash or two. */
1506 for (i = 1; i < argc; i++)
1507 if (argv[i][0] == '-' && argv[i][1] == '-') argv[i]++;
1509 toplevel = XtAppInitialize (&app, progclass, 0, 0, &argc, argv,
1511 dpy = XtDisplay (toplevel);
1512 screen = XtScreen (toplevel);
1513 db = XtDatabase (dpy);
1514 XtGetApplicationNameAndClass (dpy, &s, &progclass);
1515 XSetErrorHandler (x_ehandler);
1518 /* Randomize -- only need to do this here because this program
1519 doesn't use the `screenhack.h' or `lockmore.h' APIs. */
1520 # undef ya_rand_init
1523 memset (&P, 0, sizeof(P));
1525 load_init_file (&P);
1527 progname = argv[0] = oprogname;
1529 for (i = 1; i < argc; i++)
1534 /* Have to re-process these, or else the .xscreensaver file
1535 has priority over the command line...
1537 if (!strcmp (argv[i], "-v") || !strcmp (argv[i], "-verbose"))
1539 else if (!strcmp (argv[i], "-desktop")) P.grab_desktop_p = True;
1540 else if (!strcmp (argv[i], "-no-desktop")) P.grab_desktop_p = False;
1541 else if (!strcmp (argv[i], "-video")) P.grab_video_p = True;
1542 else if (!strcmp (argv[i], "-no-video")) P.grab_video_p = False;
1543 else if (!strcmp (argv[i], "-images")) P.random_image_p = True;
1544 else if (!strcmp (argv[i], "-no-images")) P.random_image_p = False;
1545 else if (!strcmp (argv[i], "-file")) file = argv[++i];
1546 else if (!strcmp (argv[i], "-directory") || !strcmp (argv[i], "-dir"))
1547 P.image_directory = argv[++i];
1548 else if (!strcmp (argv[i], "-root") || !strcmp (argv[i], "root"))
1552 fprintf (stderr, "%s: both %s and %s specified?\n",
1553 progname, argv[i], window_str);
1556 window_str = argv[i];
1557 window = VirtualRootWindowOfScreen (screen);
1559 else if ((1 == sscanf (argv[i], " 0x%lx %c", &w, &dummy) ||
1560 1 == sscanf (argv[i], " %lu %c", &w, &dummy)) &&
1565 fprintf (stderr, "%s: both %s and %s specified?\n",
1566 progname, drawable_str, argv[i]);
1571 drawable_str = argv[i];
1572 drawable = (Drawable) w;
1576 window_str = argv[i];
1577 window = (Window) w;
1582 if (argv[i][0] == '-')
1583 fprintf (stderr, "\n%s: unknown option \"%s\"\n",
1586 fprintf (stderr, "\n%s: unparsable window/pixmap ID: \"%s\"\n",
1590 __extension__ /* don't warn about "string length is greater than
1591 the length ISO C89 compilers are required to
1592 support" in the usage string... */
1594 fprintf (stderr, USAGE, progname, version, progname);
1601 fprintf (stderr, "\n%s: no window ID specified!\n", progname);
1607 if (P.verbose_p) /* Print out all the resources we can see. */
1609 XrmName name = { 0 };
1610 XrmClass class = { 0 };
1612 XrmEnumerateDatabase (db, &name, &class, XrmEnumAllLevels, mapper,
1613 (XtPointer) &count);
1617 if (!window) abort();
1618 if (!drawable) drawable = window;
1620 get_image (screen, window, drawable, P.verbose_p,
1621 P.grab_desktop_p, P.grab_video_p, P.random_image_p,
1622 P.image_directory, file);