[vlc-devel] [PATCH v2 14/16] qt: extract interface window handling from MainInterface

Pierre Lamot pierre at videolabs.io
Fri Aug 14 18:43:48 CEST 2020


---
 modules/gui/qt/Makefile.am                    |   3 +
 .../gui/qt/maininterface/compositor_dcomp.cpp |   8 +-
 .../gui/qt/maininterface/compositor_dcomp.hpp |   2 +
 .../gui/qt/maininterface/compositor_dummy.cpp |   3 +
 .../interface_window_handler.cpp              | 229 ++++++++++++++++++
 .../interface_window_handler.hpp              |  72 ++++++
 .../gui/qt/maininterface/main_interface.cpp   | 142 +----------
 .../gui/qt/maininterface/main_interface.hpp   |  90 ++++++-
 .../qt/maininterface/main_interface_win32.cpp | 111 +++++++--
 .../qt/maininterface/main_interface_win32.hpp |  13 +-
 .../qt/maininterface/video_window_handler.cpp |  44 ++--
 11 files changed, 519 insertions(+), 198 deletions(-)
 create mode 100644 modules/gui/qt/maininterface/interface_window_handler.cpp
 create mode 100644 modules/gui/qt/maininterface/interface_window_handler.hpp

diff --git a/modules/gui/qt/Makefile.am b/modules/gui/qt/Makefile.am
index 305f94103d..7b1a3a2236 100644
--- a/modules/gui/qt/Makefile.am
+++ b/modules/gui/qt/Makefile.am
@@ -118,6 +118,8 @@ libqt_plugin_la_SOURCES = \
 	gui/qt/maininterface/compositor.cpp \
 	gui/qt/maininterface/compositor_dummy.hpp \
 	gui/qt/maininterface/compositor_dummy.cpp \
+	gui/qt/maininterface/interface_window_handler.cpp \
+	gui/qt/maininterface/interface_window_handler.hpp \
 	gui/qt/maininterface/main_interface.cpp \
 	gui/qt/maininterface/main_interface.hpp \
 	gui/qt/maininterface/mainui.cpp \
@@ -288,6 +290,7 @@ nodist_libqt_plugin_la_SOURCES = \
 	gui/qt/dialogs/sout/sout_widgets.moc.cpp \
 	gui/qt/dialogs/toolbar/toolbareditor.moc.cpp \
 	gui/qt/maininterface/compositor_dummy.moc.cpp \
+	gui/qt/maininterface/interface_window_handler.moc.cpp \
 	gui/qt/maininterface/main_interface.moc.cpp \
 	gui/qt/maininterface/mainui.moc.cpp \
 	gui/qt/maininterface/videosurface.moc.cpp \
diff --git a/modules/gui/qt/maininterface/compositor_dcomp.cpp b/modules/gui/qt/maininterface/compositor_dcomp.cpp
index dd381eeacd..51e20f5d81 100644
--- a/modules/gui/qt/maininterface/compositor_dcomp.cpp
+++ b/modules/gui/qt/maininterface/compositor_dcomp.cpp
@@ -36,7 +36,7 @@
 
 #include <qpa/qplatformnativeinterface.h>
 #include "compositor_dcomp_error.hpp"
