1 /* xset.c --- interacting with server extensions and the builtin screensaver.
2 * xscreensaver, Copyright (c) 1991-2005 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 knows... */
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 /* XSetScreenSaver() generates BadValue if either timeout parameter
260 exceeds 15 bits (signed short.) That is 09:06:07.
262 if (desired_server_timeout > 0x7FFF) desired_server_timeout = 0x7FFF;
263 if (desired_server_interval > 0x7FFF) desired_server_interval = 0x7FFF;
265 if (desired_server_timeout != current_server_timeout ||
266 desired_server_interval != current_server_interval ||
267 desired_prefer_blank != current_prefer_blank ||
268 desired_allow_exp != current_allow_exp)
272 "%s: disabling server builtin screensaver:\n"
273 "%s: (xset s %d %d; xset s %s; xset s %s)\n",
275 desired_server_timeout, desired_server_interval,
276 (desired_prefer_blank ? "blank" : "noblank"),
277 (desired_allow_exp ? "expose" : "noexpose"));
279 XSetScreenSaver (si->dpy,
280 desired_server_timeout, desired_server_interval,
281 desired_prefer_blank, desired_allow_exp);
282 XSync(si->dpy, False);
286 #if defined(HAVE_MIT_SAVER_EXTENSION) || defined(HAVE_SGI_SAVER_EXTENSION)
288 static Bool extension_initted = False;
289 if (!extension_initted)
291 extension_initted = True;
292 # ifdef HAVE_MIT_SAVER_EXTENSION
293 if (si->using_mit_saver_extension) init_mit_saver_extension(si);
295 # ifdef HAVE_SGI_SAVER_EXTENSION
296 if (si->using_sgi_saver_extension) init_sgi_saver_extension(si);
300 #endif /* HAVE_MIT_SAVER_EXTENSION || HAVE_SGI_SAVER_EXTENSION */
302 if (unblank_screen_p)
303 /* Turn off the server builtin saver if it is now running. */
304 XForceScreenSaver (si->dpy, ScreenSaverReset);