/* timers.c --- detecting when the user is idle, and other timer-related tasks.
- * xscreensaver, Copyright (c) 1991-2008 Jamie Zawinski <jwz@jwz.org>
+ * xscreensaver, Copyright (c) 1991-2011 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
/* 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);
+ monitor_power_on (si, True);
#endif
}
sleep_until_idle (saver_info *si, Bool until_idle_p)
{
saver_preferences *p = &si->prefs;
- XEvent event;
+
+ /* We have to go through this union bullshit because gcc-4.4.0 has
+ stricter struct-aliasing rules. Without this, the optimizer
+ can fuck things up.
+ */
+ union {
+ XEvent x_event;
+# ifdef HAVE_RANDR
+ XRRScreenChangeNotifyEvent xrr_event;
+# endif /* HAVE_RANDR */
+# ifdef HAVE_MIT_SAVER_EXTENSION
+ XScreenSaverNotifyEvent sevent;
+# endif /* HAVE_MIT_SAVER_EXTENSION */
+ } event;
/* We need to select events on all windows if we're not using any extensions.
Otherwise, we don't need to. */
Bool polling_mouse_position = (si->using_proc_interrupts ||
!(si->using_xidle_extension ||
si->using_mit_saver_extension ||
- si->using_sgi_saver_extension));
+ si->using_sgi_saver_extension) ||
+ si->using_xinput_extension);
+
+ const char *why = 0; /* What caused the idle-state to change? */
if (until_idle_p)
{
while (1)
{
- XtAppNextEvent (si->app, &event);
+ XtAppNextEvent (si->app, &event.x_event);
- switch (event.xany.type) {
+ switch (event.x_event.xany.type) {
case 0: /* our synthetic "timeout" event has been signalled */
if (until_idle_p)
{
if (idle >= p->timeout)
{
/* Look, we've been idle long enough. We're done. */
+ why = "timeout";
goto DONE;
}
else if (si->emergency_lock_p)
{
/* Oops, the wall clock has jumped far into the future, so
we need to lock down in a hurry! */
+ why = "large wall clock change";
goto DONE;
}
else
break;
case ClientMessage:
- if (handle_clientmessage (si, &event, until_idle_p))
- goto DONE;
+ if (handle_clientmessage (si, &event.x_event, until_idle_p))
+ {
+ why = "ClientMessage";
+ goto DONE;
+ }
break;
case CreateNotify:
supposed to scan all windows for events, prepare this window. */
if (scanning_all_windows)
{
- Window w = event.xcreatewindow.window;
+ Window w = event.x_event.xcreatewindow.window;
start_notice_events_timer (si, w, p->debug_p);
}
break;
Window root=0, window=0;
int x=-1, y=-1;
const char *type = 0;
- if (event.xany.type == MotionNotify)
+ if (event.x_event.xany.type == MotionNotify)
{
/*type = "MotionNotify";*/
- root = event.xmotion.root;
- window = event.xmotion.window;
- x = event.xmotion.x_root;
- y = event.xmotion.y_root;
+ root = event.x_event.xmotion.root;
+ window = event.x_event.xmotion.window;
+ x = event.x_event.xmotion.x_root;
+ y = event.x_event.xmotion.y_root;
}
- else if (event.xany.type == KeyPress)
+ else if (event.x_event.xany.type == KeyPress)
{
type = "KeyPress";
- root = event.xkey.root;
- window = event.xkey.window;
+ root = event.x_event.xkey.root;
+ window = event.x_event.xkey.window;
x = y = -1;
}
- else if (event.xany.type == ButtonPress)
+ else if (event.x_event.xany.type == ButtonPress)
{
type = "ButtonPress";
- root = event.xkey.root;
- window = event.xkey.window;
- x = event.xmotion.x_root;
- y = event.xmotion.y_root;
+ root = event.x_event.xkey.root;
+ window = event.x_event.xkey.window;
+ x = event.x_event.xmotion.x_root;
+ y = event.x_event.xmotion.y_root;
}
if (type)
/* Be careful never to do this unless in -debug mode, as
this could expose characters from the unlock password. */
- if (p->debug_p && event.xany.type == KeyPress)
+ if (p->debug_p && event.x_event.xany.type == KeyPress)
{
KeySym keysym;
char c = 0;
- XLookupString (&event.xkey, &c, 1, &keysym, 0);
+ XLookupString (&event.x_event.xkey, &c, 1, &keysym, 0);
fprintf (stderr, " (%s%s)",
- (event.xkey.send_event ? "synthetic " : ""),
+ (event.x_event.xkey.send_event ? "synthetic " : ""),
XKeysymToString (keysym));
}
}
/* If any widgets want to handle this event, let them. */
- dispatch_event (si, &event);
+ dispatch_event (si, &event.x_event);
/* If we got a MotionNotify event, figure out what screen it
far enough to count as "real" motion, then ignore this
event.
*/
- if (event.xany.type == MotionNotify)
+ if (event.x_event.xany.type == MotionNotify)
{
int i;
for (i = 0; i < si->nscreens; i++)
- if (event.xmotion.root ==
+ if (event.x_event.xmotion.root ==
RootWindowOfScreen (si->screens[i].screen))
break;
if (i < si->nscreens)
if (!until_idle_p)
{
if (si->demoing_p &&
- (event.xany.type == MotionNotify ||
- event.xany.type == KeyRelease))
+ (event.x_event.xany.type == MotionNotify ||
+ event.x_event.xany.type == KeyRelease))
/* When we're demoing a single hack, mouse motion doesn't
cause deactivation. Only clicks and keypresses do. */
;
else
- /* If we're not demoing, then any activity causes deactivation.
- */
- goto DONE;
+ {
+ /* If we're not demoing, then any activity causes deactivation.
+ */
+ why = (event.x_event.xany.type == MotionNotify ?"mouse motion":
+ event.x_event.xany.type == KeyPress?"keyboard activity":
+ event.x_event.xany.type == ButtonPress ? "mouse click" :
+ "unknown user activity");
+ goto DONE;
+ }
}
else
reset_timers (si);
default:
#ifdef HAVE_MIT_SAVER_EXTENSION
- if (event.type == si->mit_saver_ext_event_number)
+ if (event.x_event.type == si->mit_saver_ext_event_number)
{
/* This event's number is that of the MIT-SCREEN-SAVER server
extension. This extension has one event number, and the event
itself contains sub-codes that say what kind of event it was
(an "idle" or "not-idle" event.)
*/
- XScreenSaverNotifyEvent *sevent =
- (XScreenSaverNotifyEvent *) &event;
- if (sevent->state == ScreenSaverOn)
+ if (event.sevent.state == ScreenSaverOn)
{
int i = 0;
if (p->verbose_p)
XUnmapWindow (si->dpy, ssi->server_mit_saver_window);
}
- if (sevent->kind != ScreenSaverExternal)
+ if (event.sevent.kind != ScreenSaverExternal)
{
fprintf (stderr,
"%s: ScreenSaverOn event wasn't of type External!\n",
}
if (until_idle_p)
- goto DONE;
+ {
+ why = "MIT ScreenSaverOn";
+ goto DONE;
+ }
}
- else if (sevent->state == ScreenSaverOff)
+ else if (event.sevent.state == ScreenSaverOff)
{
if (p->verbose_p)
fprintf (stderr, "%s: MIT ScreenSaverOff event received.\n",
blurb());
if (!until_idle_p)
- goto DONE;
+ {
+ why = "MIT ScreenSaverOff";
+ goto DONE;
+ }
}
else
fprintf (stderr,
"%s: unknown MIT-SCREEN-SAVER event %d received!\n",
- blurb(), sevent->state);
+ blurb(), event.sevent.state);
}
else
#ifdef HAVE_SGI_SAVER_EXTENSION
- if (event.type == (si->sgi_saver_ext_event_number + ScreenSaverStart))
+ if (event.x_event.type == (si->sgi_saver_ext_event_number + ScreenSaverStart))
{
/* The SGI SCREEN_SAVER server extension has two event numbers,
and this event matches the "idle" event. */
blurb());
if (until_idle_p)
- goto DONE;
+ {
+ why = "SGI ScreenSaverStart";
+ goto DONE;
+ }
}
- else if (event.type == (si->sgi_saver_ext_event_number +
+ else if (event.x_event.type == (si->sgi_saver_ext_event_number +
ScreenSaverEnd))
{
/* The SGI SCREEN_SAVER server extension has two event numbers,
fprintf (stderr, "%s: SGI ScreenSaverEnd event received.\n",
blurb());
if (!until_idle_p)
- goto DONE;
+ {
+ why = "SGI ScreenSaverEnd";
+ goto DONE;
+ }
}
else
#endif /* HAVE_SGI_SAVER_EXTENSION */
+#ifdef HAVE_XINPUT
+ if ((!until_idle_p) &&
+ (si->num_xinput_devices > 0) &&
+ (event.x_event.type == si->xinput_DeviceMotionNotify ||
+ event.x_event.type == si->xinput_DeviceButtonPress))
+ /* Ignore DeviceButtonRelease, see ButtonRelease comment above. */
+ {
+
+ dispatch_event (si, &event.x_event);
+ if (si->demoing_p &&
+ event.x_event.type == si->xinput_DeviceMotionNotify)
+ /* When we're demoing a single hack, mouse motion doesn't
+ cause deactivation. Only clicks and keypresses do. */
+ ;
+ else
+ /* If we're not demoing, then any activity causes deactivation.
+ */
+ {
+ why = (event.x_event.type == si->xinput_DeviceMotionNotify
+ ? "XI mouse motion" :
+ event.x_event.type == si->xinput_DeviceButtonPress
+ ? "XI mouse click" : "unknown XINPUT event");
+ goto DONE;
+ }
+ }
+ else
+#endif /* HAVE_XINPUT */
+
#ifdef HAVE_RANDR
- if (event.type == (si->randr_event_number + RRScreenChangeNotify))
+ if (si->using_randr_extension &&
+ (event.x_event.type ==
+ (si->randr_event_number + RRScreenChangeNotify)))
{
/* The Resize and Rotate extension sends an event when the
size, rotation, or refresh rate of any screen has changed.
*/
- XRRScreenChangeNotifyEvent *xrr_event =
- (XRRScreenChangeNotifyEvent *) &event;
-
if (p->verbose_p)
{
/* XRRRootToScreen is in Xrandr.h 1.4, 2001/06/07 */
- int screen = XRRRootToScreen (si->dpy, xrr_event->window);
+ int screen = XRRRootToScreen (si->dpy, event.xrr_event.window);
fprintf (stderr, "%s: %d: screen change event received\n",
blurb(), screen);
}
# ifdef RRScreenChangeNotifyMask
/* Inform Xlib that it's ok to update its data structures. */
- XRRUpdateConfiguration (&event); /* Xrandr.h 1.9, 2002/09/29 */
+ XRRUpdateConfiguration (&event.x_event); /* Xrandr.h 1.9, 2002/09/29 */
# endif /* RRScreenChangeNotifyMask */
/* Resize the existing xscreensaver windows and cached ssi data. */
#endif /* HAVE_RANDR */
/* Just some random event. Let the Widgets handle it, if desired. */
- dispatch_event (si, &event);
+ dispatch_event (si, &event.x_event);
}
}
DONE:
+ if (p->verbose_p)
+ {
+ if (! why) why = "unknown reason";
+ fprintf (stderr, "%s: %s (%s)\n", blurb(),
+ (until_idle_p ? "user is idle" : "user is active"),
+ why);
+ }
/* If there's a user event on the queue, swallow it.
If we're using a server extension, and the user becomes active, we
there's only one event generated by user activity, not two.)
*/
if (!until_idle_p && si->locked_p)
- swallow_unlock_typeahead_events (si, &event);
+ swallow_unlock_typeahead_events (si, &event.x_event);
else
while (XCheckMaskEvent (si->dpy,
(KeyPressMask|ButtonPressMask|PointerMotionMask),
- &event))
+ &event.x_event))
;