diff options
Diffstat (limited to 'driver/xset.c')
-rw-r--r-- | driver/xset.c | 389 |
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, ¤t_server_timeout, ¤t_server_interval, + ¤t_prefer_blank, ¤t_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); +} |