http://ftp.x.org/contrib/applications/xscreensaver-3.20.tar.gz
[xscreensaver] / driver / xset.c
1 /* xset.c --- interacting with server extensions and the builtin screensaver.
2  * xscreensaver, Copyright (c) 1991-1998 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 <X11/Xlib.h>
19 #include <X11/Xutil.h>
20 #include <X11/Xatom.h>
21 #include <X11/Xos.h>
22
23 /* This file doesn't need the Xt headers, so stub these types out... */
24 #undef XtPointer
25 #define XtAppContext void*
26 #define XrmDatabase  void*
27 #define XtIntervalId void*
28 #define XtPointer    void*
29 #define Widget       void*
30
31 #include "xscreensaver.h"
32
33 #ifdef _VROOT_H_
34 ERROR!  You must not include vroot.h in this file.
35 #endif
36
37 \f
38 /* MIT SCREEN-SAVER server extension hackery.
39  */
40
41 #ifdef HAVE_MIT_SAVER_EXTENSION
42
43 # include <X11/extensions/scrnsaver.h>
44
45 Bool
46 query_mit_saver_extension (saver_info *si)
47 {
48   return XScreenSaverQueryExtension (si->dpy,
49                                      &si->mit_saver_ext_event_number,
50                                      &si->mit_saver_ext_error_number);
51 }
52
53 static int
54 ignore_all_errors_ehandler (Display *dpy, XErrorEvent *error)
55 {
56   return 0;
57 }
58
59 static void
60 init_mit_saver_extension (saver_info *si)
61 {
62   int i;
63   Pixmap *blank_pix = (Pixmap *) calloc (sizeof(Pixmap), si->nscreens);
64
65   for (i = 0; i < si->nscreens; i++)
66     {
67       saver_screen_info *ssi = &si->screens[i];
68       XID kill_id = 0;
69       Atom kill_type = 0;
70       Window root = RootWindowOfScreen (ssi->screen);
71       blank_pix[i] = XCreatePixmap (si->dpy, root, 1, 1, 1);
72
73       /* Kill off the old MIT-SCREEN-SAVER client if there is one.
74          This tends to generate X errors, though (possibly due to a bug
75          in the server extension itself?) so just ignore errors here. */
76       if (XScreenSaverGetRegistered (si->dpy,
77                                      XScreenNumberOfScreen (ssi->screen),
78                                      &kill_id, &kill_type)
79           && kill_id != blank_pix[i])
80         {
81           XErrorHandler old_handler =
82             XSetErrorHandler (ignore_all_errors_ehandler);
83           XKillClient (si->dpy, kill_id);
84           XSync (si->dpy, False);
85           XSetErrorHandler (old_handler);
86         }
87       XScreenSaverSelectInput (si->dpy, root, ScreenSaverNotifyMask);
88       XScreenSaverRegister (si->dpy,
89                             XScreenNumberOfScreen (ssi->screen),
90                             (XID) blank_pix[i], XA_PIXMAP);
91     }
92   free(blank_pix);
93 }
94 #endif /* HAVE_MIT_SAVER_EXTENSION */
95
96 \f
97 /* SGI SCREEN_SAVER server extension hackery.
98  */
99
100 #ifdef HAVE_SGI_SAVER_EXTENSION
101
102 # include <X11/extensions/XScreenSaver.h>
103
104 Bool
105 query_sgi_saver_extension (saver_info *si)
106 {
107   return XScreenSaverQueryExtension (si->dpy,
108                                      &si->sgi_saver_ext_event_number,
109                                      &si->sgi_saver_ext_error_number);
110 }
111
112 static void
113 init_sgi_saver_extension (saver_info *si)
114 {
115   saver_preferences *p = &si->prefs;
116   int i;
117   if (si->screen_blanked_p)
118     /* If you mess with this while the server thinks it's active,
119        the server crashes. */
120     return;
121
122   for (i = 0; i < si->nscreens; i++)
123     {
124       saver_screen_info *ssi = &si->screens[i];
125       XScreenSaverDisable (si->dpy, XScreenNumberOfScreen(ssi->screen));
126       if (! XScreenSaverEnable (si->dpy, XScreenNumberOfScreen(ssi->screen)))
127         {
128           fprintf (stderr,
129        "%s: SGI SCREEN_SAVER extension exists, but can't be initialized;\n\
130                 perhaps some other screensaver program is already running?\n",
131                    blurb());
132           si->using_sgi_saver_extension = False;
133           return;
134         }
135     }
136 }
137
138 #endif /* HAVE_SGI_SAVER_EXTENSION */
139
140 \f
141 /* XIDLE server extension hackery.
142  */
143
144 #ifdef HAVE_XIDLE_EXTENSION
145
146 # include <X11/extensions/xidle.h>
147
148 Bool
149 query_xidle_extension (saver_info *si)
150 {
151   int event_number;
152   int error_number;
153   return XidleQueryExtension (si->dpy, &event_number, &error_number);
154 }
155
156 #endif /* HAVE_XIDLE_EXTENSION */
157
158
159 \f
160 /* Figuring out what the appropriate XSetScreenSaver() parameters are
161    (one wouldn't expect this to be rocket science.)
162  */
163
164 void
165 disable_builtin_screensaver (saver_info *si, Bool unblank_screen_p)
166 {
167   saver_preferences *p = &si->prefs;
168   int current_server_timeout, current_server_interval;
169   int current_prefer_blank, current_allow_exp;
170   int desired_server_timeout, desired_server_interval;
171   int desired_prefer_blank, desired_allow_exp;
172
173   XGetScreenSaver (si->dpy, &current_server_timeout, &current_server_interval,
174                    &current_prefer_blank, &current_allow_exp);
175
176   desired_server_timeout = current_server_timeout;
177   desired_server_interval = current_server_interval;
178   desired_prefer_blank = current_prefer_blank;
179   desired_allow_exp = current_allow_exp;
180
181   /* On SGIs, if interval is non-zero, it is the number of seconds after
182      screen saving starts at which the monitor should be powered down.
183      Obviously I don't want that, so set it to 0 (meaning "never".)
184
185      Power saving is disabled if DontPreferBlanking, but in that case,
186      we don't get extension events either.  So we can't turn it off that way.
187
188      Note: if you're running Irix 6.3 (O2), you may find that your monitor is
189      powering down anyway, regardless of the xset settings.  This is fixed by
190      installing SGI patches 2447 and 2537.
191    */
192   desired_server_interval = 0;
193
194   /* I suspect (but am not sure) that DontAllowExposures might have
195      something to do with powering off the monitor as well, at least
196      on some systems that don't support XDPMS?  Who know... */
197   desired_allow_exp = AllowExposures;
198
199   if (si->using_mit_saver_extension || si->using_sgi_saver_extension)
200     {
201       desired_server_timeout = (p->timeout / 1000);
202
203       /* The SGI extension won't give us events unless blanking is on.
204          I think (unsure right now) that the MIT extension is the opposite. */
205       if (si->using_sgi_saver_extension)
206         desired_prefer_blank = PreferBlanking;
207       else
208         desired_prefer_blank = DontPreferBlanking;
209     }
210   else
211     {
212       /* When we're not using an extension, set the server-side timeout to 0,
213          so that the server never gets involved with screen blanking, and we
214          do it all ourselves.  (However, when we *are* using an extension,
215          we tell the server when to notify us, and rather than blanking the
216          screen, the server will send us an X event telling us to blank.)
217        */
218       desired_server_timeout = 0;
219     }
220
221   if (desired_server_timeout != current_server_timeout ||
222       desired_server_interval != current_server_interval ||
223       desired_prefer_blank != current_prefer_blank ||
224       desired_allow_exp != current_allow_exp)
225     {
226       if (p->verbose_p && unblank_screen_p)
227         /* Used to print this all the time, but really, nobody cares.
228            Now only print it when verbose. */
229         fprintf (stderr,
230                  "%s disabling server builtin screensaver.\n"
231                  "%s: you can re-enable it with \"xset s on\".\n",
232                  blurb(), blurb());
233
234       if (p->verbose_p)
235         fprintf (stderr, "%s: (xset s %d %d; xset s %s; xset s %s)\n", blurb(),
236                  desired_server_timeout, desired_server_interval,
237                  (desired_prefer_blank ? "blank" : "noblank"),
238                  (desired_allow_exp ? "expose" : "noexpose"));
239
240       XSetScreenSaver (si->dpy,
241                        desired_server_timeout, desired_server_interval,
242                        desired_prefer_blank, desired_allow_exp);
243       XSync(si->dpy, False);
244     }
245
246
247 #if defined(HAVE_MIT_SAVER_EXTENSION) || defined(HAVE_SGI_SAVER_EXTENSION)
248   {
249     static Bool extension_initted = False;
250     if (!extension_initted)
251       {
252         extension_initted = True;
253 # ifdef HAVE_MIT_SAVER_EXTENSION
254         if (si->using_mit_saver_extension) init_mit_saver_extension(si);
255 # endif
256 # ifdef HAVE_SGI_SAVER_EXTENSION
257         if (si->using_sgi_saver_extension) init_sgi_saver_extension(si);
258 # endif
259       }
260   }
261 #endif /* HAVE_MIT_SAVER_EXTENSION || HAVE_SGI_SAVER_EXTENSION */
262
263   if (unblank_screen_p)
264     /* Turn off the server builtin saver if it is now running. */
265     XForceScreenSaver (si->dpy, ScreenSaverReset);
266 }
267
268 \f
269 /* Display Power Management System (DPMS.)
270
271    On XFree86 systems, "man xset" reports:
272
273        -dpms    The -dpms option disables DPMS (Energy Star) features.
274        +dpms    The +dpms option enables DPMS (Energy Star) features.
275
276        dpms flags...
277                 The dpms option allows the DPMS (Energy Star)
278                 parameters to be set.  The option can take up to three
279                 numerical values, or the `force' flag followed by a
280                 DPMS state.  The `force' flags forces the server to
281                 immediately switch to the DPMS state specified.  The
282                 DPMS state can be one of `standby', `suspend', or
283                 `off'.  When numerical values are given, they set the
284                 inactivity period before the three modes are activated.
285                 The first value given is for the `standby' mode, the
286                 second is for the `suspend' mode, and the third is for
287                 the `off' mode.  Setting these values implicitly
288                 enables the DPMS features.  A value of zero disables a
289                 particular mode.
290
291    However, note that the implementation is more than a little bogus,
292    in that there is code in /usr/X11R6/lib/libXdpms.a to implement all
293    the usual server-extension-querying utilities -- but there are no
294    prototypes in any header file!  Thus, the prototypes here.  (The
295    stuff in X11/extensions/dpms.h and X11/extensions/dpmsstr.h define
296    the raw X protcol, they don't define the API to libXdpms.a.)
297
298    Some documentation:
299    Library:  ftp://ftp.x.org/pub/R6.4/xc/doc/specs/Xext/DPMSLib.ms
300    Protocol: ftp://ftp.x.org/pub/R6.4/xc/doc/specs/Xext/DPMS.ms
301  */
302
303 #ifdef HAVE_DPMS_EXTENSION
304
305 #include <X11/Xproto.h>                 /* for CARD16 */
306 #include <X11/extensions/dpms.h>
307 #include <X11/extensions/dpmsstr.h>
308
309 extern Bool DPMSQueryExtension (Display *dpy, int *event_ret, int *error_ret);
310 extern Bool DPMSCapable (Display *dpy);
311 extern Status DPMSForceLevel (Display *dpy, CARD16 level);
312 extern Status DPMSInfo (Display *dpy, CARD16 *power_level, BOOL *state);
313
314 #if 0 /* others we don't use */
315 extern Status DPMSGetVersion (Display *dpy, int *major_ret, int *minor_ret);
316 extern Status DPMSSetTimeouts (Display *dpy,
317                                CARD16 standby, CARD16 suspend, CARD16 off);
318 extern Bool DPMSGetTimeouts (Display *dpy,
319                              CARD16 *standby, CARD16 *suspend, CARD16 *off);
320 extern Status DPMSEnable (Display *dpy);
321 extern Status DPMSDisable (Display *dpy);
322 #endif /* 0 */
323
324
325 Bool
326 monitor_powered_on_p (saver_info *si)
327 {
328   Bool result;
329   int event_number, error_number;
330   BOOL onoff = False;
331   CARD16 state;
332
333   if (!DPMSQueryExtension(si->dpy, &event_number, &error_number))
334     /* Server doesn't know -- assume the monitor is on. */
335     result = True;
336
337   else if (!DPMSCapable(si->dpy))
338     /* Server says the monitor doesn't do power management -- so it's on. */
339     result = True;
340
341   else
342     {
343       DPMSInfo(si->dpy, &state, &onoff);
344       if (!onoff)
345         /* Server says DPMS is disabled -- so the monitor is on. */
346         result = True;
347       else
348         switch (state) {
349         case DPMSModeOn:      result = True;  break;  /* really on */
350         case DPMSModeStandby: result = False; break;  /* kinda off */
351         case DPMSModeSuspend: result = False; break;  /* pretty off */
352         case DPMSModeOff:     result = False; break;  /* really off */
353         default:              result = True;  break;  /* protocol error? */
354         }
355     }
356
357   return result;
358 }
359
360 void
361 monitor_power_on (saver_info *si)
362 {
363   if (!monitor_powered_on_p (si))
364     {
365       DPMSForceLevel(si->dpy, DPMSModeOn);
366       XSync(si->dpy, False);
367       if (!monitor_powered_on_p (si))
368         fprintf (stderr,
369        "%s: DPMSForceLevel(dpy, DPMSModeOn) did not power the monitor on?\n",
370                  blurb());
371     }
372 }
373
374 #else  /* !HAVE_DPMS_EXTENSION */
375
376 Bool
377 monitor_powered_on_p (saver_info *si) 
378 {
379   return True; 
380 }
381
382 void
383 monitor_power_on (saver_info *si)
384 {
385   return; 
386 }
387
388 #endif /* !HAVE_DPMS_EXTENSION */