summaryrefslogtreecommitdiffstats
path: root/src/corelib/kernel
diff options
context:
space:
mode:
authorAhmad Samir <a.samirh78@gmail.com>2024-02-22 16:01:54 +0200
committerAhmad Samir <a.samirh78@gmail.com>2024-03-03 19:56:55 +0200
commit4fa9034d0c592e5f07531d41463c8c462f5e8895 (patch)
tree2457778849a1e49a85569ccac8a2dd72ad58c04c /src/corelib/kernel
parent7ff1285e7a93d51e1f2a079ae33349906d9e9fea (diff)
Copy QTimer source files to QChronoTimer
Ultimately this is the best way to keep the log history of the code. Change-Id: I3413deffdb093a3239d65b6ca939e744224e722a Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Diffstat (limited to 'src/corelib/kernel')
-rw-r--r--src/corelib/kernel/qchronotimer.cpp646
-rw-r--r--src/corelib/kernel/qchronotimer.h187
2 files changed, 833 insertions, 0 deletions
diff --git a/src/corelib/kernel/qchronotimer.cpp b/src/corelib/kernel/qchronotimer.cpp
new file mode 100644
index 0000000000..cbeeb97934
--- /dev/null
+++ b/src/corelib/kernel/qchronotimer.cpp
@@ -0,0 +1,646 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// Copyright (C) 2016 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qtimer.h"
+#include "qtimer_p.h"
+#include "qsingleshottimer_p.h"
+
+#include "qabstracteventdispatcher.h"
+#include "qcoreapplication.h"
+#include "qcoreapplication_p.h"
+#include "qdeadlinetimer.h"
+#include "qmetaobject_p.h"
+#include "qobject_p.h"
+#include "qproperty_p.h"
+#include "qthread.h"
+
+using namespace std::chrono_literals;
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QTimer
+ \inmodule QtCore
+ \brief The QTimer class provides repetitive and single-shot timers.
+
+ \ingroup events
+
+
+ The QTimer class provides a high-level programming interface for
+ timers. To use it, create a QTimer, connect its timeout() signal
+ to the appropriate slots, and call start(). From then on, it will
+ emit the timeout() signal at constant intervals.
+
+ Example for a one second (1000 millisecond) timer (from the
+ \l{widgets/analogclock}{Analog Clock} example):
+
+ \snippet ../widgets/widgets/analogclock/analogclock.cpp 4
+ \snippet ../widgets/widgets/analogclock/analogclock.cpp 5
+ \snippet ../widgets/widgets/analogclock/analogclock.cpp 6
+
+ From then on, the \c update() slot is called every second.
+
+ You can set a timer to time out only once by calling
+ setSingleShot(true). You can also use the static
+ QTimer::singleShot() function to call a slot after a specified
+ interval:
+
+ \snippet timers/timers.cpp 3
+
+ In multithreaded applications, you can use QTimer in any thread
+ that has an event loop. To start an event loop from a non-GUI
+ thread, use QThread::exec(). Qt uses the timer's
+ \l{QObject::thread()}{thread affinity} to determine which thread
+ will emit the \l{QTimer::}{timeout()} signal. Because of this, you
+ must start and stop the timer in its thread; it is not possible to
+ start a timer from another thread.
+
+ As a special case, a QTimer with a timeout of 0 will time out as soon as
+ possible, though the ordering between zero timers and other sources of
+ events is unspecified. Zero timers can be used to do some work while still
+ providing a snappy user interface:
+
+ \snippet timers/timers.cpp 4
+ \snippet timers/timers.cpp 5
+ \snippet timers/timers.cpp 6
+
+ From then on, \c processOneThing() will be called repeatedly. It
+ should be written in such a way that it always returns quickly
+ (typically after processing one data item) so that Qt can deliver
+ events to the user interface and stop the timer as soon as it has done all
+ its work. This is the traditional way of implementing heavy work
+ in GUI applications, but as multithreading is nowadays becoming available on
+ more and more platforms, we expect that zero-millisecond
+ QTimer objects will gradually be replaced by \l{QThread}s.
+
+ \section1 Accuracy and Timer Resolution
+
+ The accuracy of timers depends on the underlying operating system
+ and hardware. Most platforms support a resolution of 1 millisecond,
+ though the accuracy of the timer will not equal this resolution
+ in many real-world situations.
+
+ The accuracy also depends on the \l{Qt::TimerType}{timer type}. For
+ Qt::PreciseTimer, QTimer will try to keep the accuracy at 1 millisecond.
+ Precise timers will also never time out earlier than expected.
+
+ For Qt::CoarseTimer and Qt::VeryCoarseTimer types, QTimer may wake up
+ earlier than expected, within the margins for those types: 5% of the
+ interval for Qt::CoarseTimer and 500 ms for Qt::VeryCoarseTimer.
+
+ All timer types may time out later than expected if the system is busy or
+ unable to provide the requested accuracy. In such a case of timeout
+ overrun, Qt will emit timeout() only once, even if multiple timeouts have
+ expired, and then will resume the original interval.
+
+ \section1 Alternatives to QTimer
+
+ An alternative to using QTimer is to call QObject::startTimer()
+ for your object and reimplement the QObject::timerEvent() event
+ handler in your class (which must inherit QObject). The
+ disadvantage is that timerEvent() does not support such
+ high-level features as single-shot timers or signals.
+
+ Another alternative is QBasicTimer. It is typically less
+ cumbersome than using QObject::startTimer()
+ directly. See \l{Timers} for an overview of all three approaches.
+
+ Some operating systems limit the number of timers that may be
+ used; Qt tries to work around these limitations.
+
+ \sa QBasicTimer, QTimerEvent, QObject::timerEvent(), Timers,
+ {Analog Clock}
+*/
+
+/*!
+ Constructs a timer with the given \a parent.
+*/
+
+QTimer::QTimer(QObject *parent)
+ : QObject(*new QTimerPrivate(this), parent)
+{
+ Q_ASSERT(d_func()->isQTimer);
+}
+
+
+/*!
+ Destroys the timer.
+*/
+
+QTimer::~QTimer()
+{
+ if (d_func()->id != QTimerPrivate::INV_TIMER) // stop running timer
+ stop();
+}
+
+
+/*!
+ \fn void QTimer::timeout()
+
+ This signal is emitted when the timer times out.
+
+ \sa interval, start(), stop()
+*/
+
+/*!
+ \property QTimer::active
+ \since 4.3
+
+ This boolean property is \c true if the timer is running; otherwise
+ false.
+*/
+
+/*!
+ \fn bool QTimer::isActive() const
+
+ Returns \c true if the timer is running (pending); otherwise returns
+ false.
+*/
+bool QTimer::isActive() const
+{
+ return d_func()->isActiveData.value();
+}
+
+QBindable<bool> QTimer::bindableActive()
+{
+ return QBindable<bool>(&d_func()->isActiveData);
+}
+
+/*!
+ \fn int QTimer::timerId() const
+
+ Returns the ID of the timer if the timer is running; otherwise returns
+ -1.
+*/
+int QTimer::timerId() const
+{
+ return d_func()->id;
+}
+
+
+/*! \overload start()
+
+ Starts or restarts the timer with the timeout specified in \l interval.
+
+ If the timer is already running, it will be
+ \l{QTimer::stop()}{stopped} and restarted.
+
+ If \l singleShot is true, the timer will be activated only once.
+*/
+void QTimer::start()
+{
+ Q_D(QTimer);
+ if (d->id != QTimerPrivate::INV_TIMER) // stop running timer
+ stop();
+ const int id = QObject::startTimer(std::chrono::milliseconds{d->inter}, d->type);
+ if (id > 0) {
+ d->id = id;
+ d->isActiveData.notify();
+ }
+}
+
+/*!
+ Starts or restarts the timer with a timeout interval of \a msec
+ milliseconds.
+
+ If the timer is already running, it will be
+ \l{QTimer::stop()}{stopped} and restarted.
+
+ If \l singleShot is true, the timer will be activated only once. This is
+ equivalent to:
+
+ \code
+ timer.setInterval(msec);
+ timer.start();
+ \endcode
+
+ \note Keeping the event loop busy with a zero-timer is bound to
+ cause trouble and highly erratic behavior of the UI.
+*/
+void QTimer::start(int msec)
+{
+ start(msec * 1ms);
+}
+
+void QTimer::start(std::chrono::milliseconds interval)
+{
+ Q_D(QTimer);
+ // This could be narrowing as the interval is stored in an `int` QProperty,
+ // and the type can't be changed in Qt6.
+ const int msec = interval.count();
+ const bool intervalChanged = msec != d->inter;
+ d->inter.setValue(msec);
+ start();
+ if (intervalChanged)
+ d->inter.notify();
+}
+
+
+
+/*!
+ Stops the timer.
+
+ \sa start()
+*/
+
+void QTimer::stop()
+{
+ Q_D(QTimer);
+ if (d->id != QTimerPrivate::INV_TIMER) {
+ QObject::killTimer(d->id);
+ d->id = QTimerPrivate::INV_TIMER;
+ d->isActiveData.notify();
+ }
+}
+
+
+/*!
+ \reimp
+*/
+void QTimer::timerEvent(QTimerEvent *e)
+{
+ Q_D(QTimer);
+ if (e->timerId() == d->id) {
+ if (d->single)
+ stop();
+ emit timeout(QPrivateSignal());
+ }
+}
+
+/*!
+ \internal
+
+ Implementation of the template version of singleShot
+
+ \a msec is the timer interval
+ \a timerType is the timer type
+ \a receiver is the receiver object, can be null. In such a case, it will be the same
+ as the final sender class.
+ \a slotObj the slot object
+*/
+void QTimer::singleShotImpl(std::chrono::milliseconds msec, Qt::TimerType timerType,
+ const QObject *receiver,
+ QtPrivate::QSlotObjectBase *slotObj)
+{
+ if (msec == 0ms) {
+ bool deleteReceiver = false;
+ // Optimize: set a receiver context when none is given, such that we can use
+ // QMetaObject::invokeMethod which is more efficient than going through a timer.
+ // We need a QObject living in the current thread. But the QThread itself lives
+ // in a different thread - with the exception of the main QThread which lives in
+ // itself. And QThread::currentThread() is among the few QObjects we know that will
+ // most certainly be there. Note that one can actually call singleShot before the
+ // QApplication is created!
+ if (!receiver && QThread::currentThread() == QCoreApplicationPrivate::mainThread()) {
+ // reuse main thread as context object
+ receiver = QThread::currentThread();
+ } else if (!receiver) {
+ // Create a receiver context object on-demand. According to the benchmarks,
+ // this is still more efficient than going through a timer.
+ receiver = new QObject;
+ deleteReceiver = true;
+ }
+
+ auto h = QtPrivate::invokeMethodHelper({});
+ QMetaObject::invokeMethodImpl(const_cast<QObject *>(receiver), slotObj,
+ Qt::QueuedConnection, h.parameterCount(), h.parameters.data(), h.typeNames.data(),
+ h.metaTypes.data());
+
+ if (deleteReceiver)
+ const_cast<QObject *>(receiver)->deleteLater();
+ return;
+ }
+
+ new QSingleShotTimer(msec, timerType, receiver, slotObj);
+}
+
+/*!
+ \fn void QTimer::singleShot(int msec, const QObject *receiver, const char *member)
+ \reentrant
+ \deprecated [6.8] Use the chrono overloads.
+ This static function calls a slot after a given time interval.
+
+ It is very convenient to use this function because you do not need
+ to bother with a \l{QObject::timerEvent()}{timerEvent} or
+ create a local QTimer object.
+
+ Example:
+ \snippet code/src_corelib_kernel_qtimer.cpp 0
+
+ This sample program automatically terminates after 10 minutes
+ (600,000 milliseconds).
+
+ The \a receiver is the receiving object and the \a member is the
+ slot. The time interval is \a msec milliseconds.
+
+ \sa start()
+*/
+
+/*!
+ \fn void QTimer::singleShot(int msec, Qt::TimerType timerType, const QObject *receiver, const char *member)
+ \overload
+ \reentrant
+ \deprecated [6.8] Use the chrono overloads.
+ This static function calls a slot after a given time interval.
+
+ It is very convenient to use this function because you do not need
+ to bother with a \l{QObject::timerEvent()}{timerEvent} or
+ create a local QTimer object.
+
+ The \a receiver is the receiving object and the \a member is the slot. The
+ time interval is \a msec milliseconds. The \a timerType affects the
+ accuracy of the timer.
+
+ \sa start()
+*/
+
+void QTimer::singleShot(std::chrono::milliseconds msec, Qt::TimerType timerType,
+ const QObject *receiver, const char *member)
+{
+ if (Q_UNLIKELY(msec < 0ms)) {
+ qWarning("QTimer::singleShot: Timers cannot have negative timeouts");
+ return;
+ }
+ if (receiver && member) {
+ if (msec == 0ms) {
+ // special code shortpath for 0-timers
+ const char* bracketPosition = strchr(member, '(');
+ if (!bracketPosition || !(member[0] >= '0' && member[0] <= '2')) {
+ qWarning("QTimer::singleShot: Invalid slot specification");
+ return;
+ }
+ const auto methodName = QByteArrayView(member + 1, // extract method name
+ bracketPosition - 1 - member).trimmed();
+ QMetaObject::invokeMethod(const_cast<QObject *>(receiver), methodName.toByteArray().constData(),
+ Qt::QueuedConnection);
+ return;
+ }
+ (void) new QSingleShotTimer(msec, timerType, receiver, member);
+ }
+}
+
+/*! \fn template<typename Duration, typename Functor> void QTimer::singleShot(Duration msec, const QObject *context, Functor &&functor)
+ \fn template<typename Duration, typename Functor> void QTimer::singleShot(Duration msec, Qt::TimerType timerType, const QObject *context, Functor &&functor)
+ \fn template<typename Duration, typename Functor> void QTimer::singleShot(Duration msec, Functor &&functor)
+ \fn template<typename Duration, typename Functor> void QTimer::singleShot(Duration msec, Qt::TimerType timerType, Functor &&functor)
+ \since 5.4
+
+ \reentrant
+ This static function calls \a functor after \a msec milliseconds.
+
+ It is very convenient to use this function because you do not need
+ to bother with a \l{QObject::timerEvent()}{timerEvent} or
+ create a local QTimer object.
+
+ If \a context is specified, then the \a functor will be called only if the
+ \a context object has not been destroyed before the interval occurs. The functor
+ will then be run the thread of \a context. The context's thread must have a
+ running Qt event loop.
+
+ If \a functor is a member
+ function of \a context, then the function will be called on the object.
+
+ The \a msec parameter can be an \c int or a \c std::chrono::milliseconds value.
+
+ \sa start()
+*/
+
+/*!
+ \fn void QTimer::singleShot(std::chrono::milliseconds msec, const QObject *receiver, const char *member)
+ \since 5.8
+ \overload
+ \reentrant
+
+ This static function calls a slot after a given time interval.
+
+ It is very convenient to use this function because you do not need
+ to bother with a \l{QObject::timerEvent()}{timerEvent} or
+ create a local QTimer object.
+
+ The \a receiver is the receiving object and the \a member is the slot. The
+ time interval is given in the duration object \a msec.
+
+ \sa start()
+*/
+
+/*!
+ \fn void QTimer::singleShot(std::chrono::milliseconds msec, Qt::TimerType timerType, const QObject *receiver, const char *member)
+ \since 5.8
+ \overload
+ \reentrant
+
+ This static function calls a slot after a given time interval.
+
+ It is very convenient to use this function because you do not need
+ to bother with a \l{QObject::timerEvent()}{timerEvent} or
+ create a local QTimer object.
+
+ The \a receiver is the receiving object and the \a member is the slot. The
+ time interval is given in the duration object \a msec. The \a timerType affects the
+ accuracy of the timer.
+
+ \sa start()
+*/
+
+/*!
+ \fn template <typename Functor> QMetaObject::Connection QTimer::callOnTimeout(Functor &&slot)
+ \since 5.12
+
+ Creates a connection from the timer's timeout() signal to \a slot.
+ Returns a handle to the connection.
+
+ This method is provided for convenience. It's equivalent to calling:
+ \code
+ QObject::connect(timer, &QTimer::timeout, timer, slot, Qt::DirectConnection);
+ \endcode
+
+ \note This overload is not available when \c {QT_NO_CONTEXTLESS_CONNECT} is
+ defined, instead use the callOnTimeout() overload that takes a context object.
+
+ \sa QObject::connect(), timeout()
+*/
+
+/*!
+ \fn template <typename Functor> QMetaObject::Connection QTimer::callOnTimeout(const QObject *context, Functor &&slot, Qt::ConnectionType connectionType = Qt::AutoConnection)
+ \since 5.12
+ \overload callOnTimeout()
+
+ Creates a connection from the timeout() signal to \a slot to be placed in a specific
+ event loop of \a context, and returns a handle to the connection.
+
+ This method is provided for convenience. It's equivalent to calling:
+ \code
+ QObject::connect(timer, &QTimer::timeout, context, slot, connectionType);
+ \endcode
+
+ \sa QObject::connect(), timeout()
+*/
+
+/*!
+ \fn void QTimer::start(std::chrono::milliseconds msec)
+ \since 5.8
+ \overload
+
+ Starts or restarts the timer with a timeout of duration \a msec milliseconds.
+
+ If the timer is already running, it will be
+ \l{QTimer::stop()}{stopped} and restarted.
+
+ If \l singleShot is true, the timer will be activated only once. This is
+ equivalent to:
+
+ \code
+ timer.setInterval(msec);
+ timer.start();
+ \endcode
+*/
+
+/*!
+ \fn std::chrono::milliseconds QTimer::intervalAsDuration() const
+ \since 5.8
+
+ Returns the interval of this timer as a \c std::chrono::milliseconds object.
+
+ \sa interval
+*/
+
+/*!
+ \fn std::chrono::milliseconds QTimer::remainingTimeAsDuration() const
+ \since 5.8
+
+ Returns the time remaining in this timer object as a \c
+ std::chrono::milliseconds object. If this timer is due or overdue, the
+ returned value is \c std::chrono::milliseconds::zero(). If the remaining
+ time could not be found or the timer is not active, this function returns a
+ negative duration.
+
+ \sa remainingTime()
+*/
+
+/*!
+ \property QTimer::singleShot
+ \brief whether the timer is a single-shot timer
+
+ A single-shot timer fires only once, non-single-shot timers fire
+ every \l interval milliseconds.
+
+ The default value for this property is \c false.
+
+ \sa interval, singleShot()
+*/
+void QTimer::setSingleShot(bool singleShot)
+{
+ d_func()->single = singleShot;
+}
+
+bool QTimer::isSingleShot() const
+{
+ return d_func()->single;
+}
+
+QBindable<bool> QTimer::bindableSingleShot()
+{
+ return QBindable<bool>(&d_func()->single);
+}
+
+/*!
+ \property QTimer::interval
+ \brief the timeout interval in milliseconds
+
+ The default value for this property is 0. A QTimer with a timeout
+ interval of 0 will time out as soon as all the events in the window
+ system's event queue have been processed.
+
+ Setting the interval of an active timer changes its timerId().
+
+ \sa singleShot
+*/
+void QTimer::setInterval(int msec)
+{
+ setInterval(std::chrono::milliseconds{msec});
+}
+
+void QTimer::setInterval(std::chrono::milliseconds interval)
+{
+ Q_D(QTimer);
+ // This could be narrowing as the interval is stored in an `int` QProperty,
+ // and the type can't be changed in Qt6.
+ const int msec = interval.count();
+ d->inter.removeBindingUnlessInWrapper();
+ const bool intervalChanged = msec != d->inter.valueBypassingBindings();
+ d->inter.setValueBypassingBindings(msec);
+ if (d->id != QTimerPrivate::INV_TIMER) { // create new timer
+ QObject::killTimer(d->id); // restart timer
+ const int id = QObject::startTimer(std::chrono::milliseconds{msec}, d->type);
+ if (id > 0) {
+ // Restarted successfully. No need to update the active state.
+ d->id = id;
+ } else {
+ // Failed to start the timer.
+ // Need to notify about active state change.
+ d->id = QTimerPrivate::INV_TIMER;
+ d->isActiveData.notify();
+ }
+ }
+ if (intervalChanged)
+ d->inter.notify();
+}
+
+int QTimer::interval() const
+{
+ return d_func()->inter;
+}
+
+QBindable<int> QTimer::bindableInterval()
+{
+ return QBindable<int>(&d_func()->inter);
+}
+
+/*!
+ \property QTimer::remainingTime
+ \since 5.0
+ \brief the remaining time in milliseconds
+
+ Returns the timer's remaining value in milliseconds left until the timeout.
+ If the timer is inactive, the returned value will be -1. If the timer is
+ overdue, the returned value will be 0.
+
+ \sa interval
+*/
+int QTimer::remainingTime() const
+{
+ Q_D(const QTimer);
+ if (d->id != QTimerPrivate::INV_TIMER) {
+ return QAbstractEventDispatcher::instance()->remainingTime(d->id);
+ }
+
+ return -1;
+}
+
+/*!
+ \property QTimer::timerType
+ \brief controls the accuracy of the timer
+
+ The default value for this property is \c Qt::CoarseTimer.
+
+ \sa Qt::TimerType
+*/
+void QTimer::setTimerType(Qt::TimerType atype)
+{
+ d_func()->type = atype;
+}
+
+Qt::TimerType QTimer::timerType() const
+{
+ return d_func()->type;
+}
+
+QBindable<Qt::TimerType> QTimer::bindableTimerType()
+{
+ return QBindable<Qt::TimerType>(&d_func()->type);
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qtimer.cpp"
diff --git a/src/corelib/kernel/qchronotimer.h b/src/corelib/kernel/qchronotimer.h
new file mode 100644
index 0000000000..9b59895e60
--- /dev/null
+++ b/src/corelib/kernel/qchronotimer.h
@@ -0,0 +1,187 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QTIMER_H
+#define QTIMER_H
+
+#include <QtCore/qglobal.h>
+
+#ifndef QT_NO_QOBJECT
+
+#include <QtCore/qbasictimer.h> // conceptual inheritance
+#include <QtCore/qobject.h>
+
+#include <chrono>
+
+QT_BEGIN_NAMESPACE
+
+class QTimerPrivate;
+class Q_CORE_EXPORT QTimer : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(bool singleShot READ isSingleShot WRITE setSingleShot BINDABLE bindableSingleShot)
+ Q_PROPERTY(int interval READ interval WRITE setInterval BINDABLE bindableInterval)
+ Q_PROPERTY(int remainingTime READ remainingTime)
+ Q_PROPERTY(Qt::TimerType timerType READ timerType WRITE setTimerType BINDABLE bindableTimerType)
+ Q_PROPERTY(bool active READ isActive STORED false BINDABLE bindableActive)
+public:
+ explicit QTimer(QObject *parent = nullptr);
+ ~QTimer();
+
+ bool isActive() const;
+ QBindable<bool> bindableActive();
+ int timerId() const;
+
+ void setInterval(int msec);
+ int interval() const;
+ QBindable<int> bindableInterval();
+
+ int remainingTime() const;
+
+ void setTimerType(Qt::TimerType atype);
+ Qt::TimerType timerType() const;
+ QBindable<Qt::TimerType> bindableTimerType();
+
+ void setSingleShot(bool singleShot);
+ bool isSingleShot() const;
+ QBindable<bool> bindableSingleShot();
+
+ QT_CORE_INLINE_SINCE(6, 8)
+ static void singleShot(int msec, const QObject *receiver, const char *member);
+
+ QT_CORE_INLINE_SINCE(6, 8)
+ static void singleShot(int msec, Qt::TimerType timerType, const QObject *receiver, const char *member);
+
+ // singleShot with context
+#ifdef Q_QDOC
+ template <typename Duration, typename Functor>
+ static inline void singleShot(Duration interval, const QObject *receiver, Functor &&slot);
+ template <typename Duration, typename Functor>
+ static inline void singleShot(Duration interval, Qt::TimerType timerType,
+ const QObject *receiver, Functor &&slot);
+#else
+ template <typename Duration, typename Functor>
+ static inline void singleShot(Duration interval,
+ const typename QtPrivate::ContextTypeForFunctor<Functor>::ContextType *receiver,
+ Functor &&slot)
+ {
+ singleShot(interval, defaultTypeFor(interval), receiver, std::forward<Functor>(slot));
+ }
+ template <typename Duration, typename Functor>
+ static inline void singleShot(Duration interval, Qt::TimerType timerType,
+ const typename QtPrivate::ContextTypeForFunctor<Functor>::ContextType *receiver,
+ Functor &&slot)
+ {
+ using Prototype = void(*)();
+ singleShotImpl(interval, timerType, receiver,
+ QtPrivate::makeCallableObject<Prototype>(std::forward<Functor>(slot)));
+ }
+#endif
+
+ // singleShot without context
+ template <typename Duration, typename Functor>
+ static inline void singleShot(Duration interval, Functor &&slot)
+ {
+ singleShot(interval, defaultTypeFor(interval), nullptr, std::forward<Functor>(slot));
+ }
+ template <typename Duration, typename Functor>
+ static inline void singleShot(Duration interval, Qt::TimerType timerType, Functor &&slot)
+ {
+ singleShot(interval, timerType, nullptr, std::forward<Functor>(slot));
+ }
+
+#ifdef Q_QDOC
+ template <typename Functor>
+ QMetaObject::Connection callOnTimeout(Functor &&slot);
+ template <typename Functor>
+ QMetaObject::Connection callOnTimeout(const QObject *context, Functor &&slot, Qt::ConnectionType connectionType = Qt::AutoConnection);
+#else
+ template <typename ... Args>
+ QMetaObject::Connection callOnTimeout(Args && ...args)
+ {
+ return QObject::connect(this, &QTimer::timeout, std::forward<Args>(args)... );
+ }
+
+#endif
+
+public Q_SLOTS:
+ void start(int msec);
+
+ void start();
+ void stop();
+
+Q_SIGNALS:
+ void timeout(QPrivateSignal);
+
+public:
+ void setInterval(std::chrono::milliseconds value);
+
+ std::chrono::milliseconds intervalAsDuration() const
+ {
+ return std::chrono::milliseconds(interval());
+ }
+
+ std::chrono::milliseconds remainingTimeAsDuration() const
+ {
+ return std::chrono::milliseconds(remainingTime());
+ }
+
+ static void singleShot(std::chrono::milliseconds value, const QObject *receiver, const char *member)
+ {
+ singleShot(value, defaultTypeFor(value), receiver, member);
+ }
+ static void singleShot(std::chrono::milliseconds interval, Qt::TimerType timerType,
+ const QObject *receiver, const char *member);
+
+ void start(std::chrono::milliseconds value);
+
+protected:
+ void timerEvent(QTimerEvent *) override;
+
+private:
+ Q_DISABLE_COPY(QTimer)
+ Q_DECLARE_PRIVATE(QTimer)
+
+ inline int startTimer(int){ return -1;}
+ inline void killTimer(int){}
+
+ static constexpr Qt::TimerType defaultTypeFor(int msecs) noexcept
+ { return defaultTypeFor(std::chrono::milliseconds{msecs}); }
+
+ static constexpr Qt::TimerType defaultTypeFor(std::chrono::milliseconds interval) noexcept
+ {
+ // coarse timers are worst in their first firing
+ // so we prefer a high precision timer for something that happens only once
+ // unless the timeout is too big, in which case we go for coarse anyway
+ using namespace std::chrono_literals;
+ return interval >= 2s ? Qt::CoarseTimer : Qt::PreciseTimer;
+ }
+
+ QT_CORE_INLINE_SINCE(6, 8)
+ static void singleShotImpl(int msec, Qt::TimerType timerType,
+ const QObject *receiver, QtPrivate::QSlotObjectBase *slotObj);
+
+ static void singleShotImpl(std::chrono::milliseconds interval, Qt::TimerType timerType,
+ const QObject *receiver, QtPrivate::QSlotObjectBase *slotObj);
+};
+
+#if QT_CORE_INLINE_IMPL_SINCE(6, 8)
+void QTimer::singleShot(int msec, const QObject *receiver, const char *member)
+{ singleShot(std::chrono::milliseconds{msec}, receiver, member); }
+
+void QTimer::singleShot(int msec, Qt::TimerType timerType, const QObject *receiver,
+ const char *member)
+{ singleShot(std::chrono::milliseconds{msec}, timerType, receiver, member); }
+
+void QTimer::singleShotImpl(int msec, Qt::TimerType timerType,
+ const QObject *receiver, QtPrivate::QSlotObjectBase *slotObj)
+{
+ singleShotImpl(std::chrono::milliseconds{msec}, timerType, receiver, slotObj);
+}
+#endif
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_QOBJECT
+
+#endif // QTIMER_H