/* xset.c --- interacting with server extensions and the builtin screensaver. * xscreensaver, Copyright (c) 1991-2008 Jamie Zawinski * * 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 #include #include #include #include /* 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 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 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); }