http://www.jwz.org/xscreensaver/xscreensaver-5.12.tar.gz
[xscreensaver] / driver / xset.c
index cd2aa38c2a8b07d12fae2e41b7f8a95efde3f709..46607977ada484781ecd9b82b74bb471bb309fd1 100644 (file)
@@ -1,5 +1,5 @@
 /* xset.c --- interacting with server extensions and the builtin screensaver.
 /* xset.c --- interacting with server extensions and the builtin screensaver.
- * xscreensaver, Copyright (c) 1991-1997 Jamie Zawinski <jwz@netscape.com>
+ * 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
  *
  * Permission to use, copy, modify, distribute, and sell this software and its
  * documentation for any purpose is hereby granted without fee, provided that
 
 #include "xscreensaver.h"
 
 
 #include "xscreensaver.h"
 
+#ifdef _VROOT_H_
+ERROR!  You must not include vroot.h in this file.
+#endif
+
 \f
 /* MIT SCREEN-SAVER server extension hackery.
  */
 \f
 /* MIT SCREEN-SAVER server extension hackery.
  */
 
 # include <X11/extensions/scrnsaver.h>
 
 
 # include <X11/extensions/scrnsaver.h>
 
-Bool
-query_mit_saver_extension (saver_info *si)
-{
-  return XScreenSaverQueryExtension (si->dpy,
-                                    &si->mit_saver_ext_event_number,
-                                    &si->mit_saver_ext_error_number);
-}
-
 static int
 ignore_all_errors_ehandler (Display *dpy, XErrorEvent *error)
 {
 static int
 ignore_all_errors_ehandler (Display *dpy, XErrorEvent *error)
 {
@@ -89,6 +85,180 @@ init_mit_saver_extension (saver_info *si)
 }
 #endif /* HAVE_MIT_SAVER_EXTENSION */
 
 }
 #endif /* HAVE_MIT_SAVER_EXTENSION */
 
+\f
+#ifdef HAVE_XINPUT
+/* XInputExtension device support */
+#include <X11/extensions/XInput.h>
+
+struct xinput_dev_info {
+  XDevice      *device;
+  XEventClass  press, release, valuator;
+};
+
+Bool
+query_xinput_extension (saver_info *si)
+{
+  XExtCodes codes;
+
+  if (!XQueryExtension (si->dpy, INAME, &codes.major_opcode,
+                       &codes.first_event, &codes.first_error))
+    {
+      if (si->prefs.verbose_p)
+       fprintf (stderr, "\t XInputExtension is not present!\n");
+      return False;
+    }
+  else
+    {
+      if (si->prefs.verbose_p)
+       fprintf (stderr, "\t XInputExtension is present!\n");
+      return True;
+    }
+}
+
+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 */
+
 \f
 /* SGI SCREEN_SAVER server extension hackery.
  */
 \f
 /* SGI SCREEN_SAVER server extension hackery.
  */
@@ -97,14 +267,6 @@ init_mit_saver_extension (saver_info *si)
 
 # include <X11/extensions/XScreenSaver.h>
 
 
 # include <X11/extensions/XScreenSaver.h>
 
-Bool
-query_sgi_saver_extension (saver_info *si)
-{
-  return XScreenSaverQueryExtension (si->dpy,
-                                    &si->sgi_saver_ext_event_number,
-                                    &si->sgi_saver_ext_error_number);
-}
-
 static void
 init_sgi_saver_extension (saver_info *si)
 {
 static void
 init_sgi_saver_extension (saver_info *si)
 {
@@ -124,8 +286,8 @@ init_sgi_saver_extension (saver_info *si)
          fprintf (stderr,
        "%s: SGI SCREEN_SAVER extension exists, but can't be initialized;\n\
                perhaps some other screensaver program is already running?\n",
          fprintf (stderr,
        "%s: SGI SCREEN_SAVER extension exists, but can't be initialized;\n\
                perhaps some other screensaver program is already running?\n",
-                  progname);
-         p->use_sgi_saver_extension = False;
+                  blurb());
+         si->using_sgi_saver_extension = False;
          return;
        }
     }
          return;
        }
     }
@@ -133,13 +295,14 @@ init_sgi_saver_extension (saver_info *si)
 
 #endif /* HAVE_SGI_SAVER_EXTENSION */
 
 
 #endif /* HAVE_SGI_SAVER_EXTENSION */
 
