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)
102 return XQueryExtension (si->dpy, INAME, &codes.major_opcode,
103 &codes.first_event, &codes.first_error);
107 init_xinput_extension (saver_info *si)
114 XEventClass *event_list;
117 /* skip if already initialized */
118 if (si->num_xinput_devices && si->xinput_devices)
121 si->num_xinput_devices = 0;
123 list = XListInputDevices (si->dpy, &ndevices);
126 si->xinput_devices = NULL;
130 /* We only care about 3 event types per device (DeviceButtonPress,
131 DeviceButtonRelease, and DeviceMotionNotify), hence the "* 3"
132 for the event count. */
133 event_list = calloc(ndevices * 3, sizeof(XEventClass));
134 if (event_list == NULL)
137 si->xinput_devices = calloc(ndevices, sizeof(struct xinput_dev_info));
138 if (si->xinput_devices == NULL)
144 for (i = 0; i < ndevices; i++)
146 if ((list[i].use == IsXExtensionDevice)
147 #ifdef IsXExtensionPointer
148 || (list[i].use == IsXExtensionPointer)
152 struct xinput_dev_info *dev_info =
153 &si->xinput_devices[si->num_xinput_devices];
154 Bool device_we_want = False;
156 if (si->prefs.debug_p)
158 "Extension device #%2d: XID=%2d type=%3d name=\"%s\"\n",
159 i, (int) list[i].id, (int) list[i].type, list[i].name);
161 dev = XOpenDevice (si->dpy, list[i].id);
164 dev_info->device = dev;
166 pClass = list[i].inputclassinfo;
167 for (class = 0; class < list[i].num_classes; class++)
169 switch (pClass->class)
172 if (((XButtonInfo *) pClass)->num_buttons > 0)
174 /* Macros set values in the second & third arguments */
175 DeviceButtonPress (dev, si->xinput_DeviceButtonPress,
177 event_list[nevents++] = dev_info->press;
179 DeviceButtonRelease (dev, si->xinput_DeviceButtonRelease,
181 event_list[nevents++] = dev_info->release;
182 device_we_want = True;
187 if (((XValuatorInfo *) pClass)->num_axes > 0)
189 DeviceMotionNotify (dev, si->xinput_DeviceMotionNotify,
191 event_list[nevents++] = dev_info->valuator;
192 device_we_want = True;
197 /* ignore other classes of devices/events */
201 pClass = (XAnyClassPtr) & ((char *) pClass)[pClass->length];
205 si->num_xinput_devices++;
207 XCloseDevice (si->dpy, dev);
212 XFreeDeviceList (list);
214 if ((nevents == 0) || (si->num_xinput_devices == 0))
217 free(si->xinput_devices);
218 si->xinput_devices = NULL;
219 si->num_xinput_devices = 0;
223 for (i = 0; i < si->nscreens; i++)
225 saver_screen_info *ssi = &si->screens[i];
226 Window root = RootWindowOfScreen (ssi->screen);
227 XSelectExtensionEvent (si->dpy, root, event_list, nevents);
236 close_xinput_extension (saver_info *si)
240 for (i = 0; i < si->num_xinput_devices; i++)
241 XCloseDevice (si->dpy, si->xinput_devices[i].device);
243 free(si->xinput_devices);
244 si->xinput_devices = NULL;
245 si->num_xinput_devices = 0;
248 #endif /* HAVE_XINPUT */
251 /* SGI SCREEN_SAVER server extension hackery.
254 #ifdef HAVE_SGI_SAVER_EXTENSION
256 # include <X11/extensions/XScreenSaver.h>
259 init_sgi_saver_extension (saver_info *si)
261 saver_preferences *p = &si->prefs;
263 if (si->screen_blanked_p)
264 /* If you mess with this while the server thinks it's active,
265 the server crashes. */
268 for (i = 0; i < si->nscreens; i++)
270 saver_screen_info *ssi = &si->screens[i];
271 XScreenSaverDisable (si->dpy, XScreenNumberOfScreen(ssi->screen));
272 if (! XScreenSaverEnable (si->dpy, XScreenNumberOfScreen(ssi->screen)))
275 "%s: SGI SCREEN_SAVER extension exists, but can't be initialized;\n\
276 perhaps some other screensaver program is already running?\n",
278 si->using_sgi_saver_extension = False;
284 #endif /* HAVE_SGI_SAVER_EXTENSION */
288 /* Figuring out what the appropriate XSetScreenSaver() parameters are
289 (one wouldn't expect this to be rocket science.)
293 disable_builtin_screensaver (saver_info *si, Bool unblank_screen_p)
295 saver_preferences *p = &si->prefs;
296 int current_server_timeout, current_server_interval;
297 int current_prefer_blank, current_allow_exp;
298 int desired_server_timeout, desired_server_interval;
299 int desired_prefer_blank, desired_allow_exp;
301 XGetScreenSaver (si->dpy, ¤t_server_timeout, ¤t_server_interval,
302 ¤t_prefer_blank, ¤t_allow_exp);
304 desired_server_timeout = current_server_timeout;
305 desired_server_interval = current_server_interval;
306 desired_prefer_blank = current_prefer_blank;
307 desired_allow_exp = current_allow_exp;
309 /* On SGIs, if interval is non-zero, it is the number of seconds after
310 screen saving starts at which the monitor should be powered down.
311 Obviously I don't want that, so set it to 0 (meaning "never".)
313 Power saving is disabled if DontPreferBlanking, but in that case,
314 we don't get extension events either. So we can't turn it off that way.
316 Note: if you're running Irix 6.3 (O2), you may find that your monitor is
317 powering down anyway, regardless of the xset settings. This is fixed by
318 installing SGI patches 2447 and 2537.
320 desired_server_interval = 0;
322 /* I suspect (but am not sure) that DontAllowExposures might have
323 something to do with powering off the monitor as well, at least
324 on some systems that don't support XDPMS? Who knows... */
325 desired_allow_exp = AllowExposures;
327 if (si->using_mit_saver_extension || si->using_sgi_saver_extension)
329 desired_server_timeout = (p->timeout / 1000);
331 /* The SGI extension won't give us events unless blanking is on.
332 I think (unsure right now) that the MIT extension is the opposite. */
333 if (si->using_sgi_saver_extension)
334 desired_prefer_blank = PreferBlanking;
336 desired_prefer_blank = DontPreferBlanking;
340 /* When we're not using an extension, set the server-side timeout to 0,
341 so that the server never gets involved with screen blanking, and we
342 do it all ourselves. (However, when we *are* using an extension,
343 we tell the server when to notify us, and rather than blanking the
344 screen, the server will send us an X event telling us to blank.)
346 desired_server_timeout = 0;
349 /* XSetScreenSaver() generates BadValue if either timeout parameter
350 exceeds 15 bits (signed short.) That is 09:06:07.
352 if (desired_server_timeout > 0x7FFF) desired_server_timeout = 0x7FFF;
353 if (desired_server_interval > 0x7FFF) desired_server_interval = 0x7FFF;
355 if (desired_server_timeout != current_server_timeout ||
356 desired_server_interval != current_server_interval ||
357 desired_prefer_blank != current_prefer_blank ||
358 desired_allow_exp != current_allow_exp)
362 "%s: disabling server builtin screensaver:\n"
363 "%s: (xset s %d %d; xset s %s; xset s %s)\n",
365 desired_server_timeout, desired_server_interval,
366 (desired_prefer_blank ? "blank" : "noblank"),
367 (desired_allow_exp ? "expose" : "noexpose"));
369 XSetScreenSaver (si->dpy,
370 desired_server_timeout, desired_server_interval,
371 desired_prefer_blank, desired_allow_exp);
372 XSync(si->dpy, False);
376 #if defined(HAVE_MIT_SAVER_EXTENSION) || defined(HAVE_SGI_SAVER_EXTENSION)
378 static Bool extension_initted = False;
379 if (!extension_initted)
381 extension_initted = True;
382 # ifdef HAVE_MIT_SAVER_EXTENSION
383 if (si->using_mit_saver_extension) init_mit_saver_extension(si);
385 # ifdef HAVE_SGI_SAVER_EXTENSION
386 if (si->using_sgi_saver_extension) init_sgi_saver_extension(si);
390 #endif /* HAVE_MIT_SAVER_EXTENSION || HAVE_SGI_SAVER_EXTENSION */
392 if (unblank_screen_p)
393 /* Turn off the server builtin saver if it is now running. */
394 XForceScreenSaver (si->dpy, ScreenSaverReset);