-
+#include "maininterface/interface_window_handler.hpp"
 
 namespace vlc {
 
@@ -207,9 +207,15 @@ MainInterface* CompositorDirectComposition::makeMainInterface()
         m_videoWindowHandler = std::make_unique<VideoWindowHandler>(m_intf, m_rootWindow);
         m_videoWindowHandler->setWindow( m_rootWindow->windowHandle() );
 
+        m_interfaceWindowHandler = new InterfaceWindowHandlerWin32(m_intf, m_rootWindow, m_rootWindow->windowHandle(), m_rootWindow);
+
         m_qmlVideoSurfaceProvider = std::make_unique<VideoSurfaceProvider>();
         m_rootWindow->setVideoSurfaceProvider(m_qmlVideoSurfaceProvider.get());
 
+        connect(m_qmlVideoSurfaceProvider.get(), &VideoSurfaceProvider::hasVideoChanged,
+                m_interfaceWindowHandler, &InterfaceWindowHandlerWin32::onVideoEmbedChanged);
+
+
         HR(m_dcompDevice->CreateTargetForHwnd((HWND)m_rootWindow->windowHandle()->winId(), TRUE, &m_dcompTarget), "create target");
         HR(m_dcompDevice->CreateVisual(&m_rootVisual), "create root visual");
         HR(m_dcompTarget->SetRoot(m_rootVisual.Get()), "set root visual");
diff --git a/modules/gui/qt/maininterface/compositor_dcomp.hpp b/modules/gui/qt/maininterface/compositor_dcomp.hpp
index 23b86ca708..1c415daf2a 100644
--- a/modules/gui/qt/maininterface/compositor_dcomp.hpp
+++ b/modules/gui/qt/maininterface/compositor_dcomp.hpp
@@ -29,6 +29,7 @@
 #include "maininterface/mainui.hpp"
 #include "compositor_dcomp_uisurface.hpp"
 #include "videosurface.hpp"
+#include "interface_window_handler.hpp"
 #include "video_window_handler.hpp"
 
 #include <QOpenGLContext>
@@ -68,6 +69,7 @@ private:
     std::unique_ptr<MainUI> m_ui;
     std::unique_ptr<VideoWindowHandler> m_videoWindowHandler;
     std::unique_ptr<VideoSurfaceProvider> m_qmlVideoSurfaceProvider;
+    InterfaceWindowHandler* m_interfaceWindowHandler = nullptr;
 
     //main window composition
     HINSTANCE m_dcomp_dll = nullptr;
diff --git a/modules/gui/qt/maininterface/compositor_dummy.cpp b/modules/gui/qt/maininterface/compositor_dummy.cpp
index 16012e1c34..81e5d3f867 100644
--- a/modules/gui/qt/maininterface/compositor_dummy.cpp
+++ b/modules/gui/qt/maininterface/compositor_dummy.cpp
@@ -19,6 +19,7 @@
 
 #include "maininterface/main_interface.hpp"
 #include "maininterface/mainui.hpp"
+#include "maininterface/interface_window_handler.hpp"
 
 namespace vlc {
 
@@ -35,6 +36,8 @@ MainInterface* CompositorDummy::makeMainInterface()
     QQuickWidget* centralWidget = new QQuickWidget(m_rootWindow);
     centralWidget->setResizeMode(QQuickWidget::SizeRootObjectToView);
 
+    new InterfaceWindowHandler(m_intf, m_rootWindow, m_rootWindow->windowHandle(), m_rootWindow);
+
     MainUI* m_ui = new MainUI(m_intf, m_rootWindow, this);
     m_ui->setup(centralWidget->engine());
     centralWidget->setContent(QUrl(), m_ui->getComponent(), m_ui->createRootItem());
diff --git a/modules/gui/qt/maininterface/interface_window_handler.cpp b/modules/gui/qt/maininterface/interface_window_handler.cpp
new file mode 100644
index 0000000000..e7bbbc86c3
--- /dev/null
+++ b/modules/gui/qt/maininterface/interface_window_handler.cpp
@@ -0,0 +1,229 @@
+/*****************************************************************************
+ * Copyright (C) 2020 VideoLAN and AUTHORS
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+#include "interface_window_handler.hpp"
+#include "main_interface.hpp"
+#include <player/player_controller.hpp>
+#include <playlist/playlist_controller.hpp>
+
+InterfaceWindowHandler::InterfaceWindowHandler(intf_thread_t *_p_intf, MainInterface* mainInterface, QWindow* window, QObject *parent)
+    : QObject(parent)
+    , p_intf(_p_intf)
+    , m_window(window)
+    , m_mainInterface(mainInterface)
+{
+    assert(m_window);
+    assert(m_mainInterface);
+
+    /* */
+    m_pauseOnMinimize = var_InheritBool( p_intf, "qt-pause-minimized" );
+
+    m_window->setIcon( QApplication::windowIcon() );
+    m_window->setOpacity( var_InheritFloat( p_intf, "qt-opacity" ) );
+
+    WindowStateHolder::holdOnTop( m_window,  WindowStateHolder::INTERFACE, m_mainInterface->isInterfaceAlwaysOnTop() );
+    WindowStateHolder::holdFullscreen( m_window,  WindowStateHolder::INTERFACE, m_mainInterface->isInterfaceFullScreen() );
+
+    if (m_mainInterface->isHideAfterCreation())
+    {
+        //this needs to be called asynchronously
+        //otherwise QQuickWidget won't initialize properly
+        QMetaObject::invokeMethod(this, [this]() {
+                m_window->hide();
+            }, Qt::QueuedConnection, nullptr);
+    }
+
+
+    m_window->setTitle("");
+
+    if( var_InheritBool( p_intf, "qt-name-in-title" ) )
+    {
+        connect( THEMIM, &PlayerController::nameChanged, m_window, &QWindow::setTitle );
+    }
+
+    connect( m_mainInterface, &MainInterface::askBoss,
+             this, &InterfaceWindowHandler::setBoss, Qt::QueuedConnection  );
+    connect( m_mainInterface, &MainInterface::askRaise,
+             this, &InterfaceWindowHandler::setRaise, Qt::QueuedConnection  );
+
+    connect( m_mainInterface, &MainInterface::interfaceAlwaysOnTopChanged,
+             this, &InterfaceWindowHandler::setInterfaceAlwaysOnTop);
+
+    connect( m_mainInterface, &MainInterface::interfaceFullScreenChanged,
+             this, &InterfaceWindowHandler::setInterfaceFullScreen);
+
+    connect( m_mainInterface, &MainInterface::toggleWindowVisibility,
+             this, &InterfaceWindowHandler::toggleWindowVisiblity);
+
+    connect( m_mainInterface, &MainInterface::setInterfaceVisibible,
+             this, &InterfaceWindowHandler::setInterfaceVisible);
+
+    m_window->installEventFilter(this);
+}
+
+InterfaceWindowHandler::~InterfaceWindowHandler()
+{
+    m_window->removeEventFilter(this);
+    WindowStateHolder::holdOnTop( m_window,  WindowStateHolder::INTERFACE, false );
+    WindowStateHolder::holdFullscreen( m_window,  WindowStateHolder::INTERFACE, false );
+}
+
+bool InterfaceWindowHandler::eventFilter(QObject*, QEvent* event)
+{
+    if( event->type() == QEvent::WindowStateChange )
+    {
+        QWindowStateChangeEvent *windowStateChangeEvent = static_cast<QWindowStateChangeEvent*>(event);
+        Qt::WindowStates newState = m_window->windowStates();
+        Qt::WindowStates oldState = windowStateChangeEvent->oldState();
+
+        /* b_maximizedView stores if the window was maximized before entering fullscreen.
+         * It is set when entering maximized mode, unset when leaving it to normal mode.
+         * Upon leaving full screen, if b_maximizedView is set,
+         * the window should be maximized again. */
+        if( newState & Qt::WindowMaximized &&
+            !( oldState & Qt::WindowMaximized ) )
+            m_maximizedView = true;
+
+        if( !( newState & Qt::WindowMaximized ) &&
+            oldState & Qt::WindowMaximized ) //FIXME && !b_videoFullScreen )
+            m_maximizedView = false;
+
+        if( !( newState & Qt::WindowFullScreen ) &&
+            oldState & Qt::WindowFullScreen &&
+            m_maximizedView )
+        {
+            m_window->showMaximized();
+            return false;
+        }
+
+        if( newState & Qt::WindowMinimized )
+        {
+
+            m_hasPausedWhenMinimized = false;
+
+            if( THEMIM->getPlayingState() == PlayerController::PLAYING_STATE_PLAYING &&
+                THEMIM->hasVideoOutput() && !THEMIM->hasAudioVisualization() &&
+                m_pauseOnMinimize )
+            {
+                m_hasPausedWhenMinimized = true;
+                THEMPL->pause();
+            }
+        }
+        else if( oldState & Qt::WindowMinimized && !( newState & Qt::WindowMinimized ) )
+        {
+            if( m_hasPausedWhenMinimized )
+            {
+                THEMPL->play();
+            }
+        }
+    }
+
+    return false;
+}
+
+void InterfaceWindowHandler::onVideoEmbedChanged(bool embed)
+{
+    if (embed)
+    {
+        m_interfaceGeometry = m_window->geometry();
+    }
+    else if (!m_interfaceGeometry.isNull())
+    {
+        m_window->setGeometry(m_interfaceGeometry);
+        m_interfaceGeometry = QRect();
+    }
+}
+
+
+void InterfaceWindowHandler::toggleWindowVisiblity()
+{
+    switch ( m_window->visibility() )
+    {
+    case QWindow::Hidden:
+        /* If hidden, show it */
+        m_window->show();
+        m_window->requestActivate();
+        break;
+    case QWindow::Minimized:
+        m_window->showNormal();
+        m_window->requestActivate();
+        break;
+    default:
+        m_window->hide();
+        break;
+    }
+}
+
+
+void InterfaceWindowHandler::setInterfaceVisible(bool visible)
+{
+    if (visible)
+    {
+        switch ( m_window->visibility() )
+        {
+        case QWindow::Hidden:
+            m_window->show();
+            break;
+        case QWindow::Minimized:
+            m_window->showNormal();
+            break;
+        default:
+            break;
+        }
+        m_window->requestActivate();
+    }
+    else
+    {
+        m_window->hide();
+    }
+}
+
+
+void InterfaceWindowHandler::setFullScreen( bool fs )
+{
+    WindowStateHolder::holdFullscreen(m_window, WindowStateHolder::INTERFACE, fs);
+}
+
+void InterfaceWindowHandler::setInterfaceFullScreen( bool fs )
+{
+    setFullScreen(fs);
+    emit interfaceFullScreenChanged( fs );
+}
+
+void InterfaceWindowHandler::setRaise()
+{
+    m_window->requestActivate();
+    m_window->raise();
+}
+
+void InterfaceWindowHandler::setBoss()
+{
+    THEMPL->pause();
+    if( m_mainInterface->getSysTray() )
+    {
+        m_window->hide();
+    }
+    else
+    {
+        m_window->showMinimized();
+    }
+}
+
+void InterfaceWindowHandler::setInterfaceAlwaysOnTop( bool on_top )
+{
+    WindowStateHolder::holdOnTop(m_window, WindowStateHolder::INTERFACE, on_top);
+}
diff --git a/modules/gui/qt/maininterface/interface_window_handler.hpp b/modules/gui/qt/maininterface/interface_window_handler.hpp
new file mode 100644
index 0000000000..dcb2f43680
--- /dev/null
+++ b/modules/gui/qt/maininterface/interface_window_handler.hpp
@@ -0,0 +1,72 @@
+/*****************************************************************************
+ * Copyright (C) 2020 VideoLAN and AUTHORS
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+#ifndef INTERFACEWINDOWHANDLER_H
+#define INTERFACEWINDOWHANDLER_H
+
+#include "qt.hpp"
+
+#include <QObject>
+#include <QWindow>
+
+class MainInterface;
+class InterfaceWindowHandler : public QObject
+{
+    Q_OBJECT
+public:
+    explicit InterfaceWindowHandler(intf_thread_t *_p_intf, MainInterface* mainInterface, QWindow* window, QObject *parent = nullptr);
+    virtual ~InterfaceWindowHandler();
+
+public slots:
+    virtual void onVideoEmbedChanged( bool embed );
+
+protected slots:
+    virtual void setFullScreen( bool fs );
+    virtual void setInterfaceFullScreen( bool fs );
+    virtual void setInterfaceAlwaysOnTop( bool on_top );
+    virtual void toggleWindowVisiblity();
+    virtual void setInterfaceVisible(bool);
+
+
+    virtual void setRaise();
+    virtual void setBoss();
+
+    virtual bool eventFilter(QObject*, QEvent* event) override;
+
+signals:
+    void minimalViewToggled( bool );
+    void fullscreenInterfaceToggled( bool );
+    void interfaceAlwaysOnTopChanged(bool);
+    void interfaceFullScreenChanged(bool);
+
+protected:
+    intf_thread_t* p_intf = nullptr;
+    QWindow* m_window = nullptr;
+    MainInterface* m_mainInterface = nullptr;
+
+    bool m_hasPausedWhenMinimized = false;
+
+    bool m_isWindowTiled = false;
+
+    bool m_pauseOnMinimize ;
+    bool m_maximizedView = false;
+    bool m_hideAfterCreation  = false; // --qt-start-minimized
+
+    QRect m_interfaceGeometry;
+};
+
+#endif // INTERFACEWINDOWHANDLER_H
diff --git a/modules/gui/qt/maininterface/main_interface.cpp b/modules/gui/qt/maininterface/main_interface.cpp
index 64c4fd9ffc..6850dd0882 100644
--- a/modules/gui/qt/maininterface/main_interface.cpp
+++ b/modules/gui/qt/maininterface/main_interface.cpp
@@ -110,10 +110,7 @@ MainInterface::MainInterface(intf_thread_t *_p_intf , QWidget* parent, Qt::Windo
     playlistVisible      = false;
     playlistWidthFactor  = 4.0;
     b_interfaceFullScreen= false;
-    b_hasPausedWhenMinimized = false;
     i_kc_offset          = false;
-    b_maximizedView      = false;
-    b_isWindowTiled      = false;
 
     /**
      *  Configuration and settings
@@ -127,8 +124,6 @@ MainInterface::MainInterface(intf_thread_t *_p_intf , QWidget* parent, Qt::Windo
     i_notificationSetting = var_InheritInteger( p_intf, "qt-notification" );
 
     /* */
-    b_pauseOnMinimize = var_InheritBool( p_intf, "qt-pause-minimized" );
-
     m_intfUserScaleFactor = var_InheritFloat(p_intf, "qt-interface-scale");
     winId(); //force window creation
     QWindow* window = windowHandle();
@@ -161,17 +156,10 @@ MainInterface::MainInterface(intf_thread_t *_p_intf , QWidget* parent, Qt::Windo
     /**************************
      *  UI and Widgets design
      **************************/
-    setWindowTitle("");
 
     /* Main settings */
     setFocusPolicy( Qt::StrongFocus );
     setAcceptDrops( true );
-    setWindowRole( "vlc-main" );
-    setWindowIcon( QApplication::windowIcon() );
-    setWindowOpacity( var_InheritFloat( p_intf, "qt-opacity" ) );
-    if ( b_interfaceOnTop )
-        setWindowFlags( windowFlags() | Qt::WindowStaysOnTopHint );
-
 
     /*********************************
      * Create the Systray Management *
@@ -188,18 +176,12 @@ MainInterface::MainInterface(intf_thread_t *_p_intf , QWidget* parent, Qt::Windo
      **/
     /* Main Interface statusbar */
     /* and title of the Main Interface*/
-    if( var_InheritBool( p_intf, "qt-name-in-title" ) )
-    {
-        connect( THEMIM, &PlayerController::nameChanged, this, &MainInterface::setWindowTitle );
-    }
     connect( THEMIM, &PlayerController::inputChanged, this, &MainInterface::onInputChanged );
 
     /* END CONNECTS ON IM */
 
     /* VideoWidget connects for asynchronous calls */
     connect( this, &MainInterface::askToQuit, THEDP, &DialogsProvider::quit, Qt::QueuedConnection  );
-    connect( this, &MainInterface::askBoss, this, &MainInterface::setBoss, Qt::QueuedConnection  );
-    connect( this, &MainInterface::askRaise, this, &MainInterface::setRaise, Qt::QueuedConnection  );
 
     connect( THEDP, &DialogsProvider::toolBarConfUpdated, this, &MainInterface::toolBarConfUpdated );
 
@@ -227,9 +209,6 @@ MainInterface::MainInterface(intf_thread_t *_p_intf , QWidget* parent, Qt::Windo
     widget->setStyleSheet("background-color: transparent");
     setCentralWidget(widget);
 
-
-    setVisible( !b_hideAfterCreation );
-
     computeMinimumSize();
 }
 
@@ -279,7 +258,6 @@ void MainInterface::computeMinimumSize()
 void MainInterface::reloadPrefs()
 {
     i_notificationSetting = var_InheritInteger( p_intf, "qt-notification" );
-    b_pauseOnMinimize = var_InheritBool( p_intf, "qt-pause-minimized" );
 }
 
 
@@ -379,17 +357,6 @@ void MainInterface::setShowRemainingTime( bool show )
 void MainInterface::setInterfaceAlwaysOnTop( bool on_top )
 {
     b_interfaceOnTop = on_top;
-    Qt::WindowFlags oldflags = windowFlags(), newflags;
-
-    if( on_top )
-        newflags = oldflags | Qt::WindowStaysOnTopHint;
-    else
-        newflags = oldflags & ~Qt::WindowStaysOnTopHint;
-    if( newflags != oldflags ) //FIXME  &&  !b_videoFullScreen )
-    {
-        setWindowFlags( newflags );
-        show(); /* necessary to apply window flags */
-    }
     emit interfaceAlwaysOnTopChanged(on_top);
 }
 
@@ -464,33 +431,12 @@ void MainInterface::createSystray()
              this, &MainInterface::updateSystrayTooltipStatus );
 }
 
