1 /* xset.c --- interacting with server extensions and the builtin screensaver.
2 * xscreensaver, Copyright (c) 1991-2004 Jamie Zawinski <jwz@jwz.org>
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
19 #include <X11/Xutil.h>
20 #include <X11/Xatom.h>
23 /* This file doesn't need the Xt headers, so stub these types out... */
25 #define XtAppContext void*
26 #define XrmDatabase void*
27 #define XtIntervalId void*
28 #define XtPointer void*
31 #include "xscreensaver.h"
34 ERROR! You must not include vroot.h in this file.
38 /* MIT SCREEN-SAVER server extension hackery.
41 #ifdef HAVE_MIT_SAVER_EXTENSION
43 # include <X11/extensions/scrnsaver.h>
46 query_mit_saver_extension (saver_info *si)
48 return XScreenSaverQueryExtension (si->dpy,
49 &si->mit_saver_ext_event_number,
50 &si->mit_saver_ext_error_number);
54 ignore_all_errors_ehandler (Display *dpy, XErrorEvent *error)
60 init_mit_saver_extension (saver_info *si)
63 Pixmap *blank_pix = (Pixmap *) calloc (sizeof(Pixmap), si->nscreens);
65 for (i = 0; i < si->nscreens; i++)
67 saver_screen_info *ssi = &si->screens[i];
70 Window root = RootWindowOfScreen (ssi->screen);
71 blank_pix[i] = XCreatePixmap (si->dpy, root, 1, 1, 1);
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),
79 && kill_id != blank_pix[i])
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);
87 XScreenSaverSelectInput (si->dpy, root, ScreenSaverNotifyMask);
88 XScreenSaverRegister (si->dpy,
89 XScreenNumberOfScreen (ssi->screen),
90 (XID) blank_pix[i], XA_PIXMAP);
94 #endif /* HAVE_MIT_SAVER_EXTENSION */
97 /* SGI SCREEN_SAVER server extension hackery.
100 #ifdef HAVE_SGI_SAVER_EXTENSION
102 # include <X11/extensions/XScreenSaver.h>
105 query_sgi_saver_extension (saver_info *si)
107 return XScreenSaverQueryExtension (si->dpy,
108 &si->sgi_saver_ext_event_number,
109 &si->sgi_saver_ext_error_number);
113 init_sgi_saver_extension (saver_info *si)
115 saver_preferences *p = &si->prefs;
117 if (si->screen_blanked_p)
118 /* If you mess with this while the server thinks it's active,
119 the server crashes. */
122 for (i = 0; i < si->nscreens; i++)
124 saver_screen_info *ssi = &si->screens[i];
125 XScreenSaverDisable (si->dpy, XScreenNumberOfScreen(ssi->screen));
126 if (! XScreenSaverEnable (si->dpy, XScreenNumberOfScreen(ssi->screen)))
129 "%s: SGI SCREEN_SAVER extension exists, but can't be initialized;\n\
130 perhaps some other screensaver program is already running?\n",
132 si->using_sgi_saver_extension = False;
138 #endif /* HAVE_SGI_SAVER_EXTENSION */
141 /* XIDLE server extension hackery.
144 #ifdef HAVE_XIDLE_EXTENSION
146 # include <X11/extensions/xidle.h>
149 query_xidle_extension (saver_info *si)
153 return XidleQueryExtension (si->dpy, &event_number, &error_number);
156 #endif /* HAVE_XIDLE_EXTENSION */
160 /* Resize and Rotate server extension hackery.
165 # include <X11/extensions/Xrandr.h>
168 query_randr_extension (saver_info *si)
170 saver_preferences *p = &si->prefs;
171 Bool ok = XRRQueryExtension (si->dpy,
172 &si->randr_event_number,
173 &si->randr_error_number);
176 int nscreens = ScreenCount (si->dpy); /* number of *real* screens */
180 fprintf (stderr, "%s: selecting RANDR events\n", blurb());
181 for (i = 0; i < nscreens; i++)
182 XRRSelectInput (si->dpy, RootWindow (si->dpy, i),
183 RRScreenChangeNotifyMask);
189 #endif /* HAVE_XIDLE_EXTENSION */
193 /* Figuring out what the appropriate XSetScreenSaver() parameters are
194 (one wouldn't expect this to be rocket science.)
198 disable_builtin_screensaver (saver_info *si, Bool unblank_screen_p)
200 saver_preferences *p = &si->prefs;
201 int current_server_timeout, current_server_interval;
202 int current_prefer_blank, current_allow_exp;
203 int desired_server_timeout, desired_server_interval;
204 int desired_prefer_blank, desired_allow_exp;
206 XGetScreenSaver (si->dpy, ¤t_server_timeout, ¤t_server_interval,
207 ¤t_prefer_blank, ¤t_allow_exp);
209 desired_server_timeout = current_server_timeout;
210 desired_server_interval = current_server_interval;
211 desired_prefer_blank = current_prefer_blank;
212 desired_allow_exp = current_allow_exp;
214 /* On SGIs, if interval is non-zero, it is the number of seconds after
215 screen saving starts at which the monitor should be powered down.
216 Obviously I don't want that, so set it to 0 (meaning "never".)
218 Power saving is disabled if DontPreferBlanking, but in that case,
219 we don't get extension events either. So we can't turn it off that way.
221 Note: if you're running Irix 6.3 (O2), you may find that your monitor is
222 powering down anyway, regardless of the xset settings. This is fixed by
223 installing SGI patches 2447 and 2537.
225 desired_server_interval = 0;
227 /* I suspect (but am not sure) that DontAllowExposures might have
228 something to do with powering off the monitor as well, at least
229 on some systems that don't support XDPMS? Who know... */
230 desired_allow_exp = AllowExposures;
232 if (si->using_mit_saver_extension || si->using_sgi_saver_extension)
234 desired_server_timeout = (p->timeout / 1000);
236 /* The SGI extension won't give us events unless blanking is on.
237 I think (unsure right now) that the MIT extension is the opposite. */
238 if (si->using_sgi_saver_extension)
239 desired_prefer_blank = PreferBlanking;
241 desired_prefer_blank = DontPreferBlanking;
245 /* When we're not using an extension, set the server-side timeout to 0,
246 so that the server never gets involved with screen blanking, and we
247 do it all ourselves. (However, when we *are* using an extension,
248 we tell the server when to notify us, and rather than blanking the
249 screen, the server will send us an X event telling us to blank.)
251 desired_server_timeout = 0;
254 if (desired_server_timeout != current_server_timeout ||
255 desired_server_interval != current_server_interval ||
256 desired_prefer_blank != current_prefer_blank ||
257 desired_allow_exp != current_allow_exp)
261 "%s: disabling server builtin screensaver:\n"
262 "%s: (xset s %d %d; xset s %s; xset s %s)\n",
264 desired_server_timeout, desired_server_interval,
265 (desired_prefer_blank ? "blank" : "noblank"),
266 (desired_allow_exp ? "expose" : "noexpose"));
268 XSetScreenSaver (si->dpy,
269 desired_server_timeout, desired_server_interval,
270 desired_prefer_blank, desired_allow_exp);
271 XSync(si->dpy, False);
275 #if defined(HAVE_MIT_SAVER_EXTENSION) || defined(HAVE_SGI_SAVER_EXTENSION)
277 static Bool extension_initted = False;
278 if (!extension_initted)
280 extension_initted = True;
281 # ifdef HAVE_MIT_SAVER_EXTENSION
282 if (si->using_mit_saver_extension) init_mit_saver_extension(si);
284 # ifdef HAVE_SGI_SAVER_EXTENSION
285 if (si->using_sgi_saver_extension) init_sgi_saver_extension(si);
289 #endif /* HAVE_MIT_SAVER_EXTENSION || HAVE_SGI_SAVER_EXTENSION */
291 if (unblank_screen_p)
292 /* Turn off the server builtin saver if it is now running. */
293 XForceScreenSaver (si->dpy, ScreenSaverReset);
297 /* Display Power Management System (DPMS.)
299 On XFree86 systems, "man xset" reports:
301 -dpms The -dpms option disables DPMS (Energy Star) features.
302 +dpms The +dpms option enables DPMS (Energy Star) features.
305 The dpms option allows the DPMS (Energy Star)
306 parameters to be set. The option can take up to three
307 numerical values, or the `force' flag followed by a
308 DPMS state. The `force' flags forces the server to
309 immediately switch to the DPMS state specified. The
310 DPMS state can be one of `standby', `suspend', or
311 `off'. When numerical values are given, they set the
312 inactivity period before the three modes are activated.
313 The first value given is for the `standby' mode, the
314 second is for the `suspend' mode, and the third is for
315 the `off' mode. Setting these values implicitly
316 enables the DPMS features. A value of zero disables a
319 However, note that the implementation is more than a little bogus,
320 in that there is code in /usr/X11R6/lib/libXdpms.a to implement all
321 the usual server-extension-querying utilities -- but there are no
322 prototypes in any header file! Thus, the prototypes here. (The
323 stuff in X11/extensions/dpms.h and X11/extensions/dpmsstr.h define
324 the raw X protcol, they don't define the API to libXdpms.a.)
327 Library: ftp://ftp.x.org/pub/R6.4/xc/doc/specs/Xext/DPMSLib.ms
328 Protocol: ftp://ftp.x.org/pub/R6.4/xc/doc/specs/Xext/DPMS.ms
331 #ifdef HAVE_DPMS_EXTENSION
333 #include <X11/Xproto.h> /* for CARD16 */
334 #include <X11/extensions/dpms.h>
335 #include <X11/extensions/dpmsstr.h>
337 extern Bool DPMSQueryExtension (Display *dpy, int *event_ret, int *error_ret);
338 extern Bool DPMSCapable (Display *dpy);
339 extern Status DPMSForceLevel (Display *dpy, CARD16 level);
340 extern Status DPMSInfo (Display *dpy, CARD16 *power_level, BOOL *state);
342 #if 0 /* others we don't use */
343 extern Status DPMSGetVersion (Display *dpy, int *major_ret, int *minor_ret);
344 extern Status DPMSSetTimeouts (Display *dpy,
345 CARD16 standby, CARD16 suspend, CARD16 off);
346 extern Bool DPMSGetTimeouts (Display *dpy,
347 CARD16 *standby, CARD16 *suspend, CARD16 *off);
348 extern Status DPMSEnable (Display *dpy);
349 extern Status DPMSDisable (Display *dpy);
354 monitor_powered_on_p (saver_info *si)
357 int event_number, error_number;
361 if (!DPMSQueryExtension(si->dpy, &event_number, &error_number))
362 /* Server doesn't know -- assume the monitor is on. */
365 else if (!DPMSCapable(si->dpy))
366 /* Server says the monitor doesn't do power management -- so it's on. */
371 DPMSInfo(si->dpy, &state, &onoff);
373 /* Server says DPMS is disabled -- so the monitor is on. */
377 case DPMSModeOn: result = True; break; /* really on */
378 case DPMSModeStandby: result = False; break; /* kinda off */
379 case DPMSModeSuspend: result = False; break; /* pretty off */
380 case DPMSModeOff: result = False; break; /* really off */
381 default: result = True; break; /* protocol error? */
389 monitor_power_on (saver_info *si)
391 if (!monitor_powered_on_p (si))
393 DPMSForceLevel(si->dpy, DPMSModeOn);
394 XSync(si->dpy, False);
395 if (!monitor_powered_on_p (si))
397 "%s: DPMSForceLevel(dpy, DPMSModeOn) did not power the monitor on?\n",
402 #else /* !HAVE_DPMS_EXTENSION */
405 monitor_powered_on_p (saver_info *si)
411 monitor_power_on (saver_info *si)
416 #endif /* !HAVE_DPMS_EXTENSION */