1 /* xset.c --- interacting with server extensions and the builtin screensaver.
2 * xscreensaver, Copyright (c) 1991-2008 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 ignore_all_errors_ehandler (Display *dpy, XErrorEvent *error)
52 init_mit_saver_extension (saver_info *si)
55 Pixmap *blank_pix = (Pixmap *) calloc (sizeof(Pixmap), si->nscreens);
57 for (i = 0; i < si->nscreens; i++)
59 saver_screen_info *ssi = &si->screens[i];
62 Window root = RootWindowOfScreen (ssi->screen);
63 blank_pix[i] = XCreatePixmap (si->dpy, root, 1, 1, 1);
65 /* Kill off the old MIT-SCREEN-SAVER client if there is one.
66 This tends to generate X errors, though (possibly due to a bug
67 in the server extension itself?) so just ignore errors here. */
68 if (XScreenSaverGetRegistered (si->dpy,
69 XScreenNumberOfScreen (ssi->screen),
71 && kill_id != blank_pix[i])
73 XErrorHandler old_handler =
74 XSetErrorHandler (ignore_all_errors_ehandler);
75 XKillClient (si->dpy, kill_id);
76 XSync (si->dpy, False);
77 XSetErrorHandler (old_handler);
79 XScreenSaverSelectInput (si->dpy, root, ScreenSaverNotifyMask);
80 XScreenSaverRegister (si->dpy,
81 XScreenNumberOfScreen (ssi->screen),
82 (XID) blank_pix[i], XA_PIXMAP);
86 #endif /* HAVE_MIT_SAVER_EXTENSION */
90 /* XInputExtension device support */
91 #include <X11/extensions/XInput.h>
93 struct xinput_dev_info {
95 XEventClass press, release, valuator;
99 query_xinput_extension (saver_info *si)
103 if (!XQueryExtension (si->dpy, INAME, &codes.major_opcode,
104 &codes.first_event, &codes.first_error))
106 if (si->prefs.verbose_p)
107 fprintf (stderr, "\t XInputExtension is not present!\n");
112 if (si->prefs.verbose_p)
113 fprintf (stderr, "\t XInputExtension is present!\n");
119 init_xinput_extension (saver_info *si)
126 XEventClass *event_list;
129 /* skip if already initialized */
130 if (si->num_xinput_devices && si->xinput_devices)
133 si->num_xinput_devices = 0;
135 list = XListInputDevices (si->dpy, &ndevices);
138 si->xinput_devices = NULL;
142 /* We only care about 3 event types per device (DeviceButtonPress,
143 DeviceButtonRelease, and DeviceMotionNotify), hence the "* 3"
144 for the event count. */
145 event_list = calloc(ndevices * 3, sizeof(XEventClass));
146 if (event_list == NULL)
149 si->xinput_devices = calloc(ndevices, sizeof(struct xinput_dev_info));
150 if (si->xinput_devices == NULL)
156 for (i = 0; i < ndevices; i++)
158 if ((list[i].use == IsXExtensionDevice)
159 #ifdef IsXExtensionPointer
160 || (list[i].use == IsXExtensionPointer)
164 struct xinput_dev_info *dev_info =
165 &si->xinput_devices[si->num_xinput_devices];
166 Bool device_we_want = False;
168 if (si->prefs.debug_p)
170 "Extension device #%2d: XID=%2d type=%3d name=\"%s\"\n",
171 i, (int) list[i].id, (int) list[i].type, list[i].name);
173 dev = XOpenDevice (si->dpy, list[i].id);
176 dev_info->device = dev;
178 pClass = list[i].inputclassinfo;
179 for (class = 0; class < list[i].num_classes; class++)
181 switch (pClass->class)
184 if (((XButtonInfo *) pClass)->num_buttons > 0)
186 /* Macros set values in the second & third arguments */
187 DeviceButtonPress (dev, si->xinput_DeviceButtonPress,
189 event_list[nevents++] = dev_info->press;
191 DeviceButtonRelease (dev, si->xinput_DeviceButtonRelease,
193 event_list[nevents++] = dev_info->release;
194 device_we_want = True;
199 if (((XValuatorInfo *) pClass)->num_axes > 0)
201 DeviceMotionNotify (dev, si->xinput_DeviceMotionNotify,
203 event_list[nevents++] = dev_info->valuator;
204 device_we_want = True;
209 /* ignore other classes of devices/events */
213 pClass = (XAnyClassPtr) & ((char *) pClass)[pClass->length];
217 si->num_xinput_devices++;
219 XCloseDevice (si->dpy, dev);
224 XFreeDeviceList (list);
226 if ((nevents == 0) || (si->num_xinput_devices == 0))
229 free(si->xinput_devices);
230 si->xinput_devices = NULL;
231 si->num_xinput_devices = 0;
235 for (i = 0; i < si->nscreens; i++)
237 saver_screen_info *ssi = &si->screens[i];
238 Window root = RootWindowOfScreen (ssi->screen);
239 XSelectExtensionEvent (si->dpy, root, event_list, nevents);
248 close_xinput_extension (saver_info *si)
252 for (i = 0; i < si->num_xinput_devices; i++)
253 XCloseDevice (si->dpy, si->xinput_devices[i].device);
255 free(si->xinput_devices);
256 si->xinput_devices = NULL;
257 si->num_xinput_devices = 0;
260 #endif /* HAVE_XINPUT */
263 /* SGI SCREEN_SAVER server extension hackery.
266 #ifdef HAVE_SGI_SAVER_EXTENSION
268 # include <X11/extensions/XScreenSaver.h>
271 init_sgi_saver_extension (saver_info *si)
273 saver_preferences *p = &si->prefs;
275 if (si->screen_blanked_p)
276 /* If you mess with this while the server thinks it's active,
277 the server crashes. */
280 for (i = 0; i < si->nscreens; i++)
282 saver_screen_info *ssi = &si->screens[i];
283 XScreenSaverDisable (si->dpy, XScreenNumberOfScreen(ssi->screen));
284 if (! XScreenSaverEnable (si->dpy, XScreenNumberOfScreen(ssi->screen)))
287 "%s: SGI SCREEN_SAVER extension exists, but can't be initialized;\n\
288 perhaps some other screensaver program is already running?\n",
290 si->using_sgi_saver_extension = False;
296 #endif /* HAVE_SGI_SAVER_EXTENSION */
300 /* Figuring out what the appropriate XSetScreenSaver() parameters are
301 (one wouldn't expect this to be rocket science.)
305 disable_builtin_screensaver (saver_info *si, Bool unblank_screen_p)
307 saver_preferences *p = &si->prefs;
308 int current_server_timeout, current_server_interval;
309 int current_prefer_blank, current_allow_exp;
310 int desired_server_timeout, desired_server_interval;
311 int desired_prefer_blank, desired_allow_exp;
313 XGetScreenSaver (si->dpy, ¤t_server_timeout, ¤t_server_interval,
314 ¤t_prefer_blank, ¤t_allow_exp);
316 desired_server_timeout = current_server_timeout;
317 desired_server_interval = current_server_interval;
318 desired_prefer_blank = current_prefer_blank;
319 desired_allow_exp = current_allow_exp;
321 /* On SGIs, if interval is non-zero, it is the number of seconds after
322 screen saving starts at which the monitor should be powered down.
323 Obviously I don't want that, so set it to 0 (meaning "never".)
325 Power saving is disabled if DontPreferBlanking, but in that case,
326 we don't get extension events either. So we can't turn it off that way.
328 Note: if you're running Irix 6.3 (O2), you may find that your monitor is
329 powering down anyway, regardless of the xset settings. This is fixed by
330 installing SGI patches 2447 and 2537.
332 desired_server_interval = 0;
334 /* I suspect (but am not sure) that DontAllowExposures might have
335 something to do with powering off the monitor as well, at least
336 on some systems that don't support XDPMS? Who knows... */
337 desired_allow_exp = AllowExposures;
339 if (si->using_mit_saver_extension || si->using_sgi_saver_extension)
341 desired_server_timeout = (p->timeout / 1000);
343 /* The SGI extension won't give us events unless blanking is on.
344 I think (unsure right now) that the MIT extension is the opposite. */
345 if (si->using_sgi_saver_extension)
346 desired_prefer_blank = PreferBlanking;
348 desired_prefer_blank = DontPreferBlanking;
352 /* When we're not using an extension, set the server-side timeout to 0,
353 so that the server never gets involved with screen blanking, and we
354 do it all ourselves. (However, when we *are* using an extension,
355 we tell the server when to notify us, and rather than blanking the
356 screen, the server will send us an X event telling us to blank.)
358 desired_server_timeout = 0;
361 /* XSetScreenSaver() generates BadValue if either timeout parameter
362 exceeds 15 bits (signed short.) That is 09:06:07.
364 if (desired_server_timeout > 0x7FFF) desired_server_timeout = 0x7FFF;
365 if (desired_server_interval > 0x7FFF) desired_server_interval = 0x7FFF;
367 if (desired_server_timeout != current_server_timeout ||
368 desired_server_interval != current_server_interval ||
369 desired_prefer_blank != current_prefer_blank ||
370 desired_allow_exp != current_allow_exp)
374 "%s: disabling server builtin screensaver:\n"
375 "%s: (xset s %d %d; xset s %s; xset s %s)\n",
377 desired_server_timeout, desired_server_interval,
378 (desired_prefer_blank ? "blank" : "noblank"),
379 (desired_allow_exp ? "expose" : "noexpose"));
381 XSetScreenSaver (si->dpy,
382 desired_server_timeout, desired_server_interval,
383 desired_prefer_blank, desired_allow_exp);
384 XSync(si->dpy, False);
388 #if defined(HAVE_MIT_SAVER_EXTENSION) || defined(HAVE_SGI_SAVER_EXTENSION)
390 static Bool extension_initted = False;
391 if (!extension_initted)
393 extension_initted = True;
394 # ifdef HAVE_MIT_SAVER_EXTENSION
395 if (si->using_mit_saver_extension) init_mit_saver_extension(si);
397 # ifdef HAVE_SGI_SAVER_EXTENSION
398 if (si->using_sgi_saver_extension) init_sgi_saver_extension(si);
402 #endif /* HAVE_MIT_SAVER_EXTENSION || HAVE_SGI_SAVER_EXTENSION */
404 if (unblank_screen_p)
405 /* Turn off the server builtin saver if it is now running. */
406 XForceScreenSaver (si->dpy, ScreenSaverReset);