WinRT: move most of GUI event dispatcher logic into core

The native event dispatcher is responsible for delivering callbacks
to non-GUI handlers, such as network socket listeners. So, the non-GUI
logic is moved into the core dispatcher so that the event loop works
better for apps (and test cases) which use QCoreApplication.

Change-Id: Ic5f7d939cf164198fd39aa5880e265ae560b39b4
Reviewed-by: Oliver Wolff <oliver.wolff@digia.com>
bb10
Andrew Knight 2014-02-10 10:11:18 +02:00 committed by The Qt Project
parent 2b66a37a3e
commit 2eda13c965
5 changed files with 70 additions and 74 deletions

View File

@ -44,18 +44,19 @@
#include <QtCore/QCoreApplication>
#include <QtCore/QThread>
#include <QtCore/QHash>
#include <private/qcoreapplication_p.h>
#include <private/qthread_p.h>
#include <private/qabstracteventdispatcher_p.h>
#include <wrl.h>
#include <windows.foundation.h>
#include <windows.system.threading.h>
#include <windows.ui.core.h>
#include <windows.applicationmodel.core.h>
using namespace Microsoft::WRL;
using namespace Microsoft::WRL::Wrappers;
using namespace ABI::Windows::System::Threading;
using namespace ABI::Windows::Foundation;
using namespace ABI::Windows::UI::Core;
using namespace ABI::Windows::ApplicationModel::Core;
QT_BEGIN_NAMESPACE
@ -92,7 +93,6 @@ public:
void unregisterTimer(WinRTTimerInfo *t);
void sendTimerEvent(int timerId);
private:
static HRESULT timerExpiredCallback(IThreadPoolTimer *timer);
@ -100,11 +100,33 @@ private:
QHash<IThreadPoolTimer *, int> timerIds;
ComPtr<IThreadPoolTimerStatics> timerFactory;
ComPtr<ICoreDispatcher> coreDispatcher;
bool interrupt;
};
QEventDispatcherWinRT::QEventDispatcherWinRT(QObject *parent)
: QAbstractEventDispatcher(*new QEventDispatcherWinRTPrivate, parent)
{
Q_D(QEventDispatcherWinRT);
ComPtr<ICoreApplication> application;
HRESULT hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_ApplicationModel_Core_CoreApplication).Get(),
IID_PPV_ARGS(&application));
if (SUCCEEDED(hr)) {
ComPtr<ICoreApplicationView> view;
hr = application->GetCurrentView(&view);
if (SUCCEEDED(hr)) {
ComPtr<ICoreWindow> window;
hr = view->get_CoreWindow(&window);
if (SUCCEEDED(hr)) {
hr = window->get_Dispatcher(&d->coreDispatcher);
if (SUCCEEDED(hr))
return;
}
}
}
qCritical("QEventDispatcherWinRT: Unable to capture the core dispatcher. %s",
qPrintable(qt_error_string(hr)));
}
QEventDispatcherWinRT::QEventDispatcherWinRT(QEventDispatcherWinRTPrivate &dd, QObject *parent)
@ -116,13 +138,41 @@ QEventDispatcherWinRT::~QEventDispatcherWinRT()
}
bool QEventDispatcherWinRT::processEvents(QEventLoop::ProcessEventsFlags flags)
{
Q_D(QEventDispatcherWinRT);
bool didProcess = false;
forever {
// Process native events
if (d->coreDispatcher)
d->coreDispatcher->ProcessEvents(CoreProcessEventsOption_ProcessAllIfPresent);
// Dispatch accumulated user events
didProcess = sendPostedEvents(flags);
if (didProcess)
break;
if (d->interrupt)
break;
// Short sleep if there is nothing to do
if (flags & QEventLoop::WaitForMoreEvents) {
emit aboutToBlock();
WaitForSingleObjectEx(GetCurrentThread(), 1, FALSE);
emit awake();
}
}
d->interrupt = false;
return didProcess;
}
bool QEventDispatcherWinRT::sendPostedEvents(QEventLoop::ProcessEventsFlags flags)
{
Q_UNUSED(flags);
// we are awake, broadcast it
emit awake();
QCoreApplicationPrivate::sendPostedEvents(0, 0, QThreadData::current());
if (hasPendingEvents()) {
QCoreApplication::sendPostedEvents();
return true;
}
return false;
}
@ -268,6 +318,8 @@ void QEventDispatcherWinRT::wakeUp()
void QEventDispatcherWinRT::interrupt()
{
Q_D(QEventDispatcherWinRT);
d->interrupt = true;
}
void QEventDispatcherWinRT::flush()
@ -318,6 +370,7 @@ bool QEventDispatcherWinRT::event(QEvent *e)
}
QEventDispatcherWinRTPrivate::QEventDispatcherWinRTPrivate()
: interrupt(false)
{
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
HRESULT hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_System_Threading_ThreadPoolTimer).Get(), &timerFactory);

