ftp://ftp.uni-heidelberg.de/pub/X11/contrib/applications/xscreensaver-2.07.tar.gz
[xscreensaver] / driver / xscreensaver-command.c
1 /* xscreensaver-command, Copyright (c) 1991-1997
2  *  by Jamie Zawinski <jwz@netscape.com>
3  *
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 
10  * implied warranty.
11  */
12
13 #ifdef HAVE_CONFIG_H
14 # include "config.h"
15 #endif
16
17 #include <stdio.h>
18 #include <X11/Xproto.h>         /* for CARD32 */
19 #include <X11/Xlib.h>
20 #include <X11/Xatom.h>
21 #include <X11/Xutil.h>          /* for XGetClassHint() */
22 #include <X11/Xos.h>
23 #include <stdlib.h>
24
25 #include "version.h"
26
27 #ifdef _VROOT_H_
28 ERROR! you must not include vroot.h in this file
29 #endif
30
31 static char *screensaver_version;
32 static char *usage = "usage: %s -<switch>\n\
33 \n\
34   This program provides external control of a running xscreensaver process.\n\
35   Version %s, copyright (c) 1991-1997 Jamie Zawinski <jwz@netscape.com>.\n\
36 \n\
37   -demo         Enter interactive demo mode.\n\
38   -deactivate   Turns off the screensaver if it is on, as user input would.\n\
39   -activate     Turns it on as if the user had been idle for long enough.\n\
40   -cycle        Stops the current hack and runs a new one.\n\
41   -next         Like either -activate or -cycle, depending on which is more\n\
42                 appropriate, except that the screenhack that will be run is\n\
43                 the next one in the list of hacks, instead of a randomly-\n\
44                 chosen one.  This option is good for looking at a demo of\n\
45                 each of the hacks in place.\n\
46   -prev         Like -next, but goes in the other direction.\n\
47   -exit         Causes the screensaver process to exit.  It should be ok to\n\
48                 just kill the process (NOT with -9!) but this is a slightly\n\
49                 easier way.\n\
50   -restart      Causes the screensaver process to exit and then restart with\n\
51                 the same command line arguments.  This is a good way of \n\
52                 causing the screensaver to re-read the resource database.\n\
53   -lock         Same as -activate, but with immediate locking.\n\
54   -version      Prints the version of XScreenSaver that is running.\n\
55   -time         Prints the time at which the screensaver turned on.\n\
56 \n\
57   See the man page for more details.\n\
58   For updates, check http://people.netscape.com/jwz/xscreensaver/\n\
59 \n";
60
61 static Window
62 find_screensaver_window (Display *dpy, char *progname, char **version)
63 {
64   int i;
65   Window root = RootWindowOfScreen (DefaultScreenOfDisplay (dpy));
66   Window root2, parent, *kids;
67   unsigned int nkids;
68
69   if (version) *version = 0;
70
71   if (! XQueryTree (dpy, root, &root2, &parent, &kids, &nkids))
72     abort ();
73   if (root != root2)
74     abort ();
75   if (parent)
76     abort ();
77   if (! (kids && nkids))
78     abort ();
79   for (i = 0; i < nkids; i++)
80     {
81       Atom type;
82       int format;
83       unsigned long nitems, bytesafter;
84       char *v;
85
86       if (XGetWindowProperty (dpy, kids[i],
87                               XInternAtom (dpy, "_SCREENSAVER_VERSION", False),
88                               0, 200, False, XA_STRING,
89                               &type, &format, &nitems, &bytesafter,
90                               (unsigned char **) &v)
91           == Success
92           && type != None)
93         {
94           if (version)
95             *version = v;
96           return kids[i];
97         }
98     }
99   fprintf (stderr, "%s: no screensaver is running on display %s\n", progname,
100            DisplayString (dpy));
101   exit (1);
102 }
103
104
105 #define USAGE() \
106  { fprintf (stderr, usage, argv[0], screensaver_version); exit (1); }
107
108 int
109 main (int argc, char **argv)
110 {
111   Display *dpy;
112   Window window;
113   int i;
114   int query = 0;
115 #define Q_version 1
116 #define Q_time    2
117   char *message = 0, *dpyname = 0;
118   char *v = 0;
119
120   screensaver_version = (char *) malloc (5);
121   memcpy (screensaver_version, screensaver_id + 17, 4);
122   screensaver_version [4] = 0;
123   for (i = 1; i < argc; i++)
124     {
125       char *s = argv [i];
126       int L = strlen (s);
127       if (L < 2) USAGE ();
128       if (!strncmp (s, "-display", L))          dpyname = argv [++i];
129       else if (message) USAGE ()
130       else if (!strncmp (s, "-activate", L))    message = "ACTIVATE";
131       else if (!strncmp (s, "-deactivate", L))  message = "DEACTIVATE";
132       else if (!strncmp (s, "-cycle", L))       message = "CYCLE";
133       else if (!strncmp (s, "-next", L))        message = "NEXT";
134       else if (!strncmp (s, "-prev", L))        message = "PREV";
135       else if (!strncmp (s, "-exit", L))        message = "EXIT";
136       else if (!strncmp (s, "-restart", L))     message = "RESTART";
137       else if (!strncmp (s, "-demo", L))        message = "DEMO";
138       else if (!strncmp (s, "-lock", L))        message = "LOCK";
139       else if (!strncmp (s, "-version", L))     query   = Q_version;
140       else if (!strncmp (s, "-time", L))        query   = Q_time;
141       else USAGE ();
142     }
143   if (!message && !query) USAGE ();
144   if (!dpyname) dpyname = (char *) getenv ("DISPLAY");
145   dpy = XOpenDisplay (dpyname);
146   if (!dpy)
147     {
148       fprintf (stderr, "%s: can't open display %s\n", argv[0],
149                (dpyname ? dpyname : "(null)"));
150       exit (1);
151     }
152   window = find_screensaver_window (dpy, argv[0], &v);
153
154   if (message)
155     {
156       XEvent event;
157       event.xany.type = ClientMessage;
158       event.xclient.display = dpy;
159       event.xclient.window = window;
160       event.xclient.message_type = XInternAtom (dpy, "SCREENSAVER", False);
161       event.xclient.format = 32;
162       event.xclient.data.l[0] = (long) XInternAtom (dpy, message, False);
163       if (! XSendEvent (dpy, window, False, 0L, &event))
164         {
165           fprintf (stderr, "%s: XSendEvent(dpy, 0x%x ...) failed.\n", argv [0],
166                    (unsigned int) window);
167           exit (1);
168         }
169     }
170   else if (query)
171     {
172       XClassHint hint;
173       memset (&hint, 0, sizeof(hint));
174       if (!v || !*v)
175         {
176           fprintf (stderr, "%s: version property not set on window 0x%x?\n",
177                    argv [0], (unsigned int) window);
178           exit (1);
179         }
180
181       XGetClassHint(dpy, window, &hint);
182       if (!hint.res_class)
183         {
184           fprintf (stderr, "%s: class hints not set on window 0x%x?\n",
185                    argv [0], (unsigned int) window);
186           exit (1);
187         }
188
189       fprintf (stdout, "%s %s", hint.res_class, v);
190
191       if (query != Q_time)
192         {
193           fprintf (stdout, "\n");
194         }
195       else
196         {
197           Atom type;
198           int format;
199           unsigned long nitems, bytesafter;
200           unsigned char *data = 0;
201           XWindowAttributes xgwa;
202           Bool active_p = False;
203
204           xgwa.map_state = IsViewable;
205           XGetWindowAttributes (dpy, window, &xgwa);
206
207           if (XGetWindowProperty (dpy, window,
208                                   XInternAtom (dpy, "__SWM_VROOT", False),
209                                   0, 0, False, XA_WINDOW,
210                                   &type, &format, &nitems, &bytesafter,
211                                   &data)
212               == Success
213               && type != None)
214             active_p = True;
215
216           if (data) free (data);
217           data = 0;
218
219           if (XGetWindowProperty (dpy, window,
220                                   XInternAtom (dpy, "_SCREENSAVER_TIME",False),
221                                   0, 1, False, XA_INTEGER,
222                                   &type, &format, &nitems, &bytesafter,
223                                   &data)
224               == Success
225               && type == XA_INTEGER
226               && data)
227             {
228               CARD32 time32 = *((CARD32 *)data);
229               time_t tt = (time_t) time32;
230
231               if (active_p)
232                 fprintf (stdout, ": active since ");
233               else
234                 fprintf (stdout, ": inactive since ");
235               fprintf (stdout, "%s", ctime(&tt));
236               if (data) free (data);
237             }
238           else
239             {
240               if (data) free (data);
241               fprintf (stdout, "\n");
242               fflush (stdout);
243               fprintf (stderr, "%s: no time on window 0x%x (%s %s).\n",
244                        argv[0], (unsigned int) window,
245                        hint.res_class, (v ? v : "???"));
246               exit (1);
247             }
248         }
249     }
250
251   XSync (dpy, 0);
252   fflush (stdout);
253   fflush (stderr);
254   exit (0);
255 }