summaryrefslogtreecommitdiffstats
path: root/driver/xset.c
diff options
context:
space:
mode:
Diffstat (limited to 'driver/xset.c')
-rw-r--r--driver/xset.c389
1 files changed, 389 insertions, 0 deletions
diff --git a/driver/xset.c b/driver/xset.c
new file mode 100644
index 0000000..a381429
--- /dev/null
+++ b/driver/xset.c
@@ -0,0 +1,389 @@
+/* xset.c --- interacting with server extensions and the builtin screensaver.
+ * xscreensaver, Copyright (c) 1991-2008 Jamie Zawinski <jwz@jwz.org>
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation. No representations are made about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdio.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xatom.h>
+#include <X11/Xos.h>
+
+/* This file doesn't need the Xt headers, so stub these types out... */
+#undef XtPointer
+#define XtAppContext void*
+#define XrmDatabase void*
+#define XtIntervalId void*
+#define XtPointer void*
+#define Widget void*
+
+#include "xscreensaver.h"
+
+#ifdef _VROOT_H_
+ERROR! You must not include vroot.h in this file.
+#endif
+
+
+/* MIT SCREEN-SAVER server extension hackery.
+ */
+
+#ifdef HAVE_MIT_SAVER_EXTENSION
+
+# include <X11/extensions/scrnsaver.h>
+
+static int
+ignore_all_errors_ehandler (Display *dpy, XErrorEvent *error)
+{
+ return 0;
+}
+
+static void
+init_mit_saver_extension (saver_info *si)
+{
+ int i;
+ Pixmap *blank_pix = (Pixmap *) calloc (sizeof(Pixmap), si->nscreens);
+
+ for (i = 0; i < si->nscreens; i++)
+ {
+ saver_screen_info *ssi = &si->screens[i];
+ XID kill_id = 0;
+ Atom kill_type = 0;
+ Window root = RootWindowOfScreen (ssi->screen);
+ blank_pix[i] = XCreatePixmap (si->dpy, root, 1, 1, 1);
+
+ /* Kill off the old MIT-SCREEN-SAVER client if there is one.
+ This tends to generate X errors, though (possibly due to a bug
+ in the server extension itself?) so just ignore errors here. */
+ if (XScreenSaverGetRegistered (si->dpy,
+ XScreenNumberOfScreen (ssi->screen),
+ &kill_id, &kill_type)
+ && kill_id != blank_pix[i])
+ {
+ XErrorHandler old_handler =
+ XSetErrorHandler (ignore_all_errors_ehandler);
+ XKillClient (si->dpy, kill_id);
+ XSync (si->dpy, False);
+ XSetErrorHandler (old_handler);
+ }
+ XScreenSaverSelectInput (si->dpy, root, ScreenSaverNotifyMask);
+ XScreenSaverRegister (si->dpy,
+ XScreenNumberOfScreen (ssi->screen),
+ (XID) blank_pix[i], XA_PIXMAP);
+ }
+ free(blank_pix);
+}
+#endif /* HAVE_MIT_SAVER_EXTENSION */
+
+
+#ifdef HAVE_XINPUT
+/* XInputExtension device support */
+
+Bool
+query_xinput_extension (saver_info *si)
+{
+ XExtCodes codes;
+ return XQueryExtension (si->dpy, INAME, &codes.major_opcode,
+ &codes.first_event, &codes.first_error);
+}
+
+void
+init_xinput_extension (saver_info *si)
+{
+ int i, ndevices;
+ int class;
+ XDeviceInfo *list;
+ XDevice *dev;
+ XAnyClassPtr pClass;
+ XEventClass *event_list;
+ int nevents = 0;
+
+ /* skip if already initialized */
+ if (si->num_xinput_devices && si->xinput_devices)
+ return;
+
+ si->num_xinput_devices = 0;
+
+ list = XListInputDevices (si->dpy, &ndevices);
+ if (list == NULL)
+ {
+ si->xinput_devices = NULL;
+ return;
+ }
+
+ /* We only care about 3 event types per device (DeviceButtonPress,
+ DeviceButtonRelease, and DeviceMotionNotify), hence the "* 3"
+ for the event count. */
+ event_list = calloc(ndevices * 3, sizeof(XEventClass));
+ if (event_list == NULL)
+ return;
+
+ si->xinput_devices = calloc(ndevices, sizeof(struct xinput_dev_info));
+ if (si->xinput_devices == NULL)
+ {
+ free(event_list);
+ return;
+ }
+
+ for (i = 0; i < ndevices; i++)
+ {
+ if ((list[i].use == IsXExtensionDevice)
+#ifdef IsXExtensionPointer
+ || (list[i].use == IsXExtensionPointer)
+#endif
+ )
+ {
+ struct xinput_dev_info *dev_info =
+ &si->xinput_devices[si->num_xinput_devices];
+ Bool device_we_want = False;
+
+ if (si->prefs.debug_p)
+ fprintf(stderr,
+ "Extension device #%2d: XID=%2d type=%3d name=\"%s\"\n",
+ i, (int) list[i].id, (int) list[i].type, list[i].name);
+
+ dev = XOpenDevice (si->dpy, list[i].id);
+ if (!dev)
+ continue;
+ dev_info->device = dev;
+
+ pClass = list[i].inputclassinfo;
+ for (class = 0; class < list[i].num_classes; class++)
+ {
+ switch (pClass->class)
+ {
+ case ButtonClass:
+ if (((XButtonInfo *) pClass)->num_buttons > 0)
+ {
+ /* Macros set values in the second & third arguments */
+ DeviceButtonPress (dev, si->xinput_DeviceButtonPress,
+ dev_info->press);
+ event_list[nevents++] = dev_info->press;
+
+ DeviceButtonRelease (dev, si->xinput_DeviceButtonRelease,
+ dev_info->release);
+ event_list[nevents++] = dev_info->release;
+ device_we_want = True;
+ }
+ break;
+
+ case ValuatorClass:
+ if (((XValuatorInfo *) pClass)->num_axes > 0)
+ {
+ DeviceMotionNotify (dev, si->xinput_DeviceMotionNotify,
+ dev_info->valuator);
+ event_list[nevents++] = dev_info->valuator;
+ device_we_want = True;
+ }
+ break;
+
+ default:
+ /* ignore other classes of devices/events */
+ break;
+ }
+
+ pClass = (XAnyClassPtr) & ((char *) pClass)[pClass->length];
+ }
+
+ if (device_we_want)
+ si->num_xinput_devices++;
+ else
+ XCloseDevice (si->dpy, dev);
+ }
+ }
+
+ if (list)
+ XFreeDeviceList (list);
+
+ if ((nevents == 0) || (si->num_xinput_devices == 0))
+ {
+ free(event_list);
+ free(si->xinput_devices);
+ si->xinput_devices = NULL;
+ si->num_xinput_devices = 0;
+ return;
+ }
+
+ for (i = 0; i < si->nscreens; i++)
+ {
+ saver_screen_info *ssi = &si->screens[i];
+ Window root = RootWindowOfScreen (ssi->screen);
+ XSelectExtensionEvent (si->dpy, root, event_list, nevents);
+ }
+
+ free(event_list);
+}
+
+#if 0
+/* not used */
+static void
+close_xinput_extension (saver_info *si)
+{
+ int i;
+
+ for (i = 0; i < si->num_xinput_devices; i++)
+ XCloseDevice (si->dpy, si->xinput_devices[i].device);
+
+ free(si->xinput_devices);
+ si->xinput_devices = NULL;
+ si->num_xinput_devices = 0;
+}
+#endif
+#endif /* HAVE_XINPUT */
+
+
+/* SGI SCREEN_SAVER server extension hackery.
+ */
+
+#ifdef HAVE_SGI_SAVER_EXTENSION
+
+# include <X11/extensions/XScreenSaver.h>
+
+static void
+init_sgi_saver_extension (saver_info *si)
+{
+ saver_preferences *p = &si->prefs;
+ int i;
+ if (si->screen_blanked_p)
+ /* If you mess with this while the server thinks it's active,
+ the server crashes. */
+ return;
+
+ for (i = 0; i < si->nscreens; i++)
+ {
+ saver_screen_info *ssi = &si->screens[i];
+ XScreenSaverDisable (si->dpy, XScreenNumberOfScreen(ssi->screen));
+ if (! XScreenSaverEnable (si->dpy, XScreenNumberOfScreen(ssi->screen)))
+ {
+ fprintf (stderr,
+ "%s: SGI SCREEN_SAVER extension exists, but can't be initialized;\n\
+ perhaps some other screensaver program is already running?\n",
+ blurb());
+ si->using_sgi_saver_extension = False;
+ return;
+ }
+ }
+}
+
+#endif /* HAVE_SGI_SAVER_EXTENSION */
+
+
+
+/* Figuring out what the appropriate XSetScreenSaver() parameters are
+ (one wouldn't expect this to be rocket science.)
+ */
+
+void
+disable_builtin_screensaver (saver_info *si, Bool unblank_screen_p)
+{
+ saver_preferences *p = &si->prefs;
+ int current_server_timeout, current_server_interval;
+ int current_prefer_blank, current_allow_exp;
+ int desired_server_timeout, desired_server_interval;
+ int desired_prefer_blank, desired_allow_exp;
+
+ XGetScreenSaver (si->dpy, &current_server_timeout, &current_server_interval,
+ &current_prefer_blank, &current_allow_exp);
+
+ desired_server_timeout = current_server_timeout;
+ desired_server_interval = current_server_interval;
+ desired_prefer_blank = current_prefer_blank;
+ desired_allow_exp = current_allow_exp;
+
+ /* On SGIs, if interval is non-zero, it is the number of seconds after
+ screen saving starts at which the monitor should be powered down.
+ Obviously I don't want that, so set it to 0 (meaning "never".)
+
+ Power saving is disabled if DontPreferBlanking, but in that case,
+ we don't get extension events either. So we can't turn it off that way.
+
+ Note: if you're running Irix 6.3 (O2), you may find that your monitor is
+ powering down anyway, regardless of the xset settings. This is fixed by
+ installing SGI patches 2447 and 2537.
+ */
+ desired_server_interval = 0;
+
+ /* I suspect (but am not sure) that DontAllowExposures might have
+ something to do with powering off the monitor as well, at least
+ on some systems that don't support XDPMS? Who knows... */
+ desired_allow_exp = AllowExposures;
+
+ if (si->using_mit_saver_extension || si->using_sgi_saver_extension)
+ {
+ desired_server_timeout = (p->timeout / 1000);
+
+ /* The SGI extension won't give us events unless blanking is on.
+ I think (unsure right now) that the MIT extension is the opposite. */
+ if (si->using_sgi_saver_extension)
+ desired_prefer_blank = PreferBlanking;
+ else
+ desired_prefer_blank = DontPreferBlanking;
+ }
+ else
+ {
+ /* When we're not using an extension, set the server-side timeout to 0,
+ so that the server never gets involved with screen blanking, and we
+ do it all ourselves. (However, when we *are* using an extension,
+ we tell the server when to notify us, and rather than blanking the
+ screen, the server will send us an X event telling us to blank.)
+ */
+ desired_server_timeout = 0;
+ }
+
+ /* XSetScreenSaver() generates BadValue if either timeout parameter
+ exceeds 15 bits (signed short.) That is 09:06:07.
+ */
+ if (desired_server_timeout > 0x7FFF) desired_server_timeout = 0x7FFF;
+ if (desired_server_interval > 0x7FFF) desired_server_interval = 0x7FFF;
+
+ if (desired_server_timeout != current_server_timeout ||
+ desired_server_interval != current_server_interval ||
+ desired_prefer_blank != current_prefer_blank ||
+ desired_allow_exp != current_allow_exp)
+ {
+ if (p->verbose_p)
+ fprintf (stderr,
+ "%s: disabling server builtin screensaver:\n"
+ "%s: (xset s %d %d; xset s %s; xset s %s)\n",
+ blurb(), blurb(),
+ desired_server_timeout, desired_server_interval,
+ (desired_prefer_blank ? "blank" : "noblank"),
+ (desired_allow_exp ? "expose" : "noexpose"));
+
+ XSetScreenSaver (si->dpy,
+ desired_server_timeout, desired_server_interval,
+ desired_prefer_blank, desired_allow_exp);
+ XSync(si->dpy, False);
+ }
+
+
+#if defined(HAVE_MIT_SAVER_EXTENSION) || defined(HAVE_SGI_SAVER_EXTENSION)
+ {
+ static Bool extension_initted = False;
+ if (!extension_initted)
+ {
+ extension_initted = True;
+# ifdef HAVE_MIT_SAVER_EXTENSION
+ if (si->using_mit_saver_extension) init_mit_saver_extension(si);
+# endif
+# ifdef HAVE_SGI_SAVER_EXTENSION
+ if (si->using_sgi_saver_extension) init_sgi_saver_extension(si);
+# endif
+ }
+ }
+#endif /* HAVE_MIT_SAVER_EXTENSION || HAVE_SGI_SAVER_EXTENSION */
+
+ if (unblank_screen_p)
+ /* Turn off the server builtin saver if it is now running. */
+ XForceScreenSaver (si->dpy, ScreenSaverReset);
+}