-void MainInterface::toggleUpdateSystrayMenuWhenVisible()
-{
-    hide();
-}
-
 /**
  * Updates the Systray Icon's menu and toggle the main interface
  */
 void MainInterface::toggleUpdateSystrayMenu()
 {
-    /* If hidden, show it */
-    if( isHidden() )
-    {
-        show();
-        activateWindow();
-    }
-    else if( isMinimized() )
-    {
-        /* Minimized */
-        showNormal();
-        activateWindow();
-    }
-    else
-    {
-        /* Visible (possibly under other windows) */
-        toggleUpdateSystrayMenuWhenVisible();
-    }
+    emit toggleWindowVisibility();
     if( sysTray )
         VLCMenuBar::updateSystrayMenu( this, p_intf );
 }
@@ -498,19 +444,14 @@ void MainInterface::toggleUpdateSystrayMenu()
 /* First Item of the systray menu */
 void MainInterface::showUpdateSystrayMenu()
 {
-    if( isHidden() )
-        show();
-    if( isMinimized() )
-        showNormal();
-    activateWindow();
-
+    emit setInterfaceVisibible(true);
     VLCMenuBar::updateSystrayMenu( this, p_intf );
 }
 
 /* First Item of the systray menu */
 void MainInterface::hideUpdateSystrayMenu()
 {
-    hide();
+    emit setInterfaceVisibible(false);
     VLCMenuBar::updateSystrayMenu( this, p_intf );
 }
 
