http://www.jwz.org/xscreensaver/xscreensaver-5.09.tar.gz
[xscreensaver] / driver / dpms.c
1 /* dpms.c --- syncing the X Display Power Management values
2  * xscreensaver, Copyright (c) 2001-2009 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 /* Display Power Management System (DPMS.)
14
15    On XFree86 systems, "man xset" reports:
16
17        -dpms    The -dpms option disables DPMS (Energy Star) features.
18        +dpms    The +dpms option enables DPMS (Energy Star) features.
19
20        dpms flags...
21                 The dpms option allows the DPMS (Energy Star)
22                 parameters to be set.  The option can take up to three
23                 numerical values, or the `force' flag followed by a
24                 DPMS state.  The `force' flags forces the server to
25                 immediately switch to the DPMS state specified.  The
26                 DPMS state can be one of `standby', `suspend', or
27                 `off'.  When numerical values are given, they set the
28                 inactivity period before the three modes are activated.
29                 The first value given is for the `standby' mode, the
30                 second is for the `suspend' mode, and the third is for
31                 the `off' mode.  Setting these values implicitly
32                 enables the DPMS features.  A value of zero disables a
33                 particular mode.
34
35    However, note that the implementation is more than a little bogus,
36    in that there is code in /usr/X11R6/lib/libXdpms.a to implement all
37    the usual server-extension-querying utilities -- but there are no
38    prototypes in any header file!  Thus, the prototypes here.  (The
39    stuff in X11/extensions/dpms.h and X11/extensions/dpmsstr.h define
40    the raw X protcol, they don't define the API to libXdpms.a.)
41
42    Some documentation:
43    Library:  ftp://ftp.x.org/pub/R6.4/xc/doc/specs/Xext/DPMSLib.ms
44    Protocol: ftp://ftp.x.org/pub/R6.4/xc/doc/specs/Xext/DPMS.ms
45  */
46
47 #ifdef HAVE_CONFIG_H
48 # include "config.h"
49 #endif
50
51 #include <stdio.h>
52 #include <X11/Xlib.h>
53
54 #ifdef HAVE_DPMS_EXTENSION   /* almost the whole file */
55
56 # include <X11/Xproto.h>
57 # include <X11/extensions/dpms.h>
58 /*# include <X11/extensions/dpmsstr.h>*/
59
60   /* Why this crap is not in a header file somewhere, I have no idea.  Losers!
61    */
62   extern Bool   DPMSQueryExtension (Display *, int *event_ret, int *err_ret);
63   extern Status DPMSGetVersion (Display *, int *major_ret, int *minor_ret);
64   extern Bool   DPMSCapable (Display *);
65   extern Status DPMSInfo (Display *, CARD16 *power_level, BOOL *state);
66   extern Status DPMSEnable (Display *dpy);
67   extern Status DPMSDisable (Display *dpy);
68   extern Status DPMSForceLevel (Display *, CARD16 level);
69   extern Status DPMSSetTimeouts (Display *, CARD16 standby, CARD16 suspend,
70                                  CARD16 off);
71   extern Bool   DPMSGetTimeouts (Display *, CARD16 *standby,
72                                  CARD16 *suspend, CARD16 *off);
73
74 #endif /* HAVE_DPMS_EXTENSION */
75
76
77 /* This file doesn't need the Xt headers, so stub these types out... */
78 #undef XtPointer
79 #define XtAppContext void*
80 #define XrmDatabase  void*
81 #define XtIntervalId void*
82 #define XtPointer    void*
83 #define Widget       void*
84
85 #include "xscreensaver.h"
86
87 #ifdef HAVE_DPMS_EXTENSION
88
89 void
90 sync_server_dpms_settings (Display *dpy, Bool enabled_p,
91                            int standby_secs, int suspend_secs, int off_secs,
92                            Bool verbose_p)
93 {
94   int event = 0, error = 0;
95   BOOL o_enabled = False;
96   CARD16 o_power = 0;
97   CARD16 o_standby = 0, o_suspend = 0, o_off = 0;
98   Bool bogus_p = False;
99
100   if (standby_secs == 0 && suspend_secs == 0 && off_secs == 0)
101     /* all zero implies "DPMS disabled" */
102     enabled_p = False;
103
104   else if ((standby_secs != 0 && standby_secs < 10) ||
105            (suspend_secs != 0 && suspend_secs < 10) ||
106            (off_secs     != 0 && off_secs     < 10))
107     /* any negative, or any positive-and-less-than-10-seconds, is crazy. */
108     bogus_p = True;
109
110   if (bogus_p) enabled_p = False;
111
112   /* X protocol sends these values in a CARD16, so truncate them to 16 bits.
113      This means that the maximum timeout is 18:12:15.
114    */
115   if (standby_secs > 0xFFFF) standby_secs = 0xFFFF;
116   if (suspend_secs > 0xFFFF) suspend_secs = 0xFFFF;
117   if (off_secs     > 0xFFFF) off_secs     = 0xFFFF;
118
119   if (! DPMSQueryExtension (dpy, &event, &error))
120     {
121       if (verbose_p)
122         fprintf (stderr, "%s: XDPMS extension not supported.\n", blurb());
123       return;
124     }
125
126   if (! DPMSCapable (dpy))
127     {
128       if (verbose_p)
129         fprintf (stderr, "%s: DPMS not supported.\n", blurb());
130       return;
131     }
132
133   if (! DPMSInfo (dpy, &o_power, &o_enabled))
134     {
135       if (verbose_p)
136         fprintf (stderr, "%s: unable to get DPMS state.\n", blurb());
137       return;
138     }
139
140   if (o_enabled != enabled_p)
141     {
142       if (! (enabled_p ? DPMSEnable (dpy) : DPMSDisable (dpy)))
143         {
144           if (verbose_p)
145             fprintf (stderr, "%s: unable to set DPMS state.\n", blurb());
146           return;
147         }
148       else if (verbose_p)
149         fprintf (stderr, "%s: turned DPMS %s.\n", blurb(),
150                  enabled_p ? "on" : "off");
151     }
152
153   if (bogus_p)
154     {
155       if (verbose_p)
156         fprintf (stderr, "%s: not setting bogus DPMS timeouts: %d %d %d.\n",
157                  blurb(), standby_secs, suspend_secs, off_secs);
158       return;
159     }
160
161   if (!DPMSGetTimeouts (dpy, &o_standby, &o_suspend, &o_off))
162     {
163       if (verbose_p)
164         fprintf (stderr, "%s: unable to get DPMS timeouts.\n", blurb());
165       return;
166     }
167
168   if (o_standby != standby_secs ||
169       o_suspend != suspend_secs ||
170       o_off != off_secs)
171     {
172       if (!DPMSSetTimeouts (dpy, standby_secs, suspend_secs, off_secs))
173         {
174           if (verbose_p)
175             fprintf (stderr, "%s: unable to set DPMS timeouts.\n", blurb());
176           return;
177         }
178       else if (verbose_p)
179         fprintf (stderr, "%s: set DPMS timeouts: %d %d %d.\n", blurb(),
180                  standby_secs, suspend_secs, off_secs);
181     }
182 }
183
184 Bool
185 monitor_powered_on_p (saver_info *si)
186 {
187   Bool result;
188   int event_number, error_number;
189   BOOL onoff = False;
190   CARD16 state;
191
192   if (!DPMSQueryExtension(si->dpy, &event_number, &error_number))
193     /* Server doesn't know -- assume the monitor is on. */
194     result = True;
195
196   else if (!DPMSCapable(si->dpy))
197     /* Server says the monitor doesn't do power management -- so it's on. */
198     result = True;
199
200   else
201     {
202       DPMSInfo(si->dpy, &state, &onoff);
203       if (!onoff)
204         /* Server says DPMS is disabled -- so the monitor is on. */
205         result = True;
206       else
207         switch (state) {
208         case DPMSModeOn:      result = True;  break;  /* really on */
209         case DPMSModeStandby: result = False; break;  /* kinda off */
210         case DPMSModeSuspend: result = False; break;  /* pretty off */
211         case DPMSModeOff:     result = False; break;  /* really off */
212         default:              result = True;  break;  /* protocol error? */
213         }
214     }
215
216   return result;
217 }
218
219 void
220 monitor_power_on (saver_info *si)
221 {
222   if (!monitor_powered_on_p (si))
223     {
224       DPMSForceLevel(si->dpy, DPMSModeOn);
225       XSync(si->dpy, False);
226       if (!monitor_powered_on_p (si))
227         fprintf (stderr,
228        "%s: DPMSForceLevel(dpy, DPMSModeOn) did not power the monitor on?\n",
229                  blurb());
230     }
231 }
232
233 #else  /* !HAVE_DPMS_EXTENSION */
234
235 void
236 sync_server_dpms_settings (Display *dpy, Bool enabled_p,
237                            int standby_secs, int suspend_secs, int off_secs,
238                            Bool verbose_p)
239 {
240   if (verbose_p)
241     fprintf (stderr, "%s: DPMS support not compiled in.\n", blurb());
242 }
243
244 Bool
245 monitor_powered_on_p (saver_info *si) 
246 {
247   return True; 
248 }
249
250 void
251 monitor_power_on (saver_info *si)
252 {
253   return; 
254 }
255
256 #endif /* !HAVE_DPMS_EXTENSION */