From f2edb41c38d2e7f14b339daea4871512be252320 Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Tue, 10 Jan 2012 10:34:30 +0100 Subject: [PATCH] Use Qt::TimerType on Windows when starting timers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make all Qt::PreciseTimers and timers with intervals < 20ms use Multimedia timers for maximum accuracy. Qt::CoarseTimers and Qt::VeryCoarseTimers use normal Windows timers, with Qt::VeryCoarseTimers having their interval rounded to the nearest full second. Note that the Windows timer implementation does not attempt to align timers and reduce CPU wakeups like the UNIX implementation does. This might be done in the future, though. However, this change does the best we can do now, keeping most timers working as-is, while allowing explicit use of Multimedia timers via Qt::PreciseTimer. Change-Id: I1898272b101c572a2a9b9454fef27a651eb178f5 Reviewed-by: João Abecasis Reviewed-by: Friedemann Kleint --- src/corelib/global/qnamespace.qdoc | 6 ++++++ src/corelib/kernel/qeventdispatcher_win.cpp | 23 ++++++++++++--------- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/src/corelib/global/qnamespace.qdoc b/src/corelib/global/qnamespace.qdoc index 58ca8d312e..dbc399809f 100644 --- a/src/corelib/global/qnamespace.qdoc +++ b/src/corelib/global/qnamespace.qdoc @@ -2875,4 +2875,10 @@ \value PreciseTimer Precise timers try to keep millisecond accuracy \value CoarseTimer Coarse timers try to keep accuracy within 5% of the desired interval \value VeryCoarseTimer Very coarse timers only keep full second accuracy + + On Windows, Qt will use Windows's Multimedia timer facility (if available) + for Qt::PreciseTimer and normal Windows timers for Qt::CoarseTimer and + Qt::VeryCoarseTimer. The interval for Qt::VeryCoarseTimer is rounded to the + nearest full second (e.g. an interval of 23500ms will be rounded to + 24000ms, and 20300ms to 20000ms). */ diff --git a/src/corelib/kernel/qeventdispatcher_win.cpp b/src/corelib/kernel/qeventdispatcher_win.cpp index b52a4decac..41b1909bf1 100644 --- a/src/corelib/kernel/qeventdispatcher_win.cpp +++ b/src/corelib/kernel/qeventdispatcher_win.cpp @@ -530,18 +530,21 @@ void QEventDispatcherWin32Private::registerTimer(WinTimerInfo *t) Q_Q(QEventDispatcherWin32); int ok = 0; - if (t->interval > 20 || !t->interval || !qtimeSetEvent) { + uint interval = t->interval; + if (interval == 0u) { + // optimization for single-shot-zero-timer + QCoreApplication::postEvent(q, new QZeroTimerEvent(t->timerId)); ok = 1; - if (!t->interval) // optimization for single-shot-zero-timer - QCoreApplication::postEvent(q, new QZeroTimerEvent(t->timerId)); - else - ok = SetTimer(internalHwnd, t->timerId, (uint) t->interval, 0); - } else { - ok = t->fastTimerId = qtimeSetEvent(t->interval, 1, qt_fast_timer_proc, (DWORD_PTR)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); - if (ok == 0) { // fall back to normal timer if no more multimedia timers available - ok = SetTimer(internalHwnd, t->timerId, (uint) t->interval, 0); - } + } 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); } if (ok == 0)