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)
: 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<milliseconds>(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::TimerInfo>
QEventDispatcherWin32::registeredTimers(QObject *object) const
QList<QEventDispatcherWin32::TimerInfoV2>
QEventDispatcherWin32::timersForObject(QObject *object) const
{
#ifndef QT_NO_DEBUG
if (!object) {
qWarning("QEventDispatcherWin32:registeredTimers: invalid argument");
return QList<TimerInfo>();
return QList<TimerInfoV2>();
}
#endif
Q_D(const QEventDispatcherWin32);
QList<TimerInfo> list;
QList<TimerInfoV2> 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()

View File

@ -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<TimerInfo> 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<TimerInfoV2> 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<qintptr, QSockFd> 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

View File

@ -194,8 +194,8 @@ 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<QAbstractEventDispatcherV2 *>(m_eventDispatcher))
#ifdef Q_OS_WIN
// Windows does not have a nanosecond-resolution timer
interval = PreciseTimerInterval;
#endif
QCOMPARE(timerInfo.interval, interval);