http://www.tienza.es/crux/src/www.jwz.org/xscreensaver/xscreensaver-5.05.tar.gz
[xscreensaver] / driver / timers.c
index 7e769a77301ba56e5c6e72f157849bb481672361..c7434925286b02e2d13c8ba04e0cb689457af9c2 100644 (file)
@@ -1,5 +1,5 @@
 /* timers.c --- detecting when the user is idle, and other timer-related tasks.
- * xscreensaver, Copyright (c) 1991-2004 Jamie Zawinski <jwz@jwz.org>
+ * 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
 
 #include "xscreensaver.h"
 
+#undef ABS
+#define ABS(x)((x)<0?-(x):(x))
+
+#undef MAX
+#define MAX(x,y)((x)>(y)?(x):(y))
+
+
 #ifdef HAVE_PROC_INTERRUPTS
 static Bool proc_interrupts_activity_p (saver_info *si);
 #endif /* HAVE_PROC_INTERRUPTS */
@@ -324,6 +331,137 @@ reset_timers (saver_info *si)
   if (si->cycle_id) abort ();  /* no cycle timer when inactive */
 
   si->last_activity_time = time ((time_t *) 0);
+
+  /* This will (hopefully, supposedly) tell the server to re-set its
+     DPMS timer.  Without this, the -deactivate clientmessage would
+     prevent xscreensaver from blanking, but would not prevent the
+     monitor from powering down. */
+#if 0
+  /* #### With some servers, this causes the screen to flicker every
+     time a key is pressed!  Ok, I surrender.  I give up on ever
+     having DPMS work properly.
+   */
+  XForceScreenSaver (si->dpy, ScreenSaverReset);
+
+  /* And if the monitor is already powered off, turn it on.
+     You'd think the above would do that, but apparently not? */
+  monitor_power_on (si);
+#endif
+
+}
+
+
+/* Returns true if the mouse has moved since the last time we checked.
+   Small motions (of less than "hysteresis" pixels/second) are ignored.
+ */
+static Bool
+pointer_moved_p (saver_screen_info *ssi, Bool mods_p)
+{
+  saver_info *si = ssi->global;
+  saver_preferences *p = &si->prefs;
+
+  Window root, child;
+  int root_x, root_y, x, y;
+  unsigned int mask;
+  time_t now = time ((time_t *) 0);
+  unsigned int distance, dps;
+  unsigned long seconds = 0;
+  Bool moved_p = False;
+
+  /* don't check xinerama pseudo-screens. */
+  if (!ssi->real_screen_p) return False;
+
+  if (!XQueryPointer (si->dpy, ssi->screensaver_window, &root, &child,
+                      &root_x, &root_y, &x, &y, &mask))
+    {
+      /* If XQueryPointer() returns false, the mouse is not on this screen.
+       */
+      x = root_x = -1;
+      y = root_y = -1;
+      root = child = 0;
+      mask = 0;
+    }
+
+  distance = MAX (ABS (ssi->poll_mouse_last_root_x - root_x),
+                  ABS (ssi->poll_mouse_last_root_y - root_y));
+  seconds = (now - ssi->poll_mouse_last_time);
+
+
+  /* When the screen is blanked, we get MotionNotify events, but when not
+     blanked, we poll only every 5 seconds, and that's not enough resolution
+     to do hysteresis based on a 1 second interval.  So, assume that any
+     motion we've seen during the 5 seconds when our eyes were closed happened
+     in the last 1 second instead.
+   */
+  if (seconds > 1) seconds = 1;
+
+  dps = (seconds <= 0 ? distance : (distance / seconds));
+
+  /* Motion only counts if the rate is more than N pixels per second.
+   */
+  if (dps >= p->pointer_hysteresis &&
+      distance > 0)
+    moved_p = True;
+
+  /* If the mouse is not on this screen but used to be, that's motion.
+     If the mouse was not on this screen, but is now, that's motion.
+   */
+  {
+    Bool on_screen_p  = (root_x != -1 && root_y != -1);
+    Bool was_on_screen_p = (ssi->poll_mouse_last_root_x != -1 &&
+                            ssi->poll_mouse_last_root_y != -1);
+
+    if (on_screen_p != was_on_screen_p)
+      moved_p = True;
+  }
+
+  if (p->debug_p && (distance != 0 || moved_p))
+    {
+      fprintf (stderr, "%s: %d: pointer %s", blurb(), ssi->number,
+               (moved_p ? "moved:  " : "ignored:"));
+      if (ssi->poll_mouse_last_root_x == -1)
+        fprintf (stderr, "off screen");
+      else
+        fprintf (stderr, "%d,%d",
+                 ssi->poll_mouse_last_root_x,
+                 ssi->poll_mouse_last_root_y);
+      fprintf (stderr, " -> ");
+      if (root_x == -1)
+        fprintf (stderr, "off screen");
+      else
+        fprintf (stderr, "%d,%d", root_x, root_y);
+      if (ssi->poll_mouse_last_root_x != -1 && root_x != -1)
+        fprintf (stderr, " (%d,%d; %d/%lu=%d)",
+                 ABS(ssi->poll_mouse_last_root_x - root_x),
+                 ABS(ssi->poll_mouse_last_root_y - root_y),
+                 distance, seconds, dps);
+
+      fprintf (stderr, ".\n");
+    }
+
+  if (!moved_p &&
+      mods_p &&
+      mask != ssi->poll_mouse_last_mask)
+    {
+      moved_p = True;
+
+      if (p->debug_p)
+        fprintf (stderr, "%s: %d: modifiers changed: 0x%04x -> 0x%04x.\n",
+                 blurb(), ssi->number, ssi->poll_mouse_last_mask, mask);
+    }
+
+  si->last_activity_screen   = ssi;
+  ssi->poll_mouse_last_child = child;
+  ssi->poll_mouse_last_mask  = mask;
+
+  if (moved_p || seconds > 0)
+    {
+      ssi->poll_mouse_last_time   = now;
+      ssi->poll_mouse_last_root_x = root_x;
+      ssi->poll_mouse_last_root_y = root_y;
+    }
+
+  return moved_p;
 }
 
 
