115 Q_ASSERT(t->interval >= 20ms);
117 const auto timeoutInSecs = time_point_cast<seconds>(t->timeout);
119 auto recalculate = [&](
const milliseconds frac) {
120 t->timeout = timeoutInSecs + frac;
121 if (t->timeout < now)
122 t->timeout += t->interval;
126 milliseconds interval = roundToMillisecond(t->interval);
127 const milliseconds absMaxRounding = interval / 20;
129 auto fracMsec = duration_cast<milliseconds>(t->timeout - timeoutInSecs);
131 if (interval < 100ms && interval != 25ms && interval != 50ms && interval != 75ms) {
132 auto fracCount = fracMsec.count();
134 if (interval < 50ms) {
137 bool roundUp = (fracCount % 50) >= 25;
139 fracCount |= roundUp;
144 bool roundUp = (fracCount % 100) >= 50;
146 fracCount |= roundUp;
149 fracMsec = milliseconds{fracCount};
150 recalculate(fracMsec);
154 milliseconds min = std::max(0ms, fracMsec - absMaxRounding);
155 milliseconds max = std::min(1000ms, fracMsec + absMaxRounding);
162 recalculate(fracMsec);
164 }
else if (max == 1000ms) {
166 recalculate(fracMsec);
170 milliseconds wantedBoundaryMultiple{25};
176 if ((interval % 500) == 0ms) {
177 if (interval >= 5s) {
178 fracMsec = fracMsec >= 500ms ? max : min;
179 recalculate(fracMsec);
182 wantedBoundaryMultiple = 500ms;
184 }
else if ((interval % 50) == 0ms) {
186 milliseconds mult50 = interval / 50;
187 if ((mult50 % 4) == 0ms) {
189 wantedBoundaryMultiple = 200ms;
190 }
else if ((mult50 % 2) == 0ms) {
192 wantedBoundaryMultiple = 100ms;
193 }
else if ((mult50 % 5) == 0ms) {
195 wantedBoundaryMultiple = 250ms;
198 wantedBoundaryMultiple = 50ms;
202 milliseconds base = (fracMsec / wantedBoundaryMultiple) * wantedBoundaryMultiple;
203 milliseconds middlepoint = base + wantedBoundaryMultiple / 2;
204 if (fracMsec < middlepoint)
205 fracMsec = qMax(base, min);
207 fracMsec = qMin(base + wantedBoundaryMultiple, max);
209 recalculate(fracMsec);
214 switch (t->timerType) {
215 case Qt::PreciseTimer:
216 case Qt::CoarseTimer:
217 t->timeout += t->interval;
218 if (t->timeout < now) {
220 t->timeout += t->interval;
222 if (t->timerType == Qt::CoarseTimer)
223 calculateCoarseTimerTimeout(t, now);
226 case Qt::VeryCoarseTimer:
228 t->timeout += t->interval;
229 if (t->timeout <= now)
230 t->timeout = time_point_cast<seconds>(now + t->interval);
239std::optional<QTimerInfoList::Duration> QTimerInfoList::timerWait()
241 steady_clock::time_point now = updateCurrentTime();
243 auto isWaiting = [](QTimerInfo *tinfo) {
return !tinfo->activateRef; };
245 auto it = std::find_if(timers.cbegin(), timers.cend(), isWaiting);
246 if (it == timers.cend())
249 Duration timeToWait = (*it)->timeout - now;
250 if (timeToWait > 0ns)
251 return roundToMillisecond(timeToWait);
278void QTimerInfoList::registerTimer(Qt::TimerId timerId, QTimerInfoList::Duration interval,
279 Qt::TimerType timerType, QObject *object)
282 if (timerType == Qt::CoarseTimer) {
288 timerType = Qt::VeryCoarseTimer;
289 else if (interval <= 20ms)
290 timerType = Qt::PreciseTimer;
293 QTimerInfo *t =
new QTimerInfo(timerId, interval, timerType, object);
294 QTimerInfo::TimePoint expected = updateCurrentTime() + interval;
297 case Qt::PreciseTimer:
300 t->timeout = expected;
303 case Qt::CoarseTimer:
304 t->timeout = expected;
305 t->interval = roundToMillisecond(interval);
306 calculateCoarseTimerTimeout(t, currentTime);
309 case Qt::VeryCoarseTimer:
310 t->interval = roundToSecs(t->interval);
311 const auto currentTimeInSecs = floor<seconds>(currentTime);
312 t->timeout = currentTimeInSecs + t->interval;
314 if (currentTime - currentTimeInSecs > 500ms)
374int QTimerInfoList::activateTimers()
376 if (qt_disable_lowpriority_timers || timers.isEmpty())
379 firstTimerInfo =
nullptr;
381 const steady_clock::time_point now = updateCurrentTime();
384 auto stillActive = [&now](
const QTimerInfo *t) {
return now < t->timeout; };
386 auto it = std::find_if(timers.cbegin(), timers.cend(), stillActive);
387 auto maxCount = it - timers.cbegin();
392 if (timers.isEmpty())
395 QTimerInfo *currentTimerInfo = timers.constFirst();
396 if (now < currentTimerInfo->timeout)
399 if (!firstTimerInfo) {
400 firstTimerInfo = currentTimerInfo;
401 }
else if (firstTimerInfo == currentTimerInfo) {
404 }
else if (currentTimerInfo->interval < firstTimerInfo->interval
405 || currentTimerInfo->interval == firstTimerInfo->interval) {
406 firstTimerInfo = currentTimerInfo;
410 calculateNextTimeout(currentTimerInfo, now);
411 if (timers.size() > 1) {
414 auto afterCurrentIt = timers.begin() + 1;
415 auto iter = std::upper_bound(afterCurrentIt, timers.end(), currentTimerInfo, byTimeout);
416 currentTimerInfo = *std::rotate(timers.begin(), afterCurrentIt, iter);
419 if (currentTimerInfo->interval > 0ms)
423 if (!currentTimerInfo->activateRef) {
424 currentTimerInfo->activateRef = ¤tTimerInfo;
426 QTimerEvent e(currentTimerInfo->id);
427 QCoreApplication::sendEvent(currentTimerInfo->obj, &e);
432 if (currentTimerInfo)
433 currentTimerInfo->activateRef =
nullptr;
437 firstTimerInfo =
nullptr;