8ace1506e486b32ef318ec98c9597f65db571915
[xscreensaver] / driver / xscreensaver-command.c
1 /* xscreensaver-command, Copyright (c) 1991-1998
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 #define STANDALONE
14
15 #ifdef HAVE_CONFIG_H
16 # include "config.h"
17 #endif
18
19 #include <stdio.h>
20 #include <stdlib.h>
21
22 #ifdef HAVE_UNISTD_H
23 # include <unistd.h>
24 #endif
25
26 #include <X11/Xproto.h>         /* for CARD32 */
27 #include <X11/Xlib.h>
28 #include <X11/Xatom.h>
29 #include <X11/Xutil.h>          /* for XGetClassHint() */
30 #include <X11/Xos.h>
31
32 #include <X11/Intrinsic.h>      /* only needed to get through xscreensaver.h */
33
34 #include "version.h"
35
36 #ifdef STANDALONE
37   static char *progname;
38   static Atom XA_VROOT;
39   static Atom XA_SCREENSAVER, XA_SCREENSAVER_VERSION, XA_SCREENSAVER_TIME;
40 #else  /* !STANDALONE */
41 # include "xscreensaver.h"
42 #endif /* !STANDALONE */
43
44
45 #ifdef _VROOT_H_
46 ERROR! you must not include vroot.h in this file
47 #endif
48
49 static Window
50 find_screensaver_window (Display *dpy, char **version)
51 {
52   int i;
53   Window root = RootWindowOfScreen (DefaultScreenOfDisplay (dpy));
54   Window root2, parent, *kids;
55   unsigned int nkids;
56
57   if (version) *version = 0;
58
59   if (! XQueryTree (dpy, root, &root2, &parent, &kids, &nkids))
60     abort ();
61   if (root != root2)
62     abort ();
63   if (parent)
64     abort ();
65   if (! (kids && nkids))
66     abort ();
67   for (i = 0; i < nkids; i++)
68     {
69       Atom type;
70       int format;
71       unsigned long nitems, bytesafter;
72       char *v;
73
74       if (XGetWindowProperty (dpy, kids[i],
75                               XA_SCREENSAVER_VERSION,
76                               0, 200, False, XA_STRING,
77                               &type, &format, &nitems, &bytesafter,
78                               (unsigned char **) &v)
79           == Success
80           && type != None)
81         {
82           if (version)
83             *version = v;
84           return kids[i];
85         }
86     }
87   fprintf (stderr, "%s: no screensaver is running on display %s\n", progname,
88            DisplayString (dpy));
89   exit (1);
90 }
91
92
93 void
94 xscreensaver_command (Display *dpy, Atom command)
95 {
96   char *v = 0;
97   Window window = find_screensaver_window (dpy, &v);
98
99   if (command == XA_SCREENSAVER_TIME ||
100       command == XA_SCREENSAVER_VERSION)
101     {
102       XClassHint hint;
103       memset (&hint, 0, sizeof(hint));
104       if (!v || !*v)
105         {
106           fprintf (stderr, "%s: version property not set on window 0x%x?\n",
107                    progname, (unsigned int) window);
108           exit (1);
109         }
110
111       XGetClassHint(dpy, window, &hint);
112       if (!hint.res_class)
113         {
114           fprintf (stderr, "%s: class hints not set on window 0x%x?\n",
115                    progname, (unsigned int) window);
116           exit (1);
117         }
118
119       fprintf (stdout, "%s %s", hint.res_class, v);
120
121       if (command != XA_SCREENSAVER_TIME)
122         {
123           fprintf (stdout, "\n");
124         }
125       else
126         {
127           Atom type;
128           int format;
129           unsigned long nitems, bytesafter;
130           unsigned char *data = 0;
131           XWindowAttributes xgwa;
132           Bool active_p = False;
133
134           xgwa.map_state = IsViewable;
135           XGetWindowAttributes (dpy, window, &xgwa);
136
137           if (XGetWindowProperty (dpy, window, XA_VROOT,
138                                   0, 0, False, XA_WINDOW,
139                                   &type, &format, &nitems, &bytesafter,
140                                   &data)
141               == Success
142               && type != None)
143             active_p = True;
144
145           if (data) free (data);
146           data = 0;
147
148           if (XGetWindowProperty (dpy, window,
149                                   XA_SCREENSAVER_TIME,
150                                   0, 1, False, XA_INTEGER,
151                                   &type, &format, &nitems, &bytesafter,
152                                   &data)
153               == Success
154               && type == XA_INTEGER
155               && data)
156             {
157               CARD32 time32 = *((CARD32 *)data);
158               time_t tt = (time_t) time32;
159
160               if (active_p)
161                 fprintf (stdout, ": screen blanked since ");
162               else
163                 /* suggestions for a better way to phrase this are welcome. */
164                 fprintf (stdout, ": screen non-blanked since ");
165               fprintf (stdout, "%s", ctime(&tt));
166               if (data) free (data);
167             }
168           else
169             {
170               if (data) free (data);
171               fprintf (stdout, "\n");
172               fflush (stdout);
173               fprintf (stderr, "%s: no time on window 0x%x (%s %s).\n",
174                        progname, (unsigned int) window,
175                        hint.res_class, (v ? v : "???"));
176               exit (1);
177             }
178         }
179     }
180   else
181     {
182       XEvent event;
183       event.xany.type = ClientMessage;
184       event.xclient.display = dpy;
185       event.xclient.window = window;
186       event.xclient.message_type = XA_SCREENSAVER;
187       event.xclient.format = 32;
188       event.xclient.data.l[0] = (long) command;
189       if (! XSendEvent (dpy, window, False, 0L, &event))
190         {
191           fprintf (stderr, "%s: XSendEvent(dpy, 0x%x ...) failed.\n",
192                    progname, (unsigned int) window);
193           exit (1);
194         }
195     }
196   XSync (dpy, 0);
197 }
198
199
200 \f
201 #ifdef STANDALONE
202 static Atom XA_ACTIVATE, XA_DEACTIVATE, XA_CYCLE, XA_NEXT, XA_PREV;
203 static Atom XA_EXIT, XA_RESTART, XA_DEMO, XA_LOCK;
204
205 static char *progname;
206 static char *screensaver_version;
207 static char *usage = "\n\
208 usage: %s -<switch>\n\
209 \n\
210   This program provides external control of a running xscreensaver process.\n\
211   Version %s, copyright (c) 1991-1997 Jamie Zawinski <jwz@netscape.com>.\n\
212 \n\
213   The xscreensaver program is a daemon that runs in the background.\n\
214   You control a running xscreensaver process by sending it messages\n\
215   with this program, xscreensaver-command.  See the man pages for\n\
216   details.  These are the arguments understood by xscreensaver-command:\n\
217 \n\
218   -demo         Ask the xscreensaver process to enter interactive demo mode.\n\
219 \n\
220   -activate     Turn on the screensaver (blank the screen), as if the user\n\
221                 had been idle for long enough.\n\
222 \n\
223   -deactivate   Turns off the screensaver (un-blank the screen), as if user\n\
224                 activity had been detected.\n\
225 \n\
226   -cycle        If the screensaver is active (the screen is blanked), then\n\
227                 stop the current graphics demo and run a new one (chosen\n\
228                 randomly.)\n\
229 \n\
230   -next         Like either -activate or -cycle, depending on which is more\n\
231                 appropriate, except that the graphics hack that will be run\n\
232                 is the next one in the list, instead of a randomly-chosen\n\
233                 one.  In other words, repeatedly executing -next will cause\n\
234                 the xscreensaver process to invoke each graphics demo\n\
235                 sequentially.  (Though using the -demo option is probably\n\
236                 an easier way to accomplish that.)\n\
237 \n\
238   -prev         Like -next, but goes in the other direction.\n\
239 \n\
240   -exit         Causes the xscreensaver process to exit gracefully.  This is\n\
241                 roughly the same as killing the process with `kill', but it\n\
242                 is easier, since you don't need to first figure out the pid.\n\
243                 (Note that one must *never* kill xscreensaver with -9!)\n\
244 \n\
245   -restart      Causes the screensaver process to exit and then restart with\n\
246                 the same command line arguments as last time.  Do this after\n\
247                 you've changed your X resource settings, to cause\n\
248                 xscreensaver to notice the changes.\n\
249 \n\
250   -lock         Tells the running xscreensaver process to lock the screen\n\
251                 immediately.  This is like -activate, but forces locking as\n\
252                 well, even if locking is not the default.\n\
253 \n\
254   -version      Prints the version of xscreensaver that is currently running\n\
255                 on the display -- that is, the actual version number of the\n\
256                 running xscreensaver background process, rather than the\n\
257                 version number of xscreensaver-command.\n\
258 \n\
259   -time         Prints the time at which the screensaver last activated or\n\
260                 deactivated (roughly, how long the user has been idle or\n\
261                 non-idle -- but not quite, since it only tells you when the\n\
262                 screen became blanked or un-blanked.)\n\
263 \n\
264   See the man page for more details.\n\
265   For updates, check http://people.netscape.com/jwz/xscreensaver/\n\
266 \n";
267
268 #define USAGE() \
269  { fprintf (stderr, usage, progname, screensaver_version); exit (1); }
270
271 int
272 main (int argc, char **argv)
273 {
274   Display *dpy;
275   int i;
276   char *dpyname = 0;
277   Atom *cmd = 0;
278
279   progname = argv[0];
280   screensaver_version = (char *) malloc (5);
281   memcpy (screensaver_version, screensaver_id + 17, 4);
282   screensaver_version [4] = 0;
283
284   for (i = 1; i < argc; i++)
285     {
286       const char *s = argv [i];
287       int L;
288       if (s[0] == '-' && s[1] == '-') s++;
289       L = strlen (s);
290       if (L < 2) USAGE ();
291       if (!strncmp (s, "-display", L))          dpyname = argv [++i];
292       else if (cmd) USAGE ()
293       else if (!strncmp (s, "-activate", L))   cmd = &XA_ACTIVATE;
294       else if (!strncmp (s, "-deactivate", L)) cmd = &XA_DEACTIVATE;
295       else if (!strncmp (s, "-cycle", L))      cmd = &XA_CYCLE;
296       else if (!strncmp (s, "-next", L))       cmd = &XA_NEXT;
297       else if (!strncmp (s, "-prev", L))       cmd = &XA_PREV;
298       else if (!strncmp (s, "-exit", L))       cmd = &XA_EXIT;
299       else if (!strncmp (s, "-restart", L))    cmd = &XA_RESTART;
300       else if (!strncmp (s, "-demo", L))       cmd = &XA_DEMO;
301       else if (!strncmp (s, "-lock", L))       cmd = &XA_LOCK;
302       else if (!strncmp (s, "-version", L))    cmd = &XA_SCREENSAVER_VERSION;
303       else if (!strncmp (s, "-time", L))       cmd = &XA_SCREENSAVER_TIME;
304       else USAGE ();
305     }
306   if (!cmd)
307     USAGE ();
308
309   if (!dpyname) dpyname = (char *) getenv ("DISPLAY");
310   dpy = XOpenDisplay (dpyname);
311   if (!dpy)
312     {
313       fprintf (stderr, "%s: can't open display %s\n", progname,
314                (dpyname ? dpyname : "(null)"));
315       exit (1);
316     }
317
318   XA_VROOT = XInternAtom (dpy, "__SWM_VROOT", False);
319   XA_SCREENSAVER = XInternAtom (dpy, "SCREENSAVER", False);
320   XA_SCREENSAVER_VERSION = XInternAtom (dpy, "_SCREENSAVER_VERSION",False);
321   XA_SCREENSAVER_TIME = XInternAtom (dpy, "_SCREENSAVER_TIME", False);
322   XA_ACTIVATE = XInternAtom (dpy, "ACTIVATE", False);
323   XA_DEACTIVATE = XInternAtom (dpy, "DEACTIVATE", False);
324   XA_RESTART = XInternAtom (dpy, "RESTART", False);
325   XA_CYCLE = XInternAtom (dpy, "CYCLE", False);
326   XA_NEXT = XInternAtom (dpy, "NEXT", False);
327   XA_PREV = XInternAtom (dpy, "PREV", False);
328   XA_EXIT = XInternAtom (dpy, "EXIT", False);
329   XA_DEMO = XInternAtom (dpy, "DEMO", False);
330   XA_LOCK = XInternAtom (dpy, "LOCK", False);
331
332   xscreensaver_command(dpy, *cmd);
333
334   fflush (stdout);
335   fflush (stderr);
336   exit (0);
337 }
338
339 #endif /* STANDALONE */