@@ -571,57 +512,6 @@ void MainInterface::updateSystrayTooltipStatus( PlayerController::PlayingState )
     VLCMenuBar::updateSystrayMenu( this, p_intf );
 }
 
-void MainInterface::changeEvent(QEvent *event)
-{
-    if( event->type() == QEvent::WindowStateChange )
-    {
-        QWindowStateChangeEvent *windowStateChangeEvent = static_cast<QWindowStateChangeEvent*>(event);
-        Qt::WindowStates newState = windowState();
-        Qt::WindowStates oldState = windowStateChangeEvent->oldState();
-
-        /* b_maximizedView stores if the window was maximized before entering fullscreen.
-         * It is set when entering maximized mode, unset when leaving it to normal mode.
-         * Upon leaving full screen, if b_maximizedView is set,
-         * the window should be maximized again. */
-        if( newState & Qt::WindowMaximized &&
-            !( oldState & Qt::WindowMaximized ) )
-            b_maximizedView = true;
-
-        if( !( newState & Qt::WindowMaximized ) &&
-            oldState & Qt::WindowMaximized ) //FIXME && !b_videoFullScreen )
-            b_maximizedView = false;
-
-        if( !( newState & Qt::WindowFullScreen ) &&
-            oldState & Qt::WindowFullScreen &&
-            b_maximizedView )
-        {
-            showMaximized();
-            return;
-        }
-
-        if( newState & Qt::WindowMinimized )
-        {
-            b_hasPausedWhenMinimized = false;
-
-            if( THEMIM->getPlayingState() == PlayerController::PLAYING_STATE_PLAYING &&
-                THEMIM->hasVideoOutput() && !THEMIM->hasAudioVisualization() &&
-                b_pauseOnMinimize )
-            {
-                b_hasPausedWhenMinimized = true;
-                THEMPL->pause();
-            }
-        }
-        else if( oldState & Qt::WindowMinimized && !( newState & Qt::WindowMinimized ) )
-        {
-            if( b_hasPausedWhenMinimized )
-            {
-                THEMPL->play();
-            }
-        }
-    }
-
-    QWidget::changeEvent(event);
-}
 
 /************************************************************************
  * D&D Events
@@ -747,18 +637,9 @@ void MainInterface::closeEvent( QCloseEvent *e )
     }
 }
 
-void MainInterface::setFullScreen( bool fs )
-{
-    if( fs )
-        setWindowState( windowState() | Qt::WindowFullScreen );
-    else
-        setWindowState( windowState() & ~Qt::WindowFullScreen );
-}
-
 void MainInterface::setInterfaceFullScreen( bool fs )
 {
     b_interfaceFullScreen = fs;
-    setFullScreen(fs);
     emit interfaceFullScreenChanged( fs );
 }
 
@@ -772,18 +653,6 @@ void MainInterface::emitBoss()
 {
     emit askBoss();
 }
-void MainInterface::setBoss()
-{
-    THEMPL->pause();
-    if( sysTray )
-    {
-        hide();
-    }
-    else
-    {
-        showMinimized();
-    }
-}
 
 void MainInterface::emitShow()
 {
@@ -799,11 +668,6 @@ void MainInterface::emitRaise()
 {
     emit askRaise();
 }
-void MainInterface::setRaise()
-{
-    activateWindow();
-    raise();
-}
 
 VLCVarChoiceModel* MainInterface::getExtraInterfaces()
 {
diff --git a/modules/gui/qt/maininterface/main_interface.hpp b/modules/gui/qt/maininterface/main_interface.hpp
index 5b05f78f2c..b60b0c9014 100644
--- a/modules/gui/qt/maininterface/main_interface.hpp
+++ b/modules/gui/qt/maininterface/main_interface.hpp
@@ -58,6 +58,83 @@ class StandardPLPanel;
 struct vout_window_t;
 class VideoSurfaceProvider;
 
+class WindowStateHolder : public QObject
+{
+public:
+    enum Source {
+        INTERFACE = 1,
+        VIDEO = 2,
+    };
+
+    static bool holdFullscreen( QWindow* window, Source source, bool hold )
+    {
+        QVariant prop = window->property("__windowFullScreen");
+        bool ok = false;
+        unsigned fullscreenCounter = prop.toUInt(&ok);
+        if (!ok)
+            fullscreenCounter = 0;
+
+        if (hold)
+            fullscreenCounter |= source;
+        else
+            fullscreenCounter &= ~source;
+
+        Qt::WindowStates oldflags = window->windowStates();
+        Qt::WindowStates newflags;
+
+        if( fullscreenCounter != 0 )
+            newflags = oldflags | Qt::WindowFullScreen;
+        else
+            newflags = oldflags & ~Qt::WindowFullScreen;
+
+        if( newflags != oldflags )
+        {
+            window->setWindowStates( newflags );
+        }
+
+        window->setProperty("__windowFullScreen", QVariant::fromValue(fullscreenCounter));
+
+        return fullscreenCounter != 0;
+    }
+
+
+    static bool holdOnTop( QWindow* window, Source source, bool hold )
+    {
+        QVariant prop = window->property("__windowOnTop");
+        bool ok = false;
+        unsigned onTopCounter = prop.toUInt(&ok);
+        if (!ok)
+            onTopCounter = 0;
+
+        if (hold)
+            onTopCounter |= source;
+        else
+            onTopCounter &= ~source;
+
+        Qt::WindowStates oldStates = window->windowStates();
+        Qt::WindowFlags oldflags = window->flags();
+        Qt::WindowFlags newflags;
+
+        if( onTopCounter != 0 )
+            newflags = oldflags | Qt::WindowStaysOnTopHint;
+        else
+            newflags = oldflags & ~Qt::WindowStaysOnTopHint;
+        if( newflags != oldflags )
+        {
+
+            window->setFlags( newflags );
+            window->show(); /* necessary to apply window flags */
+            //workaround: removing onTop state might drop fullscreen state
+            window->setWindowStates(oldStates);
+        }
+
+        window->setProperty("__windowOnTop", QVariant::fromValue(onTopCounter));
+
+        return onTopCounter != 0;
+    }
+
+};
+
 class MainInterface : public QVLCMW
 {
     Q_OBJECT
@@ -101,6 +178,7 @@ public:
     bool isPlaylistVisible() { return playlistVisible; }
     inline double getPlaylistWidthFactor() const { return playlistWidthFactor; }
     bool isInterfaceAlwaysOnTop() { return b_interfaceOnTop; }
+    inline bool isHideAfterCreation() const { return b_hideAfterCreation; }
     inline bool isShowRemainingTime() const  { return m_showRemainingTime; }
     inline float getIntfScaleFactor() const { return m_intfScaleFactor; }
 
@@ -110,13 +188,11 @@ public:
 
 protected:
     void dropEventPlay( QDropEvent* event, bool b_play );
-    void changeEvent( QEvent * ) Q_DECL_OVERRIDE;
     void dropEvent( QDropEvent *) Q_DECL_OVERRIDE;
     void dragEnterEvent( QDragEnterEvent * ) Q_DECL_OVERRIDE;
     void dragMoveEvent( QDragMoveEvent * ) Q_DECL_OVERRIDE;
     void dragLeaveEvent( QDragLeaveEvent * ) Q_DECL_OVERRIDE;
     void closeEvent( QCloseEvent *) Q_DECL_OVERRIDE;
-    virtual void toggleUpdateSystrayMenuWhenVisible();
 
 protected:
     /* Systray */
@@ -162,9 +238,6 @@ protected:
     bool                 b_playlistDocked;
     bool                 b_interfaceFullScreen;
     bool                 b_interfaceOnTop;      ///keep UI on top
-    bool                 b_pauseOnMinimize;
-    bool                 b_maximizedView;
-    bool                 b_isWindowTiled;
 #ifdef QT5_HAS_WAYLAND
     bool                 b_hasWayland;
 #endif
@@ -173,8 +246,6 @@ protected:
     bool                 playlistVisible;       ///< Is the playlist visible ?
     double               playlistWidthFactor;   ///< playlist size: root.width / playlistScaleFactor
 
-    bool                 b_hasPausedWhenMinimized;
-
     static const Qt::Key kc[10]; /* easter eggs */
     int i_kc_offset;
 
@@ -206,9 +277,6 @@ protected slots:
 
     void showBuffering( float );
 
-    void setBoss();
-    void setRaise();
-    void setFullScreen( bool );
     void onInputChanged( bool );
     void updateIntfScaleFactor();
 
@@ -217,6 +285,8 @@ protected slots:
 signals:
     void minimalViewToggled( bool );
     void fullscreenInterfaceToggled( bool );
+    void setInterfaceVisibible(bool );
+    void toggleWindowVisibility();
     void askToQuit();
     void askShow();
     void askBoss();
diff --git a/modules/gui/qt/maininterface/main_interface_win32.cpp b/modules/gui/qt/maininterface/main_interface_win32.cpp
index 28a826581d..a4c47cb9cc 100644
--- a/modules/gui/qt/maininterface/main_interface_win32.cpp
+++ b/modules/gui/qt/maininterface/main_interface_win32.cpp
@@ -410,32 +410,101 @@ bool MainInterfaceWin32::nativeEvent(const QByteArray &eventType, void *message,
     return false;
 }
 
-void MainInterfaceWin32::toggleUpdateSystrayMenuWhenVisible()
+InterfaceWindowHandlerWin32::InterfaceWindowHandlerWin32(intf_thread_t *_p_intf, MainInterface* mainInterface, QWindow* window, QObject *parent)
+    : InterfaceWindowHandler(_p_intf, mainInterface, window, parent)
 {
-    /* check if any visible window is above vlc in the z-order,
-     * but ignore the ones always on top
-     * and the ones which can't be activated */
-    HWND winId = WinId(this->windowHandle());
-
-    WINDOWINFO wi;
-    HWND hwnd;
-    wi.cbSize = sizeof( WINDOWINFO );
-    for( hwnd = GetNextWindow( winId, GW_HWNDPREV );
-            hwnd && ( !IsWindowVisible( hwnd ) || ( GetWindowInfo( hwnd, &wi ) &&
-                                                    ( wi.dwExStyle&WS_EX_NOACTIVATE ) ) );
-            hwnd = GetNextWindow( hwnd, GW_HWNDPREV ) )
-    {
-    }
-    if( !hwnd || !GetWindowInfo( hwnd, &wi ) || (wi.dwExStyle&WS_EX_TOPMOST) )
-        hide();
-    else
-        activateWindow();
 }
 
-
-
 void MainInterfaceWin32::reloadPrefs()
 {
     p_intf->p_sys->disable_volume_keys = var_InheritBool( p_intf, "qt-disable-volume-keys" );
     MainInterface::reloadPrefs();
 }
+
+
+void InterfaceWindowHandlerWin32::toggleWindowVisiblity()
+{
+
+    switch ( m_window->visibility() )
+    {
+    case QWindow::Hidden:
+        /* If hidden, show it */
+        m_window->show();
+        m_window->requestActivate();
+        break;
+    case QWindow::Minimized:
+        m_window->showNormal();
+        m_window->requestActivate();
+        break;
+    default:
+        {
+            /* check if any visible window is above vlc in the z-order,
+             * but ignore the ones always on top
+             * and the ones which can't be activated */
+            HWND winId = WinId(m_window);
+
+            WINDOWINFO wi;
+            HWND hwnd;
+            wi.cbSize = sizeof( WINDOWINFO );
+            for( hwnd = GetNextWindow( winId, GW_HWNDPREV );
+                    hwnd && ( !IsWindowVisible( hwnd ) || ( GetWindowInfo( hwnd, &wi ) &&
+                                                            ( wi.dwExStyle&WS_EX_NOACTIVATE ) ) );
+                    hwnd = GetNextWindow( hwnd, GW_HWNDPREV ) )
+            {
+            }
+            if( !hwnd || !GetWindowInfo( hwnd, &wi ) || (wi.dwExStyle&WS_EX_TOPMOST) )
+                m_window->hide();
+            else
+                m_window->requestActivate();
+        }
+        break;
+    }
+
+}
+
+
+bool InterfaceWindowHandlerWin32::eventFilter(QObject* obj, QEvent* ev)
+{
+    bool ret = InterfaceWindowHandler::eventFilter(obj, ev);
+    if (ret)
+        return ret;
+
+    if (ev->type() == QEvent::Resize)
+    {
+        /*
+         * Detects if window placement is not in its normal position (ex: win7 aero snap)
+         * This function compares the normal position (non snapped) to the current position.
+         * The current position is translated from screen referential to workspace referential
+         * to workspace referential
+         */
+        m_isWindowTiled = false;
+        HWND winHwnd = WinId( m_window );
+
+        WINDOWPLACEMENT windowPlacement;
+        windowPlacement.length = sizeof( windowPlacement );
+        if ( GetWindowPlacement( winHwnd, &windowPlacement ) == 0 )
+            return ret;
+
+        if ( windowPlacement.showCmd != SW_SHOWNORMAL )
+            return ret;
+
+        HMONITOR monitor = MonitorFromWindow( winHwnd, MONITOR_DEFAULTTONEAREST );
+
+        MONITORINFO monitorInfo;
+        monitorInfo.cbSize = sizeof( monitorInfo );
+        if ( GetMonitorInfo( monitor, &monitorInfo )  == 0 )
+            return ret;
+
+        RECT windowRect;
+        if ( GetWindowRect( winHwnd, &windowRect ) == 0 )
+            return ret;
+
+        OffsetRect( &windowRect,
+                    monitorInfo.rcMonitor.left - monitorInfo.rcWork.left ,
+                    monitorInfo.rcMonitor.top - monitorInfo.rcWork.top );
+
+        m_isWindowTiled = ( EqualRect( &windowPlacement.rcNormalPosition, &windowRect ) == 0 );
+    }
+
+    return ret;
+}
diff --git a/modules/gui/qt/maininterface/main_interface_win32.hpp b/modules/gui/qt/maininterface/main_interface_win32.hpp
index 1cbb99d51a..422905ca52 100644
--- a/modules/gui/qt/maininterface/main_interface_win32.hpp
+++ b/modules/gui/qt/maininterface/main_interface_win32.hpp
@@ -25,6 +25,7 @@
 #define MAIN_INTERFACE_WIN32_HPP
 
 #include "maininterface/main_interface.hpp"
+#include "interface_window_handler.hpp"
 #include <QAbstractNativeEventFilter>
 
 class WinTaskbarWidget : public QObject, public QAbstractNativeEventFilter
@@ -63,11 +64,21 @@ public:
 
 private:
     virtual bool nativeEvent(const QByteArray &eventType, void *message, long *result) override;
-    virtual void toggleUpdateSystrayMenuWhenVisible() override;
 
 public slots:
     virtual void reloadPrefs() override;
 
 };
 
