winrt: Enable window visibility for the root window.
authorSamuel Nevala <samuel.nevala@intopalo.com>
Thu, 27 Aug 2015 06:17:05 +0000 (09:17 +0300)
committerSamuel Nevala <samuel.nevala@intopalo.com>
Mon, 31 Aug 2015 11:57:56 +0000 (11:57 +0000)
- 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 <andrew.knight@intopalo.com>
src/plugins/platforms/winrt/qwinrtscreen.cpp
src/plugins/platforms/winrt/qwinrtscreen.h
src/plugins/platforms/winrt/qwinrtwindow.cpp
src/plugins/platforms/winrt/qwinrtwindow.h

index 6c40d5a1d2f5ad0f63d5292e8a7e942555d3b991..563753cfcbedfe12ba5dcbb2049639888ff961aa 100644 (file)
@@ -83,6 +83,9 @@ typedef ITypedEventHandler<CoreWindow*, PointerEventArgs*> PointerHandler;
 typedef ITypedEventHandler<CoreWindow*, WindowSizeChangedEventArgs*> SizeChangedHandler;
 typedef ITypedEventHandler<CoreWindow*, VisibilityChangedEventArgs*> VisibilityChangedHandler;
 typedef ITypedEventHandler<DisplayInformation*, IInspectable*> DisplayInformationHandler;
+#ifdef Q_OS_WINPHONE
+typedef ITypedEventHandler<StatusBar*, IInspectable*> 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<IDisplayInformation> displayInformation;
 #ifdef Q_OS_WINPHONE
     ComPtr<IStatusBar> statusBar;
-#endif // Q_OS_WINPHONE
+#endif
 
     QScopedPointer<QWinRTCursor> cursor;
     QHash<quint32, QWindowSystemInterface::TouchPoint> touchPoints;
@@ -434,6 +441,9 @@ public:
 
     QHash<CoreWindowCallbackRemover, EventRegistrationToken> windowTokens;
     QHash<DisplayCallbackRemover, EventRegistrationToken> displayTokens;
+#ifdef Q_OS_WINPHONE
+    QHash<StatusBarCallbackRemover, EventRegistrationToken> 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<PointerHandler>(this, &QWinRTScreen::onPointerUpdated).Get(), &d->windowTokens[&ICoreWindow::remove_PointerWheelChanged]);
     Q_ASSERT_SUCCEEDED(hr);
+#ifndef Q_OS_WINPHONE
     hr = d->coreWindow->add_SizeChanged(Callback<SizeChangedHandler>(this, &QWinRTScreen::onSizeChanged).Get(), &d->windowTokens[&ICoreWindow::remove_SizeChanged]);
     Q_ASSERT_SUCCEEDED(hr);
+#endif
     hr = d->coreWindow->add_Activated(Callback<ActivatedHandler>(this, &QWinRTScreen::onActivated).Get(), &d->windowTokens[&ICoreWindow::remove_Activated]);
     Q_ASSERT_SUCCEEDED(hr);
     hr = d->coreWindow->add_Closed(Callback<ClosedHandler>(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<StatusBarHandler>(this, &QWinRTScreen::onStatusBarShowing).Get(), &d->statusBarTokens[&IStatusBar::remove_Showing]);
+    Q_ASSERT_SUCCEEDED(hr);
+    hr = d->statusBar->add_Hiding(Callback<StatusBarHandler>(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<StatusBarCallbackRemover, EventRegistrationToken>::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<IAsyncAction> 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<IAsyncAction> 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<Qt::ScreenOrientation>(static_cast<int>(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
index 4112e49c4da9b62aefbc16d464dec7dc76a9340b..32976177402ab1df878270e00e405c64199b2fbe 100644 (file)
@@ -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<QWinRTScreenPrivate> d_ptr;
     Q_DECLARE_PRIVATE(QWinRTScreen)
 };
index 634d62ef249e58508994361e5e1e1c30e9a972b7..23e4e163e4867cc8a71605f429236fdac2889f18 100644 (file)
@@ -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<Xaml::Controls::ISwapChainPanel> swapChainPanel;
+    ComPtr<ISwapChainPanel> swapChainPanel;
+    ComPtr<ICanvasStatics> canvas;
+    ComPtr<IUIElement> 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<Xaml::IUIElement> uiElement;
-        hr = d->swapChainPanel.As(&uiElement);
+        hr = d->swapChainPanel.As(&d->uiElement);
         Q_ASSERT_SUCCEEDED(hr);
 
-        ComPtr<Xaml::IDependencyObject> canvas = d->screen->canvas();
-        ComPtr<Xaml::Controls::IPanel> panel;
+        ComPtr<IDependencyObject> canvas = d->screen->canvas();
+        ComPtr<IPanel> panel;
         hr = canvas.As(&panel);
         Q_ASSERT_SUCCEEDED(hr);
-        ComPtr<IVector<Xaml::UIElement *>> children;
+        ComPtr<IVector<UIElement *>> 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<Xaml::IDependencyObject> canvas = d->screen->canvas();
-        ComPtr<Xaml::Controls::IPanel> panel;
+        ComPtr<IDependencyObject> canvas = d->screen->canvas();
+        ComPtr<IPanel> panel;
         hr = canvas.As(&panel);
         Q_ASSERT_SUCCEEDED(hr);
-        ComPtr<IVector<Xaml::UIElement *>> children;
+        ComPtr<IVector<UIElement *>> children;
         hr = panel->get_Children(&children);
         Q_ASSERT_SUCCEEDED(hr);
 
-        ComPtr<Xaml::IUIElement> 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<Xaml::IFrameworkElement> 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
index 88c149b08023d06307bebb158e58acc49f620301..2957a7498bca858e29b1116a95facda8a94c8b81 100644 (file)
@@ -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<QWinRTWindowPrivate> d_ptr;