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 \include qtimer.cpp stop-restart-timer
227
228 \include qtimer.cpp singleshot-activation
229 This is equivalent to:
230
231 \code
232 timer.setInterval(msec);
233 timer.start();
234 \endcode
235
236 \note Keeping the event loop busy with a zero-timer is bound to
237 cause trouble and highly erratic behavior of the UI.
238*/
239void QTimer::start(int msec)
240{
241 start(value: msec * 1ms);
242}
243
244void QTimer::start(std::chrono::milliseconds interval)
245{
246 Q_D(QTimer);
247 // This could be narrowing as the interval is stored in an `int` QProperty,
248 // and the type can't be changed in Qt6.
249 const int msec = interval.count();
250 const bool intervalChanged = msec != d->inter;
251 d->inter.setValue(msec);
252 start();
253 if (intervalChanged)
254 d->inter.notify();
255}
256
257
258
259/*!
260 Stops the timer.
261
262 \sa start()
263*/
264
265void QTimer::stop()
266{
267 Q_D(QTimer);
268 if (d->isActive()) {
269 QObject::killTimer(id: d->id);
270 d->id = Qt::TimerId::Invalid;
271 d->isActiveData.notify();
272 }
273}
274
275
276/*!
277 \reimp
278*/
279void QTimer::timerEvent(QTimerEvent *e)
280{
281 Q_D(QTimer);
282 if (Qt::TimerId{e->timerId()} == d->id) {
283 if (d->single)
284 stop();
285 emit timeout(QPrivateSignal());
286 }
287}
288
289QAbstractEventDispatcher::Duration // statically asserts that Duration is nanoseconds
290QTimer::from_msecs(std::chrono::milliseconds ms)
291{
292 using Duration = QAbstractEventDispatcher::Duration;
293
294 using namespace std::chrono;
295 using ratio = std::ratio_divide<std::milli, Duration::period>;
296 static_assert(ratio::den == 1);
297
298 Duration::rep r;
299 if (qMulOverflow<ratio::num>(v1: ms.count(), r: &r)) {
300 qWarning(msg: "QTimer::singleShot(std::chrono::milliseconds, ...): "
301 "interval argument overflowed when converted to nanoseconds.");
302 return Duration::max();
303 }
304 return Duration{r};
305}
306
307/*!
308 \internal
309
310 Implementation of the template version of singleShot
311
312 \a msec is the timer interval
313 \a timerType is the timer type
314 \a receiver is the receiver object, can be null. In such a case, it will be the same
315 as the final sender class.
316 \a slotObj the slot object
317*/
318void QTimer::singleShotImpl(std::chrono::nanoseconds ns, Qt::TimerType timerType,
319 const QObject *receiver,
320 QtPrivate::QSlotObjectBase *slotObj)
321{
322 if (ns == 0ns) {
323 bool deleteReceiver = false;
324 // Optimize: set a receiver context when none is given, such that we can use
325 // QMetaObject::invokeMethod which is more efficient than going through a timer.
326 // We need a QObject living in the current thread. But the QThread itself lives
327 // in a different thread - with the exception of the main QThread which lives in
328 // itself. And QThread::currentThread() is among the few QObjects we know that will
329 // most certainly be there. Note that one can actually call singleShot before the
330 // QApplication is created!
331 if (!receiver && QThread::currentThread() == QCoreApplicationPrivate::mainThread()) {
332 // reuse main thread as context object
333 receiver = QThread::currentThread();
334 } else if (!receiver) {
335 // Create a receiver context object on-demand. According to the benchmarks,
336 // this is still more efficient than going through a timer.
337 receiver = new QObject;
338 deleteReceiver = true;
339 }
340
341 auto h = QtPrivate::invokeMethodHelper(r: {});
342 QMetaObject::invokeMethodImpl(object: const_cast<QObject *>(receiver), slotObj,
343 type: Qt::QueuedConnection, parameterCount: h.parameterCount(), params: h.parameters.data(), names: h.typeNames.data(),
344 metaTypes: h.metaTypes.data());
345
346 if (deleteReceiver)
347 const_cast<QObject *>(receiver)->deleteLater();
348 return;
349 }
350
351 (void) new QSingleShotTimer(ns, timerType, receiver, slotObj);
352}
353
354/*!
355 \fn void QTimer::singleShot(int msec, const QObject *receiver, const char *member)
356 \reentrant
357 \deprecated [6.8] Use the chrono overloads.
358 This static function calls a slot after a given time interval.
359
360 It is very convenient to use this function because you do not need
361 to bother with a \l{QObject::timerEvent()}{timerEvent} or
362 create a local QTimer object.
363
364 Example:
365 \snippet code/src_corelib_kernel_qtimer.cpp 0
366
367 This sample program automatically terminates after 10 minutes
368 (600,000 milliseconds).
369
370 The \a receiver is the receiving object and the \a member is the
371 slot. The time interval is \a msec milliseconds.
372
373 \sa start()
374*/
375
376/*!
377 \fn void QTimer::singleShot(int msec, Qt::TimerType timerType, const QObject *receiver, const char *member)
378 \overload
379 \reentrant
380 \deprecated [6.8] Use the chrono overloads.
381 This static function calls a slot after a given time interval.
382
383 It is very convenient to use this function because you do not need
384 to bother with a \l{QObject::timerEvent()}{timerEvent} or
385 create a local QTimer object.
386
387 The \a receiver is the receiving object and the \a member is the slot. The
388 time interval is \a msec milliseconds. The \a timerType affects the
389 accuracy of the timer.
390
391 \sa start()
392*/
393
394void QTimer::singleShot(std::chrono::nanoseconds ns, Qt::TimerType timerType,
395 const QObject *receiver, const char *member)
396{
397 if (ns < 0ns) {
398 qWarning(msg: "QTimer::singleShot: Timers cannot have negative timeouts");
399 return;
400 }
401 if (receiver && member) {
402 if (ns == 0ns) {
403 // special code shortpath for 0-timers
404 const char* bracketPosition = strchr(s: member, c: '(');
405 if (!bracketPosition || !(member[0] >= '0' && member[0] <= '2')) {
406 qWarning(msg: "QTimer::singleShot: Invalid slot specification");
407 return;
408 }
409 const auto methodName = QByteArrayView(member + 1, // extract method name
410 bracketPosition - 1 - member).trimmed();
411 QMetaObject::invokeMethod(obj: const_cast<QObject *>(receiver), member: methodName.toByteArray().constData(),
412 c: Qt::QueuedConnection);
413 return;
414 }
415 (void) new QSingleShotTimer(ns, timerType, receiver, member);
416 }
417}
418
419/*! \fn template<typename Duration, typename Functor> void QTimer::singleShot(Duration interval, const QObject *context, Functor &&functor)
420 \fn template<typename Duration, typename Functor> void QTimer::singleShot(Duration interval, Qt::TimerType timerType, const QObject *context, Functor &&functor)
421 \fn template<typename Duration, typename Functor> void QTimer::singleShot(Duration interval, Functor &&functor)
422 \fn template<typename Duration, typename Functor> void QTimer::singleShot(Duration interval, Qt::TimerType timerType, Functor &&functor)
423 \since 5.4
424
425 \reentrant
426 This static function calls \a functor after \a interval.
427
428 It is very convenient to use this function because you do not need
429 to bother with a \l{QObject::timerEvent()}{timerEvent} or
430 create a local QTimer object.
431
432 If \a context is specified, then the \a functor will be called only if the
433 \a context object has not been destroyed before the interval occurs. The functor
434 will then be run the thread of \a context. The context's thread must have a
435 running Qt event loop.
436
437 If \a functor is a member
438 function of \a context, then the function will be called on the object.
439
440 The \a interval parameter can be an \c int (interpreted as a millisecond
441 count) or a \c std::chrono type that implicitly converts to nanoseconds.
442
443 \note In Qt versions prior to 6.8, the chrono overloads took chrono::milliseconds,
444 not chrono::nanoseconds. The compiler will automatically convert for you,
445 but the conversion may overflow for extremely large milliseconds counts.
446
447 \sa start()
448*/
449
450/*!
451 \fn void QTimer::singleShot(std::chrono::nanoseconds nsec, const QObject *receiver, const char *member)
452 \since 5.8
453 \overload
454 \reentrant
455
456 This static function calls a slot after a given time interval.
457
458 It is very convenient to use this function because you do not need
459 to bother with a \l{QObject::timerEvent()}{timerEvent} or
460 create a local QTimer object.
461
462 The \a receiver is the receiving object and the \a member is the slot. The
463 time interval is given in the duration object \a nsec.
464
465//! [qtimer-ns-overflow]
466 \note In Qt versions prior to 6.8, this function took chrono::milliseconds,
467 not chrono::nanoseconds. The compiler will automatically convert for you,
468 but the conversion may overflow for extremely large milliseconds counts.
469//! [qtimer-ns-overflow]
470
471 \sa start()
472*/
473
474/*!
475 \fn void QTimer::singleShot(std::chrono::nanoseconds nsec, Qt::TimerType timerType, const QObject *receiver, const char *member)
476 \since 5.8
477 \overload
478 \reentrant
479
480 This static function calls a slot after a given time interval.
481
482 It is very convenient to use this function because you do not need
483 to bother with a \l{QObject::timerEvent()}{timerEvent} or
484 create a local QTimer object.
485
486 The \a receiver is the receiving object and the \a member is the slot. The
487 time interval is given in the duration object \a nsec. The \a timerType affects the
488 accuracy of the timer.
489
490 \include qtimer.cpp qtimer-ns-overflow
491
492 \sa start()
493*/
494
495/*!
496 \fn template <typename Functor> QMetaObject::Connection QTimer::callOnTimeout(Functor &&slot)
497 \since 5.12
498
499 Creates a connection from the timer's timeout() signal to \a slot.
500 Returns a handle to the connection.
501
502 This method is provided for convenience. It's equivalent to calling:
503 \code
504 QObject::connect(timer, &QTimer::timeout, timer, slot, Qt::DirectConnection);
505 \endcode
506
507 \note This overload is not available when \c {QT_NO_CONTEXTLESS_CONNECT} is
508 defined, instead use the callOnTimeout() overload that takes a context object.
509
510 \sa QObject::connect(), timeout()
511*/
512
513/*!
514 \fn template <typename Functor> QMetaObject::Connection QTimer::callOnTimeout(const QObject *context, Functor &&slot, Qt::ConnectionType connectionType = Qt::AutoConnection)
515 \since 5.12
516 \overload callOnTimeout()
517
518 Creates a connection from the timeout() signal to \a slot to be placed in a specific
519 event loop of \a context, and returns a handle to the connection.
520
521 This method is provided for convenience. It's equivalent to calling:
522 \code
523 QObject::connect(timer, &QTimer::timeout, context, slot, connectionType);
524 \endcode
525
526 \sa QObject::connect(), timeout()
527*/
528
529/*!
530 \fn void QTimer::start(std::chrono::milliseconds msec)
531 \since 5.8
532 \overload
533
534 Starts or restarts the timer with a timeout of duration \a msec milliseconds.
535
536 \include qtimer.cpp stop-restart-timer
537
538 \include qtimer.cpp singleshot-activation
539 This is equivalent to:
540
541 \code
542 timer.setInterval(msec);
543 timer.start();
544 \endcode
545*/
546
547/*!
548 \fn std::chrono::milliseconds QTimer::intervalAsDuration() const
549 \since 5.8
550
551 Returns the interval of this timer as a \c std::chrono::milliseconds object.
552
553 \sa interval
554*/
555
556/*!
557 \fn std::chrono::milliseconds QTimer::remainingTimeAsDuration() const
558 \since 5.8
559
560 Returns the time remaining in this timer object as a \c
561 std::chrono::milliseconds object. If this timer is due or overdue, the
562 returned value is \c std::chrono::milliseconds::zero(). If the remaining
563 time could not be found or the timer is not running, this function returns a
564 negative duration.
565
566 \sa remainingTime()
567*/
568
569/*!
570 \property QTimer::singleShot
571 \brief whether the timer is a single-shot timer
572
573 A single-shot timer fires only once, non-single-shot timers fire
574 every \l interval milliseconds.
575
576 The default value for this property is \c false.
577
578 \sa interval, singleShot()
579*/
580void QTimer::setSingleShot(bool singleShot)
581{
582 d_func()->single = singleShot;
583}
584
585bool QTimer::isSingleShot() const
586{
587 return d_func()->single;
588}
589
590QBindable<bool> QTimer::bindableSingleShot()
591{
592 return QBindable<bool>(&d_func()->single);
593}
594
595/*!
596 \property QTimer::interval
597 \brief the timeout interval in milliseconds
598
599 The default value for this property is 0. A QTimer with a timeout
600 interval of 0 will time out as soon as all the events in the window
601 system's event queue have been processed.
602
603 Setting the interval of a running timer will change the interval,
604 stop() and then start() the timer, and acquire a new id().
605 If the timer is not running, only the interval is changed.
606
607 \sa singleShot
608*/
609void QTimer::setInterval(int msec)
610{
611 setInterval(std::chrono::milliseconds{msec});
612}
613
614void QTimer::setInterval(std::chrono::milliseconds interval)
615{
616 Q_D(QTimer);
617 // This could be narrowing as the interval is stored in an `int` QProperty,
618 // and the type can't be changed in Qt6.
619 const int msec = interval.count();
620 d->inter.removeBindingUnlessInWrapper();
621 const bool intervalChanged = msec != d->inter.valueBypassingBindings();
622 d->inter.setValueBypassingBindings(msec);
623 if (d->isActive()) { // create new timer
624 QObject::killTimer(id: d->id); // restart timer
625 Qt::TimerId newId{ QObject::startTimer(time: msec * 1ms, timerType: d->type) }; // overflow impossible
626 if (newId > Qt::TimerId::Invalid) {
627 // Restarted successfully. No need to update the active state.
628 d->id = newId;
629 } else {
630 // Failed to start the timer.
631 // Need to notify about active state change.
632 d->id = Qt::TimerId::Invalid;
633 d->isActiveData.notify();
634 }
635 }
636 if (intervalChanged)
637 d->inter.notify();
638}
639
640int QTimer::interval() const
641{
642 return d_func()->inter;
643}
644
645QBindable<int> QTimer::bindableInterval()
646{
647 return QBindable<int>(&d_func()->inter);
648}
649
650/*!
651 \property QTimer::remainingTime
652 \since 5.0
653 \brief the remaining time in milliseconds
654
655 Returns the timer's remaining value in milliseconds left until the timeout.
656 If the timer is inactive, the returned value will be -1. If the timer is
657 overdue, the returned value will be 0.
658
659 \sa interval
660*/
661int QTimer::remainingTime() const
662{
663 Q_D(const QTimer);
664 if (d->isActive()) {
665 using namespace std::chrono;
666 auto remaining = QAbstractEventDispatcher::instance()->remainingTime(timerId: d->id);
667 return ceil<milliseconds>(d: remaining).count();
668 }
669
670 return -1;
671}
672
673/*!
674 \property QTimer::timerType
675 \brief controls the accuracy of the timer
676
677 The default value for this property is \c Qt::CoarseTimer.
678
679 \sa Qt::TimerType
680*/
681void QTimer::setTimerType(Qt::TimerType atype)
682{
683 d_func()->type = atype;
684}
685
686Qt::TimerType QTimer::timerType() const
687{
688 return d_func()->type;
689}
690
691QBindable<Qt::TimerType> QTimer::bindableTimerType()
692{
693 return QBindable<Qt::TimerType>(&d_func()->type);
694}
695
696QT_END_NAMESPACE
697
698#include "moc_qtimer.cpp"
699

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

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