-/* xscreensaver, Copyright (c) 2001, 2002, 2003 by Jamie Zawinski <jwz@jwz.org>
+/* xscreensaver, Copyright (c) 2001-2006 by Jamie Zawinski <jwz@jwz.org>
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
#include "colorbars.h"
#include "visual.h"
#include "prefs.h"
+#include "version.h"
#include "vroot.h"
+#ifndef _XSCREENSAVER_VROOT_H_
+# error Error! You have an old version of vroot.h! Check -I args.
+#endif /* _XSCREENSAVER_VROOT_H_ */
+
#ifdef HAVE_GDK_PIXBUF
# undef HAVE_JPEGLIB
# ifdef HAVE_GTK2
#endif
+#ifdef __APPLE__
+ /* On MacOSX / XDarwin, the usual X11 mechanism of getting a screen shot
+ doesn't work, and we need to use an external program. */
+# define USE_EXTERNAL_SCREEN_GRABBER
+#endif
+
+
+#ifdef __GNUC__
+ __extension__ /* shut up about "string length is greater than the length
+ ISO C89 compilers are required to support" when including
+ the .ad file... */
+#endif
+
static char *defaults[] = {
#include "../driver/XScreenSaver_ad.h"
0
extern void grabscreen_verbose (void);
+typedef enum {
+ GRAB_DESK, GRAB_VIDEO, GRAB_FILE, GRAB_BARS
+} grab_type;
-#define GETIMAGE_VIDEO_PROGRAM "xscreensaver-getimage-video"
-#define GETIMAGE_FILE_PROGRAM "xscreensaver-getimage-file"
+
+#define GETIMAGE_VIDEO_PROGRAM "xscreensaver-getimage-video"
+#define GETIMAGE_FILE_PROGRAM "xscreensaver-getimage-file"
+#define GETIMAGE_SCREEN_PROGRAM "xscreensaver-getimage-desktop"
+
+extern const char *blurb (void);
const char *
blurb (void)
static int
x_ehandler (Display *dpy, XErrorEvent *error)
{
- fprintf (stderr, "\nX error in %s:\n", progname);
- XmuPrintDefaultErrorMessage (dpy, error, stderr);
+ if (error->error_code == BadWindow || error->error_code == BadDrawable)
+ {
+ fprintf (stderr, "%s: target %s 0x%lx unexpectedly deleted\n", progname,
+ (error->error_code == BadWindow ? "window" : "pixmap"),
+ (unsigned long) error->resourceid);
+ }
+ else
+ {
+ fprintf (stderr, "\nX error in %s:\n", progname);
+ XmuPrintDefaultErrorMessage (dpy, error, stderr);
+ }
exit (-1);
return 0;
}
return 0;
}
+#ifndef USE_EXTERNAL_SCREEN_GRABBER
+static int
+ignore_badmatch_ehandler (Display *dpy, XErrorEvent *error)
+{
+ if (error->error_code == BadMatch)
+ return ignore_all_errors_ehandler (dpy, error);
+ else
+ return x_ehandler (dpy, error);
+}
+#endif /* ! USE_EXTERNAL_SCREEN_GRABBER */
+
/* Returns True if the given Drawable is a Window; False if it's a Pixmap.
*/
}
+/* Returns true if the window is the root window, or a virtual root window,
+ but *not* the xscreensaver window. That is, if it's a "real" desktop
+ root window of some kind.
+ */
+static Bool
+root_window_p (Screen *screen, Window window)
+{
+ Display *dpy = DisplayOfScreen (screen);
+ Atom type;
+ int format;
+ unsigned long nitems, bytesafter;
+ unsigned char *version;
+
+ if (window != RootWindowOfScreen (screen))
+ return False;
+
+ if (XGetWindowProperty (dpy, window,
+ XInternAtom (dpy, "_SCREENSAVER_VERSION", False),
+ 0, 1, False, XA_STRING,
+ &type, &format, &nitems, &bytesafter,
+ &version)
+ == Success
+ && type != None)
+ return False;
+
+ return True;
+}
+
+
/* Clear the window or pixmap to black, or its background color.
*/
static void
int th = src_h * r;
int pct = (r * 100);
+#if 0
+ /* this optimization breaks things */
if (pct < 95 || pct > 105) /* don't scale if it's close */
+#endif
{
if (verbose_p)
fprintf (stderr, "%s: scaling image by %d%% (%dx%d -> %dx%d)\n",
*scaled_to_y_ret = desty;
if (verbose_p)
- fprintf (stderr, "%s: displaying %dx%d image at %d,%d.\n",
- progname, src_w, src_h, destx, desty);
+ fprintf (stderr, "%s: displaying %dx%d image at %d,%d in %dx%d.\n",
+ progname, src_w, src_h, destx, desty, dest_w, dest_h);
}
+/* Scales an XImage, modifying it in place.
+ This doesn't do dithering or smoothing, so it might have artifacts.
+ If out of memory, returns False, and the XImage will have been
+ destroyed and freed.
+ */
+#if !defined(USE_EXTERNAL_SCREEN_GRABBER) || defined(HAVE_JPEGLIB)
+static Bool
+scale_ximage (Screen *screen, Visual *visual,
+ XImage *ximage, int new_width, int new_height)
+{
+ Display *dpy = DisplayOfScreen (screen);
+ int depth = visual_depth (screen, visual);
+ int x, y;
+ double xscale, yscale;
+
+ XImage *ximage2 = XCreateImage (dpy, visual, depth,
+ ZPixmap, 0, 0,
+ new_width, new_height, 8, 0);
+ ximage2->data = (char *) calloc (ximage2->height, ximage2->bytes_per_line);
+
+ if (!ximage2->data)
+ {
+ fprintf (stderr, "%s: out of memory scaling %dx%d image to %dx%d\n",
+ progname,
+ ximage->width, ximage->height,
+ ximage2->width, ximage2->height);
+ if (ximage->data) free (ximage->data);
+ if (ximage2->data) free (ximage2->data);
+ ximage->data = 0;
+ ximage2->data = 0;
+ XDestroyImage (ximage);
+ XDestroyImage (ximage2);
+ return False;
+ }
+
+ /* Brute force scaling... */
+ xscale = (double) ximage->width / ximage2->width;
+ yscale = (double) ximage->height / ximage2->height;
+ for (y = 0; y < ximage2->height; y++)
+ for (x = 0; x < ximage2->width; x++)
+ XPutPixel (ximage2, x, y,
+ XGetPixel (ximage, x * xscale, y * yscale));
+
+ free (ximage->data);
+ ximage->data = 0;
+
+ (*ximage) = (*ximage2);
+
+ ximage2->data = 0;
+ XDestroyImage (ximage2);
+
+ return True;
+}
+#endif /* !USE_EXTERNAL_SCREEN_GRABBER || HAVE_JPEGLIB */
+
+
#ifdef HAVE_GDK_PIXBUF
/* Reads the given image file and renders it on the Drawable, using GDK.
*/
static Bool
read_file_gdk (Screen *screen, Window window, Drawable drawable,
- const char *filename, Bool verbose_p)
+ const char *filename, Bool verbose_p,
+ XRectangle *geom_ret)
{
GdkPixbuf *pb;
Display *dpy = DisplayOfScreen (screen);
- unsigned int win_width, win_height;
+ unsigned int win_width, win_height, win_depth;
# ifdef HAVE_GTK2
GError *gerr = 0;
# endif /* HAVE_GTK2 */
+ /* Find the size of the Drawable. */
{
Window root;
int x, y;
- unsigned int bw, d;
- XWindowAttributes xgwa;
- XGetWindowAttributes (dpy, window, &xgwa);
- screen = xgwa.screen;
+ unsigned int bw;
XGetGeometry (dpy, drawable,
- &root, &x, &y, &win_width, &win_height, &bw, &d);
+ &root, &x, &y, &win_width, &win_height, &bw, &win_depth);
}
gdk_pixbuf_xlib_init (dpy, screen_number (screen));
int w = gdk_pixbuf_get_width (pb);
int h = gdk_pixbuf_get_height (pb);
int srcx, srcy, destx, desty, w2, h2;
+ Bool bg_p = False;
compute_image_scaling (w, h, win_width, win_height, verbose_p,
&srcx, &srcy, &destx, &desty, &w2, &h2);
fprintf (stderr, "%s: out of memory when scaling?\n", progname);
}
- clear_drawable (screen, drawable);
+ /* If we're rendering onto the root window (and it's not the
+ xscreensaver pseudo-root) then put the image in the window's
+ background. Otherwise, just paint the image onto the window.
+ */
+ bg_p = (window == drawable && root_window_p (screen, window));
+
+ if (bg_p)
+ {
+ XGCValues gcv;
+ GC gc;
+ drawable = XCreatePixmap (dpy, window,
+ win_width, win_height, win_depth);
+ gcv.foreground = BlackPixelOfScreen (screen);
+ gc = XCreateGC (dpy, drawable, GCForeground, &gcv);
+ XFillRectangle (dpy, drawable, gc, 0, 0, win_width, win_height);
+ XFreeGC (dpy, gc);
+ }
+ else
+ clear_drawable (screen, drawable);
/* #### Note that this always uses the default colormap! Morons!
Owen says that in Gnome 2.0, I should try using
GDK_PIXBUF_ALPHA_FULL, 127,
XLIB_RGB_DITHER_NORMAL,
0, 0);
- XSync (dpy, False);
+ if (bg_p)
+ {
+ XSetWindowBackgroundPixmap (dpy, window, drawable);
+ XClearWindow (dpy, window);
+ }
+
+ if (geom_ret)
+ {
+ geom_ret->x = destx;
+ geom_ret->y = desty;
+ geom_ret->width = w;
+ geom_ret->height = h;
+ }
}
+ XSync (dpy, False);
return True;
}
ximage = XCreateImage (dpy, visual, depth, ZPixmap, 0, 0,
w, h, 8, 0);
if (ximage)
- ximage->data = (unsigned char *)
- calloc (ximage->height, ximage->bytes_per_line);
+ ximage->data = (char *) calloc (ximage->height, ximage->bytes_per_line);
if (!ximage || !ximage->data)
{
fprintf (stderr, "%s: out of memory loading %dx%d PPM file %s\n",
cinfo.output_width, cinfo.output_height,
8, 0);
if (ximage)
- ximage->data = (unsigned char *)
- calloc (ximage->height, ximage->bytes_per_line);
+ ximage->data = (char *) calloc (ximage->height, ximage->bytes_per_line);
if (ximage && ximage->data)
scanbuf = (*cinfo.mem->alloc_sarray) ((j_common_ptr) &cinfo, JPOOL_IMAGE,
int x;
for (x = 0; x < ximage->width; x++)
{
- int j = x * cinfo.num_components;
+ int j = x * cinfo.output_components;
unsigned char r = scanbuf[i][j];
unsigned char g = scanbuf[i][j+1];
unsigned char b = scanbuf[i][j+2];
pixel = ((r >> 5) | ((g >> 5) << 3) | ((b >> 6) << 6));
else if (depth == 12)
pixel = ((r >> 4) | ((g >> 4) << 4) | ((b >> 4) << 8));
- else if (depth == 16 || depth == 15)
+ else if (depth == 15)
/* Gah! I don't understand why these are in the other
order. */
pixel = (((r >> 3) << 10) | ((g >> 3) << 5) | ((b >> 3)));
+ else if (depth == 16)
+ pixel = (((r >> 3) << 11) | ((g >> 2) << 5) | ((b >> 3)));
else
abort();
}
-/* Scales an XImage, modifying it in place.
- If out of memory, returns False, and the XImage will have been
- destroyed and freed.
- */
-static Bool
-scale_ximage (Screen *screen, Visual *visual,
- XImage *ximage, int new_width, int new_height)
-{
- Display *dpy = DisplayOfScreen (screen);
- int depth = visual_depth (screen, visual);
- int x, y;
- double xscale, yscale;
-
- XImage *ximage2 = XCreateImage (dpy, visual, depth,
- ZPixmap, 0, 0,
- new_width, new_height, 8, 0);
- ximage2->data = (unsigned char *)
- calloc (ximage2->height, ximage2->bytes_per_line);
-
- if (!ximage2->data)
- {
- fprintf (stderr, "%s: out of memory scaling %dx%d image to %dx%d\n",
- progname,
- ximage->width, ximage->height,
- ximage2->width, ximage2->height);
- if (ximage->data) free (ximage->data);
- if (ximage2->data) free (ximage2->data);
- ximage->data = 0;
- ximage2->data = 0;
- XDestroyImage (ximage);
- XDestroyImage (ximage2);
- return False;
- }
-
- /* Brute force scaling... */
- xscale = (double) ximage->width / ximage2->width;
- yscale = (double) ximage->height / ximage2->height;
- for (y = 0; y < ximage2->height; y++)
- for (x = 0; x < ximage2->width; x++)
- XPutPixel (ximage2, x, y,
- XGetPixel (ximage, x * xscale, y * yscale));
-
- free (ximage->data);
- ximage->data = 0;
-
- (*ximage) = (*ximage2);
-
- ximage2->data = 0;
- XDestroyImage (ximage2);
-
- return True;
-}
-
-
/* Reads the given image file and renders it on the Drawable, using JPEG lib.
Returns False if it fails.
*/
static Bool
read_file_jpeglib (Screen *screen, Window window, Drawable drawable,
- const char *filename, Bool verbose_p)
+ const char *filename, Bool verbose_p,
+ XRectangle *geom_ret)
{
Display *dpy = DisplayOfScreen (screen);
XImage *ximage;
unsigned int win_width, win_height, win_depth;
int srcx, srcy, destx, desty, w2, h2;
+ /* Find the size of the Drawable, and the Visual/Colormap of the Window. */
{
Window root;
int x, y;
unsigned int bw;
XWindowAttributes xgwa;
-
XGetWindowAttributes (dpy, window, &xgwa);
- screen = xgwa.screen;
visual = xgwa.visual;
cmap = xgwa.colormap;
-
XGetGeometry (dpy, drawable,
&root, &x, &y, &win_width, &win_height, &bw, &win_depth);
}
/* Finally, put the resized image on the window.
*/
- clear_drawable (screen, drawable);
{
GC gc;
XGCValues gcv;
- gc = XCreateGC (dpy, drawable, 0, &gcv);
- XPutImage (dpy, drawable, gc, ximage,
- srcx, srcy, destx, desty, ximage->width, ximage->height);
+
+ /* If we're rendering onto the root window (and it's not the xscreensaver
+ pseudo-root) then put the image in the window's background. Otherwise,
+ just paint the image onto the window.
+ */
+ if (window == drawable && root_window_p (screen, window))
+ {
+ Pixmap bg = XCreatePixmap (dpy, window,
+ win_width, win_height, win_depth);
+ gcv.foreground = BlackPixelOfScreen (screen);
+ gc = XCreateGC (dpy, drawable, GCForeground, &gcv);
+ XFillRectangle (dpy, bg, gc, 0, 0, win_width, win_height);
+ XPutImage (dpy, bg, gc, ximage,
+ srcx, srcy, destx, desty, ximage->width, ximage->height);
+ XSetWindowBackgroundPixmap (dpy, window, bg);
+ XClearWindow (dpy, window);
+ }
+ else
+ {
+ gc = XCreateGC (dpy, drawable, 0, &gcv);
+ clear_drawable (screen, drawable);
+ XPutImage (dpy, drawable, gc, ximage,
+ srcx, srcy, destx, desty, ximage->width, ximage->height);
+ }
+
XFreeGC (dpy, gc);
}
+ if (geom_ret)
+ {
+ geom_ret->x = destx;
+ geom_ret->y = desty;
+ geom_ret->width = ximage->width;
+ geom_ret->height = ximage->height;
+ }
+
free (ximage->data);
ximage->data = 0;
XDestroyImage (ximage);
*/
static Bool
display_file (Screen *screen, Window window, Drawable drawable,
- const char *filename, Bool verbose_p)
+ const char *filename, Bool verbose_p,
+ XRectangle *geom_ret)
{
if (verbose_p)
fprintf (stderr, "%s: loading \"%s\"\n", progname, filename);
# if defined(HAVE_GDK_PIXBUF)
- if (read_file_gdk (screen, window, drawable, filename, verbose_p))
+ if (read_file_gdk (screen, window, drawable, filename, verbose_p, geom_ret))
return True;
# elif defined(HAVE_JPEGLIB)
- if (read_file_jpeglib (screen, window, drawable, filename, verbose_p))
+ if (read_file_jpeglib (screen, window, drawable, filename, verbose_p,
+ geom_ret))
return True;
# else /* !(HAVE_GDK_PIXBUF || HAVE_JPEGLIB) */
/* shouldn't get here if we have no image-loading methods available. */
/* Invokes a sub-process and returns its output (presumably, a file to
- load.) Free the string when done. video_p controls which program
+ load.) Free the string when done. 'grab_type' controls which program
to run.
*/
static char *
-get_filename_1 (Screen *screen, const char *directory, Bool video_p,
+get_filename_1 (Screen *screen, const char *directory, grab_type type,
Bool verbose_p)
{
Display *dpy = DisplayOfScreen (screen);
char *av[20];
int ac = 0;
- if (!video_p)
+ switch (type)
{
+ case GRAB_FILE:
av[ac++] = GETIMAGE_FILE_PROGRAM;
if (verbose_p)
av[ac++] = "--verbose";
av[ac++] = "--name";
av[ac++] = (char *) directory;
- }
- else
- {
+ break;
+
+ case GRAB_VIDEO:
av[ac++] = GETIMAGE_VIDEO_PROGRAM;
if (verbose_p)
av[ac++] = "--verbose";
av[ac++] = "--name";
+ break;
+
+# ifdef USE_EXTERNAL_SCREEN_GRABBER
+ case GRAB_DESK:
+ av[ac++] = GETIMAGE_SCREEN_PROGRAM;
+ if (verbose_p)
+ av[ac++] = "--verbose";
+ av[ac++] = "--name";
+ break;
+# endif
+
+ default:
+ abort();
}
av[ac] = 0;
close (out); /* don't need this one */
*buf = 0;
- fgets (buf, sizeof(buf)-1, f);
+ if (! fgets (buf, sizeof(buf)-1, f))
+ *buf = 0;
fclose (f);
/* Wait for the child to die. */
static char *
get_filename (Screen *screen, const char *directory, Bool verbose_p)
{
- return get_filename_1 (screen, directory, False, verbose_p);
+ return get_filename_1 (screen, directory, GRAB_FILE, verbose_p);
}
static char *
get_video_filename (Screen *screen, Bool verbose_p)
{
- return get_filename_1 (screen, 0, True, verbose_p);
+ return get_filename_1 (screen, 0, GRAB_VIDEO, verbose_p);
}
+/* Grabs a desktop image to a file, and returns a pathname to that file.
+ Delete that file when you are done with it (and free the string.)
+ */
+# ifdef USE_EXTERNAL_SCREEN_GRABBER
+static char *
+get_desktop_filename (Screen *screen, Bool verbose_p)
+{
+ return get_filename_1 (screen, 0, GRAB_DESK, verbose_p);
+}
+#endif /* USE_EXTERNAL_SCREEN_GRABBER */
+
/* Grabs a video frame, and renders it on the Drawable.
Returns False if it fails;
*/
static Bool
display_video (Screen *screen, Window window, Drawable drawable,
- Bool verbose_p)
+ Bool verbose_p, XRectangle *geom_ret)
{
char *filename = get_video_filename (screen, verbose_p);
Bool status;
return False;
}
- status = display_file (screen, window, drawable, filename, verbose_p);
+ status = display_file (screen, window, drawable, filename, verbose_p,
+ geom_ret);
if (unlink (filename))
{
}
+/* Grabs a desktop screen shot onto the window and the drawable.
+ If the window and drawable are not the same size, the image in
+ the drawable is scaled to fit.
+ Returns False if it fails.
+ */
+static Bool
+display_desktop (Screen *screen, Window window, Drawable drawable,
+ Bool verbose_p, XRectangle *geom_ret)
+{
+# ifdef USE_EXTERNAL_SCREEN_GRABBER
+
+ Display *dpy = DisplayOfScreen (screen);
+ Bool top_p = top_level_window_p (screen, window);
+ char *filename;
+ Bool status;
+
+ if (top_p)
+ {
+ if (verbose_p)
+ fprintf (stderr, "%s: unmapping 0x%lx.\n", progname,
+ (unsigned long) window);
+ XUnmapWindow (dpy, window);
+ XSync (dpy, False);
+ }
+
+ filename = get_desktop_filename (screen, verbose_p);
+
+ if (top_p)
+ {
+ if (verbose_p)
+ fprintf (stderr, "%s: mapping 0x%lx.\n", progname,
+ (unsigned long) window);
+ XMapRaised (dpy, window);
+ XSync (dpy, False);
+ }
+
+ if (!filename)
+ {
+ if (verbose_p)
+ fprintf (stderr, "%s: desktop grab failed.\n", progname);
+ return False;
+ }
+
+ status = display_file (screen, window, drawable, filename, verbose_p,
+ geom_ret);
+
+ if (unlink (filename))
+ {
+ char buf[512];
+ sprintf (buf, "%s: rm %.100s", progname, filename);
+ perror (buf);
+ }
+ else if (verbose_p)
+ fprintf (stderr, "%s: rm %s\n", progname, filename);
+
+ if (filename) free (filename);
+ return status;
+
+# else /* !USE_EXTERNAL_SCREEN_GRABBER */
+
+ Display *dpy = DisplayOfScreen (screen);
+ XGCValues gcv;
+ XWindowAttributes xgwa;
+ Window root;
+ int px, py;
+ unsigned int pw, ph, pbw, pd;
+ int srcx, srcy, destx, desty, w2, h2;
+
+ if (verbose_p)
+ {
+ fprintf (stderr, "%s: grabbing desktop image\n", progname);
+ grabscreen_verbose();
+ }
+
+ XGetWindowAttributes (dpy, window, &xgwa);
+ XGetGeometry (dpy, drawable, &root, &px, &py, &pw, &ph, &pbw, &pd);
+
+ grab_screen_image_internal (screen, window);
+
+ compute_image_scaling (xgwa.width, xgwa.height,
+ pw, ph, verbose_p,
+ &srcx, &srcy, &destx, &desty, &w2, &h2);
+
+ if (pw == w2 && ph == h2) /* it fits -- just copy server-side pixmaps */
+ {
+ GC gc = XCreateGC (dpy, drawable, 0, &gcv);
+ XCopyArea (dpy, window, drawable, gc,
+ 0, 0, xgwa.width, xgwa.height, 0, 0);
+ XFreeGC (dpy, gc);
+ }
+ else /* size mismatch -- must scale client-side images to fit drawable */
+ {
+ GC gc;
+ XImage *ximage = 0;
+ XErrorHandler old_handler;
+
+ XSync (dpy, False);
+ old_handler = XSetErrorHandler (ignore_badmatch_ehandler);
+ error_handler_hit_p = False;
+
+ /* This can return BadMatch if the window is not fully on screen.
+ Trap that error and return color bars in that case.
+ (Note that this only happens with XGetImage, not with XCopyArea:
+ yet another totally gratuitous inconsistency in X, thanks.)
+ */
+ ximage = XGetImage (dpy, window, 0, 0, xgwa.width, xgwa.height,
+ ~0L, ZPixmap);
+
+ XSync (dpy, False);
+ XSetErrorHandler (old_handler);
+ XSync (dpy, False);
+
+ if (error_handler_hit_p)
+ {
+ ximage = 0;
+ if (verbose_p)
+ fprintf (stderr, "%s: BadMatch reading window 0x%x contents!\n",
+ progname, (unsigned int) window);
+ }
+
+ if (!ximage ||
+ !scale_ximage (xgwa.screen, xgwa.visual, ximage, w2, h2))
+ return False;
+
+ gc = XCreateGC (dpy, drawable, 0, &gcv);
+ clear_drawable (screen, drawable);
+ XPutImage (dpy, drawable, gc, ximage,
+ srcx, srcy, destx, desty, ximage->width, ximage->height);
+ XDestroyImage (ximage);
+ XFreeGC (dpy, gc);
+ }
+
+ if (geom_ret)
+ {
+ geom_ret->x = destx;
+ geom_ret->y = desty;
+ geom_ret->width = w2;
+ geom_ret->height = h2;
+ }
+
+ XSync (dpy, False);
+ return True;
+
+# endif /* !USE_EXTERNAL_SCREEN_GRABBER */
+}
+
+
+/* Whether the given Drawable is unreasonably small.
+ */
+static Bool
+drawable_miniscule_p (Display *dpy, Drawable drawable)
+{
+ Window root;
+ int xx, yy;
+ unsigned int bw, d, w = 0, h = 0;
+ XGetGeometry (dpy, drawable, &root, &xx, &yy, &w, &h, &bw, &d);
+ return (w < 32 || h < 32);
+}
+
+
/* Grabs an image (from a file, video, or the desktop) and renders it on
the Drawable. If `file' is specified, always use that file. Otherwise,
select randomly, based on the other arguments.
const char *file)
{
Display *dpy = DisplayOfScreen (screen);
- enum { do_desk, do_video, do_image, do_bars } which = do_bars;
- int count = 0;
+ grab_type which = GRAB_BARS;
struct stat st;
+ const char *file_prop = 0;
+ XRectangle geom = { 0, 0, 0, 0 };
if (! drawable_window_p (dpy, window))
{
exit (1);
}
+ /* Make sure the Screen and the Window correspond. */
+ {
+ XWindowAttributes xgwa;
+ XGetWindowAttributes (dpy, window, &xgwa);
+ screen = xgwa.screen;
+ }
+
if (file && stat (file, &st))
{
fprintf (stderr, "%s: file \"%s\" does not exist\n", progname, file);
# if !(defined(HAVE_GDK_PIXBUF) || defined(HAVE_JPEGLIB))
image_p = False; /* can't load images from files... */
+# ifdef USE_EXTERNAL_SCREEN_GRABBER
+ desk_p = False; /* ...or from desktops grabbed to files. */
+# endif
+
if (file)
{
fprintf (stderr,
video_p = False;
image_p = True;
}
-
- if (!dir || !*dir)
+ else if (!dir || !*dir)
{
if (verbose_p && image_p)
fprintf (stderr,
image_p = False;
}
+ /* If the target drawable is really small, no good can come of that.
+ Always do colorbars in that case.
+ */
+ if (drawable_miniscule_p (dpy, drawable))
+ {
+ desk_p = False;
+ video_p = False;
+ image_p = False;
+ }
# ifndef _VROOT_H_
# error Error! This file definitely needs vroot.h!
# endif
- /* We can grab desktop images if:
+ /* We can grab desktop images (using the normal X11 method) if:
- the window is the real root window;
- - the window is the virtal root window;
- the window is a toplevel window.
- We cannot grab desktop images if:
+ We cannot grab desktop images that way if:
- the window is a non-top-level window.
+
+ Using the MacOS X way, desktops are just like loaded image files.
*/
+# ifndef USE_EXTERNAL_SCREEN_GRABBER
if (desk_p)
{
if (!top_level_window_p (screen, window))
progname, (unsigned int) window);
}
}
+# endif /* !USE_EXTERNAL_SCREEN_GRABBER */
- count = 0;
- if (desk_p) count++;
- if (video_p) count++;
- if (image_p) count++;
-
- if (count == 0)
- which = do_bars;
+ if (! (desk_p || video_p || image_p))
+ which = GRAB_BARS;
else
{
int i = 0;
- while (1) /* loop until we get one that's permitted */
- {
- which = (random() % 3);
- if (which == do_desk && desk_p) break;
- if (which == do_video && video_p) break;
- if (which == do_image && image_p) break;
- if (++i > 200) abort();
- }
+ int n;
+ /* Loop until we get one that's permitted.
+ If files or video are permitted, do them more often
+ than desktop.
+
+ D+V+I: 10% + 45% + 45%.
+ V+I: 50% + 50%
+ D+V: 18% + 82%
+ D+I: 18% + 82%
+ */
+ AGAIN:
+ n = (random() % 100);
+ if (++i > 300) abort();
+ else if (desk_p && n < 10) which = GRAB_DESK; /* 10% */
+ else if (video_p && n < 55) which = GRAB_VIDEO; /* 45% */
+ else if (image_p) which = GRAB_FILE; /* 45% */
+ else goto AGAIN;
}
/* If we're to search a directory to find an image file, do so now.
*/
- if (which == do_image && !file)
+ if (which == GRAB_FILE && !file)
{
file = get_filename (screen, dir, verbose_p);
if (!file)
{
- which = do_bars;
+ which = GRAB_BARS;
if (verbose_p)
fprintf (stderr, "%s: no image files found.\n", progname);
}
/* Now actually render something.
*/
- if (which == do_bars)
+ switch (which)
{
- XWindowAttributes xgwa;
- COLORBARS:
- if (verbose_p)
- fprintf (stderr, "%s: drawing colorbars.\n", progname);
- XGetWindowAttributes (dpy, window, &xgwa);
- draw_colorbars (screen, xgwa.visual, drawable, xgwa.colormap,
- 0, 0, 0, 0);
- XSync (dpy, False);
- }
- else if (which == do_desk)
- {
- GC gc;
- XGCValues gcv;
- XWindowAttributes xgwa;
+ case GRAB_BARS:
+ {
+ XWindowAttributes xgwa;
+ COLORBARS:
+ if (verbose_p)
+ fprintf (stderr, "%s: drawing colorbars.\n", progname);
+ XGetWindowAttributes (dpy, window, &xgwa);
+ draw_colorbars (screen, xgwa.visual, drawable, xgwa.colormap,
+ 0, 0, 0, 0);
+ XSync (dpy, False);
+ }
+ break;
- if (verbose_p)
- {
- fprintf (stderr, "%s: grabbing desktop image\n", progname);
- grabscreen_verbose();
- }
- gc = XCreateGC (dpy, drawable, 0, &gcv);
- XGetWindowAttributes (dpy, window, &xgwa);
- grab_screen_image (screen, window);
- XCopyArea (dpy, window, drawable, gc,
- 0, 0, xgwa.width, xgwa.height, 0, 0);
- XFreeGC (dpy, gc);
- XSync (dpy, False);
- }
- else if (which == do_image)
- {
- if (! display_file (screen, window, drawable, file, verbose_p))
+ case GRAB_DESK:
+ if (! display_desktop (screen, window, drawable, verbose_p, &geom))
goto COLORBARS;
- }
- else if (which == do_video)
- {
- if (! display_video (screen, window, drawable, verbose_p))
+ file_prop = "desktop";
+ break;
+
+ case GRAB_FILE:
+ if (! display_file (screen, window, drawable, file, verbose_p, &geom))
goto COLORBARS;
+ file_prop = file;
+ break;
+
+ case GRAB_VIDEO:
+ if (! display_video (screen, window, drawable, verbose_p, &geom))
+ goto COLORBARS;
+ file_prop = "video";
+ break;
+
+ default:
+ abort();
+ break;
}
- else
- abort();
+
+ {
+ Atom a = XInternAtom (dpy, XA_XSCREENSAVER_IMAGE_FILENAME, False);
+ if (file_prop && *file_prop)
+ XChangeProperty (dpy, window, a, XA_STRING, 8, PropModeReplace,
+ (unsigned char *) file_prop, strlen(file_prop));
+ else
+ XDeleteProperty (dpy, window, a);
+
+ a = XInternAtom (dpy, XA_XSCREENSAVER_IMAGE_GEOMETRY, False);
+ if (geom.width > 0)
+ {
+ char gstr[30];
+ sprintf (gstr, "%dx%d+%d+%d", geom.width, geom.height, geom.x, geom.y);
+ XChangeProperty (dpy, window, a, XA_STRING, 8, PropModeReplace,
+ (unsigned char *) gstr, strlen (gstr));
+ }
+ else
+ XDeleteProperty (dpy, window, a);
+ }
+
+ XSync (dpy, False);
}
#define USAGE "usage: %s [ -options... ] window-id [pixmap-id]\n" \
"\n" \
- " This program puts an image on the given window or pixmap.\n" \
+ " %s\n" \
+ "\n" \
+ " %s puts an image on the given window or pixmap.\n" \
"\n" \
" It is used by those xscreensaver demos that operate on images.\n" \
" The image may be a file loaded from disk, a frame grabbed from\n" \
Screen *screen;
char *oprogname = progname;
char *file = 0;
+ char version[255];
Window window = (Window) 0;
Drawable drawable = (Drawable) 0;
# error Error! This file definitely needs vroot.h!
# endif
+ /* Get the version number, for error messages. */
+ {
+ char *v = (char *) strdup(strchr(screensaver_id, ' '));
+ char *s1, *s2, *s3, *s4;
+ s1 = (char *) strchr(v, ' '); s1++;
+ s2 = (char *) strchr(s1, ' ');
+ s3 = (char *) strchr(v, '('); s3++;
+ s4 = (char *) strchr(s3, ')');
+ *s2 = 0;
+ *s4 = 0;
+ sprintf (version, "Part of XScreenSaver %s -- %s.", s1, s3);
+ free(v);
+ }
+
/* We must read exactly the same resources as xscreensaver.
That means we must have both the same progclass *and* progname,
at least as far as the resource database is concerned. So,
memset (&P, 0, sizeof(P));
P.db = db;
- load_init_file (&P);
+ load_init_file (dpy, &P);
progname = argv[0] = oprogname;
goto LOSE;
}
window_str = argv[i];
- window = (Window) RootWindowOfScreen (screen);
+ window = VirtualRootWindowOfScreen (screen);
}
else if ((1 == sscanf (argv[i], " 0x%lx %c", &w, &dummy) ||
- 1 == sscanf (argv[i], " %ld %c", &w, &dummy)) &&
+ 1 == sscanf (argv[i], " %lu %c", &w, &dummy)) &&
w != 0)
{
if (drawable)
fprintf (stderr, "\n%s: unparsable window/pixmap ID: \"%s\"\n",
progname, argv[i]);
LOSE:
- fprintf (stderr, USAGE, progname);
+# ifdef __GNUC__
+ __extension__ /* don't warn about "string length is greater than
+ the length ISO C89 compilers are required to
+ support" in the usage string... */
+# endif
+ fprintf (stderr, USAGE, progname, version, progname);
exit (1);
}
}