@@ -361,67 +499,8 @@ check_pointer_timer (XtPointer closure, XtIntervalId *id)
   for (i = 0; i < si->nscreens; i++)
     {
       saver_screen_info *ssi = &si->screens[i];
-      Window root, child;
-      int root_x, root_y, x, y;
-      unsigned int mask;
-
-      if (!ssi->real_screen_p) continue;
-
-      if (!XQueryPointer (si->dpy, ssi->screensaver_window, &root, &child,
-                          &root_x, &root_y, &x, &y, &mask))
-        {
-          /* If XQueryPointer() returns false, the mouse is not on this screen.
-           */
-          root_x = -1;
-          root_y = -1;
-        }
-
-      if (root_x == ssi->poll_mouse_last_root_x &&
-         root_y == ssi->poll_mouse_last_root_y &&
-         child  == ssi->poll_mouse_last_child &&
-         mask   == ssi->poll_mouse_last_mask)
-       continue;
-
-      active_p = True;
-
-      if (p->debug_p)
-        {
-          if (root_x == ssi->poll_mouse_last_root_x &&
-              root_y == ssi->poll_mouse_last_root_y &&
-              child  == ssi->poll_mouse_last_child)
-            fprintf (stderr, "%s: %d: modifiers changed: 0x%04x -> 0x%04x.\n",
-                     blurb(), i, ssi->poll_mouse_last_mask, mask);
-          else
-            {
-              fprintf (stderr, "%s: %d: pointer moved: ", blurb(), i);
-              if (ssi->poll_mouse_last_root_x == -1)
-                fprintf (stderr, "off screen");
-              else
-                fprintf (stderr, "%d,%d",
-                         ssi->poll_mouse_last_root_x,
-                         ssi->poll_mouse_last_root_y);
-              fprintf (stderr, " -> ");
-              if (root_x == -1)
-                fprintf (stderr, "off screen.");
-              else
-                fprintf (stderr, "%d,%d", root_x, root_y);
-              if (ssi->poll_mouse_last_root_x == -1 || root_x == -1)
-                fprintf (stderr, ".\n");
-              else
-#   undef ABS
-#   define ABS(x)((x)<0?-(x):(x))
-                fprintf (stderr, " (%d,%d).\n",
-                         ABS(ssi->poll_mouse_last_root_x - root_x),
-                         ABS(ssi->poll_mouse_last_root_y - root_y));
-# undef ABS
-            }
-        }
-
-      si->last_activity_screen    = ssi;
-      ssi->poll_mouse_last_root_x = root_x;
-      ssi->poll_mouse_last_root_y = root_y;
-      ssi->poll_mouse_last_child  = child;
-      ssi->poll_mouse_last_mask   = mask;
+      if (pointer_moved_p (ssi, True))
+        active_p = True;
     }
 
 #ifdef HAVE_PROC_INTERRUPTS
@@ -433,7 +512,6 @@ check_pointer_timer (XtPointer closure, XtIntervalId *id)
     }
 #endif /* HAVE_PROC_INTERRUPTS */
 
-
   if (active_p)
     reset_timers (si);
 
@@ -747,7 +825,7 @@ sleep_until_idle (saver_info *si, Bool until_idle_p)
             const char *type = 0;
            if (event.xany.type == MotionNotify)
               {
-                type = "MotionNotify";
+                /*type = "MotionNotify";*/
                 root = event.xmotion.root;
                 window = event.xmotion.window;
                 x = event.xmotion.x_root;
@@ -800,6 +878,27 @@ sleep_until_idle (saver_info *si, Bool until_idle_p)
        /* If any widgets want to handle this event, let them. */
        dispatch_event (si, &event);
 
+        
+        /* If we got a MotionNotify event, figure out what screen it
+           was on and poll the mouse there: if the mouse hasn't moved
+           far enough to count as "real" motion, then ignore this
+           event.
+         */
+        if (event.xany.type == MotionNotify)
+          {
+            int i;
+            for (i = 0; i < si->nscreens; i++)
+              if (event.xmotion.root ==
+                  RootWindowOfScreen (si->screens[i].screen))
+                break;
+            if (i < si->nscreens)
+              {
+                if (!pointer_moved_p (&si->screens[i], False))
+                  continue;
+              }
+          }
+
+
        /* We got a user event.
           If we're waiting for the user to become active, this is it.
           If we're waiting until the user becomes idle, reset the timers
@@ -1094,7 +1193,10 @@ query_proc_interrupts_available (saver_info *si, const char **why)
 
   f = fopen (PROC_INTERRUPTS, "r");
   if (!f)
-    return False;
+    {
+      if (why) *why = "does not exist";
+      return False;
+    }
 
   fclose (f);
   return True;