From 0d0b346322f6b078e6fe60cd3612e8d08a0d5f00 Mon Sep 17 00:00:00 2001 From: Ivan Solovev Date: Wed, 8 Jan 2025 00:49:32 +0100 Subject: [PATCH] Port QEventDispatcherWin32 to QAbstractEventDispatcherV2 The new APIs use Qt::TimerId to identify timers, and also use nanosecond resolution for the timer interval. However, as the underlying Windows APIs do not support nanosecond resolution, and always use uint millisecods and int timer id, this patch does not touch the internal WinTimerInfo struct definition, but only adjusts to changes in the public QAbstractEventDispatcherV2 API. Fixes: QTBUG-129170 Change-Id: Icc8d7b99affcf34e5677cd22502717f63a1d576c Reviewed-by: Thiago Macieira --- src/corelib/kernel/qeventdispatcher_win.cpp | 57 +++++++++++-------- src/corelib/kernel/qeventdispatcher_win_p.h | 16 +++--- .../qeventdispatcher/tst_qeventdispatcher.cpp | 6 +- 3 files changed, 44 insertions(+), 35 deletions(-) diff --git a/src/corelib/kernel/qeventdispatcher_win.cpp b/src/corelib/kernel/qeventdispatcher_win.cpp index a7663b24813..d5f54db68ed 100644 --- a/src/corelib/kernel/qeventdispatcher_win.cpp +++ b/src/corelib/kernel/qeventdispatcher_win.cpp @@ -428,7 +428,7 @@ QEventDispatcherWin32::QEventDispatcherWin32(QObject *parent) } QEventDispatcherWin32::QEventDispatcherWin32(QEventDispatcherWin32Private &dd, QObject *parent) - : QAbstractEventDispatcher(dd, parent) + : QAbstractEventDispatcherV2(dd, parent) { Q_D(QEventDispatcherWin32); @@ -670,10 +670,11 @@ void QEventDispatcherWin32::doUnregisterSocketNotifier(QSocketNotifier *notifier delete sn; } -void QEventDispatcherWin32::registerTimer(int timerId, qint64 interval, Qt::TimerType timerType, QObject *object) +void QEventDispatcherWin32::registerTimer(Qt::TimerId timerId, Duration interval, + Qt::TimerType timerType, QObject *object) { #ifndef QT_NO_DEBUG - if (timerId < 1 || interval < 0 || !object) { + if (qToUnderlying(timerId) < 1 || interval.count() < 0 || !object) { qWarning("QEventDispatcherWin32::registerTimer: invalid arguments"); return; } @@ -690,10 +691,13 @@ void QEventDispatcherWin32::registerTimer(int timerId, qint64 interval, Qt::Time if (d->closingDown) return; + using namespace std::chrono; + WinTimerInfo *t = new WinTimerInfo; t->dispatcher = this; - t->timerId = timerId; - t->interval = interval; + t->timerId = qToUnderlying(timerId); + // Windows does not have a ns-resolution timer + t->interval = ceil(interval).count(); t->timerType = timerType; t->obj = object; t->inTimerEvent = false; @@ -704,10 +708,10 @@ void QEventDispatcherWin32::registerTimer(int timerId, qint64 interval, Qt::Time d->timerDict.insert(t->timerId, t); // store timers in dict } -bool QEventDispatcherWin32::unregisterTimer(int timerId) +bool QEventDispatcherWin32::unregisterTimer(Qt::TimerId timerId) { #ifndef QT_NO_DEBUG - if (timerId < 1) { + if (qToUnderlying(timerId) < 1) { qWarning("QEventDispatcherWin32::unregisterTimer: invalid argument"); return false; } @@ -719,7 +723,7 @@ bool QEventDispatcherWin32::unregisterTimer(int timerId) Q_D(QEventDispatcherWin32); - WinTimerInfo *t = d->timerDict.take(timerId); + WinTimerInfo *t = d->timerDict.take(qToUnderlying(timerId)); if (!t) return false; @@ -758,50 +762,55 @@ bool QEventDispatcherWin32::unregisterTimers(QObject *object) return true; } -QList -QEventDispatcherWin32::registeredTimers(QObject *object) const +QList +QEventDispatcherWin32::timersForObject(QObject *object) const { #ifndef QT_NO_DEBUG if (!object) { qWarning("QEventDispatcherWin32:registeredTimers: invalid argument"); - return QList(); + return QList(); } #endif Q_D(const QEventDispatcherWin32); - QList list; + QList list; for (WinTimerInfo *t : std::as_const(d->timerDict)) { Q_ASSERT(t); - if (t->obj == object) - list << TimerInfo(t->timerId, t->interval, t->timerType); + if (t->obj == object) { + list << TimerInfoV2{std::chrono::milliseconds{t->interval}, + Qt::TimerId{t->timerId}, + t->timerType}; + } } return list; } -int QEventDispatcherWin32::remainingTime(int timerId) +QEventDispatcherWin32::Duration QEventDispatcherWin32::remainingTime(Qt::TimerId timerId) const { #ifndef QT_NO_DEBUG - if (timerId < 1) { + if (qToUnderlying(timerId) < 1) { qWarning("QEventDispatcherWin32::remainingTime: invalid argument"); - return -1; + return Duration::min(); } #endif - Q_D(QEventDispatcherWin32); + Q_D(const QEventDispatcherWin32); - quint64 currentTime = qt_msectime(); - - WinTimerInfo *t = d->timerDict.value(timerId); + WinTimerInfo *t = d->timerDict.value(qToUnderlying(timerId)); if (t) { // timer found, return time to wait - return t->timeout > currentTime ? t->timeout - currentTime : 0; + using namespace std::chrono; + using namespace std::chrono_literals; + const Duration currentTimeNs = steady_clock::now().time_since_epoch(); + const Duration timeoutNs = Duration{t->timeout * 1ms}; + return timeoutNs > currentTimeNs ? timeoutNs - currentTimeNs : 0ns; } #ifndef QT_NO_DEBUG - qWarning("QEventDispatcherWin32::remainingTime: timer id %d not found", timerId); + qWarning("QEventDispatcherWin32::remainingTime: timer id %d not found", qToUnderlying(timerId)); #endif - return -1; + return Duration::min(); } void QEventDispatcherWin32::wakeUp() diff --git a/src/corelib/kernel/qeventdispatcher_win_p.h b/src/corelib/kernel/qeventdispatcher_win_p.h index e46cdec71dc..3b3dd84ee9f 100644 --- a/src/corelib/kernel/qeventdispatcher_win_p.h +++ b/src/corelib/kernel/qeventdispatcher_win_p.h @@ -29,7 +29,7 @@ class QEventDispatcherWin32Private; // forward declaration LRESULT QT_WIN_CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp); -class Q_CORE_EXPORT QEventDispatcherWin32 : public QAbstractEventDispatcher +class Q_CORE_EXPORT QEventDispatcherWin32 : public QAbstractEventDispatcherV2 { Q_OBJECT Q_DECLARE_PRIVATE(QEventDispatcherWin32) @@ -43,12 +43,12 @@ public: void registerSocketNotifier(QSocketNotifier *notifier) override; void unregisterSocketNotifier(QSocketNotifier *notifier) override; - void registerTimer(int timerId, qint64 interval, Qt::TimerType timerType, QObject *object) override; - bool unregisterTimer(int timerId) override; - bool unregisterTimers(QObject *object) override; - QList registeredTimers(QObject *object) const override; - - int remainingTime(int timerId) override; + void registerTimer(Qt::TimerId timerId, Duration interval, Qt::TimerType timerType, + QObject *object) final; + bool unregisterTimer(Qt::TimerId timerId) final; + bool unregisterTimers(QObject *object) final; + QList timersForObject(QObject *object) const final; + Duration remainingTime(Qt::TimerId timerId) const final; void wakeUp() override; void interrupt() override; @@ -85,7 +85,7 @@ struct QSockFd { typedef QHash QSFDict; struct WinTimerInfo { // internal timer info - qint64 interval; + qint64 interval; // - in milliseconds quint64 timeout; // - when to actually fire QObject *dispatcher; QObject *obj; // - object to receive events diff --git a/tests/auto/corelib/kernel/qeventdispatcher/tst_qeventdispatcher.cpp b/tests/auto/corelib/kernel/qeventdispatcher/tst_qeventdispatcher.cpp index a61f3983662..07a2b6629bf 100644 --- a/tests/auto/corelib/kernel/qeventdispatcher/tst_qeventdispatcher.cpp +++ b/tests/auto/corelib/kernel/qeventdispatcher/tst_qeventdispatcher.cpp @@ -194,9 +194,9 @@ private: // For precise timers, we expect the fudge factor to be present QAbstractEventDispatcher::Duration interval = fudgeInterval(PreciseTimerInterval, Qt::PreciseTimer); -#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) - if (!qobject_cast(m_eventDispatcher)) - interval = PreciseTimerInterval; +#ifdef Q_OS_WIN + // Windows does not have a nanosecond-resolution timer + interval = PreciseTimerInterval; #endif QCOMPARE(timerInfo.interval, interval); QCOMPARE(timerInfo.timerType, Qt::PreciseTimer);