http://www.jwz.org/xscreensaver/xscreensaver-5.12.tar.gz
[xscreensaver] / driver / remote.c
index 592d5d03ec75206c7262865e29f678b601eb8b86..775036ac3032899596282b3ba4321fd1ed5050da 100644 (file)
@@ -1,5 +1,4 @@
-/* xscreensaver-command, Copyright (c) 1991-1998
- *  by Jamie Zawinski <jwz@jwz.org>
+/* xscreensaver-command, Copyright (c) 1991-2009 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
@@ -16,6 +15,7 @@
 
 #include <stdio.h>
 #include <stdlib.h>
+#include <time.h>
 #include <sys/time.h>
 #include <sys/types.h>
 
@@ -88,7 +88,7 @@ find_screensaver_window (Display *dpy, char **version)
       Atom type;
       int format;
       unsigned long nitems, bytesafter;
-      char *v;
+      unsigned char *v;
       int status;
 
       /* We're walking the list of root-level windows and trying to find
@@ -105,7 +105,7 @@ find_screensaver_window (Display *dpy, char **version)
                                    XA_SCREENSAVER_VERSION,
                                    0, 200, False, XA_STRING,
                                    &type, &format, &nitems, &bytesafter,
-                                   (unsigned char **) &v);
+                                   &v);
       XSync (dpy, False);
       XSetErrorHandler (old_handler);
       old_handler = 0;
@@ -118,11 +118,15 @@ find_screensaver_window (Display *dpy, char **version)
 
       if (status == Success && type != None)
        {
+          Window ret = kids[i];
          if (version)
-           *version = v;
-         return kids[i];
+           *version = (char *) v;
+          XFree (kids);
+         return ret;
        }
     }
+
+  if (kids) XFree (kids);
   return 0;
 }
 
@@ -131,6 +135,7 @@ static int
 send_xscreensaver_command (Display *dpy, Atom command, long arg,
                           Window *window_ret, char **error_ret)
 {
+  int status = -1;
   char *v = 0;
   Window window = find_screensaver_window (dpy, &v);
   XWindowAttributes xgwa;
@@ -147,15 +152,20 @@ send_xscreensaver_command (Display *dpy, Atom command, long arg,
       if (error_ret)
         {
           *error_ret = strdup (err);
-          return -1;
+          status = -1;
+          goto DONE;
         }
 
       if (command == XA_EXIT)
-        /* Don't print an error if xscreensaver is already dead. */
-        return 1;
+        {
+          /* Don't print an error if xscreensaver is already dead. */
+          status = 1;
+          goto DONE;
+        }
 
       fprintf (stderr, "%s: %s\n", progname, err);
-      return -1;
+      status = -1;
+      goto DONE;
     }
 
   /* Select for property change events, so that we can read the response. */
@@ -175,7 +185,9 @@ send_xscreensaver_command (Display *dpy, Atom command, long arg,
             *error_ret = strdup (err);
           else
             fprintf (stderr, "%s: %s\n", progname, err);
-         return -1;
+
+          status = -1;
+          goto DONE;
        }
 
       XGetClassHint(dpy, window, &hint);
@@ -187,7 +199,9 @@ send_xscreensaver_command (Display *dpy, Atom command, long arg,
             *error_ret = strdup (err);
           else
             fprintf (stderr, "%s: %s\n", progname, err);
-         return -1;
+
+          status = -1;
+          goto DONE;
        }
 
       fprintf (stdout, "%s %s", hint.res_class, v);
