WinRT: Clean up core event dispatcher

- Move private classes in the .cpp file (they aren't needed outside)
- Conform to Qt style, such as includes and braces
- Use ComPtr where appropriate
- Use foreach where appropriate
- Remove non-functional wake/interrupt leftovers
- Remove redundant timer list
- Make the timer callback a static method, so it won't crash if it
  gets called on shutdown

Task-number: QTBUG-35945

Change-Id: I5426fba2735e908a04ea60287f9936f5abde6644
Reviewed-by: Oliver Wolff <oliver.wolff@digia.com>
This commit is contained in:
Andrew Knight 2014-01-05 12:41:16 +02:00 committed by The Qt Project
parent 1f31c6c6b1
commit 9b19a69c89
3 changed files with 88 additions and 139 deletions

View File

@ -41,13 +41,15 @@
#include "qeventdispatcher_winrt_p.h" #include "qeventdispatcher_winrt_p.h"
#include "qelapsedtimer.h" #include <QtCore/QCoreApplication>
#include "qcoreapplication.h" #include <QtCore/QThread>
#include "qthread.h" #include <QtCore/QHash>
#include <private/qcoreapplication_p.h> #include <private/qcoreapplication_p.h>
#include <private/qthread_p.h> #include <private/qthread_p.h>
#include <private/qabstracteventdispatcher_p.h>
#include <wrl.h>
#include <windows.foundation.h> #include <windows.foundation.h>
#include <windows.system.threading.h> #include <windows.system.threading.h>
using namespace Microsoft::WRL; using namespace Microsoft::WRL;
@ -57,6 +59,58 @@ using namespace ABI::Windows::Foundation;
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
class QZeroTimerEvent : public QTimerEvent
{
public:
explicit inline QZeroTimerEvent(int timerId)
: QTimerEvent(timerId)
{ t = QEvent::ZeroTimerEvent; }
};
struct WinRTTimerInfo // internal timer info
{
WinRTTimerInfo() : timer(0) {}
int id;
int interval;
Qt::TimerType timerType;
quint64 timeout; // - when to actually fire
QObject *obj; // - object to receive events
bool inTimerEvent;
ComPtr<IThreadPoolTimer> timer;
};
class QEventDispatcherWinRTPrivate : public QAbstractEventDispatcherPrivate
{
Q_DECLARE_PUBLIC(QEventDispatcherWinRT)
public:
QEventDispatcherWinRTPrivate();
~QEventDispatcherWinRTPrivate();
void registerTimer(WinRTTimerInfo *t);
void unregisterTimer(WinRTTimerInfo *t);
void sendTimerEvent(int timerId);
private:
static HRESULT timerExpiredCallback(ABI::Windows::System::Threading::IThreadPoolTimer *source);
static int idForTimer(IThreadPoolTimer *timer)
{
QAbstractEventDispatcher *eventDispatcher = QCoreApplication::eventDispatcher();
if (!eventDispatcher)
return -1;
if (QEventDispatcherWinRTPrivate *that = static_cast<QEventDispatcherWinRTPrivate *>(get(eventDispatcher)))
return that->timerIds.value(timer, -1);
return -1;
}
QHash<int, WinRTTimerInfo*> timerDict;
QHash<IThreadPoolTimer *, int> timerIds;
ComPtr<IThreadPoolTimerStatics> timerFactory;
};
QEventDispatcherWinRT::QEventDispatcherWinRT(QObject *parent) QEventDispatcherWinRT::QEventDispatcherWinRT(QObject *parent)
: QAbstractEventDispatcher(*new QEventDispatcherWinRTPrivate, parent) : QAbstractEventDispatcher(*new QEventDispatcherWinRTPrivate, parent)
{ {
@ -110,19 +164,15 @@ void QEventDispatcherWinRT::registerTimer(int timerId, int interval, Qt::TimerTy
} }
Q_D(QEventDispatcherWinRT); Q_D(QEventDispatcherWinRT);
WinRTTimerInfo *t = new WinRTTimerInfo(); WinRTTimerInfo *t = new WinRTTimerInfo();
t->dispatcher = this; t->id = timerId;
t->timerId = timerId;
t->interval = interval; t->interval = interval;
t->timeout = interval;
t->timerType = timerType; t->timerType = timerType;
t->obj = object; t->obj = object;
t->inTimerEvent = false; t->inTimerEvent = false;
d->registerTimer(t); d->registerTimer(t);
d->timerVec.append(t); // store in timer vector d->timerDict.insert(t->id, t);
d->timerDict.insert(t->timerId, t); // store timers in dict
} }
bool QEventDispatcherWinRT::unregisterTimer(int timerId) bool QEventDispatcherWinRT::unregisterTimer(int timerId)
@ -137,17 +187,11 @@ bool QEventDispatcherWinRT::unregisterTimer(int timerId)
} }
Q_D(QEventDispatcherWinRT); Q_D(QEventDispatcherWinRT);
if (d->timerVec.isEmpty() || timerId <= 0)
return false;
WinRTTimerInfo *t = d->timerDict.value(timerId); WinRTTimerInfo *t = d->timerDict.value(timerId);
if (!t) if (!t)
return false; return false;
if (t->timer)
d->threadPoolTimerDict.remove(t->timer);
d->timerDict.remove(t->timerId);
d->timerVec.removeAll(t);
d->unregisterTimer(t); d->unregisterTimer(t);
return true; return true;
} }
@ -165,19 +209,9 @@ bool QEventDispatcherWinRT::unregisterTimers(QObject *object)
} }
Q_D(QEventDispatcherWinRT); Q_D(QEventDispatcherWinRT);
if (d->timerVec.isEmpty()) foreach (WinRTTimerInfo *t, d->timerDict) {
return false; if (t->obj == object)
register WinRTTimerInfo *t;
for (int i = 0; i < d->timerVec.size(); i++) {
t = d->timerVec.at(i);
if (t && t->obj == object) { // object found
if (t->timer)
d->threadPoolTimerDict.remove(t->timer);
d->timerDict.remove(t->timerId);
d->timerVec.removeAt(i);
d->unregisterTimer(t); d->unregisterTimer(t);
--i;
}
} }
return true; return true;
} }
@ -191,10 +225,9 @@ QList<QAbstractEventDispatcher::TimerInfo> QEventDispatcherWinRT::registeredTime
Q_D(const QEventDispatcherWinRT); Q_D(const QEventDispatcherWinRT);
QList<TimerInfo> list; QList<TimerInfo> list;
for (int i = 0; i < d->timerVec.size(); ++i) { foreach (const WinRTTimerInfo *t, d->timerDict) {
const WinRTTimerInfo *t = d->timerVec.at(i); if (t->obj == object)
if (t && t->obj == object) list.append(TimerInfo(t->id, t->interval, t->timerType));
list << TimerInfo(t->timerId, t->interval, t->timerType);
} }
return list; return list;
} }
@ -222,45 +255,28 @@ int QEventDispatcherWinRT::remainingTime(int timerId)
#endif #endif
Q_D(QEventDispatcherWinRT); Q_D(QEventDispatcherWinRT);
if (WinRTTimerInfo *t = d->timerDict.value(timerId)) {
if (d->timerVec.isEmpty()) const quint64 currentTime = qt_msectime();
return -1; if (currentTime < t->timeout) {
// time to wait
quint64 currentTime = qt_msectime(); return t->timeout - currentTime;
} else {
register WinRTTimerInfo *t; return 0;
for (int i = 0; i < d->timerVec.size(); i++) {
t = d->timerVec.at(i);
if (t && t->timerId == timerId) { // timer found
if (currentTime < t->timeout) {
// time to wait
return t->timeout - currentTime;
} else {
return 0;
}
} }
} }
#ifndef QT_NO_DEBUG #ifndef QT_NO_DEBUG
qWarning("QEventDispatcherWinRT::remainingTime: timer id %d not found", timerId); qWarning("QEventDispatcherWinRT::remainingTime: timer id %d not found", timerId);
#endif #endif
return -1; return -1;
} }
void QEventDispatcherWinRT::wakeUp() void QEventDispatcherWinRT::wakeUp()
{ {
Q_D(QEventDispatcherWinRT);
if (d->wakeUps.testAndSetAcquire(0, 1)) {
// ###TODO: is there any thing to wake up?
}
} }
void QEventDispatcherWinRT::interrupt() void QEventDispatcherWinRT::interrupt()
{ {
Q_D(QEventDispatcherWinRT);
d->interrupt = true;
wakeUp();
} }
void QEventDispatcherWinRT::flush() void QEventDispatcherWinRT::flush()
@ -274,13 +290,10 @@ void QEventDispatcherWinRT::startingUp()
void QEventDispatcherWinRT::closingDown() void QEventDispatcherWinRT::closingDown()
{ {
Q_D(QEventDispatcherWinRT); Q_D(QEventDispatcherWinRT);
foreach (WinRTTimerInfo *t, d->timerDict)
// clean up any timers d->unregisterTimer(t);
for (int i = 0; i < d->timerVec.count(); ++i)
d->unregisterTimer(d->timerVec.at(i));
d->timerVec.clear();
d->timerDict.clear(); d->timerDict.clear();
d->threadPoolTimerDict.clear(); d->timerIds.clear();
} }
bool QEventDispatcherWinRT::event(QEvent *e) bool QEventDispatcherWinRT::event(QEvent *e)
@ -314,8 +327,6 @@ bool QEventDispatcherWinRT::event(QEvent *e)
} }
QEventDispatcherWinRTPrivate::QEventDispatcherWinRTPrivate() QEventDispatcherWinRTPrivate::QEventDispatcherWinRTPrivate()
: interrupt(false)
, timerFactory(0)
{ {
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
HRESULT hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_System_Threading_ThreadPoolTimer).Get(), &timerFactory); HRESULT hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_System_Threading_ThreadPoolTimer).Get(), &timerFactory);
@ -325,8 +336,6 @@ QEventDispatcherWinRTPrivate::QEventDispatcherWinRTPrivate()
QEventDispatcherWinRTPrivate::~QEventDispatcherWinRTPrivate() QEventDispatcherWinRTPrivate::~QEventDispatcherWinRTPrivate()
{ {
if (timerFactory)
timerFactory->Release();
CoUninitialize(); CoUninitialize();
} }
@ -334,22 +343,22 @@ void QEventDispatcherWinRTPrivate::registerTimer(WinRTTimerInfo *t)
{ {
Q_Q(QEventDispatcherWinRT); Q_Q(QEventDispatcherWinRT);
int ok = 0; bool ok = false;
uint interval = t->interval; uint interval = t->interval;
if (interval == 0u) { if (interval == 0u) {
// optimization for single-shot-zero-timer // optimization for single-shot-zero-timer
QCoreApplication::postEvent(q, new QZeroTimerEvent(t->timerId)); QCoreApplication::postEvent(q, new QZeroTimerEvent(t->id));
ok = 1; ok = true;
} else { } else {
TimeSpan period; TimeSpan period;
period.Duration = interval * 10000; // TimeSpan is based on 100-nanosecond units period.Duration = interval * 10000; // TimeSpan is based on 100-nanosecond units
ok = SUCCEEDED(timerFactory->CreatePeriodicTimer( ok = SUCCEEDED(timerFactory->CreatePeriodicTimer(
Callback<ITimerElapsedHandler>(this, &QEventDispatcherWinRTPrivate::timerExpiredCallback).Get(), period, &t->timer)); Callback<ITimerElapsedHandler>(&QEventDispatcherWinRTPrivate::timerExpiredCallback).Get(), period, &t->timer));
if (ok) if (ok)
threadPoolTimerDict.insert(t->timer, t); timerIds.insert(t->timer.Get(), t->id);
} }
t->timeout = qt_msectime() + interval; t->timeout = qt_msectime() + interval;
if (ok == 0) if (!ok)
qErrnoWarning("QEventDispatcherWinRT::registerTimer: Failed to create a timer"); qErrnoWarning("QEventDispatcherWinRT::registerTimer: Failed to create a timer");
} }
@ -357,10 +366,10 @@ void QEventDispatcherWinRTPrivate::unregisterTimer(WinRTTimerInfo *t)
{ {
if (t->timer) { if (t->timer) {
t->timer->Cancel(); t->timer->Cancel();
t->timer->Release(); timerIds.remove(t->timer.Get());
} }
timerDict.remove(t->id);
delete t; delete t;
t = 0;
} }
void QEventDispatcherWinRTPrivate::sendTimerEvent(int timerId) void QEventDispatcherWinRTPrivate::sendTimerEvent(int timerId)
@ -370,22 +379,21 @@ void QEventDispatcherWinRTPrivate::sendTimerEvent(int timerId)
// send event, but don't allow it to recurse // send event, but don't allow it to recurse
t->inTimerEvent = true; t->inTimerEvent = true;
QTimerEvent e(t->timerId); QTimerEvent e(t->id);
QCoreApplication::sendEvent(t->obj, &e); QCoreApplication::sendEvent(t->obj, &e);
// timer could have been removed // timer could have been removed
t = timerDict.value(timerId); t = timerDict.value(timerId);
if (t) { if (t)
t->inTimerEvent = false; t->inTimerEvent = false;
}
} }
} }
HRESULT QEventDispatcherWinRTPrivate::timerExpiredCallback(IThreadPoolTimer *source) HRESULT QEventDispatcherWinRTPrivate::timerExpiredCallback(IThreadPoolTimer *source)
{ {
register WinRTTimerInfo *t = threadPoolTimerDict.value(source); int timerId = idForTimer(source);
if (t) if (timerId > 0)
QCoreApplication::postEvent(t->dispatcher, new QTimerEvent(t->timerId)); QCoreApplication::postEvent(QCoreApplication::eventDispatcher(), new QTimerEvent(timerId));
else else
qWarning("QEventDispatcherWinRT::timerExpiredCallback: Could not find timer %d in timer list", source); qWarning("QEventDispatcherWinRT::timerExpiredCallback: Could not find timer %d in timer list", source);
return S_OK; return S_OK;

View File

@ -55,21 +55,8 @@
// //
#include "QtCore/qabstracteventdispatcher.h" #include "QtCore/qabstracteventdispatcher.h"
#include "private/qabstracteventdispatcher_p.h"
#include <qt_windows.h> #include <qt_windows.h>
#include <wrl.h>
namespace ABI {
namespace Windows {
namespace System {
namespace Threading {
struct IThreadPoolTimer;
struct IThreadPoolTimerStatics;
}
}
}
}
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
@ -112,56 +99,10 @@ public:
protected: protected:
QEventDispatcherWinRT(QEventDispatcherWinRTPrivate &dd, QObject *parent = 0); QEventDispatcherWinRT(QEventDispatcherWinRTPrivate &dd, QObject *parent = 0);
bool event(QEvent *); bool event(QEvent *);
int activateTimers(); int activateTimers();
}; };
struct WinRTTimerInfo // internal timer info
{
WinRTTimerInfo() : timer(0) {}
QObject *dispatcher;
int timerId;
int interval;
Qt::TimerType timerType;
quint64 timeout; // - when to actually fire
QObject *obj; // - object to receive events
bool inTimerEvent;
ABI::Windows::System::Threading::IThreadPoolTimer *timer;
};
class QZeroTimerEvent : public QTimerEvent
{
public:
explicit inline QZeroTimerEvent(int timerId)
: QTimerEvent(timerId)
{ t = QEvent::ZeroTimerEvent; }
};
class Q_CORE_EXPORT QEventDispatcherWinRTPrivate : public QAbstractEventDispatcherPrivate
{
Q_DECLARE_PUBLIC(QEventDispatcherWinRT)
public:
QEventDispatcherWinRTPrivate();
~QEventDispatcherWinRTPrivate();
QList<WinRTTimerInfo*> timerVec;
QHash<int, WinRTTimerInfo*> timerDict;
QHash<ABI::Windows::System::Threading::IThreadPoolTimer*, WinRTTimerInfo*> threadPoolTimerDict;
void registerTimer(WinRTTimerInfo *t);
void unregisterTimer(WinRTTimerInfo *t);
void sendTimerEvent(int timerId);
HRESULT timerExpiredCallback(ABI::Windows::System::Threading::IThreadPoolTimer *source);
QAtomicInt wakeUps;
bool interrupt;
ABI::Windows::System::Threading::IThreadPoolTimerStatics *timerFactory;
};
QT_END_NAMESPACE QT_END_NAMESPACE
#endif // QEVENTDISPATCHER_WINRT_P_H #endif // QEVENTDISPATCHER_WINRT_P_H

View File

@ -55,7 +55,7 @@
#include <private/qcoreapplication_p.h> #include <private/qcoreapplication_p.h>
#ifdef Q_OS_WINRT #ifdef Q_OS_WINRT
#include "private/qeventdispatcher_winrt_p.h" #include <private/qeventdispatcher_winrt_p.h>
#else #else
#include <private/qeventdispatcher_win_p.h> #include <private/qeventdispatcher_win_p.h>
#endif #endif