diff --git a/Xext/saver.c b/Xext/saver.c index fe81bc4d7..e06f40837 100644 --- a/Xext/saver.c +++ b/Xext/saver.c @@ -392,9 +392,7 @@ ScreenSaverFreeSuspend(pointer value, XID id) DeviceIntPtr dev; UpdateCurrentTimeIf(); nt_list_for_each_entry(dev, inputInfo.devices, next) - lastDeviceEventTime[dev->id] = currentTime; - lastDeviceEventTime[XIAllDevices] = currentTime; - lastDeviceEventTime[XIAllMasterDevices] = currentTime; + NoticeTime(dev, currentTime); SetScreenSaverTimer(); } } @@ -681,7 +679,7 @@ ProcScreenSaverQueryInfo(ClientPtr client) pPriv = GetScreenPrivate(pDraw->pScreen); UpdateCurrentTime(); - lastInput = GetTimeInMillis() - lastDeviceEventTime[XIAllDevices].milliseconds; + lastInput = GetTimeInMillis() - LastEventTime(XIAllDevices).milliseconds; rep = (xScreenSaverQueryInfoReply) { .type = X_Reply, diff --git a/Xext/sync.c b/Xext/sync.c index 9ae5b3981..b2ee92e37 100644 --- a/Xext/sync.c +++ b/Xext/sync.c @@ -699,6 +699,14 @@ SyncAwaitTriggerFired(SyncTrigger * pTrigger) FreeResource(pAwaitUnion->header.delete_id, RT_NONE); } +static CARD64 +SyncUpdateCounter(SyncCounter *pCounter, CARD64 newval) +{ + CARD64 oldval = pCounter->value; + pCounter->value = newval; + return oldval; +} + /* This function should always be used to change a counter's value so that * any triggers depending on the counter will be checked. */ @@ -708,8 +716,7 @@ SyncChangeCounter(SyncCounter * pCounter, CARD64 newval) SyncTriggerList *ptl, *pnext; CARD64 oldval; - oldval = pCounter->value; - pCounter->value = newval; + oldval = SyncUpdateCounter(pCounter, newval); /* run through triggers to see if any become true */ for (ptl = pCounter->sync.pTriglist; ptl; ptl = pnext) { @@ -1019,6 +1026,11 @@ SyncComputeBracketValues(SyncCounter * pCounter) psci->bracket_greater = pTrigger->test_value; pnewgtval = &psci->bracket_greater; } + else if (XSyncValueGreaterThan(pCounter->value, pTrigger->test_value) && + XSyncValueGreaterThan(pTrigger->test_value, psci->bracket_less)) { + psci->bracket_less = pTrigger->test_value; + pnewltval = &psci->bracket_less; + } } else if (pTrigger->test_type == XSyncNegativeComparison && ct != XSyncCounterNeverDecreases) { @@ -1028,52 +1040,53 @@ SyncComputeBracketValues(SyncCounter * pCounter) psci->bracket_less = pTrigger->test_value; pnewltval = &psci->bracket_less; } + else if (XSyncValueLessThan(pCounter->value, pTrigger->test_value) && + XSyncValueLessThan(pTrigger->test_value, psci->bracket_greater)) { + psci->bracket_greater = pTrigger->test_value; + pnewgtval = &psci->bracket_greater; + } } else if (pTrigger->test_type == XSyncNegativeTransition && ct != XSyncCounterNeverIncreases) { - if (XSyncValueGreaterThan(pCounter->value, pTrigger->test_value) && - XSyncValueGreaterThan(pTrigger->test_value, psci->bracket_less)) - { - psci->bracket_less = pTrigger->test_value; - pnewltval = &psci->bracket_less; + if (XSyncValueGreaterOrEqual(pCounter->value, pTrigger->test_value) && + XSyncValueGreaterThan(pTrigger->test_value, psci->bracket_less)) { + /* + * If the value is exactly equal to our threshold, we want one + * more event in the negative direction to ensure we pick up + * when the value is less than this threshold. + */ + psci->bracket_less = pTrigger->test_value; + pnewltval = &psci->bracket_less; } - else if (XSyncValueEqual(pCounter->value, pTrigger->test_value) && - XSyncValueGreaterThan(pTrigger->test_value, - psci->bracket_less)) { - /* - * The value is exactly equal to our threshold. We want one - * more event in the negative direction to ensure we pick up - * when the value is less than this threshold. - */ - psci->bracket_less = pTrigger->test_value; - pnewltval = &psci->bracket_less; + else if (XSyncValueLessThan(pCounter->value, pTrigger->test_value) && + XSyncValueLessThan(pTrigger->test_value, psci->bracket_greater)) { + psci->bracket_greater = pTrigger->test_value; + pnewgtval = &psci->bracket_greater; } } else if (pTrigger->test_type == XSyncPositiveTransition && ct != XSyncCounterNeverDecreases) { - if (XSyncValueLessThan(pCounter->value, pTrigger->test_value) && - XSyncValueLessThan(pTrigger->test_value, psci->bracket_greater)) - { - psci->bracket_greater = pTrigger->test_value; - pnewgtval = &psci->bracket_greater; + if (XSyncValueLessOrEqual(pCounter->value, pTrigger->test_value) && + XSyncValueLessThan(pTrigger->test_value, psci->bracket_greater)) { + /* + * If the value is exactly equal to our threshold, we + * want one more event in the positive direction to + * ensure we pick up when the value *exceeds* this + * threshold. + */ + psci->bracket_greater = pTrigger->test_value; + pnewgtval = &psci->bracket_greater; } - else if (XSyncValueEqual(pCounter->value, pTrigger->test_value) && - XSyncValueLessThan(pTrigger->test_value, - psci->bracket_greater)) { - /* - * The value is exactly equal to our threshold. We want one - * more event in the positive direction to ensure we pick up - * when the value *exceeds* this threshold. - */ - psci->bracket_greater = pTrigger->test_value; - pnewgtval = &psci->bracket_greater; + else if (XSyncValueGreaterThan(pCounter->value, pTrigger->test_value) && + XSyncValueGreaterThan(pTrigger->test_value, psci->bracket_less)) { + psci->bracket_less = pTrigger->test_value; + pnewltval = &psci->bracket_less; } } } /* end for each trigger */ - if (pnewgtval || pnewltval) { - (*psci->BracketValues) ((pointer) pCounter, pnewltval, pnewgtval); - } + (*psci->BracketValues) ((pointer) pCounter, pnewltval, pnewgtval); + } /* @@ -2619,7 +2632,7 @@ IdleTimeQueryValue(pointer pCounter, CARD64 * pValue_return) } else deviceid = XIAllDevices; - idle = GetTimeInMillis() - lastDeviceEventTime[deviceid].milliseconds; + idle = GetTimeInMillis() - LastEventTime(deviceid).milliseconds; XSyncIntsToValue(pValue_return, idle, 0); } @@ -2638,7 +2651,7 @@ IdleTimeBlockHandler(pointer pCounter, struct timeval **wt, pointer LastSelectMa return; old_idle = counter->value; - IdleTimeQueryValue(NULL, &idle); + IdleTimeQueryValue(counter, &idle); counter->value = idle; /* push, so CheckTrigger works */ if (less && XSyncValueLessOrEqual(idle, *less)) { @@ -2699,6 +2712,17 @@ 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); + } + else + SyncUpdateCounter(counter, idle); +} + static void IdleTimeWakeupHandler(pointer pCounter, int rc, pointer LastSelectMask) { @@ -2713,10 +2737,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 @@ -2734,6 +2772,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 7a1b1c3c6..4632bb7db 100644 --- a/dix/events.c +++ b/dix/events.c @@ -262,6 +262,11 @@ InputInfo inputInfo; EventSyncInfoRec syncEvents; +static struct DeviceEventTime { + Bool reset; + TimeStamp time; +} lastDeviceEventTime[MAXDEVICES]; + /** * The root window the given device is currently on. */ @@ -1043,33 +1048,73 @@ XineramaGetCursorScreen(DeviceIntPtr pDev) #define TIMESLOP (5 * 60 * 1000) /* 5 minutes */ static void -MonthChangedOrBadTime(InternalEvent *ev) +MonthChangedOrBadTime(CARD32 *ms) { /* If the ddx/OS is careless about not processing timestamped events from * different sources in sorted order, then it's possible for time to go * backwards when it should not. Here we ensure a decent time. */ - if ((currentTime.milliseconds - ev->any.time) > TIMESLOP) + if ((currentTime.milliseconds - *ms) > TIMESLOP) currentTime.months++; else - ev->any.time = currentTime.milliseconds; + *ms = currentTime.milliseconds; +} + +void +NoticeTime(const DeviceIntPtr dev, TimeStamp time) +{ + lastDeviceEventTime[XIAllDevices].time = currentTime; + lastDeviceEventTime[dev->id].time = currentTime; + + LastEventTimeToggleResetFlag(dev->id, TRUE); + LastEventTimeToggleResetFlag(XIAllDevices, TRUE); } static void -NoticeTime(InternalEvent *ev, DeviceIntPtr dev) +NoticeTimeMillis(const DeviceIntPtr dev, CARD32 *ms) { - if (ev->any.time < currentTime.milliseconds) - MonthChangedOrBadTime(ev); - currentTime.milliseconds = ev->any.time; - lastDeviceEventTime[XIAllDevices] = currentTime; - lastDeviceEventTime[dev->id] = currentTime; + TimeStamp time; + if (*ms < currentTime.milliseconds) + MonthChangedOrBadTime(ms); + time.months = currentTime.months; + time.milliseconds = *ms; + NoticeTime(dev, time); } void NoticeEventTime(InternalEvent *ev, DeviceIntPtr dev) { if (!syncEvents.playingEvents) - NoticeTime(ev, dev); + NoticeTimeMillis(dev, &ev->any.time); +} + +TimeStamp +LastEventTime(int 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); } /************************************************************************** @@ -1093,7 +1138,7 @@ EnqueueEvent(InternalEvent *ev, DeviceIntPtr device) if (!xorg_list_is_empty(&syncEvents.pending)) tail = xorg_list_last_entry(&syncEvents.pending, QdEventRec, next); - NoticeTime((InternalEvent *)event, device); + NoticeTimeMillis(device, &ev->any.time); /* Fix for key repeating bug. */ if (device->key != NULL && device->key->xkbInfo != NULL && @@ -5276,8 +5321,12 @@ InitEvents(void) inputInfo.pointer = (DeviceIntPtr) NULL; for (i = 0; i < MAXDEVICES; i++) { + DeviceIntRec dummy; memcpy(&event_filters[i], default_filter, sizeof(default_filter)); - lastDeviceEventTime[i] = currentTime; + + dummy.id = i; + NoticeTime(&dummy, currentTime); + LastEventTimeToggleResetFlag(i, FALSE); } syncEvents.replayDev = (DeviceIntPtr) NULL; diff --git a/dix/globals.c b/dix/globals.c index 332b91f5c..ad9145b01 100644 --- a/dix/globals.c +++ b/dix/globals.c @@ -122,7 +122,6 @@ Bool party_like_its_1989 = FALSE; Bool whiteRoot = FALSE; TimeStamp currentTime; -TimeStamp lastDeviceEventTime[MAXDEVICES]; int defaultColorVisualClass = -1; int monitorResolution = 0; diff --git a/dix/window.c b/dix/window.c index cff341b65..92df1eb4c 100644 --- a/dix/window.c +++ b/dix/window.c @@ -3089,9 +3089,7 @@ dixSaveScreens(ClientPtr client, int on, int mode) DeviceIntPtr dev; UpdateCurrentTimeIf(); nt_list_for_each_entry(dev, inputInfo.devices, next) - lastDeviceEventTime[dev->id] = currentTime; - lastDeviceEventTime[XIAllDevices] = currentTime; - lastDeviceEventTime[XIAllMasterDevices] = currentTime; + NoticeTime(dev, currentTime); } SetScreenSaverTimer(); } diff --git a/include/dix.h b/include/dix.h index 171e56e11..fa7ccd4a3 100644 --- a/include/dix.h +++ b/include/dix.h @@ -314,9 +314,20 @@ GetCurrentRootWindow(DeviceIntPtr pDev); extern _X_EXPORT WindowPtr GetSpriteWindow(DeviceIntPtr pDev); +extern _X_EXPORT void +NoticeTime(const DeviceIntPtr dev, + TimeStamp time); extern _X_EXPORT void 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 */ , diff --git a/include/dixstruct.h b/include/dixstruct.h index 0be7f0e27..7711cde99 100644 --- a/include/dixstruct.h +++ b/include/dixstruct.h @@ -144,7 +144,6 @@ typedef struct _WorkQueue { } WorkQueueRec; extern _X_EXPORT TimeStamp currentTime; -extern _X_EXPORT TimeStamp lastDeviceEventTime[MAXDEVICES]; extern _X_EXPORT int CompareTimeStamps(TimeStamp /*a */ , diff --git a/os/WaitFor.c b/os/WaitFor.c index 393890f19..c5f4cd78b 100644 --- a/os/WaitFor.c +++ b/os/WaitFor.c @@ -561,7 +561,7 @@ NextDPMSTimeout(INT32 timeout) static CARD32 ScreenSaverTimeoutExpire(OsTimerPtr timer, CARD32 now, pointer arg) { - INT32 timeout = now - lastDeviceEventTime[XIAllDevices].milliseconds; + INT32 timeout = now - LastEventTime(XIAllDevices).milliseconds; CARD32 nextTimeout = 0; #ifdef DPMSExtension diff --git a/os/xdmcp.c b/os/xdmcp.c index 0538ac53e..11f11333d 100644 --- a/os/xdmcp.c +++ b/os/xdmcp.c @@ -1391,7 +1391,7 @@ recv_alive_msg(unsigned length) if (SessionRunning && AliveSessionID == SessionID) { /* backoff dormancy period */ state = XDM_RUN_SESSION; - if ((GetTimeInMillis() - lastDeviceEventTime[XIAllDevices].milliseconds) > + if ((GetTimeInMillis() - LastEventTime(XIAllDevices).milliseconds) > keepaliveDormancy * 1000) { keepaliveDormancy <<= 1; if (keepaliveDormancy > XDM_MAX_DORMANCY)