114 Q_ASSERT(t->interval >= 20ms);
116 const auto timeoutInSecs = time_point_cast<seconds>(t->timeout);
118 auto recalculate = [&](
const milliseconds frac) {
119 t->timeout = timeoutInSecs + frac;
120 if (t->timeout < now)
121 t->timeout += t->interval;
125 milliseconds interval = roundToMillisecond(t->interval);
126 const milliseconds absMaxRounding = interval / 20;
128 auto fracMsec = duration_cast<milliseconds>(t->timeout - timeoutInSecs);
130 if (interval < 100ms && interval != 25ms && interval != 50ms && interval != 75ms) {
131 auto fracCount = fracMsec.count();
133 if (interval < 50ms) {
136 bool roundUp = (fracCount % 50) >= 25;
138 fracCount |= roundUp;
143 bool roundUp = (fracCount % 100) >= 50;
145 fracCount |= roundUp;
148 fracMsec = milliseconds{fracCount};
149 recalculate(fracMsec);
153 milliseconds min = std::max(0ms, fracMsec - absMaxRounding);
154 milliseconds max = std::min(1000ms, fracMsec + absMaxRounding);
161 recalculate(fracMsec);
163 }
else if (max == 1000ms) {
165 recalculate(fracMsec);
169 milliseconds wantedBoundaryMultiple{25};
175 if ((interval % 500) == 0ms) {
176 if (interval >= 5s) {
177 fracMsec = fracMsec >= 500ms ? max : min;
178 recalculate(fracMsec);
181 wantedBoundaryMultiple = 500ms;
183 }
else if ((interval % 50) == 0ms) {
185 milliseconds mult50 = interval / 50;
186 if ((mult50 % 4) == 0ms) {
188 wantedBoundaryMultiple = 200ms;
189 }
else if ((mult50 % 2) == 0ms) {
191 wantedBoundaryMultiple = 100ms;
192 }
else if ((mult50 % 5) == 0ms) {
194 wantedBoundaryMultiple = 250ms;
197 wantedBoundaryMultiple = 50ms;
201 milliseconds base = (fracMsec / wantedBoundaryMultiple) * wantedBoundaryMultiple;
202 milliseconds middlepoint = base + wantedBoundaryMultiple / 2;
203 if (fracMsec < middlepoint)
204 fracMsec = qMax(base, min);
206 fracMsec = qMin(base + wantedBoundaryMultiple, max);
208 recalculate(fracMsec);
213 switch (t->timerType) {
214 case Qt::PreciseTimer:
215 case Qt::CoarseTimer:
216 t->timeout += t->interval;
217 if (t->timeout < now) {
219 t->timeout += t->interval;
221 if (t->timerType == Qt::CoarseTimer)
222 calculateCoarseTimerTimeout(t, now);
225 case Qt::VeryCoarseTimer:
227 t->timeout += t->interval;
228 if (t->timeout <= now)
229 t->timeout = time_point_cast<seconds>(now + t->interval);
238std::optional<QTimerInfoList::Duration> QTimerInfoList::timerWait()
240 steady_clock::time_point now = updateCurrentTime();
242 auto isWaiting = [](QTimerInfo *tinfo) {
return !tinfo->activateRef; };
244 auto it = std::find_if(timers.cbegin(), timers.cend(), isWaiting);
245 if (it == timers.cend())
248 Duration timeToWait = (*it)->timeout - now;
249 if (timeToWait > 0ns)
250 return roundToMillisecond(timeToWait);
277void QTimerInfoList::registerTimer(Qt::TimerId timerId, QTimerInfoList::Duration interval,
278 Qt::TimerType timerType, QObject *object)
281 if (timerType == Qt::CoarseTimer) {
287 timerType = Qt::VeryCoarseTimer;
288 else if (interval <= 20ms)
289 timerType = Qt::PreciseTimer;
292 QTimerInfo *t =
new QTimerInfo(timerId, interval, timerType, object);
293 QTimerInfo::TimePoint expected = updateCurrentTime() + interval;
296 case Qt::PreciseTimer:
299 t->timeout = expected;
302 case Qt::CoarseTimer:
303 t->timeout = expected;
304 t->interval = roundToMillisecond(interval);
305 calculateCoarseTimerTimeout(t, currentTime);
308 case Qt::VeryCoarseTimer:
309 t->interval = roundToSecs(t->interval);
310 const auto currentTimeInSecs = floor<seconds>(currentTime);
311 t->timeout = currentTimeInSecs + t->interval;
313 if (currentTime - currentTimeInSecs > 500ms)
373int QTimerInfoList::activateTimers()
375 if (qt_disable_lowpriority_timers || timers.isEmpty())
378 firstTimerInfo =
nullptr;
380 const steady_clock::time_point now = updateCurrentTime();
383 auto stillActive = [&now](
const QTimerInfo *t) {
return now < t->timeout; };
385 auto it = std::find_if(timers.cbegin(), timers.cend(), stillActive);
386 auto maxCount = it - timers.cbegin();
391 if (timers.isEmpty())
394 QTimerInfo *currentTimerInfo = timers.constFirst();
395 if (now < currentTimerInfo->timeout)
398 if (!firstTimerInfo) {
399 firstTimerInfo = currentTimerInfo;
400 }
else if (firstTimerInfo == currentTimerInfo) {
403 }
else if (currentTimerInfo->interval < firstTimerInfo->interval
404 || currentTimerInfo->interval == firstTimerInfo->interval) {
405 firstTimerInfo = currentTimerInfo;
409 calculateNextTimeout(currentTimerInfo, now);
410 if (timers.size() > 1) {
413 auto afterCurrentIt = timers.begin() + 1;
414 auto iter = std::upper_bound(afterCurrentIt, timers.end(), currentTimerInfo, byTimeout);
415 currentTimerInfo = *std::rotate(timers.begin(), afterCurrentIt, iter);
418 if (currentTimerInfo->interval > 0ms)
422 if (!currentTimerInfo->activateRef) {
423 currentTimerInfo->activateRef = ¤tTimerInfo;
425 QTimerEvent e(currentTimerInfo->id);
426 QCoreApplication::sendEvent(currentTimerInfo->obj, &e);
431 if (currentTimerInfo)
432 currentTimerInfo->activateRef =
nullptr;
436 firstTimerInfo =
nullptr;