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:
parent
1f31c6c6b1
commit
9b19a69c89
@ -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;
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
Loading…
x
Reference in New Issue
Block a user