From 807ec8ea48281d5dbe365895fd9679da5b6753a5 Mon Sep 17 00:00:00 2001 From: Andrew Knight Date: Wed, 12 Aug 2015 12:43:54 +0300 Subject: winrt: Refactor platform plugin for XAML support By using XAML as the platform compositor, many benefits are possible: - Better input context handling for tablets - Better multiple window support (including non-fullscreen windows) - Support for transparent windows and window opacity - Integration with native platform controls - Simpler orientation handling on Windows Phone with built-in transitions This patch applies only the minimal parts to make XAML mode work just as the raw D3D mode. It does this by: - Moving all OpenGL parts into QWinRTEGLContext. This will allow us to have non-OpenGL windows later (e.g. Direct2D raster surfaces). - Moving more window-specific parts into QWinRTWindow. Each window creates a SwapChainPanel which can then be used for ANGLE (or Direct2D) content. - Moving non screen-specific parts into QWinRTIntegration. - Having QWinRTScreen create the base XAML element Canvas. - Running certain calls on the UI thread where necessary. The following code parts were removed: - The UIAutomationCore code in QWinRTInputContext, as this is incompatible with XAML automation. - The D3D Trim and device blacklist, as these have been fixed in ANGLE. - Core dispatcher processing in QEventDispatcherWinRT. Now there is only one native event dispatcher; it is always running and never needs to be pumped. Future commits should address: - Maintaining the window stack list and visibility using the XAML Canvas. - Allowing for windows (e.g. popups) to be sized and positioned instead of fullscreen. - Using the XAML automation API to improve the platform input context. [ChangeLog][QPA][winrt] Windows Store apps are now composited inside a XAML container, allowing for tighter integration with the native UI layer. Change-Id: I285c6dea657c5dab2fda2b1bd8e8e5dd15882c72 Reviewed-by: Oliver Wolff --- src/corelib/kernel/qeventdispatcher_winrt.cpp | 108 ++++++++++++++------------ 1 file changed, 58 insertions(+), 50 deletions(-) (limited to 'src/corelib/kernel/qeventdispatcher_winrt.cpp') diff --git a/src/corelib/kernel/qeventdispatcher_winrt.cpp b/src/corelib/kernel/qeventdispatcher_winrt.cpp index eceba8d002..f771974a24 100644 --- a/src/corelib/kernel/qeventdispatcher_winrt.cpp +++ b/src/corelib/kernel/qeventdispatcher_winrt.cpp @@ -40,6 +40,7 @@ #include #include +#include #include #include #include @@ -70,6 +71,23 @@ struct WinRTTimerInfo : public QAbstractEventDispatcher::TimerInfo { quint64 targetTime; }; +class AgileDispatchedHandler : public RuntimeClass, IDispatchedHandler, IAgileObject> +{ +public: + AgileDispatchedHandler(const std::function &delegate) + : delegate(delegate) + { + } + + HRESULT __stdcall Invoke() + { + return delegate(); + } + +private: + std::function delegate; +}; + class QEventDispatcherWinRTPrivate : public QAbstractEventDispatcherPrivate { Q_DECLARE_PUBLIC(QEventDispatcherWinRT) @@ -80,8 +98,6 @@ public: private: ComPtr timerFactory; - ComPtr coreDispatcher; - QPointer thread; QHash timerIdToObject; QVector timerInfos; @@ -136,40 +152,11 @@ private: } return true; } - - void fetchCoreDispatcher() - { - ComPtr application; - HRESULT hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_ApplicationModel_Core_CoreApplication).Get(), - IID_PPV_ARGS(&application)); - RETURN_VOID_IF_FAILED("Failed to get the application factory"); - - static ComPtr view; - if (view) - return; - - hr = application->get_MainView(&view); - RETURN_VOID_IF_FAILED("Failed to get the main view"); - - ComPtr view2; - hr = view.As(&view2); - RETURN_VOID_IF_FAILED("Failed to cast the main view"); - - hr = view2->get_Dispatcher(&coreDispatcher); - if (hr == HRESULT_FROM_WIN32(ERROR_NOT_FOUND)) // expected in thread pool cases - return; - RETURN_VOID_IF_FAILED("Failed to get core dispatcher"); - - thread = QThread::currentThread(); - } }; QEventDispatcherWinRT::QEventDispatcherWinRT(QObject *parent) : QAbstractEventDispatcher(*new QEventDispatcherWinRTPrivate, parent) { - Q_D(QEventDispatcherWinRT); - - d->fetchCoreDispatcher(); } QEventDispatcherWinRT::QEventDispatcherWinRT(QEventDispatcherWinRTPrivate &dd, QObject *parent) @@ -180,25 +167,43 @@ QEventDispatcherWinRT::~QEventDispatcherWinRT() { } +HRESULT QEventDispatcherWinRT::runOnXamlThread(const std::function &delegate) +{ + static __declspec(thread) ICoreDispatcher *dispatcher = nullptr; + if (!dispatcher) { + HRESULT hr; + ComPtr application; + hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_ApplicationModel_Core_CoreApplication).Get(), + IID_PPV_ARGS(&application)); + ComPtr view; + hr = application->get_MainView(&view); + Q_ASSERT_SUCCEEDED(hr); + ComPtr window; + hr = view->get_CoreWindow(&window); + Q_ASSERT_SUCCEEDED(hr); + hr = window->get_Dispatcher(&dispatcher); + Q_ASSERT_SUCCEEDED(hr); + } + + HRESULT hr; + boolean onXamlThread; + hr = dispatcher->get_HasThreadAccess(&onXamlThread); + Q_ASSERT_SUCCEEDED(hr); + if (onXamlThread) // Already there + return delegate(); + + ComPtr op; + hr = dispatcher->RunAsync(CoreDispatcherPriority_Normal, Make(delegate).Get(), &op); + if (FAILED(hr)) + return hr; + return QWinRTFunctions::await(op); +} + bool QEventDispatcherWinRT::processEvents(QEventLoop::ProcessEventsFlags flags) { Q_D(QEventDispatcherWinRT); - if (d->thread && d->thread != QThread::currentThread()) - d->fetchCoreDispatcher(); - do { - // Process native events - if (d->coreDispatcher) { - boolean hasThreadAccess; - HRESULT hr = d->coreDispatcher->get_HasThreadAccess(&hasThreadAccess); - if (SUCCEEDED(hr) && hasThreadAccess) { - hr = d->coreDispatcher->ProcessEvents(CoreProcessEventsOption_ProcessAllIfPresent); - if (FAILED(hr)) - qErrnoWarning(hr, "Failed to process events"); - } - } - // Additional user events have to be handled before timer events, but the function may not // return yet. const bool userEventsSent = sendPostedEvents(flags); @@ -284,10 +289,11 @@ void QEventDispatcherWinRT::registerTimer(int timerId, int interval, Qt::TimerTy TimeSpan period; period.Duration = interval ? (interval * 10000) : 1; // TimeSpan is based on 100-nanosecond units - IThreadPoolTimer *timer; const HANDLE handle = CreateEventEx(NULL, NULL, CREATE_EVENT_MANUAL_RESET, SYNCHRONIZE | EVENT_MODIFY_STATE); const HANDLE cancelHandle = CreateEventEx(NULL, NULL, CREATE_EVENT_MANUAL_RESET, SYNCHRONIZE|EVENT_MODIFY_STATE); - HRESULT hr = d->timerFactory->CreatePeriodicTimerWithCompletion( + HRESULT hr = runOnXamlThread([&]() { + IThreadPoolTimer *timer; + HRESULT hr = d->timerFactory->CreatePeriodicTimerWithCompletion( Callback([handle, cancelHandle](IThreadPoolTimer *timer) { DWORD cancelResult = WaitForSingleObjectEx(cancelHandle, 0, TRUE); if (cancelResult == WAIT_OBJECT_0) { @@ -306,13 +312,15 @@ void QEventDispatcherWinRT::registerTimer(int timerId, int interval, Qt::TimerTy CloseHandle(cancelHandle); return S_OK; }).Get(), &timer); + RETURN_HR_IF_FAILED("Failed to create periodic timer"); + + d->addTimer(timerId, interval, timerType, object, handle, cancelHandle); + return hr; + }); if (FAILED(hr)) { - qErrnoWarning(hr, "Failed to create periodic timer"); CloseHandle(handle); CloseHandle(cancelHandle); - return; } - d->addTimer(timerId, interval, timerType, object, handle, cancelHandle); } bool QEventDispatcherWinRT::unregisterTimer(int timerId) -- cgit v1.2.3