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