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 <thiago.macieira@intel.com>
This commit is contained in:
Ivan Solovev 2025-01-08 00:49:32 +01:00
parent 242e293323
commit 0d0b346322
3 changed files with 44 additions and 35 deletions

View File

@ -428,7 +428,7 @@ QEventDispatcherWin32::QEventDispatcherWin32(QObject *parent)
} }
QEventDispatcherWin32::QEventDispatcherWin32(QEventDispatcherWin32Private &dd, QObject *parent) QEventDispatcherWin32::QEventDispatcherWin32(QEventDispatcherWin32Private &dd, QObject *parent)
: QAbstractEventDispatcher(dd, parent) : QAbstractEventDispatcherV2(dd, parent)
{ {
Q_D(QEventDispatcherWin32); Q_D(QEventDispatcherWin32);
@ -670,10 +670,11 @@ void QEventDispatcherWin32::doUnregisterSocketNotifier(QSocketNotifier *notifier
delete sn; 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 #ifndef QT_NO_DEBUG
if (timerId < 1 || interval < 0 || !object) { if (qToUnderlying(timerId) < 1 || interval.count() < 0 || !object) {
qWarning("QEventDispatcherWin32::registerTimer: invalid arguments"); qWarning("QEventDispatcherWin32::registerTimer: invalid arguments");
return; return;
} }
@ -690,10 +691,13 @@ void QEventDispatcherWin32::registerTimer(int timerId, qint64 interval, Qt::Time
if (d->closingDown) if (d->closingDown)
return; return;
using namespace std::chrono;
WinTimerInfo *t = new WinTimerInfo; WinTimerInfo *t = new WinTimerInfo;
t->dispatcher = this; t->dispatcher = this;
t->timerId = timerId; t->timerId = qToUnderlying(timerId);
t->interval = interval; // Windows does not have a ns-resolution timer
t->interval = ceil<milliseconds>(interval).count();
t->timerType = timerType; t->timerType = timerType;
t->obj = object; t->obj = object;
t->inTimerEvent = false; 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 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 #ifndef QT_NO_DEBUG
if (timerId < 1) { if (qToUnderlying(timerId) < 1) {
qWarning("QEventDispatcherWin32::unregisterTimer: invalid argument"); qWarning("QEventDispatcherWin32::unregisterTimer: invalid argument");
return false; return false;
} }
@ -719,7 +723,7 @@ bool QEventDispatcherWin32::unregisterTimer(int timerId)
Q_D(QEventDispatcherWin32); Q_D(QEventDispatcherWin32);
WinTimerInfo *t = d->timerDict.take(timerId); WinTimerInfo *t = d->timerDict.take(qToUnderlying(timerId));
if (!t) if (!t)
return false; return false;
@ -758,50 +762,55 @@ bool QEventDispatcherWin32::unregisterTimers(QObject *object)
return true; return true;
} }
QList<QEventDispatcherWin32::TimerInfo> QList<QEventDispatcherWin32::TimerInfoV2>
QEventDispatcherWin32::registeredTimers(QObject *object) const QEventDispatcherWin32::timersForObject(QObject *object) const
{ {
#ifndef QT_NO_DEBUG #ifndef QT_NO_DEBUG
if (!object) { if (!object) {
qWarning("QEventDispatcherWin32:registeredTimers: invalid argument"); qWarning("QEventDispatcherWin32:registeredTimers: invalid argument");
return QList<TimerInfo>(); return QList<TimerInfoV2>();
} }
#endif #endif
Q_D(const QEventDispatcherWin32); Q_D(const QEventDispatcherWin32);
QList<TimerInfo> list; QList<TimerInfoV2> list;
for (WinTimerInfo *t : std::as_const(d->timerDict)) { for (WinTimerInfo *t : std::as_const(d->timerDict)) {
Q_ASSERT(t); Q_ASSERT(t);
if (t->obj == object) if (t->obj == object) {
list << TimerInfo(t->timerId, t->interval, t->timerType); list << TimerInfoV2{std::chrono::milliseconds{t->interval},
Qt::TimerId{t->timerId},
t->timerType};
}
} }
return list; return list;
} }
int QEventDispatcherWin32::remainingTime(int timerId) QEventDispatcherWin32::Duration QEventDispatcherWin32::remainingTime(Qt::TimerId timerId) const
{ {
#ifndef QT_NO_DEBUG #ifndef QT_NO_DEBUG
if (timerId < 1) { if (qToUnderlying(timerId) < 1) {
qWarning("QEventDispatcherWin32::remainingTime: invalid argument"); qWarning("QEventDispatcherWin32::remainingTime: invalid argument");
return -1; return Duration::min();
} }
#endif #endif
Q_D(QEventDispatcherWin32); Q_D(const QEventDispatcherWin32);
quint64 currentTime = qt_msectime(); WinTimerInfo *t = d->timerDict.value(qToUnderlying(timerId));
WinTimerInfo *t = d->timerDict.value(timerId);
if (t) { if (t) {
// timer found, return time to wait // 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 #ifndef QT_NO_DEBUG
qWarning("QEventDispatcherWin32::remainingTime: timer id %d not found", timerId); qWarning("QEventDispatcherWin32::remainingTime: timer id %d not found", qToUnderlying(timerId));
#endif #endif
return -1; return Duration::min();
} }
void QEventDispatcherWin32::wakeUp() void QEventDispatcherWin32::wakeUp()

View File

@ -29,7 +29,7 @@ class QEventDispatcherWin32Private;
// forward declaration // forward declaration
LRESULT QT_WIN_CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp); 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_OBJECT
Q_DECLARE_PRIVATE(QEventDispatcherWin32) Q_DECLARE_PRIVATE(QEventDispatcherWin32)
@ -43,12 +43,12 @@ public:
void registerSocketNotifier(QSocketNotifier *notifier) override; void registerSocketNotifier(QSocketNotifier *notifier) override;
void unregisterSocketNotifier(QSocketNotifier *notifier) override; void unregisterSocketNotifier(QSocketNotifier *notifier) override;
void registerTimer(int timerId, qint64 interval, Qt::TimerType timerType, QObject *object) override; void registerTimer(Qt::TimerId timerId, Duration interval, Qt::TimerType timerType,
bool unregisterTimer(int timerId) override; QObject *object) final;
bool unregisterTimers(QObject *object) override; bool unregisterTimer(Qt::TimerId timerId) final;
QList<TimerInfo> registeredTimers(QObject *object) const override; bool unregisterTimers(QObject *object) final;
QList<TimerInfoV2> timersForObject(QObject *object) const final;
int remainingTime(int timerId) override; Duration remainingTime(Qt::TimerId timerId) const final;
void wakeUp() override; void wakeUp() override;
void interrupt() override; void interrupt() override;
@ -85,7 +85,7 @@ struct QSockFd {
typedef QHash<qintptr, QSockFd> QSFDict; typedef QHash<qintptr, QSockFd> QSFDict;
struct WinTimerInfo { // internal timer info struct WinTimerInfo { // internal timer info
qint64 interval; qint64 interval; // - in milliseconds
quint64 timeout; // - when to actually fire quint64 timeout; // - when to actually fire
QObject *dispatcher; QObject *dispatcher;
QObject *obj; // - object to receive events QObject *obj; // - object to receive events

View File

@ -194,9 +194,9 @@ private:
// For precise timers, we expect the fudge factor to be present // For precise timers, we expect the fudge factor to be present
QAbstractEventDispatcher::Duration interval = QAbstractEventDispatcher::Duration interval =
fudgeInterval(PreciseTimerInterval, Qt::PreciseTimer); fudgeInterval(PreciseTimerInterval, Qt::PreciseTimer);
#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) #ifdef Q_OS_WIN
if (!qobject_cast<QAbstractEventDispatcherV2 *>(m_eventDispatcher)) // Windows does not have a nanosecond-resolution timer
interval = PreciseTimerInterval; interval = PreciseTimerInterval;
#endif #endif
QCOMPARE(timerInfo.interval, interval); QCOMPARE(timerInfo.interval, interval);
QCOMPARE(timerInfo.timerType, Qt::PreciseTimer); QCOMPARE(timerInfo.timerType, Qt::PreciseTimer);