1 /* xscreensaver, Copyright (c) 1992, 1993, 1994, 1997, 1998, 2001, 2003
2 * Jamie Zawinski <jwz@jwz.org>
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation. No representations are made about the suitability of this
9 * software for any purpose. It is provided "as is" without express or
13 /* This file contains code for running an external program to grab an image
14 onto the given window. The external program in question must take a
15 window ID as its argument, e.g., the "xscreensaver-getimage" program
16 in the hacks/ directory.
18 That program links against utils/grabimage.c, which happens to export the
19 same API as this program (utils/grabclient.c).
23 #include "grabscreen.h"
24 #include "resources.h"
27 #include <X11/Xatom.h>
29 extern char *progname;
32 static Bool error_handler_hit_p = False;
35 ignore_all_errors_ehandler (Display *dpy, XErrorEvent *error)
37 error_handler_hit_p = True;
42 /* Returns True if the given Drawable is a Window; False if it's a Pixmap.
45 drawable_window_p (Display *dpy, Drawable d)
47 XErrorHandler old_handler;
48 XWindowAttributes xgwa;
51 old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
52 error_handler_hit_p = False;
53 XGetWindowAttributes (dpy, d, &xgwa);
55 XSetErrorHandler (old_handler);
58 if (!error_handler_hit_p)
59 return True; /* It's a Window. */
61 return False; /* It's a Pixmap, or an invalid ID. */
66 xscreensaver_window_p (Display *dpy, Window window)
70 unsigned long nitems, bytesafter;
72 if (XGetWindowProperty (dpy, window,
73 XInternAtom (dpy, "_SCREENSAVER_VERSION", False),
74 0, 1, False, XA_STRING,
75 &type, &format, &nitems, &bytesafter,
76 (unsigned char **) &version)
84 /* XCopyArea seems not to work right on SGI O2s if you draw in SubwindowMode
85 on a window whose depth is not the maximal depth of the screen? Or
86 something. Anyway, things don't work unless we: use SubwindowMode for
87 the real root window (or a legitimate virtual root window); but do not
88 use SubwindowMode for the xscreensaver window. I make no attempt to
92 use_subwindow_mode_p(Screen *screen, Window window)
94 if (window != VirtualRootWindowOfScreen(screen))
96 else if (xscreensaver_window_p(DisplayOfScreen(screen), window))
104 checkerboard (Screen *screen, Drawable drawable)
106 Display *dpy = DisplayOfScreen (screen);
111 GC gc = XCreateGC (dpy, drawable, 0, &gcv);
113 unsigned int win_width, win_height;
115 fg.flags = bg.flags = DoRed|DoGreen|DoBlue;
116 fg.red = fg.green = fg.blue = 0x0000;
117 bg.red = bg.green = bg.blue = 0x4444;
121 if (drawable_window_p (dpy, drawable))
123 XWindowAttributes xgwa;
124 XGetWindowAttributes (dpy, drawable, &xgwa);
125 win_width = xgwa.width;
126 win_height = xgwa.height;
127 cmap = xgwa.colormap;
128 screen = xgwa.screen;
130 else /* it's a pixmap */
132 XWindowAttributes xgwa;
136 XGetWindowAttributes (dpy, RootWindowOfScreen (screen), &xgwa);
137 cmap = xgwa.colormap;
138 XGetGeometry (dpy, drawable,
139 &root, &x, &y, &win_width, &win_height, &bw, &d);
142 /* Allocate black and gray, but don't hold them locked. */
143 if (XAllocColor (dpy, cmap, &fg))
144 XFreeColors (dpy, cmap, &fg.pixel, 1, 0);
145 if (XAllocColor (dpy, cmap, &bg))
146 XFreeColors (dpy, cmap, &bg.pixel, 1, 0);
148 XSetForeground (dpy, gc, bg.pixel);
149 XFillRectangle (dpy, drawable, gc, 0, 0, win_width, win_height);
150 XSetForeground (dpy, gc, fg.pixel);
151 for (y = 0; y < win_height; y += size+size)
152 for (x = 0; x < win_width; x += size+size)
154 XFillRectangle (dpy, drawable, gc, x, y, size, size);
155 XFillRectangle (dpy, drawable, gc, x+size, y+size, size, size);
160 hack_subproc_environment (Display *dpy)
162 /* Store $DISPLAY into the environment, so that the $DISPLAY variable that
163 the spawned processes inherit is what we are actually using.
165 const char *odpy = DisplayString (dpy);
166 char *ndpy = (char *) malloc(strlen(odpy) + 20);
167 strcpy (ndpy, "DISPLAY=");
170 /* Allegedly, BSD 4.3 didn't have putenv(), but nobody runs such systems
171 any more, right? It's not Posix, but everyone seems to have it. */
175 #endif /* HAVE_PUTENV */
179 /* Loads an image into the Drawable.
180 When grabbing desktop images, the Window will be unmapped first.
183 load_random_image (Screen *screen, Window window, Drawable drawable,
186 Display *dpy = DisplayOfScreen (screen);
187 char *grabber = get_string_resource ("desktopGrabber", "DesktopGrabber");
191 if (!grabber || !*grabber)
194 "%s: resources installed incorrectly: \"desktopGrabber\" is unset!\n",
199 sprintf (id, "0x%lx 0x%lx",
200 (unsigned long) window,
201 (unsigned long) drawable);
202 cmd = (char *) malloc (strlen(grabber) + strlen(id) + 1);
204 /* Needn't worry about buffer overflows here, because the buffer is
205 longer than the length of the format string, and the length of what
206 we're putting into it. So the only way to crash would be if the
207 format string itself was corrupted, but that comes from the
208 resource database, and if hostile forces have access to that,
209 then the game is already over.
211 sprintf (cmd, grabber, id);
213 /* In case "cmd" fails, leave some random image on the screen, not just
214 black or white, so that it's more obvious what went wrong. */
215 checkerboard (screen, drawable);
218 hack_subproc_environment (dpy);
227 unsigned long nitems, bytesafter;
232 if (XGetWindowProperty (dpy, window,
233 XInternAtom (dpy, XA_XSCREENSAVER_IMAGE_FILENAME,
235 0, 1024, False, XA_STRING,
236 &type, &format, &nitems, &bytesafter,
237 (unsigned char **) &name)
240 *name_ret = strdup(name);