@@ -201,21 +215,22 @@ send_xscreensaver_command (Display *dpy, Atom command, long arg,
          Atom type;
          int format;
          unsigned long nitems, bytesafter;
-         CARD32 *data = 0;
+         unsigned char *dataP = 0;
 
          if (XGetWindowProperty (dpy,
                                   RootWindow (dpy, 0),
                                  XA_SCREENSAVER_STATUS,
                                  0, 999, False, XA_INTEGER,
                                  &type, &format, &nitems, &bytesafter,
-                                 (unsigned char **) &data)
+                                 &dataP)
              == Success
              && type
-             && data)
+             && dataP)
            {
               Atom blanked;
               time_t tt;
               char *s;
+              Atom *data = (Atom *) dataP;
 
               if (type != XA_INTEGER || nitems < 3)
                 {
@@ -224,7 +239,8 @@ send_xscreensaver_command (Display *dpy, Atom command, long arg,
                   fprintf (stdout, "\n");
                   fflush (stdout);
                   fprintf (stderr, "bad status format on root window.\n");
-                  return -1;
+                  status = -1;
+                  goto DONE;
                 }
                   
               blanked = (Atom) data[0];
@@ -261,13 +277,13 @@ send_xscreensaver_command (Display *dpy, Atom command, long arg,
                     }
 
                 if (any && nhacks == 1)
-                  fprintf (stdout, " (hack #%d)\n", data[2]);
+                  fprintf (stdout, " (hack #%d)\n", (int) data[2]);
                 else if (any)
                   {
                     fprintf (stdout, " (hacks: ");
                     for (i = 0; i < nhacks; i++)
                       {
-                        fprintf (stdout, "#%d", data[2 + i]);
+                        fprintf (stdout, "#%d", (int) data[2 + i]);
                         if (i != nhacks-1)
                           fputs (", ", stdout);
                       }
@@ -281,16 +297,18 @@ send_xscreensaver_command (Display *dpy, Atom command, long arg,
            }
          else
            {
-             if (data) free (data);
+             if (dataP) XFree (dataP);
              fprintf (stdout, "\n");
              fflush (stdout);
              fprintf (stderr, "no saver status on root window.\n");
-             return -1;
+              status = -1;
+              goto DONE;
            }
        }
 
       /* No need to read a response for these commands. */
-      return 1;
+      status = 1;
+      goto DONE;
     }
   else
     {
@@ -304,7 +322,7 @@ send_xscreensaver_command (Display *dpy, Atom command, long arg,
        abort();
       else if (arg != 0 && command == XA_DEMO)
        {
-         arg1 = 300;   /* version number of the XA_DEMO protocol, */
+         arg1 = 5000;  /* version number of the XA_DEMO protocol, */
          arg2 = arg;   /* since it didn't use to take an argument. */
        }
 
@@ -325,11 +343,26 @@ send_xscreensaver_command (Display *dpy, Atom command, long arg,
             *error_ret = strdup (err);
           else
             fprintf (stderr, "%s: %s\n", progname, err);
-         return -1;
+          status = -1;
+          goto DONE;
        }
     }
+
+  status = 0;
+
+ DONE:
+  if (v) free (v);
   XSync (dpy, 0);
-  return 0;
+  return status;
+}
+
+
+static Bool
+xscreensaver_command_event_p (Display *dpy, XEvent *event, XPointer arg)
+{
+  return (event->xany.type == PropertyNotify &&
+          event->xproperty.state == PropertyNewValue &&
+          event->xproperty.atom == XA_SCREENSAVER_RESPONSE);
 }
 
 
@@ -338,130 +371,122 @@ xscreensaver_command_response (Display *dpy, Window window,
                                Bool verbose_p, Bool exiting_p,
                                char **error_ret)
 {
-  int fd = ConnectionNumber (dpy);
-  int timeout = 10;
-  int status;
-  fd_set fds;
-  struct timeval tv;
+  int sleep_count = 0;
   char err[2048];
+  XEvent event;
+  Bool got_event = False;
 
-  while (1)
+  while (!(got_event = XCheckIfEvent(dpy, &event,
+                                    &xscreensaver_command_event_p, 0)) &&
+        sleep_count++ < 10)
     {
-      FD_ZERO(&fds);
-      FD_SET(fd, &fds);
-      memset(&tv, 0, sizeof(tv));
-      tv.tv_sec = timeout;
-      status = select (fd+1, &fds, 0, &fds, &tv);
+# if defined(HAVE_SELECT)
+      /* Wait for an event, but don't wait longer than 1 sec.  Note that we
+         might do this multiple times if an event comes in, but it wasn't
+         the event we're waiting for.
+       */
+      int fd = XConnectionNumber(dpy);
+      fd_set rset;
+      struct timeval tv;
+      tv.tv_sec  = 1;
+      tv.tv_usec = 0;
+      FD_ZERO (&rset);
+      FD_SET (fd, &rset);
+      select (fd+1, &rset, 0, 0, &tv);
+# else  /* !HAVE_SELECT */
+      sleep(1);
+# endif /* !HAVE_SELECT */
+    }
 
-      if (status < 0)
-       {
-         char buf[1024];
-          if (error_ret)
-            {
-              sprintf (buf, "error waiting for reply");
-              *error_ret = strdup (buf);
-            }
-          else
-            {
-              sprintf (buf, "%s: error waiting for reply", progname);
-              perror (buf);
-            }
-         return status;
-       }
-      else if (status == 0)
+  if (!got_event)
+    {
+      sprintf (err, "no response to command.");
+      if (error_ret)
+       *error_ret = strdup (err);
+      else
+       fprintf (stderr, "%s: %s\n", progname, err);
+
+      return -1;
+    }
+  else
+    {
+      Status st2;
+      Atom type;
+      int format;
+      unsigned long nitems, bytesafter;
+      unsigned char *msg = 0;
+
+      XSync (dpy, False);
+      if (old_handler) abort();
+      old_handler = XSetErrorHandler (BadWindow_ehandler);
+      st2 = XGetWindowProperty (dpy, window,
+                               XA_SCREENSAVER_RESPONSE,
+                               0, 1024, True,
+                               AnyPropertyType,
+                               &type, &format, &nitems, &bytesafter,
+                               &msg);
+      XSync (dpy, False);
+      XSetErrorHandler (old_handler);
+      old_handler = 0;
+
+      if (got_badwindow)
        {
-         sprintf (err, "no response to command.");
-          if (error_ret)
-            *error_ret = strdup (err);
-          else
-            fprintf (stderr, "%s: %s\n", progname, err);
+         if (exiting_p)
+           return 0;
+
+         sprintf (err, "xscreensaver window unexpectedly deleted.");
+
+         if (error_ret)
+           *error_ret = strdup (err);
+         else
+           fprintf (stderr, "%s: %s\n", progname, err);
+
          return -1;
        }
-      else
+
+      if (st2 == Success && type != None)
        {
-         XEvent event;
-         XNextEvent (dpy, &event);
-         if (event.xany.type == PropertyNotify &&
-             event.xproperty.state == PropertyNewValue &&
-             event.xproperty.atom == XA_SCREENSAVER_RESPONSE)
+         if (type != XA_STRING || format != 8)
            {
-             Status st2;
-             Atom type;
-             int format;
-             unsigned long nitems, bytesafter;
-             char *msg = 0;
-
-             XSync (dpy, False);
-              if (old_handler) abort();
-             old_handler = XSetErrorHandler (BadWindow_ehandler);
-             st2 = XGetWindowProperty (dpy, window,
-                                       XA_SCREENSAVER_RESPONSE,
-                                       0, 1024, True,
-                                       AnyPropertyType,
-                                       &type, &format, &nitems, &bytesafter,
-                                       (unsigned char **) &msg);
-             XSync (dpy, False);
-              XSetErrorHandler (old_handler);
-              old_handler = 0;
-
-             if (got_badwindow)
-               {
-                  if (exiting_p)
-                    return 0;
+             sprintf (err, "unrecognized response property.");
 
-                  sprintf (err, "xscreensaver window unexpectedly deleted.");
+             if (error_ret)
+               *error_ret = strdup (err);
+             else
+               fprintf (stderr, "%s: %s\n", progname, err);
 
-                  if (error_ret)
-                    *error_ret = strdup (err);
-                  else
-                    fprintf (stderr, "%s: %s\n", progname, err);
+             if (msg) XFree (msg);
+             return -1;
+           }
+         else if (!msg || (msg[0] != '+' && msg[0] != '-'))
+           {
+             sprintf (err, "unrecognized response message.");
 
-                 return -1;
-               }
+             if (error_ret)
+               *error_ret = strdup (err);
+             else  
+               fprintf (stderr, "%s: %s\n", progname, err);
 
-             if (st2 == Success && type != None)
-               {
-                 if (type != XA_STRING || format != 8)
-                   {
-                     sprintf (err, "unrecognized response property.");
-
-                      if (error_ret)
-                        *error_ret = strdup (err);
-                      else
-                        fprintf (stderr, "%s: %s\n", progname, err);
-
-                     if (msg) XFree (msg);
-                     return -1;
-                   }
-                 else if (!msg || (msg[0] != '+' && msg[0] != '-'))
-                   {
-                     sprintf (err, "unrecognized response message.");
-
-                      if (error_ret)
-                        *error_ret = strdup (err);
-                      else  
-                        fprintf (stderr, "%s: %s\n", progname, err);
-
-                     if (msg) XFree (msg);
-                     return -1;
-                   }
-                 else
-                   {
-                     int ret = (msg[0] == '+' ? 0 : -1);
-                      sprintf (err, "%s: %s\n", progname, msg+1);
-
-                      if (error_ret)
-                        *error_ret = strdup (err);
-                      else if (verbose_p || ret != 0)
-                       fprintf ((ret < 0 ? stderr : stdout), "%s\n", err);
-
-                     XFree (msg);
-                     return ret;
-                   }
-               }
+             if (msg) XFree (msg);
+             return -1;
+           }
+         else
+           {
+             int ret = (msg[0] == '+' ? 0 : -1);
+             sprintf (err, "%s: %s\n", progname, (char *) msg+1);
+
+             if (error_ret)
+               *error_ret = strdup (err);
+             else if (verbose_p || ret != 0)
+               fprintf ((ret < 0 ? stderr : stdout), "%s\n", err);
+
+             XFree (msg);
+             return ret;
            }
        }
     }
+
+  return -1;  /* warning suppression: not actually reached */
 }
 
 
@@ -506,30 +531,30 @@ server_xscreensaver_version (Display *dpy,
 
   if (version_ret)
     {
-      char *v = 0;
+      unsigned char *v = 0;
       XGetWindowProperty (dpy, window, XA_SCREENSAVER_VERSION, 0, 1,
                          False, XA_STRING, &type, &format, &nitems,
-                         &bytesafter, (unsigned char **) &v);
+                         &bytesafter, &v);
       if (v)
        {
-         *version_ret = strdup (v);
+         *version_ret = strdup ((char *) v);
          XFree (v);
        }
     }
 
   if (user_ret || host_ret)
     {
-      char *id = 0;
+      unsigned char *id = 0;
       const char *user = 0;
       const char *host = 0;
 
       XGetWindowProperty (dpy, window, XA_SCREENSAVER_ID, 0, 512,
                          False, XA_STRING, &type, &format, &nitems,
-                         &bytesafter, (unsigned char **) &id);
+                         &bytesafter, &id);
       if (id && *id)
        {
          const char *old_tag = " on host ";
-         const char *s = strstr (id, old_tag);
+         const char *s = strstr ((char *) id, old_tag);
          if (s)
            {
              /* found ID of the form "1234 on host xyz". */
@@ -539,7 +564,7 @@ server_xscreensaver_version (Display *dpy,
          else
            {
              char *o = 0, *p = 0, *c = 0;
-             o = strchr (id, '(');
+             o = strchr ((char *) id, '(');
              if (o) p = strchr (o, '@');
              if (p) c = strchr (p, ')');
              if (c)