X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=utils%2Fgrabclient.c;h=7b5298dffd156f653653a550fae454f332de4dab;hb=e4fa2ac140f7bc56571373a7b7eb585fa4500e38;hp=0a1d2ac72630aafbf4971baece2d4819a484ec4e;hpb=585e1a6717d1dd9b90fbb53acaaae82106354d33;p=xscreensaver diff --git a/utils/grabclient.c b/utils/grabclient.c index 0a1d2ac7..7b5298df 100644 --- a/utils/grabclient.c +++ b/utils/grabclient.c @@ -1,4 +1,4 @@ -/* xscreensaver, Copyright (c) 1992, 1993, 1994, 1997, 1998, 2001 +/* xscreensaver, Copyright (c) 1992, 1993, 1994, 1997, 1998, 2001, 2003 * Jamie Zawinski * * Permission to use, copy, modify, distribute, and sell this software and its @@ -26,9 +26,50 @@ #include "vroot.h" #include +#ifdef HAVE_UNISTD_H +# include +#endif +#ifdef HAVE_SYS_WAIT_H +# include /* for waitpid() and associated macros */ +#endif + + extern char *progname; +static Bool error_handler_hit_p = False; + +static int +ignore_all_errors_ehandler (Display *dpy, XErrorEvent *error) +{ + error_handler_hit_p = True; + return 0; +} + + +/* Returns True if the given Drawable is a Window; False if it's a Pixmap. + */ +static Bool +drawable_window_p (Display *dpy, Drawable d) +{ + XErrorHandler old_handler; + XWindowAttributes xgwa; + + XSync (dpy, False); + old_handler = XSetErrorHandler (ignore_all_errors_ehandler); + error_handler_hit_p = False; + XGetWindowAttributes (dpy, d, &xgwa); + XSync (dpy, False); + XSetErrorHandler (old_handler); + XSync (dpy, False); + + if (!error_handler_hit_p) + return True; /* It's a Window. */ + else + return False; /* It's a Pixmap, or an invalid ID. */ +} + + static Bool xscreensaver_window_p (Display *dpy, Window window) { @@ -68,46 +109,142 @@ use_subwindow_mode_p(Screen *screen, Window window) static void -checkerboard (Screen *screen, Window window) +checkerboard (Screen *screen, Drawable drawable) { Display *dpy = DisplayOfScreen (screen); - int x, y; + unsigned int x, y; int size = 24; XColor fg, bg; XGCValues gcv; - GC gc = XCreateGC (dpy, window, 0, &gcv); - XWindowAttributes xgwa; - XGetWindowAttributes (dpy, window, &xgwa); + GC gc = XCreateGC (dpy, drawable, 0, &gcv); + Colormap cmap; + unsigned int win_width, win_height; + fg.flags = bg.flags = DoRed|DoGreen|DoBlue; fg.red = fg.green = fg.blue = 0x0000; bg.red = bg.green = bg.blue = 0x4444; fg.pixel = 0; bg.pixel = 1; + if (drawable_window_p (dpy, drawable)) + { + XWindowAttributes xgwa; + XGetWindowAttributes (dpy, drawable, &xgwa); + win_width = xgwa.width; + win_height = xgwa.height; + cmap = xgwa.colormap; + screen = xgwa.screen; + } + else /* it's a pixmap */ + { + XWindowAttributes xgwa; + Window root; + int x, y; + unsigned int bw, d; + XGetWindowAttributes (dpy, RootWindowOfScreen (screen), &xgwa); + cmap = xgwa.colormap; + XGetGeometry (dpy, drawable, + &root, &x, &y, &win_width, &win_height, &bw, &d); + } + /* Allocate black and gray, but don't hold them locked. */ - if (XAllocColor (dpy, xgwa.colormap, &fg)) - XFreeColors (dpy, xgwa.colormap, &fg.pixel, 1, 0); - if (XAllocColor (dpy, xgwa.colormap, &bg)) - XFreeColors (dpy, xgwa.colormap, &bg.pixel, 1, 0); + if (XAllocColor (dpy, cmap, &fg)) + XFreeColors (dpy, cmap, &fg.pixel, 1, 0); + if (XAllocColor (dpy, cmap, &bg)) + XFreeColors (dpy, cmap, &bg.pixel, 1, 0); XSetForeground (dpy, gc, bg.pixel); - XFillRectangle (dpy, window, gc, 0, 0, xgwa.width, xgwa.height); + XFillRectangle (dpy, drawable, gc, 0, 0, win_width, win_height); XSetForeground (dpy, gc, fg.pixel); - for (y = 0; y < xgwa.height; y += size+size) - for (x = 0; x < xgwa.width; x += size+size) + for (y = 0; y < win_height; y += size+size) + for (x = 0; x < win_width; x += size+size) { - XFillRectangle (dpy, window, gc, x, y, size, size); - XFillRectangle (dpy, window, gc, x+size, y+size, size, size); + XFillRectangle (dpy, drawable, gc, x, y, size, size); + XFillRectangle (dpy, drawable, gc, x+size, y+size, size, size); } } +static void +hack_subproc_environment (Display *dpy) +{ + /* Store $DISPLAY into the environment, so that the $DISPLAY variable that + the spawned processes inherit is what we are actually using. + */ + const char *odpy = DisplayString (dpy); + char *ndpy = (char *) malloc(strlen(odpy) + 20); + strcpy (ndpy, "DISPLAY="); + strcat (ndpy, odpy); + + /* Allegedly, BSD 4.3 didn't have putenv(), but nobody runs such systems + any more, right? It's not Posix, but everyone seems to have it. */ +#ifdef HAVE_PUTENV + if (putenv (ndpy)) + abort (); +#endif /* HAVE_PUTENV */ +} + + +/* Spawn a program, and wait for it to finish. + If we just use system() for this, then sometimes the subprocess + doesn't die when *this* process is sent a TERM signal. Perhaps + this is due to the intermediate /bin/sh that system() uses to + parse arguments? I'm not sure. But using fork() and execvp() + here seems to close the race. + */ + +static void +exec_simple_command (const char *command) +{ + char *av[1024]; + int ac = 0; + char *token = strtok (strdup(command), " \t"); + while (token) + { + av[ac++] = token; + token = strtok(0, " \t"); + } + av[ac] = 0; + + execvp (av[0], av); /* shouldn't return. */ +} + +static void +fork_exec_wait (const char *command) +{ + char buf [255]; + pid_t forked; + int status; + + switch ((int) (forked = fork ())) + { + case -1: + sprintf (buf, "%s: couldn't fork", progname); + perror (buf); + return; + + case 0: + exec_simple_command (command); + exit (1); /* exits child fork */ + break; + + default: + waitpid (forked, &status, 0); + break; + } +} + + +/* Loads an image into the Drawable. + When grabbing desktop images, the Window will be unmapped first. + */ void -grab_screen_image (Screen *screen, Window window) +load_random_image (Screen *screen, Window window, Drawable drawable, + char **name_ret) { Display *dpy = DisplayOfScreen (screen); char *grabber = get_string_resource ("desktopGrabber", "DesktopGrabber"); char *cmd; - char id[20]; + char id[200]; if (!grabber || !*grabber) { @@ -117,7 +254,9 @@ grab_screen_image (Screen *screen, Window window) exit (1); } - sprintf (id, "0x%x", (unsigned long) window); + sprintf (id, "0x%lx 0x%lx", + (unsigned long) window, + (unsigned long) drawable); cmd = (char *) malloc (strlen(grabber) + strlen(id) + 1); /* Needn't worry about buffer overflows here, because the buffer is @@ -131,10 +270,31 @@ grab_screen_image (Screen *screen, Window window) /* In case "cmd" fails, leave some random image on the screen, not just black or white, so that it's more obvious what went wrong. */ - checkerboard (screen, window); + checkerboard (screen, drawable); XSync (dpy, True); - system (cmd); + hack_subproc_environment (dpy); + fork_exec_wait (cmd); free (cmd); XSync (dpy, True); + + if (name_ret) + { + Atom type; + int format; + unsigned long nitems, bytesafter; + char *name=NULL; + + *name_ret = NULL; + + if (XGetWindowProperty (dpy, window, + XInternAtom (dpy, XA_XSCREENSAVER_IMAGE_FILENAME, + False), + 0, 1024, False, XA_STRING, + &type, &format, &nitems, &bytesafter, + (unsigned char **) &name) + == Success + && type != None) + *name_ret = strdup(name); + } }