ftp://ftp.smr.ru/pub/0/FreeBSD/releases/distfiles/xscreensaver-3.16.tar.gz
[xscreensaver] / driver / xscreensaver-command.c
1 /* xscreensaver-command, Copyright (c) 1991-1999
2  *  by Jamie Zawinski <jwz@jwz.org>
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 <stdlib.h>
19 #include <sys/time.h>
20 #include <sys/types.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 "remote.h"
35 #include "version.h"
36
37 #ifdef _VROOT_H_
38 ERROR! you must not include vroot.h in this file
39 #endif
40
41 char *progname;
42
43 Atom XA_VROOT;
44 Atom XA_SCREENSAVER, XA_SCREENSAVER_VERSION, XA_SCREENSAVER_RESPONSE;
45 Atom XA_SCREENSAVER_ID, XA_SCREENSAVER_TIME, XA_SELECT, XA_DEMO;
46 static Atom XA_ACTIVATE, XA_DEACTIVATE, XA_CYCLE, XA_NEXT, XA_PREV, XA_EXIT;
47 static Atom XA_RESTART, XA_PREFS, XA_LOCK, XA_THROTTLE, XA_UNTHROTTLE;
48
49 static char *screensaver_version;
50 static char *usage = "\n\
51 usage: %s -<option>\n\
52 \n\
53   This program provides external control of a running xscreensaver process.\n\
54   Version %s, copyright (c) 1991-1999 Jamie Zawinski <jwz@jwz.org>.\n\
55 \n\
56   The xscreensaver program is a daemon that runs in the background.\n\
57   You control a running xscreensaver process by sending it messages\n\
58   with this program, xscreensaver-command.  See the man pages for\n\
59   details.  These are the arguments understood by xscreensaver-command:\n\
60 \n\
61   -demo         Ask the xscreensaver process to enter interactive demo mode.\n\
62 \n\
63   -prefs        Ask the xscreensaver process to bring up the preferences\n\
64                 panel.\n\
65 \n\
66   -activate     Turn on the screensaver (blank the screen), as if the user\n\
67                 had been idle for long enough.\n\
68 \n\
69   -deactivate   Turns off the screensaver (un-blank the screen), as if user\n\
70                 activity had been detected.\n\
71 \n\
72   -cycle        If the screensaver is active (the screen is blanked), then\n\
73                 stop the current graphics demo and run a new one (chosen\n\
74                 randomly.)\n\
75 \n\
76   -next         Like either -activate or -cycle, depending on which is more\n\
77                 appropriate, except that the graphics hack that will be run\n\
78                 is the next one in the list, instead of a randomly-chosen\n\
79                 one.  In other words, repeatedly executing -next will cause\n\
80                 the xscreensaver process to invoke each graphics demo\n\
81                 sequentially.  (Though using the -demo option is probably\n\
82                 an easier way to accomplish that.)\n\
83 \n\
84   -prev         Like -next, but goes in the other direction.\n\
85 \n\
86   -select <N>   Like -activate, but runs the Nth element in the list of\n\
87                 hacks.  By knowing what is in the `programs' list, and in\n\
88                 what order, you can use this to activate the screensaver\n\
89                 with a particular graphics demo.  (The first element in the\n\
90                 list is numbered 1, not 0.)\n\
91 \n\
92   -exit         Causes the xscreensaver process to exit gracefully.  This is\n\
93                 roughly the same as killing the process with `kill', but it\n\
94                 is easier, since you don't need to first figure out the pid.\n\
95                 (Note that one must *never* kill xscreensaver with -9!)\n\
96 \n\
97   -restart      Causes the screensaver process to exit and then restart with\n\
98                 the same command line arguments as last time.  Do this after\n\
99                 you've changed your X resource settings, to cause\n\
100                 xscreensaver to notice the changes.\n\
101 \n\
102   -lock         Tells the running xscreensaver process to lock the screen\n\
103                 immediately.  This is like -activate, but forces locking as\n\
104                 well, even if locking is not the default.  If the saver is\n\
105                 already active, this causes it to be locked as well.\n\
106 \n\
107   -throttle     Temporarily switch to ``blank screen'' mode, and don't run\n\
108                 any display modes at all, until the screensaver is next\n\
109                 de-activated.  This is useful if you're using a machine\n\
110                 remotely, and you find that some display modes are using too\n\
111                 much CPU.\n\
112 \n\
113   -unthrottle   Turn `-throttle' off and resume normal behavior.\n\
114 \n\
115   -version      Prints the version of xscreensaver that is currently running\n\
116                 on the display -- that is, the actual version number of the\n\
117                 running xscreensaver background process, rather than the\n\
118                 version number of xscreensaver-command.\n\
119 \n\
120   -time         Prints the time at which the screensaver last activated or\n\
121                 deactivated (roughly, how long the user has been idle or\n\
122                 non-idle -- but not quite, since it only tells you when the\n\
123                 screen became blanked or un-blanked.)\n\
124 \n\
125   See the man page for more details.\n\
126   For updates, check http://www.jwz.org/xscreensaver/\n\
127 \n";
128
129 #define USAGE() do { \
130  fprintf (stderr, usage, progname, screensaver_version); exit (1); \
131  } while(0)
132
133 int
134 main (int argc, char **argv)
135 {
136   Display *dpy;
137   int i;
138   char *dpyname = 0;
139   Atom *cmd = 0;
140   long arg = 0L;
141
142   progname = argv[0];
143   screensaver_version = (char *) malloc (5);
144   memcpy (screensaver_version, screensaver_id + 17, 4);
145   screensaver_version [4] = 0;
146
147   for (i = 1; i < argc; i++)
148     {
149       const char *s = argv [i];
150       int L;
151       if (s[0] == '-' && s[1] == '-') s++;
152       L = strlen (s);
153       if (L < 2) USAGE ();
154       if (!strncmp (s, "-display", L))          dpyname = argv [++i];
155       else if (cmd) USAGE();
156       else if (!strncmp (s, "-activate", L))   cmd = &XA_ACTIVATE;
157       else if (!strncmp (s, "-deactivate", L)) cmd = &XA_DEACTIVATE;
158       else if (!strncmp (s, "-cycle", L))      cmd = &XA_CYCLE;
159       else if (!strncmp (s, "-next", L))       cmd = &XA_NEXT;
160       else if (!strncmp (s, "-prev", L))       cmd = &XA_PREV;
161       else if (!strncmp (s, "-select", L))     cmd = &XA_SELECT;
162       else if (!strncmp (s, "-exit", L))       cmd = &XA_EXIT;
163       else if (!strncmp (s, "-restart", L))    cmd = &XA_RESTART;
164       else if (!strncmp (s, "-demo", L))       cmd = &XA_DEMO;
165       else if (!strncmp (s, "-preferences",L)) cmd = &XA_PREFS;
166       else if (!strncmp (s, "-prefs",L))       cmd = &XA_PREFS;
167       else if (!strncmp (s, "-lock", L))       cmd = &XA_LOCK;
168       else if (!strncmp (s, "-throttle", L))   cmd = &XA_THROTTLE;
169       else if (!strncmp (s, "-unthrottle", L)) cmd = &XA_UNTHROTTLE;
170       else if (!strncmp (s, "-version", L))    cmd = &XA_SCREENSAVER_VERSION;
171       else if (!strncmp (s, "-time", L))       cmd = &XA_SCREENSAVER_TIME;
172       else USAGE ();
173
174       if (cmd == &XA_SELECT || cmd == &XA_DEMO)
175         {
176           long a;
177           char c;
178           if (i+1 < argc && (1 == sscanf(argv[i+1], " %ld %c", &a, &c)))
179             {
180               arg = a;
181               i++;
182             }
183         }
184     }
185
186   if (!cmd)
187     USAGE ();
188
189   if (arg < 0)
190     /* no command may have a negative argument. */
191     USAGE();
192   else if (arg == 0)
193     {
194       /* SELECT must have a non-zero argument. */
195       if (cmd == &XA_SELECT)
196         USAGE();
197     }
198   else /* arg > 0 */
199     {
200       /* no command other than SELECT and DEMO may have a non-zero argument. */
201       if (cmd != &XA_DEMO && cmd != &XA_SELECT)
202         USAGE();
203     }
204
205
206
207   /* For backward compatibility: -demo with no arguments used to send a
208      "DEMO 0" ClientMessage to the xscreensaver process, which brought up
209      the built-in demo mode dialog.  Now that the demo mode dialog is no
210      longer built in, we bring it up by just running the "xscreensaver-demo"
211      program.
212
213      Note that "-DEMO <n>" still sends a ClientMessage.
214    */
215   if (cmd == &XA_PREFS ||
216       (cmd == &XA_DEMO && arg == 0))
217     {
218       char buf [512];
219       char *new_argv[] = { "xscreensaver-demo", 0, 0, 0, 0, 0 };
220       int ac = 1;
221
222       if (dpyname)
223         {
224           new_argv[ac++] = "-display";
225           new_argv[ac++] = dpyname;
226         }
227
228       if (cmd == &XA_PREFS)
229         new_argv[ac++] = "-prefs";
230
231       fflush(stdout);
232       fflush(stderr);
233       execvp (new_argv[0], new_argv);   /* shouldn't return */
234
235       sprintf (buf, "%s: could not exec %s", progname, new_argv[0]);
236       perror(buf);
237       fflush(stdout);
238       fflush(stderr);
239       exit (-1);
240     }
241
242
243
244   if (!dpyname) dpyname = (char *) getenv ("DISPLAY");
245   dpy = XOpenDisplay (dpyname);
246   if (!dpy)
247     {
248       fprintf (stderr, "%s: can't open display %s\n", progname,
249                (dpyname ? dpyname : "(null)"));
250       exit (1);
251     }
252
253   XA_VROOT = XInternAtom (dpy, "__SWM_VROOT", False);
254   XA_SCREENSAVER = XInternAtom (dpy, "SCREENSAVER", False);
255   XA_SCREENSAVER_ID = XInternAtom (dpy, "_SCREENSAVER_ID", False);
256   XA_SCREENSAVER_VERSION = XInternAtom (dpy, "_SCREENSAVER_VERSION",False);
257   XA_SCREENSAVER_TIME = XInternAtom (dpy, "_SCREENSAVER_TIME", False);
258   XA_SCREENSAVER_RESPONSE = XInternAtom (dpy, "_SCREENSAVER_RESPONSE", False);
259   XA_ACTIVATE = XInternAtom (dpy, "ACTIVATE", False);
260   XA_DEACTIVATE = XInternAtom (dpy, "DEACTIVATE", False);
261   XA_RESTART = XInternAtom (dpy, "RESTART", False);
262   XA_CYCLE = XInternAtom (dpy, "CYCLE", False);
263   XA_NEXT = XInternAtom (dpy, "NEXT", False);
264   XA_PREV = XInternAtom (dpy, "PREV", False);
265   XA_SELECT = XInternAtom (dpy, "SELECT", False);
266   XA_EXIT = XInternAtom (dpy, "EXIT", False);
267   XA_DEMO = XInternAtom (dpy, "DEMO", False);
268   XA_PREFS = XInternAtom (dpy, "PREFS", False);
269   XA_LOCK = XInternAtom (dpy, "LOCK", False);
270   XA_THROTTLE = XInternAtom (dpy, "THROTTLE", False);
271   XA_UNTHROTTLE = XInternAtom (dpy, "UNTHROTTLE", False);
272
273   XSync (dpy, 0);
274
275   if (*cmd == XA_ACTIVATE || *cmd == XA_LOCK ||
276       *cmd == XA_NEXT || *cmd == XA_PREV || *cmd == XA_SELECT)
277     /* People never guess that KeyRelease deactivates the screen saver too,
278        so if we're issuing an activation command, wait a second. */
279     sleep (1);
280
281   i = xscreensaver_command (dpy, *cmd, arg, True);
282   if (i < 0) exit (i);
283   else exit (0);
284 }