diff --git a/Xext/sync.c b/Xext/sync.c index ed891b169..ab46d8972 100644 --- a/Xext/sync.c +++ b/Xext/sync.c @@ -2685,6 +2685,15 @@ IdleTimeBlockHandler(pointer pCounter, struct timeval **wt, pointer LastSelectMa counter->value = old_idle; /* pop */ } +static void +IdleTimeCheckBrackets(SyncCounter *counter, XSyncValue idle, XSyncValue *less, XSyncValue *greater) +{ + if ((greater && XSyncValueGreaterOrEqual(idle, *greater)) || + (less && XSyncValueLessOrEqual(idle, *less))) { + SyncChangeCounter(counter, idle); + } +} + static void IdleTimeWakeupHandler(pointer pCounter, int rc, pointer LastSelectMask) { @@ -2699,10 +2708,24 @@ IdleTimeWakeupHandler(pointer pCounter, int rc, pointer LastSelectMask) IdleTimeQueryValue(pCounter, &idle); - if ((greater && XSyncValueGreaterOrEqual(idle, *greater)) || - (less && XSyncValueLessOrEqual(idle, *less))) { - SyncChangeCounter(counter, idle); + /* + There is no guarantee for the WakeupHandler to be called within a specific + timeframe. Idletime may go to 0, but by the time we get here, it may be + non-zero and alarms for a pos. transition on 0 won't get triggered. + https://bugs.freedesktop.org/show_bug.cgi?id=70476 + */ + if (LastEventTimeWasReset(priv->deviceid)) { + LastEventTimeToggleResetFlag(priv->deviceid, FALSE); + if (!XSyncValueIsZero(idle)) { + XSyncValue zero; + XSyncIntsToValue(&zero, 0, 0); + IdleTimeCheckBrackets(counter, zero, less, greater); + less = priv->value_less; + greater = priv->value_greater; + } } + + IdleTimeCheckBrackets(counter, idle, less, greater); } static void @@ -2720,6 +2743,9 @@ IdleTimeBracketValues(pointer pCounter, CARD64 * pbracket_less, IdleTimeWakeupHandler, pCounter); } else if (!registered && (pbracket_less || pbracket_greater)) { + /* Reset flag must be zero so we don't force a idle timer reset on + the first wakeup */ + LastEventTimeToggleResetAll(FALSE); RegisterBlockAndWakeupHandlers(IdleTimeBlockHandler, IdleTimeWakeupHandler, pCounter); } diff --git a/dix/events.c b/dix/events.c index c803721f3..4632bb7db 100644 --- a/dix/events.c +++ b/dix/events.c @@ -262,7 +262,10 @@ InputInfo inputInfo; EventSyncInfoRec syncEvents; -static TimeStamp lastDeviceEventTime[MAXDEVICES]; +static struct DeviceEventTime { + Bool reset; + TimeStamp time; +} lastDeviceEventTime[MAXDEVICES]; /** * The root window the given device is currently on. @@ -1060,8 +1063,11 @@ MonthChangedOrBadTime(CARD32 *ms) void NoticeTime(const DeviceIntPtr dev, TimeStamp time) { - lastDeviceEventTime[XIAllDevices] = currentTime; - lastDeviceEventTime[dev->id] = currentTime; + lastDeviceEventTime[XIAllDevices].time = currentTime; + lastDeviceEventTime[dev->id].time = currentTime; + + LastEventTimeToggleResetFlag(dev->id, TRUE); + LastEventTimeToggleResetFlag(XIAllDevices, TRUE); } static void @@ -1085,7 +1091,30 @@ NoticeEventTime(InternalEvent *ev, DeviceIntPtr dev) TimeStamp LastEventTime(int deviceid) { - return lastDeviceEventTime[deviceid]; + return lastDeviceEventTime[deviceid].time; +} + +Bool +LastEventTimeWasReset(int deviceid) +{ + return lastDeviceEventTime[deviceid].reset; +} + +void +LastEventTimeToggleResetFlag(int deviceid, Bool state) +{ + lastDeviceEventTime[deviceid].reset = state; +} + +void +LastEventTimeToggleResetAll(Bool state) +{ + DeviceIntPtr dev; + nt_list_for_each_entry(dev, inputInfo.devices, next) { + LastEventTimeToggleResetFlag(dev->id, FALSE); + } + LastEventTimeToggleResetFlag(XIAllDevices, FALSE); + LastEventTimeToggleResetFlag(XIAllMasterDevices, FALSE); } /************************************************************************** @@ -5297,6 +5326,7 @@ InitEvents(void) dummy.id = i; NoticeTime(&dummy, currentTime); + LastEventTimeToggleResetFlag(i, FALSE); } syncEvents.replayDev = (DeviceIntPtr) NULL; diff --git a/include/dix.h b/include/dix.h index fd2490fbd..fa7ccd4a3 100644 --- a/include/dix.h +++ b/include/dix.h @@ -322,6 +322,12 @@ NoticeEventTime(InternalEvent *ev, DeviceIntPtr dev); extern _X_EXPORT TimeStamp LastEventTime(int deviceid); +extern _X_EXPORT Bool +LastEventTimeWasReset(int deviceid); +extern _X_EXPORT void +LastEventTimeToggleResetFlag(int deviceid, Bool state); +extern _X_EXPORT void +LastEventTimeToggleResetAll(Bool state); extern void EnqueueEvent(InternalEvent * /* ev */ ,