+
 \f
 \f
-/* Figuring out what the appropriate XSetScreenSaver() paramters are
+/* Figuring out what the appropriate XSetScreenSaver() parameters are
    (one wouldn't expect this to be rocket science.)
  */
 
 void
    (one wouldn't expect this to be rocket science.)
  */
 
 void
-disable_builtin_screensaver (saver_info *si, Bool turn_off_p)
+disable_builtin_screensaver (saver_info *si, Bool unblank_screen_p)
 {
   saver_preferences *p = &si->prefs;
   int current_server_timeout, current_server_interval;
 {
   saver_preferences *p = &si->prefs;
   int current_server_timeout, current_server_interval;
@@ -157,51 +320,63 @@ disable_builtin_screensaver (saver_info *si, Bool turn_off_p)
 
   /* 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.
 
   /* 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 make sure it's 0.
+     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.
 
      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
    */
   desired_server_interval = 0;
 
   /* I suspect (but am not sure) that DontAllowExposures might have
-     something to do with powering off the monitor as well. */
+     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;
 
   desired_allow_exp = AllowExposures;
 
-#if defined(HAVE_MIT_SAVER_EXTENSION) || defined(HAVE_SGI_SAVER_EXTENSION)
-  if (p->use_mit_saver_extension || p->use_sgi_saver_extension)
+  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. */
     {
       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 (p->use_sgi_saver_extension)
+      if (si->using_sgi_saver_extension)
        desired_prefer_blank = PreferBlanking;
       else
        desired_prefer_blank = DontPreferBlanking;
     }
   else
        desired_prefer_blank = PreferBlanking;
       else
        desired_prefer_blank = DontPreferBlanking;
     }
   else
-#endif /* HAVE_MIT_SAVER_EXTENSION || HAVE_SGI_SAVER_EXTENSION */
     {
     {
+      /* 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;
     }
 
       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 (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 (desired_server_timeout == 0)
-       printf ("%s%sisabling server builtin screensaver.\n\
-       You can re-enable it with \"xset s on\".\n",
-               (p->verbose_p ? "" : progname),
-               (p->verbose_p ? "\n\tD" : ": d"));
-
       if (p->verbose_p)
       if (p->verbose_p)
-       fprintf (stderr, "%s: (xset s %d %d %s %s)\n", progname,
+       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_server_timeout, desired_server_interval,
                 (desired_prefer_blank ? "blank" : "noblank"),
-                (desired_allow_exp ? "noexpose" : "expose"));
+                (desired_allow_exp ? "expose" : "noexpose"));
 
       XSetScreenSaver (si->dpy,
                       desired_server_timeout, desired_server_interval,
 
       XSetScreenSaver (si->dpy,
                       desired_server_timeout, desired_server_interval,
@@ -217,16 +392,16 @@ disable_builtin_screensaver (saver_info *si, Bool turn_off_p)
       {
        extension_initted = True;
 # ifdef HAVE_MIT_SAVER_EXTENSION
       {
        extension_initted = True;
 # ifdef HAVE_MIT_SAVER_EXTENSION
-       if (p->use_mit_saver_extension) init_mit_saver_extension(si);
+       if (si->using_mit_saver_extension) init_mit_saver_extension(si);
 # endif
 # ifdef HAVE_SGI_SAVER_EXTENSION
 # endif
 # ifdef HAVE_SGI_SAVER_EXTENSION
-       if (p->use_sgi_saver_extension) init_sgi_saver_extension(si);
+       if (si->using_sgi_saver_extension) init_sgi_saver_extension(si);
 # endif
       }
   }
 #endif /* HAVE_MIT_SAVER_EXTENSION || HAVE_SGI_SAVER_EXTENSION */
 
 # endif
       }
   }
 #endif /* HAVE_MIT_SAVER_EXTENSION || HAVE_SGI_SAVER_EXTENSION */
 
-  if (turn_off_p)
+  if (unblank_screen_p)
     /* Turn off the server builtin saver if it is now running. */
     XForceScreenSaver (si->dpy, ScreenSaverReset);
 }
     /* Turn off the server builtin saver if it is now running. */
     XForceScreenSaver (si->dpy, ScreenSaverReset);
 }