http://ftp.x.org/contrib/applications/xscreensaver-2.34.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           p->use_sgi_saver_extension = False;
133           return;
134         }
135     }
136 }
137
138 #endif /* HAVE_SGI_SAVER_EXTENSION */
139
140 \f
141 /* Figuring out what the appropriate XSetScreenSaver() parameters are
142    (one wouldn't expect this to be rocket science.)
143  */
144
145 void
146 disable_builtin_screensaver (saver_info *si, Bool turn_off_p)
147 {
148   saver_preferences *p = &si->prefs;
149   int current_server_timeout, current_server_interval;
150   int current_prefer_blank, current_allow_exp;
151   int desired_server_timeout, desired_server_interval;
152   int desired_prefer_blank, desired_allow_exp;
153
154   XGetScreenSaver (si->dpy, &current_server_timeout, &current_server_interval,
155                    &current_prefer_blank, &current_allow_exp);
156
157   desired_server_timeout = current_server_timeout;
158   desired_server_interval = current_server_interval;
159   desired_prefer_blank = current_prefer_blank;
160   desired_allow_exp = current_allow_exp;
161
162   /* On SGIs, if interval is non-zero, it is the number of seconds after
163      screen saving starts at which the monitor should be powered down.
164      Obviously I don't want that, so set it to 0 (meaning "never".)
165
166      Power saving is disabled if DontPreferBlanking, but in that case,
167      we don't get extension events either.  So we can't turn it off that way.
168
169      Note: if you're running Irix 6.3 (O2), you may find that your monitor is
170      powering down anyway, regardless of the xset settings.  This is fixed by
171      installing SGI patches 2447 and 2537.
172    */
173   desired_server_interval = 0;
174
175   /* I suspect (but am not sure) that DontAllowExposures might have
176      something to do with powering off the monitor as well. */
177   desired_allow_exp = AllowExposures;
178
179 #if defined(HAVE_MIT_SAVER_EXTENSION) || defined(HAVE_SGI_SAVER_EXTENSION)
180   if (p->use_mit_saver_extension || p->use_sgi_saver_extension)
181     {
182       desired_server_timeout = (p->timeout / 1000);
183
184       /* The SGI extension won't give us events unless blanking is on.
185          I think (unsure right now) that the MIT extension is the opposite. */
186       if (p->use_sgi_saver_extension)
187         desired_prefer_blank = PreferBlanking;
188       else
189         desired_prefer_blank = DontPreferBlanking;
190     }
191   else
192 #endif /* HAVE_MIT_SAVER_EXTENSION || HAVE_SGI_SAVER_EXTENSION */
193     {
194       desired_server_timeout = 0;
195     }
196
197   if (desired_server_timeout != current_server_timeout ||
198       desired_server_interval != current_server_interval ||
199       desired_prefer_blank != current_prefer_blank ||
200       desired_allow_exp != current_allow_exp)
201     {
202       if (desired_server_timeout == 0)
203         fprintf (stderr,
204                  "%s%sisabling server builtin screensaver.\n"
205                  "\tYou can re-enable it with \"xset s on\".\n",
206                 (p->verbose_p ? "" : blurb()),
207                 (p->verbose_p ? "\n\tD" : ": d"));
208
209       if (p->verbose_p)
210         fprintf (stderr, "%s: (xset s %d %d %s %s)\n", blurb(),
211                  desired_server_timeout, desired_server_interval,
212                  (desired_prefer_blank ? "blank" : "noblank"),
213                  (desired_allow_exp ? "noexpose" : "expose"));
214
215       XSetScreenSaver (si->dpy,
216                        desired_server_timeout, desired_server_interval,
217                        desired_prefer_blank, desired_allow_exp);
218       XSync(si->dpy, False);
219     }
220
221
222 #if defined(HAVE_MIT_SAVER_EXTENSION) || defined(HAVE_SGI_SAVER_EXTENSION)
223   {
224     static Bool extension_initted = False;
225     if (!extension_initted)
226       {
227         extension_initted = True;
228 # ifdef HAVE_MIT_SAVER_EXTENSION
229         if (p->use_mit_saver_extension) init_mit_saver_extension(si);
230 # endif
231 # ifdef HAVE_SGI_SAVER_EXTENSION
232         if (p->use_sgi_saver_extension) init_sgi_saver_extension(si);
233 # endif
234       }
235   }
236 #endif /* HAVE_MIT_SAVER_EXTENSION || HAVE_SGI_SAVER_EXTENSION */
237
238   if (turn_off_p)
239     /* Turn off the server builtin saver if it is now running. */
240     XForceScreenSaver (si->dpy, ScreenSaverReset);
241 }
242
243 \f
244 /* Display Power Management System (DPMS.)
245
246    On XFree86 systems, "man xset" reports:
247
248        -dpms    The -dpms option disables DPMS (Energy Star) features.
249        +dpms    The +dpms option enables DPMS (Energy Star) features.
250
251        dpms flags...
252                 The dpms option allows the DPMS (Energy Star)
253                 parameters to be set.  The option can take up to three
254                 numerical values, or the `force' flag followed by a
255                 DPMS state.  The `force' flags forces the server to
256                 immediately switch to the DPMS state specified.  The
257                 DPMS state can be one of `standby', `suspend', or
258                 `off'.  When numerical values are given, they set the
259                 inactivity period before the three modes are activated.
260                 The first value given is for the `standby' mode, the
261                 second is for the `suspend' mode, and the third is for
262                 the `off' mode.  Setting these values implicitly
263                 enables the DPMS features.  A value of zero disables a
264                 particular mode.
265
266    However, note that the implementation is more than a little bogus,
267    in that there is code in /usr/X11R6/lib/libXdpms.a to implement all
268    the usual server-extension-querying utilities -- but there are no
269    prototypes in any header file!  Thus, the prototypes here.  (The
270    stuff in X11/extensions/dpms.h and X11/extensions/dpmsstr.h define
271    the raw X protcol, they don't define the API to libXdpms.a.)
272
273    Some documentation:
274    Library:  ftp://ftp.x.org/pub/R6.4/xc/doc/specs/Xext/DPMSLib.ms
275    Protocol: ftp://ftp.x.org/pub/R6.4/xc/doc/specs/Xext/DPMS.ms
276  */
277
278 #ifdef HAVE_DPMS_EXTENSION
279
280 #include <X11/Xproto.h>                 /* for CARD16 */
281 #include <X11/extensions/dpms.h>
282 #include <X11/extensions/dpmsstr.h>
283
284 extern Bool DPMSQueryExtension (Display *dpy, int *event_ret, int *error_ret);
285 extern Bool DPMSCapable (Display *dpy);
286 extern Status DPMSForceLevel (Display *dpy, CARD16 level);
287 extern Status DPMSInfo (Display *dpy, CARD16 *power_level, BOOL *state);
288
289 #if 0 /* others we don't use */
290 extern Status DPMSGetVersion (Display *dpy, int *major_ret, int *minor_ret);
291 extern Status DPMSSetTimeouts (Display *dpy,
292                                CARD16 standby, CARD16 suspend, CARD16 off);
293 extern Bool DPMSGetTimeouts (Display *dpy,
294                              CARD16 *standby, CARD16 *suspend, CARD16 *off);
295 extern Status DPMSEnable (Display *dpy);
296 extern Status DPMSDisable (Display *dpy);
297 #endif /* 0 */
298
299
300 Bool
301 monitor_powered_on_p (saver_info *si)
302 {
303   Bool result;
304   int event_number, error_number;
305   BOOL onoff = False;
306   CARD16 state;
307
308   if (!DPMSQueryExtension(si->dpy, &event_number, &error_number))
309     /* Server doesn't know -- assume the monitor is on. */
310     result = True;
311
312   else if (!DPMSCapable(si->dpy))
313     /* Server says the monitor doesn't do power management -- so it's on. */
314     result = True;
315
316   else
317     {
318       DPMSInfo(si->dpy, &state, &onoff);
319       if (!onoff)
320         /* Server says DPMS is disabled -- so the monitor is on. */
321         result = True;
322       else
323         switch (state) {
324         case DPMSModeOn:      result = True;  break;  /* really on */
325         case DPMSModeStandby: result = False; break;  /* kinda off */
326         case DPMSModeSuspend: result = False; break;  /* pretty off */
327         case DPMSModeOff:     result = False; break;  /* really off */
328         default:              result = True;  break;  /* protocol error? */
329         }
330     }
331
332   return result;
333 }
334
335 void
336 monitor_power_on (saver_info *si)
337 {
338   if (!monitor_powered_on_p (si))
339     {
340       DPMSForceLevel(si->dpy, DPMSModeOn);
341       XSync(si->dpy, False);
342       if (!monitor_powered_on_p (si))
343         fprintf (stderr,
344        "%s: DPMSForceLevel(dpy, DPMSModeOn) did not power the monitor on?\n",
345                  blurb());
346     }
347 }
348
349 #else  /* !HAVE_DPMS_EXTENSION */
350
351 Bool
352 monitor_powered_on_p (saver_info *si) 
353 {
354   return True; 
355 }
356
357 void
358 monitor_power_on (saver_info *si)
359 {
360   return; 
361 }
362
363 #endif /* !HAVE_DPMS_EXTENSION */