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 */
93 query_xinput_extension (saver_info *si)
96 return XQueryExtension (si->dpy, INAME, &codes.major_opcode,
97 &codes.first_event, &codes.first_error);
101 init_xinput_extension (saver_info *si)
108 XEventClass *event_list;
111 /* skip if already initialized */
112 if (si->num_xinput_devices && si->xinput_devices)
115 si->num_xinput_devices = 0;
117 list = XListInputDevices (si->dpy, &ndevices);
120 si->xinput_devices = NULL;
124 /* We only care about 3 event types per device (DeviceButtonPress,
125 DeviceButtonRelease, and DeviceMotionNotify), hence the "* 3"
126 for the event count. */
127 event_list = calloc(ndevices * 3, sizeof(XEventClass));
128 if (event_list == NULL)
131 si->xinput_devices = calloc(ndevices, sizeof(struct xinput_dev_info));
132 if (si->xinput_devices == NULL)
138 for (i = 0; i < ndevices; i++)
140 if ((list[i].use == IsXExtensionDevice)
141 #ifdef IsXExtensionPointer
142 || (list[i].use == IsXExtensionPointer)
146 struct xinput_dev_info *dev_info =
147 &si->xinput_devices[si->num_xinput_devices];
148 Bool device_we_want = False;
150 if (si->prefs.debug_p)
152 "Extension device #%2d: XID=%2d type=%3d name=\"%s\"\n",
153 i, (int) list[i].id, (int) list[i].type, list[i].name);
155 dev = XOpenDevice (si->dpy, list[i].id);
158 dev_info->device = dev;
160 pClass = list[i].inputclassinfo;
161 for (class = 0; class < list[i].num_classes; class++)
163 switch (pClass->class)
166 if (((XButtonInfo *) pClass)->num_buttons > 0)
168 /* Macros set values in the second & third arguments */
169 DeviceButtonPress (dev, si->xinput_DeviceButtonPress,
171 event_list[nevents++] = dev_info->press;
173 DeviceButtonRelease (dev, si->xinput_DeviceButtonRelease,
175 event_list[nevents++] = dev_info->release;
176 device_we_want = True;
181 if (((XValuatorInfo *) pClass)->num_axes > 0)
183 DeviceMotionNotify (dev, si->xinput_DeviceMotionNotify,
185 event_list[nevents++] = dev_info->valuator;
186 device_we_want = True;
191 /* ignore other classes of devices/events */
195 pClass = (XAnyClassPtr) & ((char *) pClass)[pClass->length];
199 si->num_xinput_devices++;
201 XCloseDevice (si->dpy, dev);
206 XFreeDeviceList (list);
208 if ((nevents == 0) || (si->num_xinput_devices == 0))
211 free(si->xinput_devices);
212 si->xinput_devices = NULL;
213 si->num_xinput_devices = 0;
217 for (i = 0; i < si->nscreens; i++)
219 saver_screen_info *ssi = &si->screens[i];
220 Window root = RootWindowOfScreen (ssi->screen);
221 XSelectExtensionEvent (si->dpy, root, event_list, nevents);
230 close_xinput_extension (saver_info *si)
234 for (i = 0; i < si->num_xinput_devices; i++)
235 XCloseDevice (si->dpy, si->xinput_devices[i].device);
237 free(si->xinput_devices);
238 si->xinput_devices = NULL;
239 si->num_xinput_devices = 0;
242 #endif /* HAVE_XINPUT */
245 /* SGI SCREEN_SAVER server extension hackery.
248 #ifdef HAVE_SGI_SAVER_EXTENSION
250 # include <X11/extensions/XScreenSaver.h>
253 init_sgi_saver_extension (saver_info *si)
255 saver_preferences *p = &si->prefs;
257 if (si->screen_blanked_p)
258 /* If you mess with this while the server thinks it's active,
259 the server crashes. */
262 for (i = 0; i < si->nscreens; i++)
264 saver_screen_info *ssi = &si->screens[i];
265 XScreenSaverDisable (si->dpy, XScreenNumberOfScreen(ssi->screen));
266 if (! XScreenSaverEnable (si->dpy, XScreenNumberOfScreen(ssi->screen)))
269 "%s: SGI SCREEN_SAVER extension exists, but can't be initialized;\n\
270 perhaps some other screensaver program is already running?\n",
272 si->using_sgi_saver_extension = False;
278 #endif /* HAVE_SGI_SAVER_EXTENSION */
282 /* Figuring out what the appropriate XSetScreenSaver() parameters are
283 (one wouldn't expect this to be rocket science.)
287 disable_builtin_screensaver (saver_info *si, Bool unblank_screen_p)
289 saver_preferences *p = &si->prefs;
290 int current_server_timeout, current_server_interval;
291 int current_prefer_blank, current_allow_exp;
292 int desired_server_timeout, desired_server_interval;
293 int desired_prefer_blank, desired_allow_exp;
295 XGetScreenSaver (si->dpy, ¤t_server_timeout, ¤t_server_interval,
296 ¤t_prefer_blank, ¤t_allow_exp);
298 desired_server_timeout = current_server_timeout;
299 desired_server_interval = current_server_interval;
300 desired_prefer_blank = current_prefer_blank;
301 desired_allow_exp = current_allow_exp;
303 /* On SGIs, if interval is non-zero, it is the number of seconds after
304 screen saving starts at which the monitor should be powered down.
305 Obviously I don't want that, so set it to 0 (meaning "never".)
307 Power saving is disabled if DontPreferBlanking, but in that case,
308 we don't get extension events either. So we can't turn it off that way.
310 Note: if you're running Irix 6.3 (O2), you may find that your monitor is
311 powering down anyway, regardless of the xset settings. This is fixed by
312 installing SGI patches 2447 and 2537.
314 desired_server_interval = 0;
316 /* I suspect (but am not sure) that DontAllowExposures might have
317 something to do with powering off the monitor as well, at least
318 on some systems that don't support XDPMS? Who knows... */
319 desired_allow_exp = AllowExposures;
321 if (si->using_mit_saver_extension || si->using_sgi_saver_extension)
323 desired_server_timeout = (p->timeout / 1000);
325 /* The SGI extension won't give us events unless blanking is on.
326 I think (unsure right now) that the MIT extension is the opposite. */
327 if (si->using_sgi_saver_extension)
328 desired_prefer_blank = PreferBlanking;
330 desired_prefer_blank = DontPreferBlanking;
334 /* When we're not using an extension, set the server-side timeout to 0,
335 so that the server never gets involved with screen blanking, and we
336 do it all ourselves. (However, when we *are* using an extension,
337 we tell the server when to notify us, and rather than blanking the
338 screen, the server will send us an X event telling us to blank.)
340 desired_server_timeout = 0;
343 /* XSetScreenSaver() generates BadValue if either timeout parameter
344 exceeds 15 bits (signed short.) That is 09:06:07.
346 if (desired_server_timeout > 0x7FFF) desired_server_timeout = 0x7FFF;
347 if (desired_server_interval > 0x7FFF) desired_server_interval = 0x7FFF;
349 if (desired_server_timeout != current_server_timeout ||
350 desired_server_interval != current_server_interval ||
351 desired_prefer_blank != current_prefer_blank ||
352 desired_allow_exp != current_allow_exp)
356 "%s: disabling server builtin screensaver:\n"
357 "%s: (xset s %d %d; xset s %s; xset s %s)\n",
359 desired_server_timeout, desired_server_interval,
360 (desired_prefer_blank ? "blank" : "noblank"),
361 (desired_allow_exp ? "expose" : "noexpose"));
363 XSetScreenSaver (si->dpy,
364 desired_server_timeout, desired_server_interval,
365 desired_prefer_blank, desired_allow_exp);
366 XSync(si->dpy, False);
370 #if defined(HAVE_MIT_SAVER_EXTENSION) || defined(HAVE_SGI_SAVER_EXTENSION)
372 static Bool extension_initted = False;
373 if (!extension_initted)
375 extension_initted = True;
376 # ifdef HAVE_MIT_SAVER_EXTENSION
377 if (si->using_mit_saver_extension) init_mit_saver_extension(si);
379 # ifdef HAVE_SGI_SAVER_EXTENSION
380 if (si->using_sgi_saver_extension) init_sgi_saver_extension(si);
384 #endif /* HAVE_MIT_SAVER_EXTENSION || HAVE_SGI_SAVER_EXTENSION */
386 if (unblank_screen_p)
387 /* Turn off the server builtin saver if it is now running. */
388 XForceScreenSaver (si->dpy, ScreenSaverReset);