1// Copyright (C) 2022 The Qt Company Ltd.
2// Copyright (C) 2016 Intel Corporation.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
5#include "qtimer.h"
6#include "qtimer_p.h"
7#include "qsingleshottimer_p.h"
8
9#include "qabstracteventdispatcher.h"
10#include "qcoreapplication.h"
11#include "qcoreapplication_p.h"
12#include "qdeadlinetimer.h"
13#include "qmetaobject_p.h"
14#include "qobject_p.h"
15#include "qproperty_p.h"
16#include "qthread.h"
17
18using namespace std::chrono_literals;
19
20QT_BEGIN_NAMESPACE
21
22QTimerPrivate::~QTimerPrivate()
23 = default;
24
25/*!
26 \class QTimer
27 \inmodule QtCore
28 \brief The QTimer class provides repetitive and single-shot timers.
29
30 \ingroup events
31
32
33 The QTimer class provides a high-level programming interface for
34 timers. To use it, create a QTimer, connect its timeout() signal
35 to the appropriate slots, and call start(). From then on, it will
36 emit the timeout() signal at constant intervals.
37
38 Example for a one second (1000 millisecond) timer (from the
39 \l{widgets/analogclock}{Analog Clock} example):
40
41 \snippet ../widgets/widgets/analogclock/analogclock.cpp 4
42 \snippet ../widgets/widgets/analogclock/analogclock.cpp 5
43 \snippet ../widgets/widgets/analogclock/analogclock.cpp 6
44
45 From then on, the \c update() slot is called every second.
46
47 You can set a timer to time out only once by calling
48 setSingleShot(true). You can also use the static
49 QTimer::singleShot() function to call a slot after a specified
50 interval:
51
52 \snippet timers/timers.cpp 3
53
54 In multithreaded applications, you can use QTimer in any thread
55 that has an event loop. To start an event loop from a non-GUI
56 thread, use QThread::exec(). Qt uses the timer's
57 \l{QObject::thread()}{thread affinity} to determine which thread
58 will emit the \l{QTimer::}{timeout()} signal. Because of this, you
59 must start and stop the timer in its thread; it is not possible to
60 start a timer from another thread.
61
62 As a special case, a QTimer with a timeout of 0 will time out as soon as
63 possible, though the ordering between zero timers and other sources of
64 events is unspecified. Zero timers can be used to do some work while still
65 providing a snappy user interface:
66
67 \snippet timers/timers.cpp 4
68 \snippet timers/timers.cpp 5
69 \snippet timers/timers.cpp 6
70
71 From then on, \c processOneThing() will be called repeatedly. It
72 should be written in such a way that it always returns quickly
73 (typically after processing one data item) so that Qt can deliver
74 events to the user interface and stop the timer as soon as it has done all
75 its work. This is the traditional way of implementing heavy work
76 in GUI applications, but as multithreading is nowadays becoming available on
77 more and more platforms, we expect that zero-millisecond
78 QTimer objects will gradually be replaced by \l{QThread}s.
79
80 \section1 Accuracy and Timer Resolution
81
82 The accuracy of timers depends on the underlying operating system
83 and hardware. Most platforms support a resolution of 1 millisecond,
84 though the accuracy of the timer will not equal this resolution
85 in many real-world situations.
86
87 The accuracy also depends on the \l{Qt::TimerType}{timer type}. For
88 Qt::PreciseTimer, QTimer will try to keep the accuracy at 1 millisecond.
89 Precise timers will also never time out earlier than expected.
90
91 For Qt::CoarseTimer and Qt::VeryCoarseTimer types, QTimer may wake up
92 earlier than expected, within the margins for those types: 5% of the
93 interval for Qt::CoarseTimer and 500 ms for Qt::VeryCoarseTimer.
94
95 All timer types may time out later than expected if the system is busy or
96 unable to provide the requested accuracy. In such a case of timeout
97 overrun, Qt will emit timeout() only once, even if multiple timeouts have
98 expired, and then will resume the original interval.
99
100 \section1 Alternatives to QTimer
101
102 Qt 6.8 introduced QChronoTimer. The main difference between the two
103 classes, is that QChronoTimer supports a larger interval range and a
104 higher precision (\c std::chrono::nanoseconds). For QTimer the maximum
105 supported interval is ±24 days, whereas for QChronoTimer it is ±292
106 years (less chances of interger overflow with intervals longer than
107 \c std::numeric_limits<int>::max()). If you only need millisecond
108 resolution and ±24 days range, you can continue to use QTimer.
109
110 \include timers-common.qdocinc q-chrono-timer-alternatives
111
112 Some operating systems limit the number of timers that may be
113 used; Qt tries to work around these limitations.
114
115 \sa QBasicTimer, QTimerEvent, QObject::timerEvent(), Timers,
116 {Analog Clock}
117*/
118
119/*!
120 Constructs a timer with the given \a parent.
121*/
122
123QTimer::QTimer(QObject *parent)
124 : QObject(*new QTimerPrivate(this), parent)
125{
126 Q_ASSERT(d_func()->isQTimer);
127}
128
129
130/*!
131 Destroys the timer.
132*/
133
134QTimer::~QTimer()
135{
136 if (d_func()->isActive()) // stop running timer
137 stop();
138}
139
140
141/*!
142 \fn void QTimer::timeout()
143
144 This signal is emitted when the timer times out.
145
146 \sa interval, start(), stop()
147*/
148
149/*!
150 \property QTimer::active
151 \since 4.3
152
153 This boolean property is \c true if the timer is running; otherwise
154 false.
155*/
156
157/*!
158 \fn bool QTimer::isActive() const
159
160 Returns \c true if the timer is running; otherwise returns \c false.
161*/
162bool QTimer::isActive() const
163{
164 return d_func()->isActiveData.value();
165}
166
167QBindable<bool> QTimer::bindableActive()
168{
169 return QBindable<bool>(&d_func()->isActiveData);
170}
171
172/*!
173 \fn int QTimer::timerId() const
174
175 Returns the ID of the timer if the timer is running; otherwise returns
176 -1.
177*/
178int QTimer::timerId() const
179{
180 auto v = qToUnderlying(e: id());
181 return v == 0 ? -1 : v;
182}
183
184/*!
185 \since 6.8
186 Returns a Qt::TimerId representing the timer ID if the timer is running;
187 otherwise returns \c Qt::TimerId::Invalid.
188
189 \sa Qt::TimerId
190*/
191Qt::TimerId QTimer::id() const
192{
193 return d_func()->id;
194}
195
196/*! \overload start()
197
198 Starts or restarts the timer with the timeout specified in \l interval.
199
200//! [stop-restart-timer]
201 If the timer is already running, it will be
202 \l{QTimer::stop()}{stopped} and restarted. This will also change its id().
203//! [stop-restart-timer]
204
205//! [singleshot-activation]
206 If \l singleShot is true, the timer will be activated only once.
207//! [singleshot-activation]
208*/
209void QTimer::start()
210{
211 Q_D(QTimer);
212 if (d->isActive()) // stop running timer
213 stop();
214
215 Qt::TimerId newId{ QObject::startTimer(time: d->inter * 1ms, timerType: d->type) }; // overflow impossible
216 if (newId > Qt::TimerId::Invalid) {
217 d->id = newId;
218 d->isActiveData.notify();
219 }
220}
221
222/*!
223 Starts or restarts the timer with a timeout interval of \a msec
224 milliseconds.
225
226 This is equivalent to:
227
228 \code
229 timer.setInterval(msec);
230 timer.start();
231 \endcode
232
233 \include qtimer.cpp stop-restart-timer
234
235 \include qtimer.cpp singleshot-activation
236
237 \include timers-common.qdocinc negative-intervals-not-allowed
238
239 \note Keeping the event loop busy with a zero-timer is bound to
240 cause trouble and highly erratic behavior of the UI.
241*/
242void QTimer::start(int msec)
243{
244 start(value: msec * 1ms);
245}
246
247static std::chrono::milliseconds
248checkInterval(const char *caller, std::chrono::milliseconds interval)
249{
250 constexpr auto maxInterval = INT_MAX * 1ms;
251 if (interval < 0ms) {
252 qWarning(msg: "%s: negative intervals aren't allowed; the interval will be set to 1ms.", caller);
253 interval = 1ms;
254 } else if (interval > maxInterval) {
255 qWarning(msg: "%s: interval exceeds maximum allowed interval, it will be clamped to "
256 "INT_MAX ms (about 24 days).", caller);
257 interval = maxInterval;
258 }
259 return interval;
260}
261
262/*!
263 \since 5.8
264 \overload
265
266 Starts or restarts the timer with a timeout of duration \a interval milliseconds.
267
268 This is equivalent to:
269
270 \code
271 timer.setInterval(interval);
272 timer.start();
273 \endcode
274
275 \include qtimer.cpp stop-restart-timer
276
277 \include qtimer.cpp singleshot-activation
278
279 \include timers-common.qdocinc negative-intervals-not-allowed
280*/
281void QTimer::start(std::chrono::milliseconds interval)
282{
283 Q_D(QTimer);
284
285 interval = checkInterval(caller: "QTimer::start", interval);
286 const int msec = interval.count();
287 const bool intervalChanged = msec != d->inter;
288 d->inter.setValue(msec);
289 start();
290 if (intervalChanged)
291 d->inter.notify();
292}
293
294
295
296/*!
297 Stops the timer.
298
299 \sa start()
300*/
301
302void QTimer::stop()
303{
304 Q_D(QTimer);
305 if (d->isActive()) {
306 QObject::killTimer(id: d->id);
307 d->id = Qt::TimerId::Invalid;
308 d->isActiveData.notify();
309 }
310}
311
312
313/*!
314 \reimp
315*/
316void QTimer::timerEvent(QTimerEvent *e)
317{
318 Q_D(QTimer);
319 if (e->id() == d->id) {
320 if (d->single)
321 stop();
322 emit timeout(QPrivateSignal());
323 }
324}
325
326QAbstractEventDispatcher::Duration // statically asserts that Duration is nanoseconds
327QTimer::from_msecs(std::chrono::milliseconds ms)
328{
329 using Duration = QAbstractEventDispatcher::Duration;
330
331 using namespace std::chrono;
332 using ratio = std::ratio_divide<std::milli, Duration::period>;
333 static_assert(ratio::den == 1);
334
335 Duration::rep r;
336 if (qMulOverflow<ratio::num>(v1: ms.count(), r: &r)) {
337 qWarning(msg: "QTimer::singleShot(std::chrono::milliseconds, ...): "
338 "interval argument overflowed when converted to nanoseconds.");
339 return Duration::max();
340 }
341 return Duration{r};
342}
343
344/*!
345 \internal
346
347 Implementation of the template version of singleShot
348
349 \a msec is the timer interval
350 \a timerType is the timer type
351 \a receiver is the receiver object, can be null. In such a case, it will be the same
352 as the final sender class.
353 \a slotObj the slot object
354*/
355void QTimer::singleShotImpl(std::chrono::nanoseconds ns, Qt::TimerType timerType,
356 const QObject *receiver,
357 QtPrivate::QSlotObjectBase *slotObj)
358{
359 if (ns == 0ns) {
360 bool deleteReceiver = false;
361 // Optimize: set a receiver context when none is given, such that we can use
362 // QMetaObject::invokeMethod which is more efficient than going through a timer.
363 // We need a QObject living in the current thread. But the QThread itself lives
364 // in a different thread - with the exception of the main QThread which lives in
365 // itself. And QThread::currentThread() is among the few QObjects we know that will
366 // most certainly be there. Note that one can actually call singleShot before the
367 // QApplication is created!
368 if (!receiver && QThread::currentThread() == QCoreApplicationPrivate::mainThread()) {
369 // reuse main thread as context object
370 receiver = QThread::currentThread();
371 } else if (!receiver) {
372 // Create a receiver context object on-demand. According to the benchmarks,
373 // this is still more efficient than going through a timer.
374 receiver = new QObject;
375 deleteReceiver = true;
376 }
377
378 auto h = QtPrivate::invokeMethodHelper(r: {});
379 QMetaObject::invokeMethodImpl(object: const_cast<QObject *>(receiver), slotObj,
380 type: Qt::QueuedConnection, parameterCount: h.parameterCount(), params: h.parameters.data(), names: h.typeNames.data(),
381 metaTypes: h.metaTypes.data());
382
383 if (deleteReceiver)
384 const_cast<QObject *>(receiver)->deleteLater();
385 return;
386 }
387
388 (void) new QSingleShotTimer(ns, timerType, receiver, slotObj);
389}
390
391/*!
392 \fn void QTimer::singleShot(int msec, const QObject *receiver, const char *member)
393 \reentrant
394 \deprecated [6.8] Use the chrono overloads.
395 This static function calls a slot after a given time interval.
396
397 It is very convenient to use this function because you do not need
398 to bother with a \l{QObject::timerEvent()}{timerEvent} or
399 create a local QTimer object.
400
401 Example:
402 \snippet code/src_corelib_kernel_qtimer.cpp 0
403
404 This sample program automatically terminates after 10 minutes
405 (600,000 milliseconds).
406
407 The \a receiver is the receiving object and the \a member is the
408 slot. The time interval is \a msec milliseconds.
409
410 \include timers-common.qdocinc negative-intervals-not-allowed
411
412 \sa start()
413*/
414
415/*!
416 \fn void QTimer::singleShot(int msec, Qt::TimerType timerType, const QObject *receiver, const char *member)
417 \overload
418 \reentrant
419 \deprecated [6.8] Use the chrono overloads.
420 This static function calls a slot after a given time interval.
421
422 It is very convenient to use this function because you do not need
423 to bother with a \l{QObject::timerEvent()}{timerEvent} or
424 create a local QTimer object.
425
426 The \a receiver is the receiving object and the \a member is the slot. The
427 time interval is \a msec milliseconds. The \a timerType affects the
428 accuracy of the timer.
429
430 \include timers-common.qdocinc negative-intervals-not-allowed
431
432 \sa start()
433*/
434
435void QTimer::singleShot(std::chrono::nanoseconds ns, Qt::TimerType timerType,
436 const QObject *receiver, const char *member)
437{
438 if (ns < 0ns) {
439 qWarning(msg: "QTimer::singleShot: negative intervals aren't allowed; the "
440 "interval will be set to 1ms.");
441 ns = 1ms;
442 }
443 if (receiver && member) {
444 if (ns == 0ns) {
445 // special code shortpath for 0-timers
446 const char* bracketPosition = strchr(s: member, c: '(');
447 if (!bracketPosition || !(member[0] >= '0' && member[0] <= '2')) {
448 qWarning(msg: "QTimer::singleShot: Invalid slot specification");
449 return;
450 }
451 const auto methodName = QByteArrayView(member + 1, // extract method name
452 bracketPosition - 1 - member).trimmed();
453 QMetaObject::invokeMethod(obj: const_cast<QObject *>(receiver), member: methodName.toByteArray().constData(),
454 c: Qt::QueuedConnection);
455 return;
456 }
457 (void) new QSingleShotTimer(ns, timerType, receiver, member);
458 }
459}
460
461/*! \fn template<typename Duration, typename Functor> void QTimer::singleShot(Duration interval, const QObject *context, Functor &&functor)
462 \fn template<typename Duration, typename Functor> void QTimer::singleShot(Duration interval, Qt::TimerType timerType, const QObject *context, Functor &&functor)
463 \fn template<typename Duration, typename Functor> void QTimer::singleShot(Duration interval, Functor &&functor)
464 \fn template<typename Duration, typename Functor> void QTimer::singleShot(Duration interval, Qt::TimerType timerType, Functor &&functor)
465 \since 5.4
466
467 \reentrant
468 This static function calls \a functor after \a interval.
469
470 It is very convenient to use this function because you do not need
471 to bother with a \l{QObject::timerEvent()}{timerEvent} or
472 create a local QTimer object.
473
474 If \a context is specified, then the \a functor will be called only if the
475 \a context object has not been destroyed before the interval occurs. The functor
476 will then be run the thread of \a context. The context's thread must have a
477 running Qt event loop.
478
479 If \a functor is a member
480 function of \a context, then the function will be called on the object.
481
482 The \a interval parameter can be an \c int (interpreted as a millisecond
483 count) or a \c std::chrono type that implicitly converts to nanoseconds.
484
485 \include timers-common.qdocinc negative-intervals-not-allowed
486
487 \note In Qt versions prior to 6.8, the chrono overloads took chrono::milliseconds,
488 not chrono::nanoseconds. The compiler will automatically convert for you,
489 but the conversion may overflow for extremely large milliseconds counts.
490
491 \sa start()
492*/
493
494/*!
495 \fn void QTimer::singleShot(std::chrono::nanoseconds nsec, const QObject *receiver, const char *member)
496 \since 5.8
497 \overload
498 \reentrant
499
500 This static function calls a slot after a given time interval.
501
502 It is very convenient to use this function because you do not need
503 to bother with a \l{QObject::timerEvent()}{timerEvent} or
504 create a local QTimer object.
505
506 The \a receiver is the receiving object and the \a member is the slot. The
507 time interval is given in the duration object \a nsec.
508
509 \include timers-common.qdocinc negative-intervals-not-allowed
510
511//! [qtimer-ns-overflow]
512 \note In Qt versions prior to 6.8, this function took chrono::milliseconds,
513 not chrono::nanoseconds. The compiler will automatically convert for you,
514 but the conversion may overflow for extremely large milliseconds counts.
515//! [qtimer-ns-overflow]
516
517 \sa start()
518*/
519
520/*!
521 \fn void QTimer::singleShot(std::chrono::nanoseconds nsec, Qt::TimerType timerType, const QObject *receiver, const char *member)
522 \since 5.8
523 \overload
524 \reentrant
525
526 This static function calls a slot after a given time interval.
527
528 It is very convenient to use this function because you do not need
529 to bother with a \l{QObject::timerEvent()}{timerEvent} or
530 create a local QTimer object.
531
532 The \a receiver is the receiving object and the \a member is the slot. The
533 time interval is given in the duration object \a nsec. The \a timerType affects the
534 accuracy of the timer.
535
536
537 \include timers-common.qdocinc negative-intervals-not-allowed
538
539 \include qtimer.cpp qtimer-ns-overflow
540
541 \sa start()
542*/
543
544/*!
545 \fn template <typename Functor> QMetaObject::Connection QTimer::callOnTimeout(Functor &&slot)
546 \since 5.12
547
548 Creates a connection from the timer's timeout() signal to \a slot.
549 Returns a handle to the connection.
550
551 This method is provided for convenience. It's equivalent to calling:
552 \code
553 QObject::connect(timer, &QTimer::timeout, timer, slot, Qt::DirectConnection);
554 \endcode
555
556 \note This overload is not available when \c {QT_NO_CONTEXTLESS_CONNECT} is
557 defined, instead use the callOnTimeout() overload that takes a context object.
558
559 \sa QObject::connect(), timeout()
560*/
561
562/*!
563 \fn template <typename Functor> QMetaObject::Connection QTimer::callOnTimeout(const QObject *context, Functor &&slot, Qt::ConnectionType connectionType = Qt::AutoConnection)
564 \since 5.12
565 \overload callOnTimeout()
566
567 Creates a connection from the timeout() signal to \a slot to be placed in a specific
568 event loop of \a context, and returns a handle to the connection.
569
570 This method is provided for convenience. It's equivalent to calling:
571 \code
572 QObject::connect(timer, &QTimer::timeout, context, slot, connectionType);
573 \endcode
574
575 \sa QObject::connect(), timeout()
576*/
577
578/*!
579 \fn std::chrono::milliseconds QTimer::intervalAsDuration() const
580 \since 5.8
581
582 Returns the interval of this timer as a \c std::chrono::milliseconds object.
583
584 \sa interval
585*/
586
587/*!
588 \fn std::chrono::milliseconds QTimer::remainingTimeAsDuration() const
589 \since 5.8
590
591 Returns the time remaining in this timer object as a \c
592 std::chrono::milliseconds object. If this timer is due or overdue, the
593 returned value is \c std::chrono::milliseconds::zero(). If the remaining
594 time could not be found or the timer is not running, this function returns a
595 negative duration.
596
597 \sa remainingTime()
598*/
599
600/*!
601 \property QTimer::singleShot
602 \brief whether the timer is a single-shot timer
603
604 A single-shot timer fires only once, non-single-shot timers fire
605 every \l interval milliseconds.
606
607 The default value for this property is \c false.
608
609 \sa interval, singleShot()
610*/
611void QTimer::setSingleShot(bool singleShot)
612{
613 d_func()->single = singleShot;
614}
615
616bool QTimer::isSingleShot() const
617{
618 return d_func()->single;
619}
620
621QBindable<bool> QTimer::bindableSingleShot()
622{
623 return QBindable<bool>(&d_func()->single);
624}
625
626/*!
627 \property QTimer::interval
628 \brief the timeout interval in milliseconds
629
630 The default value for this property is 0. A QTimer with a timeout
631 interval of 0 will time out as soon as all the events in the window
632 system's event queue have been processed.
633
634 Setting the interval of a running timer will change the interval,
635 stop() and then start() the timer, and acquire a new id().
636 If the timer is not running, only the interval is changed.
637
638 \include timers-common.qdocinc negative-intervals-not-allowed
639
640 \sa singleShot
641*/
642void QTimer::setInterval(int msec)
643{
644 setInterval(std::chrono::milliseconds{msec});
645}
646
647void QTimer::setInterval(std::chrono::milliseconds interval)
648{
649 Q_D(QTimer);
650
651 interval = checkInterval(caller: "QTimer::setInterval", interval);
652 const int msec = interval.count();
653 d->inter.removeBindingUnlessInWrapper();
654 const bool intervalChanged = msec != d->inter.valueBypassingBindings();
655 d->inter.setValueBypassingBindings(msec);
656 if (d->isActive()) { // create new timer
657 QObject::killTimer(id: d->id); // restart timer
658 Qt::TimerId newId{ QObject::startTimer(time: msec * 1ms, timerType: d->type) }; // overflow impossible
659 if (newId > Qt::TimerId::Invalid) {
660 // Restarted successfully. No need to update the active state.
661 d->id = newId;
662 } else {
663 // Failed to start the timer.
664 // Need to notify about active state change.
665 d->id = Qt::TimerId::Invalid;
666 d->isActiveData.notify();
667 }
668 }
669 if (intervalChanged)
670 d->inter.notify();
671}
672
673int QTimer::interval() const
674{
675 return d_func()->inter;
676}
677
678QBindable<int> QTimer::bindableInterval()
679{
680 return QBindable<int>(&d_func()->inter);
681}
682
683/*!
684 \property QTimer::remainingTime
685 \since 5.0
686 \brief the remaining time in milliseconds
687
688 Returns the timer's remaining value in milliseconds left until the timeout.
689 If the timer is inactive, the returned value will be -1. If the timer is
690 overdue, the returned value will be 0.
691
692 \sa interval
693*/
694int QTimer::remainingTime() const
695{
696 Q_D(const QTimer);
697 if (d->isActive()) {
698 using namespace std::chrono;
699 auto remaining = QAbstractEventDispatcher::instance()->remainingTime(timerId: d->id);
700 return ceil<milliseconds>(d: remaining).count();
701 }
702
703 return -1;
704}
705
706/*!
707 \property QTimer::timerType
708 \brief controls the accuracy of the timer
709
710 The default value for this property is \c Qt::CoarseTimer.
711
712 \sa Qt::TimerType
713*/
714void QTimer::setTimerType(Qt::TimerType atype)
715{
716 d_func()->type = atype;
717}
718
719Qt::TimerType QTimer::timerType() const
720{
721 return d_func()->type;
722}
723
724QBindable<Qt::TimerType> QTimer::bindableTimerType()
725{
726 return QBindable<Qt::TimerType>(&d_func()->type);
727}
728
729QT_END_NAMESPACE
730
731#include "moc_qtimer.cpp"
732

source code of qtbase/src/corelib/kernel/qtimer.cpp