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/plugins/platforms/winrt/qwinrtcursor.cpp | 23 +- src/plugins/platforms/winrt/qwinrteglcontext.cpp | 133 +++++++-- src/plugins/platforms/winrt/qwinrteglcontext.h | 22 +- src/plugins/platforms/winrt/qwinrtinputcontext.cpp | 131 +-------- src/plugins/platforms/winrt/qwinrtinputcontext.h | 29 +- src/plugins/platforms/winrt/qwinrtintegration.cpp | 173 +++++++++++- src/plugins/platforms/winrt/qwinrtintegration.h | 43 ++- src/plugins/platforms/winrt/qwinrtscreen.cpp | 312 +++++---------------- src/plugins/platforms/winrt/qwinrtscreen.h | 33 +-- src/plugins/platforms/winrt/qwinrtwindow.cpp | 160 +++++++++-- src/plugins/platforms/winrt/qwinrtwindow.h | 8 +- 11 files changed, 561 insertions(+), 506 deletions(-) (limited to 'src/plugins/platforms') diff --git a/src/plugins/platforms/winrt/qwinrtcursor.cpp b/src/plugins/platforms/winrt/qwinrtcursor.cpp index 94ce23bd2c..707f3bf0ba 100644 --- a/src/plugins/platforms/winrt/qwinrtcursor.cpp +++ b/src/plugins/platforms/winrt/qwinrtcursor.cpp @@ -36,11 +36,13 @@ #include "qwinrtcursor.h" #include "qwinrtscreen.h" +#include #include #include #include +#include #include #include #include @@ -77,12 +79,17 @@ void QWinRTCursor::changeCursor(QCursor *windowCursor, QWindow *window) { Q_D(QWinRTCursor); + HRESULT hr; ICoreWindow *coreWindow = static_cast(window->screen()->handle())->coreWindow(); CoreCursorType type; switch (windowCursor ? windowCursor->shape() : Qt::ArrowCursor) { case Qt::BlankCursor: - coreWindow->put_PointerCursor(Q_NULLPTR); + hr = QEventDispatcherWinRT::runOnXamlThread([coreWindow]() { + coreWindow->put_PointerCursor(Q_NULLPTR); + return S_OK; + }); + RETURN_VOID_IF_FAILED("Failed to set blank native cursor"); return; default: case Qt::OpenHandCursor: @@ -142,11 +149,13 @@ void QWinRTCursor::changeCursor(QCursor *windowCursor, QWindow *window) } ComPtr cursor; - HRESULT hr = d->cursorFactory->CreateCursor(type, 0, &cursor); + hr = d->cursorFactory->CreateCursor(type, 0, &cursor); RETURN_VOID_IF_FAILED("Failed to create native cursor."); - hr = coreWindow->put_PointerCursor(cursor.Get()); - RETURN_VOID_IF_FAILED("Failed to set native cursor."); + hr = QEventDispatcherWinRT::runOnXamlThread([coreWindow, &cursor]() { + return coreWindow->put_PointerCursor(cursor.Get()); + }); + RETURN_VOID_IF_FAILED("Failed to set native cursor"); } #endif // QT_NO_CURSOR @@ -154,8 +163,12 @@ QPoint QWinRTCursor::pos() const { ICoreWindow *coreWindow = static_cast(QGuiApplication::primaryScreen()->handle())->coreWindow(); + HRESULT hr; Point point; - coreWindow->get_PointerPosition(&point); + hr = QEventDispatcherWinRT::runOnXamlThread([coreWindow, &point]() { + return coreWindow->get_PointerPosition(&point); + }); + RETURN_IF_FAILED("Failed to get native cursor position", QPoint()); return QPoint(point.X, point.Y); } diff --git a/src/plugins/platforms/winrt/qwinrteglcontext.cpp b/src/plugins/platforms/winrt/qwinrteglcontext.cpp index 42ffe8f716..44aab266ca 100644 --- a/src/plugins/platforms/winrt/qwinrteglcontext.cpp +++ b/src/plugins/platforms/winrt/qwinrteglcontext.cpp @@ -35,38 +35,131 @@ ****************************************************************************/ #include "qwinrteglcontext.h" +#include "qwinrtwindow.h" +#include +#include + +#include #define EGL_EGLEXT_PROTOTYPES -#include "EGL/eglext.h" +#include + +#include +#include QT_BEGIN_NAMESPACE -QWinRTEGLContext::QWinRTEGLContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, EGLDisplay display, EGLSurface surface, EGLConfig config) - : QEGLPlatformContext(format, share, display, &config), m_eglSurface(surface) +class QWinRTEGLContextPrivate +{ +public: + QSurfaceFormat format; + EGLDisplay eglDisplay; + EGLConfig eglConfig; + EGLContext eglContext; + QHash surfaceForWindow; +}; + +QWinRTEGLContext::QWinRTEGLContext(QOpenGLContext *context) + : d_ptr(new QWinRTEGLContextPrivate) +{ + Q_D(QWinRTEGLContext); + d->format = context->format(); + d->format.setRenderableType(QSurfaceFormat::OpenGLES); +} + +QWinRTEGLContext::~QWinRTEGLContext() { + Q_D(QWinRTEGLContext); + foreach (const EGLSurface &surface, d->surfaceForWindow) + eglDestroySurface(d->eglDisplay, surface); + if (d->eglContext != EGL_NO_CONTEXT) + eglDestroyContext(d->eglDisplay, d->eglContext); + if (d->eglDisplay != EGL_NO_DISPLAY) + eglTerminate(d->eglDisplay); } -void QWinRTEGLContext::swapBuffers(QPlatformSurface *surface) +void QWinRTEGLContext::initialize() { -#ifdef Q_OS_WINPHONE - const QSize size = surface->surface()->size(); - eglPostSubBufferNV(eglDisplay(), eglSurfaceForPlatformSurface(surface), - 0, 0, size.width(), size.height()); -#else - eglSwapBuffers(eglDisplay(), eglSurfaceForPlatformSurface(surface)); -#endif + Q_D(QWinRTEGLContext); + + eglBindAPI(EGL_OPENGL_ES_API); + d->eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); + if (d->eglDisplay == EGL_NO_DISPLAY) + qCritical("Failed to initialize EGL display: 0x%x", eglGetError()); + + if (!eglInitialize(d->eglDisplay, nullptr, nullptr)) + qCritical("Failed to initialize EGL: 0x%x", eglGetError()); + + d->eglConfig = q_configFromGLFormat(d->eglDisplay, d->format); + + const EGLint flags = d->format.testOption(QSurfaceFormat::DebugContext) + ? EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR : 0; + const EGLint attributes[] = { + EGL_CONTEXT_CLIENT_VERSION, d->format.majorVersion(), + EGL_CONTEXT_MINOR_VERSION_KHR, d->format.minorVersion(), + EGL_CONTEXT_FLAGS_KHR, flags, + EGL_NONE + }; + d->eglContext = eglCreateContext(d->eglDisplay, d->eglConfig, nullptr, attributes); + if (d->eglContext == EGL_NO_CONTEXT) { + qWarning("QEGLPlatformContext: Failed to create context: %x", eglGetError()); + return; + } } -EGLSurface QWinRTEGLContext::eglSurfaceForPlatformSurface(QPlatformSurface *surface) +bool QWinRTEGLContext::makeCurrent(QPlatformSurface *windowSurface) { - if (surface->surface()->surfaceClass() == QSurface::Window) { - // All windows use the same surface - return m_eglSurface; - } else { - // TODO: return EGL surfaces for offscreen surfaces - qWarning("This plugin does not support offscreen surfaces."); - return EGL_NO_SURFACE; + Q_D(QWinRTEGLContext); + Q_ASSERT(windowSurface->surface()->surfaceType() == QSurface::OpenGLSurface); + + EGLSurface surface = d->surfaceForWindow.value(windowSurface); + if (surface == EGL_NO_SURFACE) { + QWinRTWindow *window = static_cast(windowSurface); + HRESULT hr = QEventDispatcherWinRT::runOnXamlThread([this, d, window, &surface]() { + surface = eglCreateWindowSurface(d->eglDisplay, d->eglConfig, + reinterpret_cast(window->winId()), + nullptr); + if (surface == EGL_NO_SURFACE) { + qCritical("Failed to create EGL window surface: 0x%x", eglGetError()); + return E_FAIL; + } + return S_OK; + }); + if (FAILED(hr)) + return false; + d->surfaceForWindow.insert(windowSurface, surface); } + + const bool ok = eglMakeCurrent(d->eglDisplay, surface, surface, d->eglContext); + if (!ok) { + qWarning("QEGLPlatformContext: eglMakeCurrent failed: %x", eglGetError()); + return false; + } + + eglSwapInterval(d->eglDisplay, d->format.swapInterval()); + return true; +} + +void QWinRTEGLContext::doneCurrent() +{ + Q_D(const QWinRTEGLContext); + const bool ok = eglMakeCurrent(d->eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + if (!ok) + qWarning("QEGLPlatformContext: eglMakeCurrent failed: %x", eglGetError()); +} + +void QWinRTEGLContext::swapBuffers(QPlatformSurface *windowSurface) +{ + Q_D(QWinRTEGLContext); + Q_ASSERT(windowSurface->surface()->surfaceType() == QSurface::OpenGLSurface); + + eglSwapBuffers(d->eglDisplay, d->surfaceForWindow.value(windowSurface)); +} + +QSurfaceFormat QWinRTEGLContext::format() const +{ + Q_D(const QWinRTEGLContext); + return d->format; } QFunctionPointer QWinRTEGLContext::getProcAddress(const QByteArray &procName) @@ -221,7 +314,7 @@ QFunctionPointer QWinRTEGLContext::getProcAddress(const QByteArray &procName) if (i != standardFuncs.end()) return i.value(); - return QEGLPlatformContext::getProcAddress(procName); + return eglGetProcAddress(procName.constData()); } QT_END_NAMESPACE diff --git a/src/plugins/platforms/winrt/qwinrteglcontext.h b/src/plugins/platforms/winrt/qwinrteglcontext.h index 958d623c4c..31a2124b03 100644 --- a/src/plugins/platforms/winrt/qwinrteglcontext.h +++ b/src/plugins/platforms/winrt/qwinrteglcontext.h @@ -37,23 +37,29 @@ #ifndef QWINDOWSEGLCONTEXT_H #define QWINDOWSEGLCONTEXT_H -#include +#include QT_BEGIN_NAMESPACE -class QWinRTEGLContext : public QEGLPlatformContext +class QWinRTEGLContextPrivate; +class QWinRTEGLContext : public QPlatformOpenGLContext { public: - explicit QWinRTEGLContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, EGLDisplay display, EGLSurface surface, EGLConfig config); + explicit QWinRTEGLContext(QOpenGLContext *context); + ~QWinRTEGLContext(); - void swapBuffers(QPlatformSurface *surface) Q_DECL_OVERRIDE; - QFunctionPointer getProcAddress(const QByteArray &procName) Q_DECL_OVERRIDE; + void initialize() Q_DECL_OVERRIDE; + + bool makeCurrent(QPlatformSurface *windowSurface) Q_DECL_OVERRIDE; + void doneCurrent() Q_DECL_OVERRIDE; + void swapBuffers(QPlatformSurface *windowSurface) Q_DECL_OVERRIDE; -protected: - EGLSurface eglSurfaceForPlatformSurface(QPlatformSurface *surface); + QSurfaceFormat format() const Q_DECL_OVERRIDE; + QFunctionPointer getProcAddress(const QByteArray &procName) Q_DECL_OVERRIDE; private: - EGLSurface m_eglSurface; + QScopedPointer d_ptr; + Q_DECLARE_PRIVATE(QWinRTEGLContext) }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/winrt/qwinrtinputcontext.cpp b/src/plugins/platforms/winrt/qwinrtinputcontext.cpp index c94b53ef1c..7bd9e87ca6 100644 --- a/src/plugins/platforms/winrt/qwinrtinputcontext.cpp +++ b/src/plugins/platforms/winrt/qwinrtinputcontext.cpp @@ -182,135 +182,6 @@ void QWinRTInputContext::hideInputPanel() qErrnoWarning(hr, "Failed to hide input panel."); } -#else // Q_OS_WINPHONE - -// IRawElementProviderSimple -HRESULT QWinRTInputContext::get_ProviderOptions(ProviderOptions *retVal) -{ - *retVal = ProviderOptions_ServerSideProvider|ProviderOptions_UseComThreading; - return S_OK; -} - -HRESULT QWinRTInputContext::GetPatternProvider(PATTERNID id, IUnknown **retVal) -{ - switch (id) { - case 10002: //UIA_ValuePatternId - return QueryInterface(__uuidof(IValueProvider), (void**)retVal); - break; - case 10014: //UIA_TextPatternId: - return QueryInterface(__uuidof(ITextProvider), (void**)retVal); - case 10029: //UIA_TextChildPatternId: - *retVal = nullptr; - break; - default: - qWarning("Unhandled pattern ID: %d", id); - break; - } - return S_OK; -} - -HRESULT QWinRTInputContext::GetPropertyValue(PROPERTYID idProp, VARIANT *retVal) -{ - switch (idProp) { - case 30003: //UIA_ControlTypePropertyId - retVal->vt = VT_I4; - retVal->lVal = 50025; //UIA_CustomControlTypeId - break; - case 30008: //UIA_IsKeyboardFocusablePropertyId - case 30009: //UIA_HasKeyboardFocusPropertyId - // These are probably never actually called - case 30016: //UIA_IsControlElementPropertyId - case 30017: //UIA_IsContentElementPropertyId - retVal->vt = VT_BOOL; - retVal->boolVal = VARIANT_TRUE; - break; - case 30019: //UIA_IsPasswordPropertyId - retVal->vt = VT_BOOL; - retVal->boolVal = VARIANT_FALSE; - break; - case 30020: //UIA_NativeWindowHandlePropertyId - retVal->vt = VT_PTR; - retVal->punkVal = m_screen->coreWindow(); - break; - } - return S_OK; -} - -HRESULT QWinRTInputContext::get_HostRawElementProvider(IRawElementProviderSimple **retVal) -{ - // Return the window's element provider - IInspectable *hostProvider; - HRESULT hr = m_screen->coreWindow()->get_AutomationHostProvider(&hostProvider); - if (SUCCEEDED(hr)) { - hr = hostProvider->QueryInterface(IID_PPV_ARGS(retVal)); - hostProvider->Release(); - } - return hr; -} - -// ITextProvider -HRESULT QWinRTInputContext::GetSelection(SAFEARRAY **) -{ - // To be useful, requires listening to the focus object for a selection change and raising an event - return S_OK; -} - -HRESULT QWinRTInputContext::GetVisibleRanges(SAFEARRAY **) -{ - // To be useful, requires listening to the focus object for a selection change and raising an event - return S_OK; -} - -HRESULT QWinRTInputContext::RangeFromChild(IRawElementProviderSimple *,ITextRangeProvider **) -{ - // To be useful, requires listening to the focus object for a selection change and raising an event - return S_OK; -} - -HRESULT QWinRTInputContext::RangeFromPoint(UiaPoint, ITextRangeProvider **) -{ - // To be useful, requires listening to the focus object for a selection change and raising an event - return S_OK; -} - -HRESULT QWinRTInputContext::get_DocumentRange(ITextRangeProvider **) -{ - // To be useful, requires listening to the focus object for a selection change and raising an event - return S_OK; -} - -HRESULT QWinRTInputContext::get_SupportedTextSelection(SupportedTextSelection *) -{ - // To be useful, requires listening to the focus object for a selection change and raising an event - return S_OK; -} - -// IValueProvider -HRESULT QWinRTInputContext::SetValue(LPCWSTR) -{ - // To be useful, requires listening to the focus object for a value change and raising an event - // May be useful for inputPanel autocomplete, etc. - return S_OK; -} - -HRESULT QWinRTInputContext::get_Value(BSTR *) -{ - // To be useful, requires listening to the focus object for a value change and raising an event - // May be useful for inputPanel autocomplete, etc. - return S_OK; -} - -HRESULT QWinRTInputContext::get_IsReadOnly(BOOL *isReadOnly) -{ - // isReadOnly dictates keyboard opening behavior when view is tapped. - // We need to decide if the user tapped within a control which is about to receive focus... - // Since this isn't possible (this function gets called before we receive the touch event), - // the most platform-aligned option is to show the keyboard if an editable item has focus, - // and close the keyboard if it is already open. - *isReadOnly = m_isInputPanelVisible || !inputMethodAccepted(); - return S_OK; -} - -#endif // !Q_OS_WINPHONE +#endif // Q_OS_WINPHONE QT_END_NAMESPACE diff --git a/src/plugins/platforms/winrt/qwinrtinputcontext.h b/src/plugins/platforms/winrt/qwinrtinputcontext.h index ce7fbabf49..cc3bce435f 100644 --- a/src/plugins/platforms/winrt/qwinrtinputcontext.h +++ b/src/plugins/platforms/winrt/qwinrtinputcontext.h @@ -41,9 +41,6 @@ #include #include -#ifndef Q_OS_WINPHONE -# include -#endif namespace ABI { namespace Windows { @@ -63,11 +60,6 @@ QT_BEGIN_NAMESPACE class QWinRTScreen; class QWinRTInputContext : public QPlatformInputContext -#ifndef Q_OS_WINPHONE - , public Microsoft::WRL::RuntimeClass< - Microsoft::WRL::RuntimeClassFlags, - IRawElementProviderSimple, ITextProvider, IValueProvider> -#endif // !Q_OS_WINPHONE { public: explicit QWinRTInputContext(QWinRTScreen *); @@ -79,26 +71,7 @@ public: #ifdef Q_OS_WINPHONE void showInputPanel(); void hideInputPanel(); -#else // Q_OS_WINPHONE - // IRawElementProviderSimple - HRESULT __stdcall get_ProviderOptions(ProviderOptions *retVal); - HRESULT __stdcall GetPatternProvider(PATTERNID, IUnknown **); - HRESULT __stdcall GetPropertyValue(PROPERTYID idProp, VARIANT *retVal); - HRESULT __stdcall get_HostRawElementProvider(IRawElementProviderSimple **retVal); - - // ITextProvider - HRESULT __stdcall GetSelection(SAFEARRAY **); - HRESULT __stdcall GetVisibleRanges(SAFEARRAY **); - HRESULT __stdcall RangeFromChild(IRawElementProviderSimple *,ITextRangeProvider **); - HRESULT __stdcall RangeFromPoint(UiaPoint, ITextRangeProvider **); - HRESULT __stdcall get_DocumentRange(ITextRangeProvider **); - HRESULT __stdcall get_SupportedTextSelection(SupportedTextSelection *); - - // IValueProvider - HRESULT __stdcall SetValue(LPCWSTR); - HRESULT __stdcall get_Value(BSTR *); - HRESULT __stdcall get_IsReadOnly(BOOL *); -#endif // !Q_OS_WINPHONE +#endif private: HRESULT onShowing(ABI::Windows::UI::ViewManagement::IInputPane *, diff --git a/src/plugins/platforms/winrt/qwinrtintegration.cpp b/src/plugins/platforms/winrt/qwinrtintegration.cpp index 70ee6dbe6a..7079d46523 100644 --- a/src/plugins/platforms/winrt/qwinrtintegration.cpp +++ b/src/plugins/platforms/winrt/qwinrtintegration.cpp @@ -45,37 +45,138 @@ #include "qwinrtfontdatabase.h" #include "qwinrttheme.h" +#include +#include #include +#include +#include #include +#include +#include +#include #include #include -#include +#include +#ifdef Q_OS_WINPHONE +# include +#endif using namespace Microsoft::WRL; +using namespace Microsoft::WRL::Wrappers; using namespace ABI::Windows::Foundation; +using namespace ABI::Windows::ApplicationModel; +using namespace ABI::Windows::ApplicationModel::Core; +using namespace ABI::Windows::UI; using namespace ABI::Windows::UI::Core; using namespace ABI::Windows::UI::ViewManagement; +using namespace ABI::Windows::Graphics::Display; using namespace ABI::Windows::ApplicationModel::Core; +#ifdef Q_OS_WINPHONE +using namespace ABI::Windows::Phone::UI::Input; +#endif + +typedef IEventHandler ResumeHandler; +typedef IEventHandler SuspendHandler; +#ifdef Q_OS_WINPHONE +typedef IEventHandler BackPressedHandler; +#endif QT_BEGIN_NAMESPACE -QWinRTIntegration::QWinRTIntegration() - : m_success(false) - , m_fontDatabase(new QWinRTFontDatabase) - , m_services(new QWinRTServices) +typedef HRESULT (__stdcall ICoreApplication::*CoreApplicationCallbackRemover)(EventRegistrationToken); +uint qHash(CoreApplicationCallbackRemover key) { void *ptr = *(void **)(&key); return qHash(ptr); } +#ifdef Q_OS_WINPHONE +typedef HRESULT (__stdcall IHardwareButtonsStatics::*HardwareButtonsCallbackRemover)(EventRegistrationToken); +uint qHash(HardwareButtonsCallbackRemover key) { void *ptr = *(void **)(&key); return qHash(ptr); } +#endif + +class QWinRTIntegrationPrivate +{ +public: + QPlatformFontDatabase *fontDatabase; + QPlatformServices *platformServices; + QWinRTScreen *mainScreen; + QScopedPointer inputContext; + + ComPtr application; + QHash applicationTokens; +#ifdef Q_OS_WINPHONE + ComPtr hardwareButtons; + QHash buttonsTokens; +#endif +}; + +QWinRTIntegration::QWinRTIntegration() : d_ptr(new QWinRTIntegrationPrivate) { - m_screen = new QWinRTScreen; - screenAdded(m_screen); + Q_D(QWinRTIntegration); + + d->fontDatabase = new QWinRTFontDatabase; + + HRESULT hr; + hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_ApplicationModel_Core_CoreApplication).Get(), + IID_PPV_ARGS(&d->application)); + Q_ASSERT_SUCCEEDED(hr); + hr = d->application->add_Suspending(Callback(this, &QWinRTIntegration::onSuspended).Get(), + &d->applicationTokens[&ICoreApplication::remove_Resuming]); + Q_ASSERT_SUCCEEDED(hr); + hr = d->application->add_Resuming(Callback(this, &QWinRTIntegration::onResume).Get(), + &d->applicationTokens[&ICoreApplication::remove_Resuming]); + Q_ASSERT_SUCCEEDED(hr); - m_success = true; +#ifdef Q_OS_WINPHONE + hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Phone_UI_Input_HardwareButtons).Get(), + IID_PPV_ARGS(&d->hardwareButtons)); + Q_ASSERT_SUCCEEDED(hr); + hr = d->hardwareButtons->add_BackPressed(Callback(this, &QWinRTIntegration::onBackButtonPressed).Get(), + &d->buttonsTokens[&IHardwareButtonsStatics::remove_BackPressed]); + Q_ASSERT_SUCCEEDED(hr); +#endif // Q_OS_WINPHONE + + hr = QEventDispatcherWinRT::runOnXamlThread([this, d]() { + HRESULT hr; + ComPtr windowStatics; + hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_UI_Xaml_Window).Get(), + IID_PPV_ARGS(&windowStatics)); + Q_ASSERT_SUCCEEDED(hr); + ComPtr window; + hr = windowStatics->get_Current(&window); + Q_ASSERT_SUCCEEDED(hr); + hr = window->Activate(); + Q_ASSERT_SUCCEEDED(hr); + + d->mainScreen = new QWinRTScreen(window.Get()); + d->inputContext.reset(new QWinRTInputContext(d->mainScreen)); + screenAdded(d->mainScreen); + return S_OK; + }); + Q_ASSERT_SUCCEEDED(hr); } QWinRTIntegration::~QWinRTIntegration() { + Q_D(QWinRTIntegration); + HRESULT hr; +#ifdef Q_OS_WINPHONE + for (QHash::const_iterator i = d->buttonsTokens.begin(); i != d->buttonsTokens.end(); ++i) { + hr = (d->hardwareButtons.Get()->*i.key())(i.value()); + Q_ASSERT_SUCCEEDED(hr); + } +#endif + for (QHash::const_iterator i = d->applicationTokens.begin(); i != d->applicationTokens.end(); ++i) { + hr = (d->application.Get()->*i.key())(i.value()); + Q_ASSERT_SUCCEEDED(hr); + } + destroyScreen(d->mainScreen); Windows::Foundation::Uninitialize(); } +bool QWinRTIntegration::succeeded() const +{ + Q_D(const QWinRTIntegration); + return d->mainScreen; +} + QAbstractEventDispatcher *QWinRTIntegration::createEventDispatcher() const { return new QWinRTEventDispatcher; @@ -112,28 +213,31 @@ QPlatformBackingStore *QWinRTIntegration::createPlatformBackingStore(QWindow *wi QPlatformOpenGLContext *QWinRTIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const { - QWinRTScreen *screen = static_cast(context->screen()->handle()); - return new QWinRTEGLContext(context->format(), context->handle(), screen->eglDisplay(), screen->eglSurface(), screen->eglConfig()); + return new QWinRTEGLContext(context); } QPlatformFontDatabase *QWinRTIntegration::fontDatabase() const { - return m_fontDatabase; + Q_D(const QWinRTIntegration); + return d->fontDatabase; } QPlatformInputContext *QWinRTIntegration::inputContext() const { - return m_screen->inputContext(); + Q_D(const QWinRTIntegration); + return d->inputContext.data(); } QPlatformServices *QWinRTIntegration::services() const { - return m_services; + Q_D(const QWinRTIntegration); + return d->platformServices; } Qt::KeyboardModifiers QWinRTIntegration::queryKeyboardModifiers() const { - return m_screen->keyboardModifiers(); + Q_D(const QWinRTIntegration); + return d->mainScreen->keyboardModifiers(); } QStringList QWinRTIntegration::themeNames() const @@ -149,4 +253,45 @@ name) const return 0; } + +// System-level integration points + +#ifdef Q_OS_WINPHONE +HRESULT QWinRTIntegration::onBackButtonPressed(IInspectable *, IBackPressedEventArgs *args) +{ + Q_D(QWinRTIntegration); + + QKeyEvent backPress(QEvent::KeyPress, Qt::Key_Back, Qt::NoModifier); + QKeyEvent backRelease(QEvent::KeyRelease, Qt::Key_Back, Qt::NoModifier); + backPress.setAccepted(false); + backRelease.setAccepted(false); + + QWindow *window = d->mainScreen->topWindow(); + QObject *receiver = window ? static_cast(window) + : static_cast(QCoreApplication::instance()); + + // If the event is ignored, the app go to the background + QCoreApplication::sendEvent(receiver, &backPress); + QCoreApplication::sendEvent(receiver, &backRelease); + args->put_Handled(backPress.isAccepted() || backRelease.isAccepted()); + + return S_OK; +} +#endif // Q_OS_WINPHONE + +HRESULT QWinRTIntegration::onSuspended(IInspectable *, ISuspendingEventArgs *) +{ + QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationSuspended); + QWindowSystemInterface::flushWindowSystemEvents(); + return S_OK; +} + +HRESULT QWinRTIntegration::onResume(IInspectable *, IInspectable *) +{ + // First the system invokes onResume and then changes + // the visibility of the screen to be active. + QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationHidden); + return S_OK; +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/winrt/qwinrtintegration.h b/src/plugins/platforms/winrt/qwinrtintegration.h index bbd6c1e41b..0115e034b5 100644 --- a/src/plugins/platforms/winrt/qwinrtintegration.h +++ b/src/plugins/platforms/winrt/qwinrtintegration.h @@ -39,11 +39,33 @@ #include +namespace ABI { + namespace Windows { + namespace ApplicationModel { + struct ISuspendingEventArgs; + } + namespace Foundation { + struct IAsyncAction; + } +#ifdef Q_OS_WINPHONE + namespace Phone { + namespace UI { + namespace Input { + struct IBackPressedEventArgs; + } + } + } +#endif + } +} +struct IAsyncInfo; +struct IInspectable; + QT_BEGIN_NAMESPACE class QAbstractEventDispatcher; -class QWinRTScreen; +class QWinRTIntegrationPrivate; class QWinRTIntegration : public QPlatformIntegration { private: @@ -53,10 +75,12 @@ public: static QWinRTIntegration *create() { - QWinRTIntegration *integration = new QWinRTIntegration; - return integration->m_success ? integration : 0; + QScopedPointer integration(new QWinRTIntegration); + return integration->succeeded() ? integration.take() : nullptr; } + bool succeeded() const; + bool hasCapability(QPlatformIntegration::Capability cap) const; QVariant styleHint(StyleHint hint) const; @@ -71,11 +95,16 @@ public: QStringList themeNames() const; QPlatformTheme *createPlatformTheme(const QString &name) const; + private: - bool m_success; - QWinRTScreen *m_screen; - QPlatformFontDatabase *m_fontDatabase; - QPlatformServices *m_services; +#ifdef Q_OS_WINPHONE + HRESULT onBackButtonPressed(IInspectable *, ABI::Windows::Phone::UI::Input::IBackPressedEventArgs *args); +#endif + HRESULT onSuspended(IInspectable *, ABI::Windows::ApplicationModel::ISuspendingEventArgs *); + HRESULT onResume(IInspectable *, IInspectable *); + + QScopedPointer d_ptr; + Q_DECLARE_PRIVATE(QWinRTIntegration) }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/winrt/qwinrtscreen.cpp b/src/plugins/platforms/winrt/qwinrtscreen.cpp index 1d36bb31f6..89ad33657b 100644 --- a/src/plugins/platforms/winrt/qwinrtscreen.cpp +++ b/src/plugins/platforms/winrt/qwinrtscreen.cpp @@ -36,26 +36,18 @@ #include "qwinrtscreen.h" -#define EGL_EGLEXT_PROTOTYPES -#include -#include -#include -#ifndef Q_OS_WINPHONE -#include -#endif - #include "qwinrtbackingstore.h" #include "qwinrtinputcontext.h" #include "qwinrtcursor.h" -#include "qwinrteglcontext.h" +#include #include #include -#include #include #include #include +#include #include #include #include @@ -64,12 +56,10 @@ #include #include #include +#include #include #include #include -#ifdef Q_OS_WINPHONE -#include -#endif using namespace Microsoft::WRL; using namespace Microsoft::WRL::Wrappers; @@ -77,17 +67,13 @@ using namespace ABI::Windows::ApplicationModel; using namespace ABI::Windows::ApplicationModel::Core; using namespace ABI::Windows::Foundation; using namespace ABI::Windows::System; +using namespace ABI::Windows::UI; using namespace ABI::Windows::UI::Core; using namespace ABI::Windows::UI::Input; using namespace ABI::Windows::UI::ViewManagement; using namespace ABI::Windows::Devices::Input; using namespace ABI::Windows::Graphics::Display; -#ifdef Q_OS_WINPHONE -using namespace ABI::Windows::Phone::UI::Input; -#endif -typedef IEventHandler ResumeHandler; -typedef IEventHandler SuspendHandler; typedef ITypedEventHandler ActivatedHandler; typedef ITypedEventHandler ClosedHandler; typedef ITypedEventHandler CharacterReceivedHandler; @@ -96,11 +82,7 @@ typedef ITypedEventHandler KeyHandler; typedef ITypedEventHandler PointerHandler; typedef ITypedEventHandler SizeChangedHandler; typedef ITypedEventHandler VisibilityChangedHandler; -typedef ITypedEventHandler AutomationProviderRequestedHandler; typedef ITypedEventHandler DisplayInformationHandler; -#ifdef Q_OS_WINPHONE -typedef IEventHandler BackPressedHandler; -#endif QT_BEGIN_NAMESPACE @@ -419,33 +401,23 @@ static inline Qt::Key qKeyFromCode(quint32 code, int mods) return static_cast(code & 0xff); } -typedef HRESULT (__stdcall ICoreApplication::*CoreApplicationCallbackRemover)(EventRegistrationToken); -uint qHash(CoreApplicationCallbackRemover key) { void *ptr = *(void **)(&key); return qHash(ptr); } typedef HRESULT (__stdcall ICoreWindow::*CoreWindowCallbackRemover)(EventRegistrationToken); uint qHash(CoreWindowCallbackRemover key) { void *ptr = *(void **)(&key); return qHash(ptr); } typedef HRESULT (__stdcall IDisplayInformation::*DisplayCallbackRemover)(EventRegistrationToken); uint qHash(DisplayCallbackRemover key) { void *ptr = *(void **)(&key); return qHash(ptr); } -#ifdef Q_OS_WINPHONE -typedef HRESULT (__stdcall IHardwareButtonsStatics::*HardwareButtonsCallbackRemover)(EventRegistrationToken); -uint qHash(HardwareButtonsCallbackRemover key) { void *ptr = *(void **)(&key); return qHash(ptr); } -#endif class QWinRTScreenPrivate { public: - ComPtr application; + QTouchDevice *touchDevice; ComPtr coreWindow; + ComPtr canvas; + ComPtr view; ComPtr displayInformation; -#ifdef Q_OS_WINPHONE - ComPtr hardwareButtons; -#endif QScopedPointer cursor; -#ifdef Q_OS_WINPHONE - QScopedPointer inputContext; -#else - ComPtr inputContext; -#endif + + QHash touchPoints; QSizeF logicalSize; QSurfaceFormat surfaceFormat; @@ -458,68 +430,30 @@ public: #ifndef Q_OS_WINPHONE QHash> activeKeys; #endif - QTouchDevice *touchDevice; - QHash touchPoints; - EGLDisplay eglDisplay; - EGLSurface eglSurface; - EGLConfig eglConfig; - - QHash applicationTokens; QHash windowTokens; QHash displayTokens; -#ifdef Q_OS_WINPHONE - QHash buttonsTokens; -#endif }; -QWinRTScreen::QWinRTScreen() +// To be called from the XAML thread +QWinRTScreen::QWinRTScreen(Xaml::IWindow *xamlWindow) : d_ptr(new QWinRTScreenPrivate) { Q_D(QWinRTScreen); d->orientation = Qt::PrimaryOrientation; d->touchDevice = Q_NULLPTR; - d->eglDisplay = EGL_NO_DISPLAY; - // Obtain the WinRT Application, view, and window HRESULT hr; - hr = RoGetActivationFactory(Wrappers::HString::MakeReference(RuntimeClass_Windows_ApplicationModel_Core_CoreApplication).Get(), - IID_PPV_ARGS(&d->application)); - Q_ASSERT_SUCCEEDED(hr); - hr = d->application->add_Suspending(Callback(this, &QWinRTScreen::onSuspended).Get(), &d->applicationTokens[&ICoreApplication::remove_Resuming]); - Q_ASSERT_SUCCEEDED(hr); - hr = d->application->add_Resuming(Callback(this, &QWinRTScreen::onResume).Get(), &d->applicationTokens[&ICoreApplication::remove_Resuming]); - Q_ASSERT_SUCCEEDED(hr); - - ComPtr view; - hr = d->application->GetCurrentView(&view); - Q_ASSERT_SUCCEEDED(hr); - hr = view->get_CoreWindow(&d->coreWindow); + hr = xamlWindow->get_CoreWindow(&d->coreWindow); Q_ASSERT_SUCCEEDED(hr); hr = d->coreWindow->Activate(); Q_ASSERT_SUCCEEDED(hr); -#ifdef Q_OS_WINPHONE - d->inputContext.reset(new QWinRTInputContext(this)); -#else - d->inputContext = Make(this); -#endif - Rect rect; hr = d->coreWindow->get_Bounds(&rect); Q_ASSERT_SUCCEEDED(hr); d->logicalSize = QSizeF(rect.Width, rect.Height); - d->surfaceFormat.setAlphaBufferSize(0); - d->surfaceFormat.setRedBufferSize(8); - d->surfaceFormat.setGreenBufferSize(8); - d->surfaceFormat.setBlueBufferSize(8); - d->surfaceFormat.setDepthBufferSize(24); - d->surfaceFormat.setStencilBufferSize(8); - d->surfaceFormat.setRenderableType(QSurfaceFormat::OpenGLES); - d->surfaceFormat.setSamples(1); - d->surfaceFormat.setSwapBehavior(QSurfaceFormat::DoubleBuffer); - hr = d->coreWindow->add_KeyDown(Callback(this, &QWinRTScreen::onKeyDown).Get(), &d->windowTokens[&ICoreWindow::remove_KeyDown]); Q_ASSERT_SUCCEEDED(hr); hr = d->coreWindow->add_KeyUp(Callback(this, &QWinRTScreen::onKeyUp).Get(), &d->windowTokens[&ICoreWindow::remove_KeyUp]); @@ -538,24 +472,14 @@ QWinRTScreen::QWinRTScreen() Q_ASSERT_SUCCEEDED(hr); hr = d->coreWindow->add_PointerWheelChanged(Callback(this, &QWinRTScreen::onPointerUpdated).Get(), &d->windowTokens[&ICoreWindow::remove_PointerWheelChanged]); Q_ASSERT_SUCCEEDED(hr); -#ifndef Q_OS_WINPHONE hr = d->coreWindow->add_SizeChanged(Callback(this, &QWinRTScreen::onSizeChanged).Get(), &d->windowTokens[&ICoreWindow::remove_SizeChanged]); Q_ASSERT_SUCCEEDED(hr); -#endif hr = d->coreWindow->add_Activated(Callback(this, &QWinRTScreen::onActivated).Get(), &d->windowTokens[&ICoreWindow::remove_Activated]); Q_ASSERT_SUCCEEDED(hr); hr = d->coreWindow->add_Closed(Callback(this, &QWinRTScreen::onClosed).Get(), &d->windowTokens[&ICoreWindow::remove_Closed]); Q_ASSERT_SUCCEEDED(hr); hr = d->coreWindow->add_VisibilityChanged(Callback(this, &QWinRTScreen::onVisibilityChanged).Get(), &d->windowTokens[&ICoreWindow::remove_VisibilityChanged]); Q_ASSERT_SUCCEEDED(hr); - hr = d->coreWindow->add_AutomationProviderRequested(Callback(this, &QWinRTScreen::onAutomationProviderRequested).Get(), &d->windowTokens[&ICoreWindow::remove_AutomationProviderRequested]); - Q_ASSERT_SUCCEEDED(hr); -#ifdef Q_OS_WINPHONE - hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Phone_UI_Input_HardwareButtons).Get(), IID_PPV_ARGS(&d->hardwareButtons)); - Q_ASSERT_SUCCEEDED(hr); - hr = d->hardwareButtons->add_BackPressed(Callback(this, &QWinRTScreen::onBackButtonPressed).Get(), &d->buttonsTokens[&IHardwareButtonsStatics::remove_BackPressed]); - Q_ASSERT_SUCCEEDED(hr); -#endif // Q_OS_WINPHONE // Orientation handling ComPtr displayInformationStatics; @@ -583,45 +507,34 @@ QWinRTScreen::QWinRTScreen() d->orientation = d->nativeOrientation; onOrientationChanged(Q_NULLPTR, Q_NULLPTR); - d->eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); - if (d->eglDisplay == EGL_NO_DISPLAY) - qCritical("Failed to initialize EGL display: 0x%x", eglGetError()); - - if (!eglInitialize(d->eglDisplay, NULL, NULL)) - qCritical("Failed to initialize EGL: 0x%x", eglGetError()); - - // Check that the device properly supports depth/stencil rendering, and disable them if not - ComPtr d3dDevice; - const EGLBoolean ok = eglQuerySurfacePointerANGLE(d->eglDisplay, EGL_NO_SURFACE, EGL_DEVICE_EXT, (void **)d3dDevice.GetAddressOf()); - if (ok && d3dDevice) { - ComPtr dxgiDevice; - hr = d3dDevice.As(&dxgiDevice); - if (SUCCEEDED(hr)) { - ComPtr dxgiAdapter; - hr = dxgiDevice->GetAdapter(&dxgiAdapter); - if (SUCCEEDED(hr)) { - ComPtr dxgiAdapter2; - hr = dxgiAdapter.As(&dxgiAdapter2); - if (SUCCEEDED(hr)) { - DXGI_ADAPTER_DESC2 desc; - hr = dxgiAdapter2->GetDesc2(&desc); - if (SUCCEEDED(hr)) { - // The following GPUs do not render properly with depth/stencil - if ((desc.VendorId == 0x4d4f4351 && desc.DeviceId == 0x32303032)) { // Qualcomm Adreno 225 - d->surfaceFormat.setDepthBufferSize(-1); - d->surfaceFormat.setStencilBufferSize(-1); - } - } - } - } - } - } + ComPtr applicationViewStatics; + hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_UI_ViewManagement_ApplicationView).Get(), + IID_PPV_ARGS(&applicationViewStatics)); + RETURN_VOID_IF_FAILED("Could not get ApplicationViewStatics"); - d->eglConfig = q_configFromGLFormat(d->eglDisplay, d->surfaceFormat); - d->surfaceFormat = q_glFormatFromConfig(d->eglDisplay, d->eglConfig, d->surfaceFormat); - d->eglSurface = eglCreateWindowSurface(d->eglDisplay, d->eglConfig, d->coreWindow.Get(), NULL); - if (d->eglSurface == EGL_NO_SURFACE) - qCritical("Failed to create EGL window surface: 0x%x", eglGetError()); + hr = applicationViewStatics->GetForCurrentView(&d->view); + RETURN_VOID_IF_FAILED("Could not access currentView"); + + // Create a canvas and set it as the window content. Eventually, this should have its own method so multiple "screens" can be added + ComPtr canvas; + hr = RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_UI_Xaml_Controls_Canvas).Get(), &canvas); + Q_ASSERT_SUCCEEDED(hr); + ComPtr frameworkElement; + hr = canvas.As(&frameworkElement); + Q_ASSERT_SUCCEEDED(hr); + hr = frameworkElement->put_Width(d->logicalSize.width()); + Q_ASSERT_SUCCEEDED(hr); + hr = frameworkElement->put_Height(d->logicalSize.height()); + Q_ASSERT_SUCCEEDED(hr); + ComPtr uiElement; + hr = canvas.As(&uiElement); + Q_ASSERT_SUCCEEDED(hr); + hr = xamlWindow->put_Content(uiElement.Get()); + Q_ASSERT_SUCCEEDED(hr); + hr = canvas.As(&d->canvas); + Q_ASSERT_SUCCEEDED(hr); + + d->cursor.reset(new QWinRTCursor); } QWinRTScreen::~QWinRTScreen() @@ -629,16 +542,20 @@ QWinRTScreen::~QWinRTScreen() Q_D(QWinRTScreen); // Unregister callbacks - for (QHash::const_iterator i = d->applicationTokens.begin(); i != d->applicationTokens.end(); ++i) - (d->application.Get()->*i.key())(i.value()); - for (QHash::const_iterator i = d->windowTokens.begin(); i != d->windowTokens.end(); ++i) - (d->coreWindow.Get()->*i.key())(i.value()); - for (QHash::const_iterator i = d->displayTokens.begin(); i != d->displayTokens.end(); ++i) - (d->displayInformation.Get()->*i.key())(i.value()); -#ifdef Q_OS_WINPHONE - for (QHash::const_iterator i = d->buttonsTokens.begin(); i != d->buttonsTokens.end(); ++i) - (d->hardwareButtons.Get()->*i.key())(i.value()); -#endif + HRESULT hr; + hr = QEventDispatcherWinRT::runOnXamlThread([this, d]() { + HRESULT hr; + for (QHash::const_iterator i = d->windowTokens.begin(); i != d->windowTokens.end(); ++i) { + hr = (d->coreWindow.Get()->*i.key())(i.value()); + Q_ASSERT_SUCCEEDED(hr); + } + for (QHash::const_iterator i = d->displayTokens.begin(); i != d->displayTokens.end(); ++i) { + hr = (d->displayInformation.Get()->*i.key())(i.value()); + Q_ASSERT_SUCCEEDED(hr); + } + return hr; + }); + RETURN_VOID_IF_FAILED("Failed to unregister screen event callbacks"); } QRect QWinRTScreen::geometry() const @@ -657,12 +574,6 @@ QImage::Format QWinRTScreen::format() const return QImage::Format_ARGB32_Premultiplied; } -QSurfaceFormat QWinRTScreen::surfaceFormat() const -{ - Q_D(const QWinRTScreen); - return d->surfaceFormat; -} - QSizeF QWinRTScreen::physicalSize() const { Q_D(const QWinRTScreen); @@ -682,21 +593,9 @@ qreal QWinRTScreen::scaleFactor() const return d->scaleFactor; } -QWinRTInputContext *QWinRTScreen::inputContext() const -{ - Q_D(const QWinRTScreen); -#ifdef Q_OS_WINPHONE - return d->inputContext.data(); -#else - return d->inputContext.Get(); -#endif -} - QPlatformCursor *QWinRTScreen::cursor() const { Q_D(const QWinRTScreen); - if (!d->cursor) - const_cast(d)->cursor.reset(new QWinRTCursor); return d->cursor.data(); } @@ -744,22 +643,10 @@ ICoreWindow *QWinRTScreen::coreWindow() const return d->coreWindow.Get(); } -EGLDisplay QWinRTScreen::eglDisplay() const -{ - Q_D(const QWinRTScreen); - return d->eglDisplay; -} - -EGLSurface QWinRTScreen::eglSurface() const -{ - Q_D(const QWinRTScreen); - return d->eglSurface; -} - -EGLConfig QWinRTScreen::eglConfig() const +Xaml::IDependencyObject *QWinRTScreen::canvas() const { Q_D(const QWinRTScreen); - return d->eglConfig; + return d->canvas.Get(); } QWindow *QWinRTScreen::topWindow() const @@ -809,6 +696,20 @@ void QWinRTScreen::lower(QWindow *window) handleExpose(); } +void QWinRTScreen::updateWindowTitle() +{ + Q_D(QWinRTScreen); + + QWindow *window = topWindow(); + if (!window) + return; + + const QString title = window->title(); + HStringReference titleRef(reinterpret_cast(title.utf16()), title.length()); + HRESULT hr = d->view->put_Title(titleRef.Get()); + RETURN_VOID_IF_FAILED("Unable to set window title"); +} + void QWinRTScreen::handleExpose() { Q_D(QWinRTScreen); @@ -1055,17 +956,6 @@ HRESULT QWinRTScreen::onPointerUpdated(ICoreWindow *, IPointerEventArgs *args) return S_OK; } -HRESULT QWinRTScreen::onAutomationProviderRequested(ICoreWindow *, IAutomationProviderRequestedEventArgs *args) -{ -#ifndef Q_OS_WINPHONE - Q_D(const QWinRTScreen); - args->put_AutomationProvider(d->inputContext.Get()); -#else - Q_UNUSED(args) -#endif - return S_OK; -} - HRESULT QWinRTScreen::onSizeChanged(ICoreWindow *, IWindowSizeChangedEventArgs *) { Q_D(QWinRTScreen); @@ -1075,18 +965,14 @@ HRESULT QWinRTScreen::onSizeChanged(ICoreWindow *, IWindowSizeChangedEventArgs * hr = d->coreWindow->get_Bounds(&size); RETURN_OK_IF_FAILED("Failed to get window bounds"); QSizeF logicalSize = QSizeF(size.Width, size.Height); -#ifndef Q_OS_WINPHONE // This handler is called from orientation changed, in which case we should always update the size if (d->logicalSize == logicalSize) return S_OK; -#endif d->logicalSize = logicalSize; - if (d->eglDisplay) { - const QRect newGeometry = geometry(); - QWindowSystemInterface::handleScreenGeometryChange(screen(), newGeometry, newGeometry); - QPlatformScreen::resizeMaximizedWindows(); - handleExpose(); - } + const QRect newGeometry = geometry(); + QWindowSystemInterface::handleScreenGeometryChange(screen(), newGeometry, newGeometry); + QPlatformScreen::resizeMaximizedWindows(); + handleExpose(); return S_OK; } @@ -1110,31 +996,6 @@ HRESULT QWinRTScreen::onActivated(ICoreWindow *, IWindowActivatedEventArgs *args return S_OK; } -HRESULT QWinRTScreen::onSuspended(IInspectable *, ISuspendingEventArgs *) -{ -#ifndef Q_OS_WINPHONE - Q_D(QWinRTScreen); - ComPtr d3dDevice; - const EGLBoolean ok = eglQuerySurfacePointerANGLE(d->eglDisplay, EGL_NO_SURFACE, EGL_DEVICE_EXT, (void **)d3dDevice.GetAddressOf()); - if (ok && d3dDevice) { - ComPtr dxgiDevice; - if (SUCCEEDED(d3dDevice.As(&dxgiDevice))) - dxgiDevice->Trim(); - } -#endif - QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationSuspended); - QWindowSystemInterface::flushWindowSystemEvents(); - return S_OK; -} - -HRESULT QWinRTScreen::onResume(IInspectable *, IInspectable *) -{ - // First the system invokes onResume and then changes - // the visibility of the screen to be active. - QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationHidden); - return S_OK; -} - HRESULT QWinRTScreen::onClosed(ICoreWindow *, ICoreWindowEventArgs *) { foreach (QWindow *w, QGuiApplication::topLevelWindows()) @@ -1165,10 +1026,6 @@ HRESULT QWinRTScreen::onOrientationChanged(IDisplayInformation *, IInspectable * d->orientation = newOrientation; QWindowSystemInterface::handleScreenOrientationChange(screen(), d->orientation); } - -#ifdef Q_OS_WINPHONE // The size changed handler is ignored in favor of this callback - onSizeChanged(Q_NULLPTR, Q_NULLPTR); -#endif return S_OK; } @@ -1205,27 +1062,4 @@ HRESULT QWinRTScreen::onDpiChanged(IDisplayInformation *, IInspectable *) return S_OK; } -#ifdef Q_OS_WINPHONE -HRESULT QWinRTScreen::onBackButtonPressed(IInspectable *, IBackPressedEventArgs *args) -{ - Q_D(QWinRTScreen); - - QKeyEvent backPress(QEvent::KeyPress, Qt::Key_Back, Qt::NoModifier); - QKeyEvent backRelease(QEvent::KeyRelease, Qt::Key_Back, Qt::NoModifier); - backPress.setAccepted(false); - backRelease.setAccepted(false); - - QObject *receiver = d->visibleWindows.isEmpty() - ? static_cast(QGuiApplication::instance()) - : static_cast(d->visibleWindows.first()); - - // If the event is ignored, the app will suspend - QGuiApplication::sendEvent(receiver, &backPress); - QGuiApplication::sendEvent(receiver, &backRelease); - args->put_Handled(backPress.isAccepted() || backRelease.isAccepted()); - - return S_OK; -} -#endif // Q_OS_WINPHONE - QT_END_NAMESPACE diff --git a/src/plugins/platforms/winrt/qwinrtscreen.h b/src/plugins/platforms/winrt/qwinrtscreen.h index d34ce75748..796e6abb80 100644 --- a/src/plugins/platforms/winrt/qwinrtscreen.h +++ b/src/plugins/platforms/winrt/qwinrtscreen.h @@ -40,8 +40,6 @@ #include #include -#include - namespace ABI { namespace Windows { namespace ApplicationModel { @@ -59,21 +57,16 @@ namespace ABI { struct IWindowActivatedEventArgs; struct IWindowSizeChangedEventArgs; } + namespace Xaml { + struct IDependencyObject; + struct IWindow; + } } namespace Graphics { namespace Display { struct IDisplayInformation; } } -#ifdef Q_OS_WINPHONE - namespace Phone { - namespace UI { - namespace Input { - struct IBackPressedEventArgs; - } - } - } -#endif } } struct IInspectable; @@ -81,23 +74,20 @@ struct IInspectable; QT_BEGIN_NAMESPACE class QTouchDevice; -class QWinRTEGLContext; class QWinRTCursor; class QWinRTInputContext; class QWinRTScreenPrivate; class QWinRTScreen : public QPlatformScreen { public: - explicit QWinRTScreen(); + explicit QWinRTScreen(ABI::Windows::UI::Xaml::IWindow *xamlWindow); ~QWinRTScreen(); QRect geometry() const; int depth() const; QImage::Format format() const; - QSurfaceFormat surfaceFormat() const; QSizeF physicalSize() const Q_DECL_OVERRIDE; QDpi logicalDpi() const Q_DECL_OVERRIDE; qreal scaleFactor() const; - QWinRTInputContext *inputContext() const; QPlatformCursor *cursor() const; Qt::KeyboardModifiers keyboardModifiers() const; @@ -110,10 +100,10 @@ public: void raise(QWindow *window); void lower(QWindow *window); + void updateWindowTitle(); + ABI::Windows::UI::Core::ICoreWindow *coreWindow() const; - EGLDisplay eglDisplay() const; // To opengl context - EGLSurface eglSurface() const; // To window - EGLConfig eglConfig() const; + ABI::Windows::UI::Xaml::IDependencyObject *canvas() const; private: void handleExpose(); @@ -127,20 +117,13 @@ private: HRESULT onSizeChanged(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IWindowSizeChangedEventArgs *); HRESULT onActivated(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IWindowActivatedEventArgs *); - HRESULT onSuspended(IInspectable *, ABI::Windows::ApplicationModel::ISuspendingEventArgs *); - HRESULT onResume(IInspectable *, IInspectable *); HRESULT onClosed(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::ICoreWindowEventArgs *); HRESULT onVisibilityChanged(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IVisibilityChangedEventArgs *); - HRESULT onAutomationProviderRequested(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IAutomationProviderRequestedEventArgs *); HRESULT onOrientationChanged(ABI::Windows::Graphics::Display::IDisplayInformation *, IInspectable *); HRESULT onDpiChanged(ABI::Windows::Graphics::Display::IDisplayInformation *, IInspectable *); -#ifdef Q_OS_WINPHONE - HRESULT onBackButtonPressed(IInspectable *, ABI::Windows::Phone::UI::Input::IBackPressedEventArgs *args); -#endif - QScopedPointer d_ptr; Q_DECLARE_PRIVATE(QWinRTScreen) }; diff --git a/src/plugins/platforms/winrt/qwinrtwindow.cpp b/src/plugins/platforms/winrt/qwinrtwindow.cpp index adc5dfb776..634d62ef24 100644 --- a/src/plugins/platforms/winrt/qwinrtwindow.cpp +++ b/src/plugins/platforms/winrt/qwinrtwindow.cpp @@ -36,47 +36,138 @@ #include "qwinrtwindow.h" #include "qwinrtscreen.h" +#include -#include +#include +#define EGL_EGLEXT_PROTOTYPES +#include + +#include #include +#include #include -#include #include +#include +#include -#include -#include +#include #include +#include +#include +#include +#include +#include using namespace ABI::Windows::UI::ViewManagement; using namespace Microsoft::WRL; using namespace Microsoft::WRL::Wrappers; +using namespace ABI::Windows::Foundation; +using namespace ABI::Windows::Foundation::Collections; +using namespace ABI::Windows::UI; QT_BEGIN_NAMESPACE +class QWinRTWindowPrivate +{ +public: + QWinRTScreen *screen; + + QSurfaceFormat surfaceFormat; + QString windowTitle; + + ComPtr swapChainPanel; +}; + QWinRTWindow::QWinRTWindow(QWindow *window) : QPlatformWindow(window) - , m_screen(static_cast(screen())) + , d_ptr(new QWinRTWindowPrivate) { + Q_D(QWinRTWindow); + + d->screen = static_cast(screen()); setWindowFlags(window->flags()); setWindowState(window->windowState()); setWindowTitle(window->title()); handleContentOrientationChange(window->contentOrientation()); + + d->surfaceFormat.setAlphaBufferSize(0); + d->surfaceFormat.setRedBufferSize(8); + d->surfaceFormat.setGreenBufferSize(8); + d->surfaceFormat.setBlueBufferSize(8); + d->surfaceFormat.setDepthBufferSize(24); + d->surfaceFormat.setStencilBufferSize(8); + d->surfaceFormat.setRenderableType(QSurfaceFormat::OpenGLES); + d->surfaceFormat.setSamples(1); + d->surfaceFormat.setSwapBehavior(QSurfaceFormat::DoubleBuffer); + + HRESULT hr; + hr = QEventDispatcherWinRT::runOnXamlThread([this, d]() { + // Create a new swapchain and place it inside the canvas + HRESULT hr; + hr = RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_UI_Xaml_Controls_SwapChainPanel).Get(), + &d->swapChainPanel); + Q_ASSERT_SUCCEEDED(hr); + ComPtr uiElement; + hr = d->swapChainPanel.As(&uiElement); + Q_ASSERT_SUCCEEDED(hr); + + ComPtr canvas = d->screen->canvas(); + ComPtr panel; + hr = canvas.As(&panel); + Q_ASSERT_SUCCEEDED(hr); + ComPtr> children; + hr = panel->get_Children(&children); + Q_ASSERT_SUCCEEDED(hr); + hr = children->Append(uiElement.Get()); + Q_ASSERT_SUCCEEDED(hr); + return S_OK; + }); + Q_ASSERT_SUCCEEDED(hr); + setGeometry(window->geometry()); } QWinRTWindow::~QWinRTWindow() { - m_screen->removeWindow(window()); + Q_D(QWinRTWindow); + + HRESULT hr; + hr = QEventDispatcherWinRT::runOnXamlThread([d]() { + HRESULT hr; + ComPtr canvas = d->screen->canvas(); + ComPtr panel; + hr = canvas.As(&panel); + Q_ASSERT_SUCCEEDED(hr); + ComPtr> children; + hr = panel->get_Children(&children); + Q_ASSERT_SUCCEEDED(hr); + + ComPtr uiElement; + hr = d->swapChainPanel.As(&uiElement); + Q_ASSERT_SUCCEEDED(hr); + quint32 index; + boolean found; + hr = children->IndexOf(uiElement.Get(), &index, &found); + Q_ASSERT_SUCCEEDED(hr); + if (found) { + hr = children->RemoveAt(index); + Q_ASSERT_SUCCEEDED(hr); + } + return S_OK; + }); + RETURN_VOID_IF_FAILED("Failed to completely destroy window resources, likely because the application is shutting down"); } QSurfaceFormat QWinRTWindow::format() const { - return m_screen->surfaceFormat(); + Q_D(const QWinRTWindow); + return d->surfaceFormat; } bool QWinRTWindow::isActive() const { - return m_screen->topWindow() == window(); + Q_D(const QWinRTWindow); + return d->screen->topWindow() == window(); } bool QWinRTWindow::isExposed() const @@ -87,55 +178,70 @@ bool QWinRTWindow::isExposed() const void QWinRTWindow::setGeometry(const QRect &rect) { + Q_D(QWinRTWindow); + if (window()->isTopLevel()) { - QPlatformWindow::setGeometry(m_screen->geometry()); + QPlatformWindow::setGeometry(d->screen->geometry()); QWindowSystemInterface::handleGeometryChange(window(), geometry()); } else { QPlatformWindow::setGeometry(rect); QWindowSystemInterface::handleGeometryChange(window(), rect); } + + HRESULT hr; + hr = QEventDispatcherWinRT::runOnXamlThread([this, d]() { + HRESULT hr; + ComPtr frameworkElement; + hr = d->swapChainPanel.As(&frameworkElement); + Q_ASSERT_SUCCEEDED(hr); + const QSizeF size = QSizeF(geometry().size()) / d->screen->scaleFactor(); + hr = frameworkElement->put_Width(size.width()); + Q_ASSERT_SUCCEEDED(hr); + hr = frameworkElement->put_Height(size.height()); + Q_ASSERT_SUCCEEDED(hr); + return S_OK; + }); + Q_ASSERT_SUCCEEDED(hr); } void QWinRTWindow::setVisible(bool visible) { + Q_D(QWinRTWindow); if (!window()->isTopLevel()) return; if (visible) - m_screen->addWindow(window()); + d->screen->addWindow(window()); else - m_screen->removeWindow(window()); + d->screen->removeWindow(window()); } void QWinRTWindow::setWindowTitle(const QString &title) { - ComPtr statics; - HRESULT hr; - - hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_UI_ViewManagement_ApplicationView).Get(), - IID_PPV_ARGS(&statics)); - RETURN_VOID_IF_FAILED("Could not get ApplicationViewStatics"); - - ComPtr view; - hr = statics->GetForCurrentView(&view); - RETURN_VOID_IF_FAILED("Could not access currentView"); - - HStringReference str(reinterpret_cast(title.utf16()), title.length()); - hr = view->put_Title(str.Get()); - RETURN_VOID_IF_FAILED("Unable to set window title"); + Q_D(QWinRTWindow); + d->windowTitle = title; + d->screen->updateWindowTitle(); } void QWinRTWindow::raise() { + Q_D(QWinRTWindow); if (!window()->isTopLevel()) return; - m_screen->raise(window()); + d->screen->raise(window()); } void QWinRTWindow::lower() { + Q_D(QWinRTWindow); if (!window()->isTopLevel()) return; - m_screen->lower(window()); + d->screen->lower(window()); +} + +WId QWinRTWindow::winId() const +{ + Q_D(const QWinRTWindow); + return WId(d->swapChainPanel.Get()); } qreal QWinRTWindow::devicePixelRatio() const diff --git a/src/plugins/platforms/winrt/qwinrtwindow.h b/src/plugins/platforms/winrt/qwinrtwindow.h index 3cfe346ab2..88c149b080 100644 --- a/src/plugins/platforms/winrt/qwinrtwindow.h +++ b/src/plugins/platforms/winrt/qwinrtwindow.h @@ -42,8 +42,7 @@ QT_BEGIN_NAMESPACE -class QWinRTScreen; - +class QWinRTWindowPrivate; class QWinRTWindow : public QPlatformWindow { public: @@ -59,10 +58,13 @@ public: void raise(); void lower(); + WId winId() const Q_DECL_OVERRIDE; + qreal devicePixelRatio() const Q_DECL_OVERRIDE; private: - QWinRTScreen *m_screen; + QScopedPointer d_ptr; + Q_DECLARE_PRIVATE(QWinRTWindow) }; QT_END_NAMESPACE -- cgit v1.2.3