From fb60f225e67db6c548fc2c5dfbe172251993daba Mon Sep 17 00:00:00 2001 From: Samuel Nevala Date: Thu, 27 Aug 2015 09:17:05 +0300 Subject: [PATCH] winrt: Enable window visibility for the root window. - Minimized and Hidden: hide the status bar and collapse winrt native ui element. - Windowed and Maximized: show the status bar and re-size the window. - FullScreen and AutomaticVisibility: hide the status bar and re-size the window. Showing & hiding the status bar and re-sizing the window affect only the windows phone build. Change-Id: Iaa412382bffc14e470720f2213bb3f6851f57a6b Task-Id: QTBUG-47811 Reviewed-by: Andrew Knight --- src/plugins/platforms/winrt/qwinrtscreen.cpp | 114 ++++++++++++++++--- src/plugins/platforms/winrt/qwinrtscreen.h | 15 +++ src/plugins/platforms/winrt/qwinrtwindow.cpp | 79 ++++++++++--- src/plugins/platforms/winrt/qwinrtwindow.h | 1 + 4 files changed, 174 insertions(+), 35 deletions(-) diff --git a/src/plugins/platforms/winrt/qwinrtscreen.cpp b/src/plugins/platforms/winrt/qwinrtscreen.cpp index 6c40d5a1d2..563753cfcb 100644 --- a/src/plugins/platforms/winrt/qwinrtscreen.cpp +++ b/src/plugins/platforms/winrt/qwinrtscreen.cpp @@ -83,6 +83,9 @@ typedef ITypedEventHandler PointerHandler; typedef ITypedEventHandler SizeChangedHandler; typedef ITypedEventHandler VisibilityChangedHandler; typedef ITypedEventHandler DisplayInformationHandler; +#ifdef Q_OS_WINPHONE +typedef ITypedEventHandler StatusBarHandler; +#endif QT_BEGIN_NAMESPACE @@ -405,6 +408,10 @@ typedef HRESULT (__stdcall ICoreWindow::*CoreWindowCallbackRemover)(EventRegistr 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 IStatusBar::*StatusBarCallbackRemover)(EventRegistrationToken); +uint qHash(StatusBarCallbackRemover key) { void *ptr = *(void **)(&key); return qHash(ptr); } +#endif class QWinRTScreenPrivate { @@ -416,7 +423,7 @@ public: ComPtr displayInformation; #ifdef Q_OS_WINPHONE ComPtr statusBar; -#endif // Q_OS_WINPHONE +#endif QScopedPointer cursor; QHash touchPoints; @@ -434,6 +441,9 @@ public: QHash windowTokens; QHash displayTokens; +#ifdef Q_OS_WINPHONE + QHash statusBarTokens; +#endif }; // To be called from the XAML thread @@ -473,8 +483,10 @@ QWinRTScreen::QWinRTScreen(Xaml::IWindow *xamlWindow) 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]); @@ -544,6 +556,10 @@ QWinRTScreen::QWinRTScreen(Xaml::IWindow *xamlWindow) Q_ASSERT_SUCCEEDED(hr); hr = statusBarStatics->GetForCurrentView(&d->statusBar); Q_ASSERT_SUCCEEDED(hr); + hr = d->statusBar->add_Showing(Callback(this, &QWinRTScreen::onStatusBarShowing).Get(), &d->statusBarTokens[&IStatusBar::remove_Showing]); + Q_ASSERT_SUCCEEDED(hr); + hr = d->statusBar->add_Hiding(Callback(this, &QWinRTScreen::onStatusBarHiding).Get(), &d->statusBarTokens[&IStatusBar::remove_Hiding]); + Q_ASSERT_SUCCEEDED(hr); #endif // Q_OS_WINPHONE } @@ -563,6 +579,12 @@ QWinRTScreen::~QWinRTScreen() hr = (d->displayInformation.Get()->*i.key())(i.value()); Q_ASSERT_SUCCEEDED(hr); } +#ifdef Q_OS_WINPHONE + for (QHash::const_iterator i = d->statusBarTokens.begin(); i != d->statusBarTokens.end(); ++i) { + hr = (d->statusBar.Get()->*i.key())(i.value()); + Q_ASSERT_SUCCEEDED(hr); + } +#endif //Q_OS_WINPHONE return hr; }); RETURN_VOID_IF_FAILED("Failed to unregister screen event callbacks"); @@ -574,6 +596,31 @@ QRect QWinRTScreen::geometry() const return QRect(QPoint(), (d->logicalSize * d->scaleFactor).toSize()); } +#ifdef Q_OS_WINPHONE +QRect QWinRTScreen::availableGeometry() const +{ + Q_D(const QWinRTScreen); + QRect statusBar; + QEventDispatcherWinRT::runOnXamlThread([d, &statusBar]() { + HRESULT hr; + Rect rect; + hr = d->statusBar->get_OccludedRect(&rect); + Q_ASSERT_SUCCEEDED(hr); + statusBar.setRect(qRound(rect.X * d->scaleFactor), + qRound(rect.Y * d->scaleFactor), + qRound(rect.Width * d->scaleFactor), + qRound(rect.Height * d->scaleFactor)); + return S_OK; + }); + + return geometry().adjusted( + d->orientation == Qt::LandscapeOrientation ? statusBar.width() : 0, + d->orientation == Qt::PortraitOrientation ? statusBar.height() : 0, + d->orientation == Qt::InvertedLandscapeOrientation ? -statusBar.width() : 0, + 0); +} +#endif //Q_OS_WINPHONE + int QWinRTScreen::depth() const { return 32; @@ -659,6 +706,26 @@ Xaml::IDependencyObject *QWinRTScreen::canvas() const return d->canvas.Get(); } +#ifdef Q_OS_WINPHONE +void QWinRTScreen::setStatusBarVisibility(bool visible, QWindow *window) +{ + Q_D(QWinRTScreen); + if (!window || (window->flags() & Qt::WindowType_Mask) != Qt::Window) + return; + + QEventDispatcherWinRT::runOnXamlThread([d, visible]() { + HRESULT hr; + ComPtr op; + if (visible) + hr = d->statusBar->ShowAsync(&op); + else + hr = d->statusBar->HideAsync(&op); + Q_ASSERT_SUCCEEDED(hr); + return S_OK; + }); +} +#endif //Q_OS_WINPHONE + QWindow *QWinRTScreen::topWindow() const { Q_D(const QWinRTScreen); @@ -672,16 +739,9 @@ void QWinRTScreen::addWindow(QWindow *window) return; #ifdef Q_OS_WINPHONE - if (d->statusBar && (window->flags() & Qt::WindowType_Mask) == Qt::Window) { - QEventDispatcherWinRT::runOnXamlThread([this, d]() { - HRESULT hr; - ComPtr op; - hr = d->statusBar->HideAsync(&op); - Q_ASSERT_SUCCEEDED(hr); - return S_OK; - }); - } -#endif // Q_OS_WINPHONE + if (window->visibility() != QWindow::Maximized && window->visibility() != QWindow::Windowed) + setStatusBarVisibility(false, window); +#endif d->visibleWindows.prepend(window); QWindowSystemInterface::handleWindowActivated(window, Qt::OtherFocusReason); @@ -691,6 +751,12 @@ void QWinRTScreen::addWindow(QWindow *window) void QWinRTScreen::removeWindow(QWindow *window) { Q_D(QWinRTScreen); + +#ifdef Q_OS_WINPHONE + if (window->visibility() == QWindow::Minimized) + setStatusBarVisibility(false, window); +#endif + const bool wasTopWindow = window == topWindow(); if (!d->visibleWindows.removeAll(window)) return; @@ -987,13 +1053,8 @@ HRESULT QWinRTScreen::onSizeChanged(ICoreWindow *, IWindowSizeChangedEventArgs * HRESULT hr; hr = d->coreWindow->get_Bounds(&size); RETURN_OK_IF_FAILED("Failed to get window bounds"); - QSizeF logicalSize = QSizeF(size.Width, size.Height); - if (d->logicalSize == logicalSize) - return S_OK; - - d->logicalSize = logicalSize; - const QRect newGeometry = geometry(); - QWindowSystemInterface::handleScreenGeometryChange(screen(), newGeometry, newGeometry); + d->logicalSize = QSizeF(size.Width, size.Height); + QWindowSystemInterface::handleScreenGeometryChange(screen(), geometry(), availableGeometry()); QPlatformScreen::resizeMaximizedWindows(); handleExpose(); return S_OK; @@ -1047,6 +1108,9 @@ HRESULT QWinRTScreen::onOrientationChanged(IDisplayInformation *, IInspectable * Qt::ScreenOrientation newOrientation = static_cast(static_cast(qtOrientationsFromNative(displayOrientation))); if (d->orientation != newOrientation) { d->orientation = newOrientation; +#ifdef Q_OS_WINPHONE + onSizeChanged(nullptr, nullptr); +#endif QWindowSystemInterface::handleScreenOrientationChange(screen(), d->orientation); handleExpose(); // Clean broken frames caused by race between Qt and ANGLE } @@ -1086,4 +1150,18 @@ HRESULT QWinRTScreen::onDpiChanged(IDisplayInformation *, IInspectable *) return S_OK; } +#ifdef Q_OS_WINPHONE +HRESULT QWinRTScreen::onStatusBarShowing(IStatusBar *, IInspectable *) +{ + onSizeChanged(nullptr, nullptr); + return S_OK; +} + +HRESULT QWinRTScreen::onStatusBarHiding(IStatusBar *, IInspectable *) +{ + onSizeChanged(nullptr, nullptr); + 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 4112e49c4d..3297617740 100644 --- a/src/plugins/platforms/winrt/qwinrtscreen.h +++ b/src/plugins/platforms/winrt/qwinrtscreen.h @@ -61,6 +61,9 @@ namespace ABI { struct IDependencyObject; struct IWindow; } + namespace ViewManagement { + struct IStatusBar; + } } namespace Graphics { namespace Display { @@ -83,6 +86,9 @@ public: explicit QWinRTScreen(ABI::Windows::UI::Xaml::IWindow *xamlWindow); ~QWinRTScreen(); QRect geometry() const Q_DECL_OVERRIDE; +#ifdef Q_OS_WINPHONE + QRect availableGeometry() const Q_DECL_OVERRIDE; +#endif int depth() const Q_DECL_OVERRIDE; QImage::Format format() const Q_DECL_OVERRIDE; QSizeF physicalSize() const Q_DECL_OVERRIDE; @@ -105,6 +111,10 @@ public: ABI::Windows::UI::Core::ICoreWindow *coreWindow() const; ABI::Windows::UI::Xaml::IDependencyObject *canvas() const; +#ifdef Q_OS_WINPHONE + void setStatusBarVisibility(bool visible, QWindow *window); +#endif + private: void handleExpose(); @@ -124,6 +134,11 @@ private: HRESULT onOrientationChanged(ABI::Windows::Graphics::Display::IDisplayInformation *, IInspectable *); HRESULT onDpiChanged(ABI::Windows::Graphics::Display::IDisplayInformation *, IInspectable *); +#ifdef Q_OS_WINPHONE + HRESULT onStatusBarShowing(ABI::Windows::UI::ViewManagement::IStatusBar *, IInspectable *); + HRESULT onStatusBarHiding(ABI::Windows::UI::ViewManagement::IStatusBar *, IInspectable *); +#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 634d62ef24..23e4e163e4 100644 --- a/src/plugins/platforms/winrt/qwinrtwindow.cpp +++ b/src/plugins/platforms/winrt/qwinrtwindow.cpp @@ -64,9 +64,22 @@ using namespace Microsoft::WRL::Wrappers; using namespace ABI::Windows::Foundation; using namespace ABI::Windows::Foundation::Collections; using namespace ABI::Windows::UI; +using namespace ABI::Windows::UI::Xaml; +using namespace ABI::Windows::UI::Xaml::Controls; QT_BEGIN_NAMESPACE +static void setUIElementVisibility(IUIElement *uiElement, bool visibility) +{ + Q_ASSERT(uiElement); + QEventDispatcherWinRT::runOnXamlThread([uiElement, visibility]() { + HRESULT hr; + hr = uiElement->put_Visibility(visibility ? Visibility_Visible : Visibility_Collapsed); + Q_ASSERT_SUCCEEDED(hr); + return S_OK; + }); +} + class QWinRTWindowPrivate { public: @@ -74,8 +87,11 @@ public: QSurfaceFormat surfaceFormat; QString windowTitle; + Qt::WindowState state; - ComPtr swapChainPanel; + ComPtr swapChainPanel; + ComPtr canvas; + ComPtr uiElement; }; QWinRTWindow::QWinRTWindow(QWindow *window) @@ -101,24 +117,26 @@ QWinRTWindow::QWinRTWindow(QWindow *window) d->surfaceFormat.setSwapBehavior(QSurfaceFormat::DoubleBuffer); HRESULT hr; + hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_UI_Xaml_Controls_Canvas).Get(), + IID_PPV_ARGS(&d->canvas)); + Q_ASSERT_SUCCEEDED(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); + hr = d->swapChainPanel.As(&d->uiElement); Q_ASSERT_SUCCEEDED(hr); - ComPtr canvas = d->screen->canvas(); - ComPtr panel; + ComPtr canvas = d->screen->canvas(); + ComPtr panel; hr = canvas.As(&panel); Q_ASSERT_SUCCEEDED(hr); - ComPtr> children; + ComPtr> children; hr = panel->get_Children(&children); Q_ASSERT_SUCCEEDED(hr); - hr = children->Append(uiElement.Get()); + hr = children->Append(d->uiElement.Get()); Q_ASSERT_SUCCEEDED(hr); return S_OK; }); @@ -134,20 +152,18 @@ QWinRTWindow::~QWinRTWindow() HRESULT hr; hr = QEventDispatcherWinRT::runOnXamlThread([d]() { HRESULT hr; - ComPtr canvas = d->screen->canvas(); - ComPtr panel; + ComPtr canvas = d->screen->canvas(); + ComPtr panel; hr = canvas.As(&panel); Q_ASSERT_SUCCEEDED(hr); - ComPtr> children; + 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); + hr = children->IndexOf(d->uiElement.Get(), &index, &found); Q_ASSERT_SUCCEEDED(hr); if (found) { hr = children->RemoveAt(index); @@ -181,7 +197,8 @@ void QWinRTWindow::setGeometry(const QRect &rect) Q_D(QWinRTWindow); if (window()->isTopLevel()) { - QPlatformWindow::setGeometry(d->screen->geometry()); + QPlatformWindow::setGeometry(window()->flags() & Qt::MaximizeUsingFullscreenGeometryHint + ? d->screen->geometry() : d->screen->availableGeometry()); QWindowSystemInterface::handleGeometryChange(window(), geometry()); } else { QPlatformWindow::setGeometry(rect); @@ -191,10 +208,16 @@ void QWinRTWindow::setGeometry(const QRect &rect) HRESULT hr; hr = QEventDispatcherWinRT::runOnXamlThread([this, d]() { HRESULT hr; + const QRect windowGeometry = geometry(); + const QPointF topLeft= QPointF(windowGeometry.topLeft()) / d->screen->scaleFactor(); + hr = d->canvas->SetTop(d->uiElement.Get(), topLeft.y()); + Q_ASSERT_SUCCEEDED(hr); + hr = d->canvas->SetLeft(d->uiElement.Get(), topLeft.x()); + Q_ASSERT_SUCCEEDED(hr); ComPtr frameworkElement; hr = d->swapChainPanel.As(&frameworkElement); Q_ASSERT_SUCCEEDED(hr); - const QSizeF size = QSizeF(geometry().size()) / d->screen->scaleFactor(); + const QSizeF size = QSizeF(windowGeometry.size()) / d->screen->scaleFactor(); hr = frameworkElement->put_Width(size.width()); Q_ASSERT_SUCCEEDED(hr); hr = frameworkElement->put_Height(size.height()); @@ -209,10 +232,13 @@ void QWinRTWindow::setVisible(bool visible) Q_D(QWinRTWindow); if (!window()->isTopLevel()) return; - if (visible) + if (visible) { d->screen->addWindow(window()); - else + setUIElementVisibility(d->uiElement.Get(), d->state != Qt::WindowMinimized); + } else { d->screen->removeWindow(window()); + setUIElementVisibility(d->uiElement.Get(), false); + } } void QWinRTWindow::setWindowTitle(const QString &title) @@ -249,4 +275,23 @@ qreal QWinRTWindow::devicePixelRatio() const return screen()->devicePixelRatio(); } +void QWinRTWindow::setWindowState(Qt::WindowState state) +{ + Q_D(QWinRTWindow); + if (d->state == state) + return; + +#ifdef Q_OS_WINPHONE + d->screen->setStatusBarVisibility(state == Qt::WindowMaximized || state == Qt::WindowNoState, window()); +#endif + + if (state == Qt::WindowMinimized) + setUIElementVisibility(d->uiElement.Get(), false); + + if (d->state == Qt::WindowMinimized) + setUIElementVisibility(d->uiElement.Get(), true); + + d->state = state; +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/winrt/qwinrtwindow.h b/src/plugins/platforms/winrt/qwinrtwindow.h index 88c149b080..2957a7498b 100644 --- a/src/plugins/platforms/winrt/qwinrtwindow.h +++ b/src/plugins/platforms/winrt/qwinrtwindow.h @@ -61,6 +61,7 @@ public: WId winId() const Q_DECL_OVERRIDE; qreal devicePixelRatio() const Q_DECL_OVERRIDE; + void setWindowState(Qt::WindowState state) Q_DECL_OVERRIDE; private: QScopedPointer d_ptr;