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>
32 #ifdef HAVE_SYS_WAIT_H
33 # include <sys/wait.h> /* for waitpid() and associated macros */
37 extern char *progname;
40 static Bool error_handler_hit_p = False;
43 ignore_all_errors_ehandler (Display *dpy, XErrorEvent *error)
45 error_handler_hit_p = True;
50 /* Returns True if the given Drawable is a Window; False if it's a Pixmap.
53 drawable_window_p (Display *dpy, Drawable d)
55 XErrorHandler old_handler;
56 XWindowAttributes xgwa;
59 old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
60 error_handler_hit_p = False;
61 XGetWindowAttributes (dpy, d, &xgwa);
63 XSetErrorHandler (old_handler);
66 if (!error_handler_hit_p)
67 return True; /* It's a Window. */
69 return False; /* It's a Pixmap, or an invalid ID. */
74 xscreensaver_window_p (Display *dpy, Window window)
78 unsigned long nitems, bytesafter;
80 if (XGetWindowProperty (dpy, window,
81 XInternAtom (dpy, "_SCREENSAVER_VERSION", False),
82 0, 1, False, XA_STRING,
83 &type, &format, &nitems, &bytesafter,
84 (unsigned char **) &version)
92 /* XCopyArea seems not to work right on SGI O2s if you draw in SubwindowMode
93 on a window whose depth is not the maximal depth of the screen? Or
94 something. Anyway, things don't work unless we: use SubwindowMode for
95 the real root window (or a legitimate virtual root window); but do not
96 use SubwindowMode for the xscreensaver window. I make no attempt to
100 use_subwindow_mode_p(Screen *screen, Window window)
102 if (window != VirtualRootWindowOfScreen(screen))
104 else if (xscreensaver_window_p(DisplayOfScreen(screen), window))
112 checkerboard (Screen *screen, Drawable drawable)
114 Display *dpy = DisplayOfScreen (screen);
119 GC gc = XCreateGC (dpy, drawable, 0, &gcv);
121 unsigned int win_width, win_height;
123 fg.flags = bg.flags = DoRed|DoGreen|DoBlue;
124 fg.red = fg.green = fg.blue = 0x0000;
125 bg.red = bg.green = bg.blue = 0x4444;
129 if (drawable_window_p (dpy, drawable))
131 XWindowAttributes xgwa;
132 XGetWindowAttributes (dpy, drawable, &xgwa);
133 win_width = xgwa.width;
134 win_height = xgwa.height;
135 cmap = xgwa.colormap;
136 screen = xgwa.screen;
138 else /* it's a pixmap */
140 XWindowAttributes xgwa;
144 XGetWindowAttributes (dpy, RootWindowOfScreen (screen), &xgwa);
145 cmap = xgwa.colormap;
146 XGetGeometry (dpy, drawable,
147 &root, &x, &y, &win_width, &win_height, &bw, &d);
150 /* Allocate black and gray, but don't hold them locked. */
151 if (XAllocColor (dpy, cmap, &fg))
152 XFreeColors (dpy, cmap, &fg.pixel, 1, 0);
153 if (XAllocColor (dpy, cmap, &bg))
154 XFreeColors (dpy, cmap, &bg.pixel, 1, 0);
156 XSetForeground (dpy, gc, bg.pixel);
157 XFillRectangle (dpy, drawable, gc, 0, 0, win_width, win_height);
158 XSetForeground (dpy, gc, fg.pixel);
159 for (y = 0; y < win_height; y += size+size)
160 for (x = 0; x < win_width; x += size+size)
162 XFillRectangle (dpy, drawable, gc, x, y, size, size);
163 XFillRectangle (dpy, drawable, gc, x+size, y+size, size, size);
168 hack_subproc_environment (Display *dpy)
170 /* Store $DISPLAY into the environment, so that the $DISPLAY variable that
171 the spawned processes inherit is what we are actually using.
173 const char *odpy = DisplayString (dpy);
174 char *ndpy = (char *) malloc(strlen(odpy) + 20);
175 strcpy (ndpy, "DISPLAY=");
178 /* Allegedly, BSD 4.3 didn't have putenv(), but nobody runs such systems
179 any more, right? It's not Posix, but everyone seems to have it. */
183 #endif /* HAVE_PUTENV */
187 /* Spawn a program, and wait for it to finish.
188 If we just use system() for this, then sometimes the subprocess
189 doesn't die when *this* process is sent a TERM signal. Perhaps
190 this is due to the intermediate /bin/sh that system() uses to
191 parse arguments? I'm not sure. But using fork() and execvp()
192 here seems to close the race.
196 exec_simple_command (const char *command)
200 char *token = strtok (strdup(command), " \t");
204 token = strtok(0, " \t");
208 execvp (av[0], av); /* shouldn't return. */
212 fork_exec_wait (const char *command)
218 switch ((int) (forked = fork ()))
221 sprintf (buf, "%s: couldn't fork", progname);
226 exec_simple_command (command);
227 exit (1); /* exits child fork */
231 waitpid (forked, &status, 0);
237 /* Loads an image into the Drawable.
238 When grabbing desktop images, the Window will be unmapped first.
241 load_random_image (Screen *screen, Window window, Drawable drawable,
244 Display *dpy = DisplayOfScreen (screen);
245 char *grabber = get_string_resource ("desktopGrabber", "DesktopGrabber");
249 if (!grabber || !*grabber)
252 "%s: resources installed incorrectly: \"desktopGrabber\" is unset!\n",
257 sprintf (id, "0x%lx 0x%lx",
258 (unsigned long) window,
259 (unsigned long) drawable);
260 cmd = (char *) malloc (strlen(grabber) + strlen(id) + 1);
262 /* Needn't worry about buffer overflows here, because the buffer is
263 longer than the length of the format string, and the length of what
264 we're putting into it. So the only way to crash would be if the
265 format string itself was corrupted, but that comes from the
266 resource database, and if hostile forces have access to that,
267 then the game is already over.
269 sprintf (cmd, grabber, id);
271 /* In case "cmd" fails, leave some random image on the screen, not just
272 black or white, so that it's more obvious what went wrong. */
273 checkerboard (screen, drawable);
276 hack_subproc_environment (dpy);
277 fork_exec_wait (cmd);
285 unsigned long nitems, bytesafter;
290 if (XGetWindowProperty (dpy, window,
291 XInternAtom (dpy, XA_XSCREENSAVER_IMAGE_FILENAME,
293 0, 1024, False, XA_STRING,
294 &type, &format, &nitems, &bytesafter,
295 (unsigned char **) &name)
298 *name_ret = strdup(name);