ftp://ftp.jp.xemacs.org/pub/NetBSD/packages/distfiles/xscreensaver-4.15.tar.gz
[xscreensaver] / utils / grabclient.c
index 2c426be83e797329566c7304e2a819b68274c53b..7b5298dffd156f653653a550fae454f332de4dab 100644 (file)
 #include "vroot.h"
 #include <X11/Xatom.h>
 
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+#ifdef HAVE_SYS_WAIT_H
+# include <sys/wait.h>         /* for waitpid() and associated macros */
+#endif
+
+
 extern char *progname;
 
 
@@ -104,7 +112,7 @@ static void
 checkerboard (Screen *screen, Drawable drawable)
 {
   Display *dpy = DisplayOfScreen (screen);
-  int x, y;
+  unsigned int x, y;
   int size = 24;
   XColor fg, bg;
   XGCValues gcv;
@@ -176,11 +184,62 @@ hack_subproc_environment (Display *dpy)
 }
 
 
+/* 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
-load_random_image (Screen *screen, Window window, Drawable drawable)
+load_random_image (Screen *screen, Window window, Drawable drawable,
+                   char **name_ret)
 {
   Display *dpy = DisplayOfScreen (screen);
   char *grabber = get_string_resource ("desktopGrabber", "DesktopGrabber");
@@ -215,7 +274,27 @@ load_random_image (Screen *screen, Window window, Drawable drawable)
 
   XSync (dpy, True);
   hack_subproc_environment (dpy);
-  system (cmd);
+  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);
+    }
 }