summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/corelib/kernel/qeventdispatcher_win.cpp21
-rw-r--r--tests/auto/corelib/kernel/qtimer/tst_qtimer.cpp59
2 files changed, 74 insertions, 6 deletions
diff --git a/src/corelib/kernel/qeventdispatcher_win.cpp b/src/corelib/kernel/qeventdispatcher_win.cpp
index b55679f3d5..6da70cf0bd 100644
--- a/src/corelib/kernel/qeventdispatcher_win.cpp
+++ b/src/corelib/kernel/qeventdispatcher_win.cpp
@@ -561,6 +561,17 @@ static HWND qt_create_internal_window(const QEventDispatcherWin32 *eventDispatch
return wnd;
}
+static void calculateNextTimeout(WinTimerInfo *t, quint64 currentTime)
+{
+ uint interval = t->interval;
+ if ((interval >= 20000u && t->timerType != Qt::PreciseTimer) || t->timerType == Qt::VeryCoarseTimer) {
+ // round the interval, VeryCoarseTimers only have full second accuracy
+ interval = ((interval + 500)) / 1000 * 1000;
+ }
+ t->interval = interval;
+ t->timeout = currentTime + interval;
+}
+
void QEventDispatcherWin32Private::registerTimer(WinTimerInfo *t)
{
Q_ASSERT(internalHwnd);
@@ -568,6 +579,7 @@ void QEventDispatcherWin32Private::registerTimer(WinTimerInfo *t)
Q_Q(QEventDispatcherWin32);
int ok = 0;
+ calculateNextTimeout(t, qt_msectime());
uint interval = t->interval;
if (interval == 0u) {
// optimization for single-shot-zero-timer
@@ -576,17 +588,13 @@ void QEventDispatcherWin32Private::registerTimer(WinTimerInfo *t)
} else if ((interval < 20u || t->timerType == Qt::PreciseTimer) && qtimeSetEvent) {
ok = t->fastTimerId = qtimeSetEvent(interval, 1, qt_fast_timer_proc, (DWORD_PTR)t,
TIME_CALLBACK_FUNCTION | TIME_PERIODIC | TIME_KILL_SYNCHRONOUS);
- } else if (interval >= 20000u || t->timerType == Qt::VeryCoarseTimer) {
- // round the interval, VeryCoarseTimers only have full second accuracy
- interval = ((interval + 500)) / 1000 * 1000;
}
+
if (ok == 0) {
// user normal timers for (Very)CoarseTimers, or if no more multimedia timers available
ok = SetTimer(internalHwnd, t->timerId, interval, 0);
}
- t->timeout = qt_msectime() + interval;
-
if (ok == 0)
qErrnoWarning("QEventDispatcherWin32::registerTimer: Failed to create a timer");
}
@@ -611,6 +619,9 @@ void QEventDispatcherWin32Private::sendTimerEvent(int timerId)
// send event, but don't allow it to recurse
t->inTimerEvent = true;
+ // recalculate next emission
+ calculateNextTimeout(t, qt_msectime());
+
QTimerEvent e(t->timerId);
QCoreApplication::sendEvent(t->obj, &e);
diff --git a/tests/auto/corelib/kernel/qtimer/tst_qtimer.cpp b/tests/auto/corelib/kernel/qtimer/tst_qtimer.cpp
index c7011dbc04..1d1432f600 100644
--- a/tests/auto/corelib/kernel/qtimer/tst_qtimer.cpp
+++ b/tests/auto/corelib/kernel/qtimer/tst_qtimer.cpp
@@ -54,6 +54,8 @@ private slots:
void singleShotTimeout();
void timeout();
void remainingTime();
+ void remainingTimeDuringActivation_data();
+ void remainingTimeDuringActivation();
void livelock_data();
void livelock();
void timerInfiniteRecursion_data();
@@ -79,14 +81,16 @@ class TimerHelper : public QObject
{
Q_OBJECT
public:
- TimerHelper() : QObject(), count(0)
+ TimerHelper() : QObject(), count(0), remainingTime(-1)
{
}
int count;
+ int remainingTime;
public slots:
void timeout();
+ void fetchRemainingTime();
};
void TimerHelper::timeout()
@@ -94,6 +98,12 @@ void TimerHelper::timeout()
++count;
}
+void TimerHelper::fetchRemainingTime()
+{
+ QTimer *timer = static_cast<QTimer *>(sender());
+ remainingTime = timer->remainingTime();
+}
+
void tst_QTimer::zeroTimer()
{
TimerHelper helper;
@@ -158,6 +168,53 @@ void tst_QTimer::remainingTime()
int remainingTime = timer.remainingTime();
QVERIFY2(qAbs(remainingTime - 150) < 50, qPrintable(QString::number(remainingTime)));
+
+ // wait for the timer to actually fire now
+ connect(&timer, SIGNAL(timeout()), &QTestEventLoop::instance(), SLOT(exitLoop()));
+ QTestEventLoop::instance().enterLoop(5);
+ QVERIFY(!QTestEventLoop::instance().timeout());
+ QCOMPARE(helper.count, 1);
+
+ // the timer is still active, so it should have a non-zero remaining time
+ remainingTime = timer.remainingTime();
+ QVERIFY2(remainingTime > 150, qPrintable(QString::number(remainingTime)));
+}
+
+void tst_QTimer::remainingTimeDuringActivation_data()
+{
+ QTest::addColumn<bool>("singleShot");
+ QTest::newRow("repeating") << true;
+ QTest::newRow("single-shot") << true;
+}
+
+void tst_QTimer::remainingTimeDuringActivation()
+{
+ QFETCH(bool, singleShot);
+
+ TimerHelper helper;
+ QTimer timer;
+
+ const int timeout = 20; // 20 ms is short enough and should not round down to 0 in any timer mode
+
+ connect(&timer, SIGNAL(timeout()), &helper, SLOT(fetchRemainingTime()));
+ connect(&timer, SIGNAL(timeout()), &QTestEventLoop::instance(), SLOT(exitLoop()));
+ timer.start(timeout);
+ timer.setSingleShot(singleShot);
+
+ QTestEventLoop::instance().enterLoop(5);
+ QVERIFY(!QTestEventLoop::instance().timeout());
+ if (singleShot)
+ QCOMPARE(helper.remainingTime, -1); // timer not running
+ else
+ QCOMPARE(helper.remainingTime, timeout);
+
+ if (!singleShot) {
+ // do it again - see QTBUG-46940
+ helper.remainingTime = -1;
+ QTestEventLoop::instance().enterLoop(5);
+ QVERIFY(!QTestEventLoop::instance().timeout());
+ QCOMPARE(helper.remainingTime, timeout);
+ }
}
void tst_QTimer::livelock_data()