diff --git a/src/corelib/kernel/qabstracteventdispatcher.cpp b/src/corelib/kernel/qabstracteventdispatcher.cpp index 98493946d8..c7cf7fe1e2 100644 --- a/src/corelib/kernel/qabstracteventdispatcher.cpp +++ b/src/corelib/kernel/qabstracteventdispatcher.cpp @@ -9,9 +9,12 @@ #include #include #include +#include QT_BEGIN_NAMESPACE +using namespace std::chrono_literals; + // we allow for 2^24 = 8^8 = 16777216 simultaneously running timers struct QtTimerIdFreeListConstants : public QFreeListDefaultConstants { @@ -52,6 +55,22 @@ Q_CONSTINIT const int QtTimerIdFreeListConstants::Sizes[QtTimerIdFreeListConstan typedef QFreeList QtTimerIdFreeList; Q_GLOBAL_STATIC(QtTimerIdFreeList, timerIdFreeList) +template static T fromDuration(std::chrono::nanoseconds interval) +{ + using namespace std::chrono; + qint64 value = ceil(interval).count(); + return qt_saturate(value); +} + +#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) +static inline QAbstractEventDispatcherV2 *v2(QAbstractEventDispatcher *self) +{ + if (QAbstractEventDispatcherPrivate::get(self)->isV2) + return static_cast(self); + return nullptr; +} +#endif // Qt 7 + QAbstractEventDispatcherPrivate::QAbstractEventDispatcherPrivate() { // Create the timer ID free list here to make sure that it is destroyed @@ -121,6 +140,15 @@ void QAbstractEventDispatcherPrivate::releaseTimerId(int timerId) \sa QEventLoop, QCoreApplication, QThread */ +/*! + \typedef QAbstractEventDispatcher::Duration + + A \c{std::chrono::duration} type that is used in various API in this class. + This type exists to facilitate a possible transition to a higher or lower + granularity. + + In all current platforms, it is \c nanoseconds. +*/ /*! Constructs a new event dispatcher with the given \a parent. @@ -214,16 +242,39 @@ QAbstractEventDispatcher *QAbstractEventDispatcher::instance(QThread *thread) */ /*! + \obsolete [6.8] This function will be removed in Qt 7. Use the overload taking \l Duration. + Registers a timer with the specified \a interval and \a timerType for the given \a object and returns the timer id. */ int QAbstractEventDispatcher::registerTimer(qint64 interval, Qt::TimerType timerType, QObject *object) { - int id = QAbstractEventDispatcherPrivate::allocateTimerId(); + return int(registerTimer(interval * 1ms, timerType, object)); +} + +/*! + \since 6.8 + \overload + + Registers a timer with the specified \a interval and \a timerType for the + given \a object and returns the timer id. +*/ +Qt::TimerId QAbstractEventDispatcher::registerTimer(Duration interval, Qt::TimerType timerType, + QObject *object) +{ + auto id = Qt::TimerId(QAbstractEventDispatcherPrivate::allocateTimerId()); +#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) + if (QAbstractEventDispatcherV2 *self = v2(this)) + self->registerTimer(id, interval, timerType, object); + else + registerTimer(qToUnderlying(id), fromDuration(interval), timerType, object); +#else registerTimer(id, interval, timerType, object); +#endif return id; } +#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) /*! \fn void QAbstractEventDispatcher::registerTimer(int timerId, qint64 interval, Qt::TimerType timerType, QObject *object) @@ -240,15 +291,6 @@ int QAbstractEventDispatcher::registerTimer(qint64 interval, Qt::TimerType timer \sa registerTimer(), unregisterTimers() */ -/*! - \fn bool QAbstractEventDispatcher::unregisterTimers(QObject *object) - - Unregisters all the timers associated with the given \a object. - Returns \c true if all timers were successful removed; otherwise returns \c false. - - \sa unregisterTimer(), registeredTimers() -*/ - /*! \fn QList QAbstractEventDispatcher::registeredTimers(QObject *object) const @@ -267,6 +309,57 @@ int QAbstractEventDispatcher::registerTimer(qint64 interval, Qt::TimerType timer \sa Qt::TimerType */ +#else // Qt 7 +/*! + \fn void QAbstractEventDispatcher::registerTimer(Qt::TimerId timerId, Duration interval, Qt::TimerType timerType, QObject *object) + \since 6.8 + + Register a timer with the specified \a timerId, \a interval, and \a + timerType for the given \a object. + + \sa unregisterTimer(), timersForObject() +*/ + +/*! + \fn bool QAbstractEventDispatcher::unregisterTimer(Qt::TimerId timerId) + \since 6.8 + + Unregisters the timer with the given \a timerId. + Returns \c true if successful; otherwise returns \c false. + + \sa registerTimer(), unregisterTimers() +*/ + +/*! + \fn QList QAbstractEventDispatcher::timersForObject(QObject *object) const + \since 6.8 + + Returns a list of registered timers for \a object. The TimerInfoV2 struct has + \c timerId, \c interval, and \c timerType members. + + \sa Qt::TimerType, registerTimer(), unregisterTimer() +*/ + +/*! + \fn QAbstractEventDispatcher::remainingTime(Qt::TimerId timerId) const + + Returns the remaining time of the timer with the given \a timerId. + If the timer is inactive, the returned value will be negative. If the timer + is overdue, the returned value will be 0. + + \sa Qt::TimerType, registerTimer(), unregisterTimer() +*/ +#endif + +/*! + \fn bool QAbstractEventDispatcher::unregisterTimers(QObject *object) + + Unregisters all the timers associated with the given \a object. Returns \c + true if all timers were successfully removed; otherwise returns \c false. + + \sa unregisterTimer(), registeredTimers() +*/ + /*! \fn void QAbstractEventDispatcher::wakeUp() \threadsafe @@ -308,6 +401,7 @@ void QAbstractEventDispatcher::closingDown() /*! \class QAbstractEventDispatcher::TimerInfo + \deprecated [6.8] Use TimerInfoV2 \inmodule QtCore This struct represents information about a timer: @@ -315,7 +409,7 @@ void QAbstractEventDispatcher::closingDown() \l{QAbstractEventDispatcher::TimerInfo::interval}{interval}, and \l{QAbstractEventDispatcher::TimerInfo::timerType}{timerType}. - \sa registeredTimers() + \sa registeredTimers(), QAbstractEventDispatcher::TimerInfoV2, timersForObject() */ /*! \fn QAbstractEventDispatcher::TimerInfo::TimerInfo(int timerId, int interval, Qt::TimerType timerType) @@ -340,6 +434,37 @@ void QAbstractEventDispatcher::closingDown() \sa Qt::TimerType */ +/*! + \class QAbstractEventDispatcher::TimerInfoV2 + \inmodule QtCore + + This struct represents information about a timer: + \l{QAbstractEventDispatcher::TimerInfoV2::timerId}{timerId}, + \l{QAbstractEventDispatcher::TimerInfoV2::interval}{interval}, and + \l{QAbstractEventDispatcher::TimerInfoV2::timerType}{timerType}. + + \sa timersForObject() +*/ +/*! + \variable QAbstractEventDispatcher::TimerInfoV2::timerId + + The timer's unique id. This is created by registerTimer() upon creation and + uniquely identifies a timer while it is active. It is also used by + QTimer::id() and returned by QObject::startTimer(). +*/ +/*! + \variable QAbstractEventDispatcher::TimerInfoV2::interval + + The timer's interval. +*/ +/*! + \variable QAbstractEventDispatcher::TimerInfoV2::timerType + + The timer's type + + \sa Qt::TimerType +*/ + /*! Installs an event filter \a filterObj for all native events received by the application. @@ -452,6 +577,89 @@ bool QAbstractEventDispatcher::filterNativeEvent(const QByteArray &eventType, vo \sa awake() */ +#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) +/*! + \class QAbstractEventDispatcherV2 + \inmodule QtCore + + This class is a temporary hack to enable transition to an API based on + \c{std::chrono} for the Qt event dispatcher. In Qt 7, it will be merged + with QAbstractEventDispatcher, replacing the pure virtuals there with the + ones defined here. + + It is recommended applications and libraries port to the new API before + that future release to simplify work when the time comes. +*/ + +/*! + Constructs a new event dispatcher with the given \a parent. +*/ +QAbstractEventDispatcherV2::QAbstractEventDispatcherV2(QObject *parent) + : QAbstractEventDispatcherV2(*new QAbstractEventDispatcherPrivate, parent) +{ +} + +/*! + \internal +*/ +QAbstractEventDispatcherV2::QAbstractEventDispatcherV2(QAbstractEventDispatcherPrivate &dd, + QObject *parent) + : QAbstractEventDispatcher((dd.isV2 = true, dd), parent) +{ +} + +/*! + Destroys the event dispatcher. +*/ +QAbstractEventDispatcherV2::~QAbstractEventDispatcherV2() = default; + +/*! + \internal + Temporary compatibility override. +*/ +void QAbstractEventDispatcherV2::registerTimer(int timerId, qint64 interval, + Qt::TimerType timerType, QObject *object) +{ + auto self = static_cast(this); + self->registerTimer(Qt::TimerId(timerId), interval * 1ms, timerType, object); +} + +/*! + \internal + Temporary compatibility override. +*/ +bool QAbstractEventDispatcherV2::unregisterTimer(int timerId) +{ + auto self = static_cast(this); + return self->unregisterTimer(Qt::TimerId(timerId)); +} + +/*! + \internal + Temporary compatibility override. +*/ +auto QAbstractEventDispatcherV2::registeredTimers(QObject *object) const -> QList +{ + auto self = static_cast(this); + QList timers = self->timersForObject(object); + QList result; + result.reserve(timers.size()); + for (const TimerInfoV2 &t : timers) + result.emplaceBack(qToUnderlying(t.timerId), fromDuration(t.interval), t.timerType); + return result; +} + +/*! + \internal + Temporary compatibility override. +*/ +int QAbstractEventDispatcherV2::remainingTime(int timerId) +{ + auto self = static_cast(this); + return fromDuration(self->remainingTime(Qt::TimerId(timerId))); +} +#endif // ! Qt 7 + QT_END_NAMESPACE #include "moc_qabstracteventdispatcher.cpp" diff --git a/src/corelib/kernel/qabstracteventdispatcher.h b/src/corelib/kernel/qabstracteventdispatcher.h index 4026bde347..2332292d09 100644 --- a/src/corelib/kernel/qabstracteventdispatcher.h +++ b/src/corelib/kernel/qabstracteventdispatcher.h @@ -19,6 +19,7 @@ class Q_CORE_EXPORT QAbstractEventDispatcher : public QObject Q_DECLARE_PRIVATE(QAbstractEventDispatcher) public: + using Duration = std::chrono::nanoseconds; struct TimerInfo { int timerId; @@ -28,6 +29,12 @@ public: inline TimerInfo(int id, int i, Qt::TimerType t) : timerId(id), interval(i), timerType(t) { } }; + struct TimerInfoV2 + { + Duration interval; + Qt::TimerId timerId; + Qt::TimerType timerType; + }; explicit QAbstractEventDispatcher(QObject *parent = nullptr); ~QAbstractEventDispatcher(); @@ -39,13 +46,23 @@ public: virtual void registerSocketNotifier(QSocketNotifier *notifier) = 0; virtual void unregisterSocketNotifier(QSocketNotifier *notifier) = 0; + Qt::TimerId registerTimer(Duration interval, Qt::TimerType timerType, QObject *object); + +#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) int registerTimer(qint64 interval, Qt::TimerType timerType, QObject *object); + + // old, integer-based API virtual void registerTimer(int timerId, qint64 interval, Qt::TimerType timerType, QObject *object) = 0; virtual bool unregisterTimer(int timerId) = 0; - virtual bool unregisterTimers(QObject *object) = 0; virtual QList registeredTimers(QObject *object) const = 0; - virtual int remainingTime(int timerId) = 0; +#else + virtual void registerTimer(Qt::TimerId timerId, Duration interval, Qt::TimerType timerType, QObject *object) = 0; + virtual bool unregisterTimer(Qt::TimerId timerId) = 0; + virtual QList timersForObject(QObject *object) const = 0; + virtual Duration remainingTime(Qt::TimerId timerId) const = 0; +#endif + virtual bool unregisterTimers(QObject *object) = 0; virtual void wakeUp() = 0; virtual void interrupt() = 0; @@ -67,6 +84,40 @@ protected: }; Q_DECLARE_TYPEINFO(QAbstractEventDispatcher::TimerInfo, Q_PRIMITIVE_TYPE); +Q_DECLARE_TYPEINFO(QAbstractEventDispatcher::TimerInfoV2, Q_PRIMITIVE_TYPE); + +#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) +class Q_CORE_EXPORT QAbstractEventDispatcherV2 : public QAbstractEventDispatcher +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QAbstractEventDispatcher) // not V2 + +public: + explicit QAbstractEventDispatcherV2(QObject *parent = nullptr); + ~QAbstractEventDispatcherV2(); + + // new virtuals + virtual void registerTimer(Qt::TimerId timerId, Duration interval, Qt::TimerType timerType, + QObject *object) = 0; + virtual bool unregisterTimer(Qt::TimerId timerId) = 0; + virtual QList timersForObject(QObject *object) const = 0; + virtual Duration remainingTime(Qt::TimerId timerId) const = 0; + +protected: + QAbstractEventDispatcherV2(QAbstractEventDispatcherPrivate &, QObject *parent); + +private: + // final overrides from V1 + virtual void registerTimer(int timerId, qint64 interval, Qt::TimerType timerType, + QObject *object) override final; + virtual bool unregisterTimer(int timerId) override final; + virtual QList registeredTimers(QObject *object) const override final; + + virtual int remainingTime(int timerId) override final; +}; +#else +using QAbstractEventDispatcherV2 = QAbstractEventDispatcher; +#endif // Qt 7 QT_END_NAMESPACE diff --git a/src/corelib/kernel/qabstracteventdispatcher_p.h b/src/corelib/kernel/qabstracteventdispatcher_p.h index 87afe6a191..2576027d52 100644 --- a/src/corelib/kernel/qabstracteventdispatcher_p.h +++ b/src/corelib/kernel/qabstracteventdispatcher_p.h @@ -33,10 +33,17 @@ public: QList eventFilters; + bool isV2 = false; + static int allocateTimerId(); static void releaseTimerId(int id); static void releaseTimerId(Qt::TimerId id) { releaseTimerId(qToUnderlying(id)); } + + static QAbstractEventDispatcherPrivate *get(QAbstractEventDispatcher *o) + { return o->d_func(); } + static const QAbstractEventDispatcherPrivate *get(const QAbstractEventDispatcher *o) + { return o->d_func(); } }; QT_END_NAMESPACE