/* 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 */
}
else
{
+ int i;
maybe_reload_init_file (si);
- kill_screenhack (si);
+ for (i = 0; i < si->nscreens; i++)
+ kill_screenhack (&si->screens[i]);
+
+ raise_window (si, True, True, False);
if (!si->throttled_p)
- spawn_screenhack (si, False);
+ for (i = 0; i < si->nscreens; i++)
+ spawn_screenhack (&si->screens[i]);
else
{
- raise_window (si, True, True, False);
if (p->verbose_p)
fprintf (stderr, "%s: not launching new hack (throttled.)\n",
blurb());
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;
}
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
}
#endif /* HAVE_PROC_INTERRUPTS */
-
if (active_p)
reset_timers (si);
break;
case '\025': case '\030': /* Erase line */
case '\012': case '\015': /* Enter */
+ case '\033': /* ESC */
i = 0;
break;
case '\040': /* Space */
break;
case KeyPress:
- case KeyRelease:
case ButtonPress:
- case ButtonRelease:
+ /* Ignore release events so that hitting ESC at the password dialog
+ doesn't result in the password dialog coming right back again when
+ the fucking release key is seen! */
+ /* case KeyRelease:*/
+ /* case ButtonRelease:*/
case MotionNotify:
if (p->debug_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;
/* 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
if (event.type == (si->randr_event_number + RRScreenChangeNotify))
{
/* The Resize and Rotate extension sends an event when the
- size, rotation, or refresh rate of the screen has changed. */
-
+ size, rotation, or refresh rate of any screen has changed.
+ */
XRRScreenChangeNotifyEvent *xrr_event =
(XRRScreenChangeNotifyEvent *) &event;
- /* XRRRootToScreen is in Xrandr.h 1.4, 2001/06/07 */
- int screen = XRRRootToScreen (si->dpy, xrr_event->window);
if (p->verbose_p)
{
- if (si->screens[screen].width == xrr_event->width &&
- si->screens[screen].height == xrr_event->height)
- fprintf (stderr,
- "%s: %d: no-op screen size change event (%dx%d)\n",
- blurb(), screen,
- xrr_event->width, xrr_event->height);
- else
- fprintf (stderr,
- "%s: %d: screen size changed from %dx%d to %dx%d\n",
- blurb(), screen,
- si->screens[screen].width,
- si->screens[screen].height,
- xrr_event->width, xrr_event->height);
+ /* XRRRootToScreen is in Xrandr.h 1.4, 2001/06/07 */
+ int screen = XRRRootToScreen (si->dpy, xrr_event->window);
+ fprintf (stderr, "%s: %d: screen change event received\n",
+ blurb(), screen);
}
# ifdef RRScreenChangeNotifyMask
# endif /* RRScreenChangeNotifyMask */
/* Resize the existing xscreensaver windows and cached ssi data. */
- resize_screensaver_window (si);
+ if (update_screen_layout (si))
+ {
+ if (p->verbose_p)
+ {
+ fprintf (stderr, "%s: new layout:\n", blurb());
+ describe_monitor_layout (si);
+ }
+ resize_screensaver_window (si);
+ }
}
else
#endif /* HAVE_RANDR */
if (until_idle_p && si->cycle_id) /* no cycle timer when inactive */
abort ();
-
- return;
}
f = fopen (PROC_INTERRUPTS, "r");
if (!f)
- return False;
+ {
+ if (why) *why = "does not exist";
+ return False;
+ }
fclose (f);
return True;
if (screenhack_running_p (si) &&
!monitor_powered_on_p (si))
{
+ int i;
if (si->prefs.verbose_p)
fprintf (stderr,
"%s: X says monitor has powered down; "
"killing running hacks.\n", blurb());
- kill_screenhack (si);
+ for (i = 0; i < si->nscreens; i++)
+ kill_screenhack (&si->screens[i]);
}
/* Re-schedule this timer. The watchdog timer defaults to a bit less