+class InterfaceWindowHandlerWin32 : public InterfaceWindowHandler
+{
+    Q_OBJECT
+public:
+    explicit InterfaceWindowHandlerWin32(intf_thread_t *_p_intf, MainInterface* mainInterface, QWindow* window, QObject *parent = nullptr);
+    virtual ~InterfaceWindowHandlerWin32() = default;
+    virtual void toggleWindowVisiblity() override;
+
+    virtual bool eventFilter(QObject*, QEvent* event) override;
+};
+
 #endif // MAIN_INTERFACE_WIN32_HPP
diff --git a/modules/gui/qt/maininterface/video_window_handler.cpp b/modules/gui/qt/maininterface/video_window_handler.cpp
index 760cbe219d..3a88f3217b 100644
--- a/modules/gui/qt/maininterface/video_window_handler.cpp
+++ b/modules/gui/qt/maininterface/video_window_handler.cpp
@@ -41,7 +41,20 @@ VideoWindowHandler::VideoWindowHandler(intf_thread_t* intf, MainInterface* mainI
 
 void VideoWindowHandler::setWindow(QWindow* window)
 {
+    if (m_window == window)
+        return;
+    if (m_window)
+    {
+        WindowStateHolder::holdOnTop(m_window, WindowStateHolder::VIDEO, false);
+        WindowStateHolder::holdFullscreen(m_window, WindowStateHolder::VIDEO, false);
+    }
     m_window = window;
+    if (m_window)
+    {
+        m_lastWinGeometry = m_window->geometry();
+    }
+    else
+        m_lastWinGeometry = QRect{};
 }
 
 void VideoWindowHandler::disable()
@@ -110,8 +123,6 @@ void VideoWindowHandler::setVideoFullScreen( bool fs )
     if (!m_window)
         return;
     m_videoFullScreen = fs;
-
-    Qt::WindowStates states = m_window->windowStates();
     if( fs )
     {
         int numscreen = var_InheritInteger( m_intf, "qt-fullscreen-screennumber" );
@@ -131,18 +142,15 @@ void VideoWindowHandler::setVideoFullScreen( bool fs )
             if( !screenres.contains( m_window->position() ) )
             {
                 m_lastWinGeometry = m_window->geometry();
-                msg_Dbg( m_intf, "Moving video to correct position");
                 m_window->setPosition(screenres.x(), screenres.y() );
             }
         }
-        m_window->setWindowStates(states | Qt::WindowFullScreen);
+        WindowStateHolder::holdFullscreen(m_window,  WindowStateHolder::VIDEO, true);
     }
     else
     {
-        if (m_interface->isInterfaceFullScreen())
-            m_window->setWindowStates(states | Qt::WindowFullScreen);
-        else
-            m_window->setWindowStates(states & ~Qt::WindowFullScreen);
+        bool hold = WindowStateHolder::holdFullscreen(m_window,  WindowStateHolder::VIDEO, false);
+
 #ifdef QT5_HAS_WAYLAND
         if( m_lastWinScreen != NULL && !m_hasWayland )
             m_window->setScreen(m_lastWinScreen);
@@ -150,8 +158,7 @@ void VideoWindowHandler::setVideoFullScreen( bool fs )
         if( m_lastWinScreen != NULL )
             m_window->setScreen(m_lastWinScreen);
 #endif
-        //FIXME m_interface->restorePosition();
-        if( m_lastWinGeometry.isNull() == false )
+        if( !hold && m_lastWinGeometry.isNull() == false )
         {
             m_window->setGeometry( m_lastWinGeometry );
             m_lastWinGeometry = QRect();
@@ -166,20 +173,5 @@ void VideoWindowHandler::setVideoOnTop( bool on_top )
 {
     if (!m_window)
         return;
-    //don't apply changes if user has already sets its interface on top
-    if ( m_interface->isInterfaceAlwaysOnTop() )
-        return;
-
-    Qt::WindowFlags oldflags = m_window->flags();
-    Qt::WindowFlags newflags;
-
-    if( on_top )
-        newflags = oldflags | Qt::WindowStaysOnTopHint;
-    else
-        newflags = oldflags & ~Qt::WindowStaysOnTopHint;
-    if( newflags != oldflags && !m_videoFullScreen )
-    {
-        m_window->setFlags( newflags );
-        m_window->show(); /* necessary to apply window flags */
-    }
+    WindowStateHolder::holdOnTop(m_window, WindowStateHolder::VIDEO, on_top);
 }
-- 
2.25.1



More information about the vlc-devel mailing list