X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=driver%2Fremote.c;h=1e67c973f730ee39fe17fedf0d61e51a17ece6da;hb=f0261d8acab611f3433160e4f07367b870439739;hp=26c855584f81d7f70e7893f53b84025f8adc8d22;hpb=df7adbee81405e2849728a24b498ad2117784b1f;p=xscreensaver diff --git a/driver/remote.c b/driver/remote.c index 26c85558..1e67c973 100644 --- a/driver/remote.c +++ b/driver/remote.c @@ -1,5 +1,4 @@ -/* xscreensaver-command, Copyright (c) 1991-1998 - * by Jamie Zawinski +/* xscreensaver-command, Copyright (c) 1991-2009 Jamie Zawinski * * 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 #include +#include #include #include @@ -41,8 +41,8 @@ ERROR! you must not include vroot.h in this file extern char *progname; extern Atom XA_SCREENSAVER, XA_SCREENSAVER_VERSION, XA_SCREENSAVER_RESPONSE; -extern Atom XA_SCREENSAVER_ID, XA_SCREENSAVER_TIME; -extern Atom XA_VROOT, XA_SELECT, XA_DEMO; +extern Atom XA_SCREENSAVER_ID, XA_SCREENSAVER_STATUS, XA_EXIT; +extern Atom XA_VROOT, XA_SELECT, XA_DEMO, XA_BLANK, XA_LOCK; static XErrorHandler old_handler = 0; @@ -82,13 +82,13 @@ find_screensaver_window (Display *dpy, char **version) if (parent) abort (); if (! (kids && nkids)) - abort (); + return 0; for (i = 0; i < nkids; i++) { 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 @@ -99,73 +99,114 @@ find_screensaver_window (Display *dpy, char **version) */ XSync (dpy, False); if (old_handler) abort(); + got_badwindow = False; old_handler = XSetErrorHandler (BadWindow_ehandler); status = XGetWindowProperty (dpy, kids[i], 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; if (got_badwindow) - status = BadWindow; + { + status = BadWindow; + got_badwindow = False; + } if (status == Success && type != None) { + Window ret = kids[i]; if (version) - *version = v; - return kids[i]; + *version = (char *) v; + XFree (kids); + return ret; } } - fprintf (stderr, "%s: no screensaver is running on display %s\n", progname, - DisplayString (dpy)); + + if (kids) XFree (kids); return 0; } static int send_xscreensaver_command (Display *dpy, Atom command, long arg, - Window *window_ret) + Window *window_ret, char **error_ret) { + int status = -1; char *v = 0; Window window = find_screensaver_window (dpy, &v); XWindowAttributes xgwa; + char err[2048]; if (window_ret) *window_ret = window; if (!window) - return -1; + { + sprintf (err, "no screensaver is running on display %s", + DisplayString (dpy)); + + if (error_ret) + { + *error_ret = strdup (err); + status = -1; + goto DONE; + } + + if (command == XA_EXIT) + { + /* Don't print an error if xscreensaver is already dead. */ + status = 1; + goto DONE; + } + + fprintf (stderr, "%s: %s\n", progname, err); + status = -1; + goto DONE; + } /* Select for property change events, so that we can read the response. */ XGetWindowAttributes (dpy, window, &xgwa); XSelectInput (dpy, window, xgwa.your_event_mask | PropertyChangeMask); - if (command == XA_SCREENSAVER_TIME || + if (command == XA_SCREENSAVER_STATUS || command == XA_SCREENSAVER_VERSION) { XClassHint hint; memset (&hint, 0, sizeof(hint)); if (!v || !*v) { - fprintf (stderr, "%s: version property not set on window 0x%x?\n", - progname, (unsigned int) window); - return -1; + sprintf (err, "version property not set on window 0x%x?", + (unsigned int) window); + if (error_ret) + *error_ret = strdup (err); + else + fprintf (stderr, "%s: %s\n", progname, err); + + status = -1; + goto DONE; } XGetClassHint(dpy, window, &hint); if (!hint.res_class) { - fprintf (stderr, "%s: class hints not set on window 0x%x?\n", - progname, (unsigned int) window); - return -1; + sprintf (err, "class hints not set on window 0x%x?", + (unsigned int) window); + if (error_ret) + *error_ret = strdup (err); + else + fprintf (stderr, "%s: %s\n", progname, err); + + status = -1; + goto DONE; } fprintf (stdout, "%s %s", hint.res_class, v); - if (command != XA_SCREENSAVER_TIME) + if (command != XA_SCREENSAVER_STATUS) { fprintf (stdout, "\n"); } @@ -174,54 +215,100 @@ send_xscreensaver_command (Display *dpy, Atom command, long arg, Atom type; int format; unsigned long nitems, bytesafter; - unsigned char *data = 0; - Bool active_p = False; - - if (XGetWindowProperty (dpy, window, XA_VROOT, - 0, 0, False, XA_WINDOW, - &type, &format, &nitems, &bytesafter, - &data) - == Success - && type != None) - active_p = True; + unsigned char *dataP = 0; - if (data) free (data); - data = 0; - - if (XGetWindowProperty (dpy, window, - XA_SCREENSAVER_TIME, - 0, 1, False, XA_INTEGER, + if (XGetWindowProperty (dpy, + RootWindow (dpy, 0), + XA_SCREENSAVER_STATUS, + 0, 999, False, XA_INTEGER, &type, &format, &nitems, &bytesafter, - &data) + &dataP) == Success - && type == XA_INTEGER - && data) + && type + && dataP) { - CARD32 time32 = *((CARD32 *)data); - time_t tt = (time_t) time32; - - if (active_p) - fprintf (stdout, ": screen blanked since "); - else + Atom blanked; + time_t tt; + char *s; + Atom *data = (Atom *) dataP; + + if (type != XA_INTEGER || nitems < 3) + { + STATUS_LOSE: + if (data) free (data); + fprintf (stdout, "\n"); + fflush (stdout); + fprintf (stderr, "bad status format on root window.\n"); + status = -1; + goto DONE; + } + + blanked = (Atom) data[0]; + tt = (time_t) data[1]; + + if (tt <= (time_t) 666000000L) /* early 1991 */ + goto STATUS_LOSE; + + if (blanked == XA_BLANK) + fputs (": screen blanked since ", stdout); + else if (blanked == XA_LOCK) + fputs (": screen locked since ", stdout); + else if (blanked == 0) /* suggestions for a better way to phrase this are welcome. */ - fprintf (stdout, ": screen non-blanked since "); - fprintf (stdout, "%s", ctime(&tt)); + fputs (": screen non-blanked since ", stdout); + else + /* `blanked' has an unknown value - fail. */ + goto STATUS_LOSE; + + s = ctime(&tt); + if (s[strlen(s)-1] == '\n') + s[strlen(s)-1] = 0; + fputs (s, stdout); + + { + int nhacks = nitems - 2; + Bool any = False; + int i; + for (i = 0; i < nhacks; i++) + if (data[i + 2] > 0) + { + any = True; + break; + } + + if (any && nhacks == 1) + fprintf (stdout, " (hack #%d)\n", (int) data[2]); + else if (any) + { + fprintf (stdout, " (hacks: "); + for (i = 0; i < nhacks; i++) + { + fprintf (stdout, "#%d", (int) data[2 + i]); + if (i != nhacks-1) + fputs (", ", stdout); + } + fputs (")\n", stdout); + } + else + fputs ("\n", stdout); + } + if (data) free (data); } else { - if (data) free (data); + if (dataP) XFree (dataP); fprintf (stdout, "\n"); fflush (stdout); - fprintf (stderr, "%s: no time on window 0x%x (%s %s).\n", - progname, (unsigned int) window, - hint.res_class, (v ? v : "???")); - return -1; + fprintf (stderr, "no saver status on root window.\n"); + status = -1; + goto DONE; } } /* No need to read a response for these commands. */ - return 1; + status = 1; + goto DONE; } else { @@ -235,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. */ } @@ -250,126 +337,158 @@ send_xscreensaver_command (Display *dpy, Atom command, long arg, event.xclient.data.l[2] = arg2; if (! XSendEvent (dpy, window, False, 0L, &event)) { - fprintf (stderr, "%s: XSendEvent(dpy, 0x%x ...) failed.\n", - progname, (unsigned int) window); - return -1; + sprintf (err, "XSendEvent(dpy, 0x%x ...) failed.\n", + (unsigned int) window); + if (error_ret) + *error_ret = strdup (err); + else + fprintf (stderr, "%s: %s\n", progname, err); + 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); } static int -xscreensaver_command_response (Display *dpy, Window window, Bool verbose_p) +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 (!(got_event = XCheckIfEvent(dpy, &event, + &xscreensaver_command_event_p, 0)) && + sleep_count++ < 10) + { + sleep(1); + } - while (1) + if (!got_event) { - FD_ZERO(&fds); - FD_SET(fd, &fds); - memset(&tv, 0, sizeof(tv)); - tv.tv_sec = timeout; - status = select (fd+1, &fds, 0, &fds, &tv); + sprintf (err, "no response to command."); + if (error_ret) + *error_ret = strdup (err); + else + fprintf (stderr, "%s: %s\n", progname, err); - if (status < 0) - { - char buf[1024]; - sprintf (buf, "%s: waiting for reply", progname); - perror (buf); - return status; - } - else if (status == 0) + 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) { - fprintf (stderr, "%s: no response to command.\n", progname); + 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) - { - fprintf (stdout, - "%s: xscreensaver window has been deleted.\n", - progname); - return 0; - } + sprintf (err, "unrecognized response property."); - if (st2 == Success && type != None) - { - if (type != XA_STRING || format != 8) - { - fprintf (stderr, - "%s: unrecognized response property.\n", - progname); - if (msg) XFree (msg); - return -1; - } - else if (!msg || (msg[0] != '+' && msg[0] != '-')) - { - fprintf (stderr, - "%s: unrecognized response message.\n", - progname); - if (msg) XFree (msg); - return -1; - } - else - { - int ret = (msg[0] == '+' ? 0 : -1); - if (verbose_p || ret != 0) - fprintf ((ret < 0 ? stderr : stdout), - "%s: %s\n", - progname, - msg+1); - XFree (msg); - return ret; - } - } + 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, (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 */ } int -xscreensaver_command (Display *dpy, Atom command, long arg, Bool verbose_p) +xscreensaver_command (Display *dpy, Atom command, long arg, Bool verbose_p, + char **error_ret) { Window w = 0; - int status = send_xscreensaver_command (dpy, command, arg, &w); + int status = send_xscreensaver_command (dpy, command, arg, &w, error_ret); if (status == 0) - status = xscreensaver_command_response (dpy, w, verbose_p); + status = xscreensaver_command_response (dpy, w, verbose_p, + (command == XA_EXIT), + error_ret); + fflush (stdout); fflush (stderr); - return status; + return (status < 0 ? status : 0); } @@ -397,30 +516,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". */ @@ -430,7 +549,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)