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