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