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);
177 int nscreens = ScreenCount (si->dpy); /* number of *real* screens */
181 fprintf (stderr, "%s: selecting RANDR events\n", blurb());
182 for (i = 0; i < nscreens; i++)
183 # ifdef RRScreenChangeNotifyMask /* randr.h 1.5, 2002/09/29 */
184 XRRSelectInput (si->dpy, RootWindow (si->dpy, i),
185 RRScreenChangeNotifyMask);
186 # else /* !RRScreenChangeNotifyMask */ /* Xrandr.h 1.4, 2001/06/07 */
187 XRRScreenChangeSelectInput (si->dpy, RootWindow (si->dpy, i), True);
188 # endif /* !RRScreenChangeNotifyMask */
194 #endif /* HAVE_RANDR */
198 /* Figuring out what the appropriate XSetScreenSaver() parameters are
199 (one wouldn't expect this to be rocket science.)
203 disable_builtin_screensaver (saver_info *si, Bool unblank_screen_p)
205 saver_preferences *p = &si->prefs;
206 int current_server_timeout, current_server_interval;
207 int current_prefer_blank, current_allow_exp;
208 int desired_server_timeout, desired_server_interval;
209 int desired_prefer_blank, desired_allow_exp;
211 XGetScreenSaver (si->dpy, ¤t_server_timeout, ¤t_server_interval,
212 ¤t_prefer_blank, ¤t_allow_exp);
214 desired_server_timeout = current_server_timeout;
215 desired_server_interval = current_server_interval;
216 desired_prefer_blank = current_prefer_blank;
217 desired_allow_exp = current_allow_exp;
219 /* On SGIs, if interval is non-zero, it is the number of seconds after
220 screen saving starts at which the monitor should be powered down.
221 Obviously I don't want that, so set it to 0 (meaning "never".)
223 Power saving is disabled if DontPreferBlanking, but in that case,
224 we don't get extension events either. So we can't turn it off that way.
226 Note: if you're running Irix 6.3 (O2), you may find that your monitor is
227 powering down anyway, regardless of the xset settings. This is fixed by
228 installing SGI patches 2447 and 2537.
230 desired_server_interval = 0;
232 /* I suspect (but am not sure) that DontAllowExposures might have
233 something to do with powering off the monitor as well, at least
234 on some systems that don't support XDPMS? Who know... */
235 desired_allow_exp = AllowExposures;
237 if (si->using_mit_saver_extension || si->using_sgi_saver_extension)
239 desired_server_timeout = (p->timeout / 1000);
241 /* The SGI extension won't give us events unless blanking is on.
242 I think (unsure right now) that the MIT extension is the opposite. */
243 if (si->using_sgi_saver_extension)
244 desired_prefer_blank = PreferBlanking;
246 desired_prefer_blank = DontPreferBlanking;
250 /* When we're not using an extension, set the server-side timeout to 0,
251 so that the server never gets involved with screen blanking, and we
252 do it all ourselves. (However, when we *are* using an extension,
253 we tell the server when to notify us, and rather than blanking the
254 screen, the server will send us an X event telling us to blank.)
256 desired_server_timeout = 0;
259 if (desired_server_timeout != current_server_timeout ||
260 desired_server_interval != current_server_interval ||
261 desired_prefer_blank != current_prefer_blank ||
262 desired_allow_exp != current_allow_exp)
266 "%s: disabling server builtin screensaver:\n"
267 "%s: (xset s %d %d; xset s %s; xset s %s)\n",
269 desired_server_timeout, desired_server_interval,
270 (desired_prefer_blank ? "blank" : "noblank"),
271 (desired_allow_exp ? "expose" : "noexpose"));
273 XSetScreenSaver (si->dpy,
274 desired_server_timeout, desired_server_interval,
275 desired_prefer_blank, desired_allow_exp);
276 XSync(si->dpy, False);
280 #if defined(HAVE_MIT_SAVER_EXTENSION) || defined(HAVE_SGI_SAVER_EXTENSION)
282 static Bool extension_initted = False;
283 if (!extension_initted)
285 extension_initted = True;
286 # ifdef HAVE_MIT_SAVER_EXTENSION
287 if (si->using_mit_saver_extension) init_mit_saver_extension(si);
289 # ifdef HAVE_SGI_SAVER_EXTENSION
290 if (si->using_sgi_saver_extension) init_sgi_saver_extension(si);
294 #endif /* HAVE_MIT_SAVER_EXTENSION || HAVE_SGI_SAVER_EXTENSION */
296 if (unblank_screen_p)
297 /* Turn off the server builtin saver if it is now running. */
298 XForceScreenSaver (si->dpy, ScreenSaverReset);
302 /* Display Power Management System (DPMS.)
304 On XFree86 systems, "man xset" reports:
306 -dpms The -dpms option disables DPMS (Energy Star) features.
307 +dpms The +dpms option enables DPMS (Energy Star) features.
310 The dpms option allows the DPMS (Energy Star)
311 parameters to be set. The option can take up to three
312 numerical values, or the `force' flag followed by a
313 DPMS state. The `force' flags forces the server to
314 immediately switch to the DPMS state specified. The
315 DPMS state can be one of `standby', `suspend', or
316 `off'. When numerical values are given, they set the
317 inactivity period before the three modes are activated.
318 The first value given is for the `standby' mode, the
319 second is for the `suspend' mode, and the third is for
320 the `off' mode. Setting these values implicitly
321 enables the DPMS features. A value of zero disables a
324 However, note that the implementation is more than a little bogus,
325 in that there is code in /usr/X11R6/lib/libXdpms.a to implement all
326 the usual server-extension-querying utilities -- but there are no
327 prototypes in any header file! Thus, the prototypes here. (The
328 stuff in X11/extensions/dpms.h and X11/extensions/dpmsstr.h define
329 the raw X protcol, they don't define the API to libXdpms.a.)
332 Library: ftp://ftp.x.org/pub/R6.4/xc/doc/specs/Xext/DPMSLib.ms
333 Protocol: ftp://ftp.x.org/pub/R6.4/xc/doc/specs/Xext/DPMS.ms
336 #ifdef HAVE_DPMS_EXTENSION
338 #include <X11/Xproto.h> /* for CARD16 */
339 #include <X11/extensions/dpms.h>
340 #include <X11/extensions/dpmsstr.h>
342 extern Bool DPMSQueryExtension (Display *dpy, int *event_ret, int *error_ret);
343 extern Bool DPMSCapable (Display *dpy);
344 extern Status DPMSForceLevel (Display *dpy, CARD16 level);
345 extern Status DPMSInfo (Display *dpy, CARD16 *power_level, BOOL *state);
347 #if 0 /* others we don't use */
348 extern Status DPMSGetVersion (Display *dpy, int *major_ret, int *minor_ret);
349 extern Status DPMSSetTimeouts (Display *dpy,
350 CARD16 standby, CARD16 suspend, CARD16 off);
351 extern Bool DPMSGetTimeouts (Display *dpy,
352 CARD16 *standby, CARD16 *suspend, CARD16 *off);
353 extern Status DPMSEnable (Display *dpy);
354 extern Status DPMSDisable (Display *dpy);
359 monitor_powered_on_p (saver_info *si)
362 int event_number, error_number;
366 if (!DPMSQueryExtension(si->dpy, &event_number, &error_number))
367 /* Server doesn't know -- assume the monitor is on. */
370 else if (!DPMSCapable(si->dpy))
371 /* Server says the monitor doesn't do power management -- so it's on. */
376 DPMSInfo(si->dpy, &state, &onoff);
378 /* Server says DPMS is disabled -- so the monitor is on. */
382 case DPMSModeOn: result = True; break; /* really on */
383 case DPMSModeStandby: result = False; break; /* kinda off */
384 case DPMSModeSuspend: result = False; break; /* pretty off */
385 case DPMSModeOff: result = False; break; /* really off */
386 default: result = True; break; /* protocol error? */
394 monitor_power_on (saver_info *si)
396 if (!monitor_powered_on_p (si))
398 DPMSForceLevel(si->dpy, DPMSModeOn);
399 XSync(si->dpy, False);
400 if (!monitor_powered_on_p (si))
402 "%s: DPMSForceLevel(dpy, DPMSModeOn) did not power the monitor on?\n",
407 #else /* !HAVE_DPMS_EXTENSION */
410 monitor_powered_on_p (saver_info *si)
416 monitor_power_on (saver_info *si)
421 #endif /* !HAVE_DPMS_EXTENSION */