X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?p=xscreensaver;a=blobdiff_plain;f=driver%2Ftimers.c;h=c9244f735e7655b29c8a968a7175d7885e364b78;hp=7e769a77301ba56e5c6e72f157849bb481672361;hb=447db08c956099b3b183886729108bf5b364c4b8;hpb=2d04c4f22466851aedb6ed0f2919d148f726b889 diff --git a/driver/timers.c b/driver/timers.c index 7e769a77..c9244f73 100644 --- a/driver/timers.c +++ b/driver/timers.c @@ -48,6 +48,13 @@ #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 */ @@ -327,6 +334,114 @@ reset_timers (saver_info *si) } +/* 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 (ssi->poll_mouse_last_root_x == -1 || + ssi->poll_mouse_last_root_y == -1 || + root_x == -1 || + root_y == -1) + 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; +} + + /* When we aren't using a server extension, this timer is used to periodically wake up and poll the mouse position, which is possibly more reliable than selecting motion events on every window. @@ -361,67 +476,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 +489,6 @@ check_pointer_timer (XtPointer closure, XtIntervalId *id) } #endif /* HAVE_PROC_INTERRUPTS */ - if (active_p) reset_timers (si); @@ -747,7 +802,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 +855,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