View File

@ -99,6 +99,7 @@ public:
protected:
QEventDispatcherWinRT(QEventDispatcherWinRTPrivate &dd, QObject *parent = 0);
virtual bool sendPostedEvents(QEventLoop::ProcessEventsFlags flags);
bool event(QEvent *);
int activateTimers();
};

View File

@ -46,20 +46,10 @@
#include <QtCore/QThread>
#include <QtGui/QGuiApplication>
#include <Windows.ui.core.h>
#include <Windows.ApplicationModel.core.h>
using namespace ABI::Windows::ApplicationModel::Core;
using namespace ABI::Windows::UI::Core;
using namespace ABI::Windows::Foundation;
using namespace Microsoft::WRL;
QT_BEGIN_NAMESPACE
QWinRTEventDispatcher::QWinRTEventDispatcher(ICoreDispatcher *dispatcher, QObject *parent)
QWinRTEventDispatcher::QWinRTEventDispatcher(QObject *parent)
: QEventDispatcherWinRT(parent)
, m_dispatcher(dispatcher)
, m_interrupt(false)
{
}
@ -68,37 +58,11 @@ bool QWinRTEventDispatcher::hasPendingEvents()
return QEventDispatcherWinRT::hasPendingEvents() || QWindowSystemInterface::windowSystemEventsQueued();
}
void QWinRTEventDispatcher::interrupt()
bool QWinRTEventDispatcher::sendPostedEvents(QEventLoop::ProcessEventsFlags flags)
{
m_interrupt = true;
}
bool QWinRTEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags)
{
bool canWait = flags & QEventLoop::WaitForMoreEvents;
bool didProcess;
m_interrupt = false;
do {
// Send Qt events
didProcess = QEventDispatcherWinRT::processEvents(flags);
// Process system events
emit aboutToBlock();
if (m_dispatcher)
m_dispatcher->ProcessEvents(CoreProcessEventsOption_ProcessAllIfPresent);
emit awake();
// Dispatch accumulated user events
bool didProcess = QEventDispatcherWinRT::sendPostedEvents(flags);
if (!(flags & QEventLoop::ExcludeUserInputEvents))
didProcess |= QWindowSystemInterface::sendWindowSystemEvents(flags);
canWait = canWait && !didProcess && !m_interrupt;
// Short sleep if there is nothing to do
if (canWait) {
emit aboutToBlock();
WaitForSingleObjectEx(GetCurrentThread(), 1, true);
emit awake();
}
} while (canWait);
return didProcess;
}

View File

@ -44,36 +44,17 @@
#include <QtCore/private/qeventdispatcher_winrt_p.h>
#include <wrl.h>
namespace ABI {
namespace Windows {
namespace UI {
namespace Core {
struct ICoreDispatcher;
}
}
}
}
QT_BEGIN_NAMESPACE
class QWinRTEventDispatcher : public QEventDispatcherWinRT
{
Q_OBJECT
public:
explicit QWinRTEventDispatcher(ABI::Windows::UI::Core::ICoreDispatcher *dispatcher, QObject *parent = 0);
explicit QWinRTEventDispatcher(QObject *parent = 0);
protected:
void interrupt();
bool hasPendingEvents();
bool processEvents(QEventLoop::ProcessEventsFlags flags);
private:
Microsoft::WRL::ComPtr<ABI::Windows::UI::Core::ICoreDispatcher> m_dispatcher;
bool m_interrupt;
friend class QWinRTIntegration;
bool sendPostedEvents(QEventLoop::ProcessEventsFlags flags);
};
QT_END_NAMESPACE

View File

@ -114,10 +114,7 @@ QWinRTIntegration::~QWinRTIntegration()
QAbstractEventDispatcher *QWinRTIntegration::createEventDispatcher() const
{
ICoreDispatcher *dispatcher;
if (FAILED(m_screen->coreWindow()->get_Dispatcher(&dispatcher)))
qCritical("Could not capture UI Dispatcher");
return new QWinRTEventDispatcher(dispatcher);
return new QWinRTEventDispatcher;
}
bool QWinRTIntegration::hasCapability(QPlatformIntegration::Capability cap) const