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

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