[vlc-devel] [PATCH 3/7] qt: provide a detached window to render video in detached or fullscreen mode

Pierre Lamot pierre at videolabs.io
Fri Aug 14 18:49:01 CEST 2020


  This allows to render video in a separate window from the main interface or
  fullscreen on a specific screen.
---
 modules/gui/qt/Makefile.am                    |   3 +
 .../maininterface/detached_video_window.cpp   | 247 ++++++++++++++++++
 .../maininterface/detached_video_window.hpp   |  75 ++++++
 3 files changed, 325 insertions(+)
 create mode 100644 modules/gui/qt/maininterface/detached_video_window.cpp
 create mode 100644 modules/gui/qt/maininterface/detached_video_window.hpp

diff --git a/modules/gui/qt/Makefile.am b/modules/gui/qt/Makefile.am
index 86add9398b..dbb43476b8 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/detached_video_window.cpp \
+	gui/qt/maininterface/detached_video_window.hpp \
 	gui/qt/maininterface/interface_window_handler.cpp \
 	gui/qt/maininterface/interface_window_handler.hpp \
 	gui/qt/maininterface/main_interface.cpp \
@@ -293,6 +295,7 @@ nodist_libqt_plugin_la_SOURCES = \
 	gui/qt/dialogs/toolbar/toolbareditor.moc.cpp \
 	gui/qt/maininterface/compositor.moc.cpp \
 	gui/qt/maininterface/compositor_dummy.moc.cpp \
+	gui/qt/maininterface/detached_video_window.moc.cpp \
 	gui/qt/maininterface/interface_window_handler.moc.cpp \
 	gui/qt/maininterface/main_interface.moc.cpp \
 	gui/qt/maininterface/mainui.moc.cpp \
diff --git a/modules/gui/qt/maininterface/detached_video_window.cpp b/modules/gui/qt/maininterface/detached_video_window.cpp
new file mode 100644
index 0000000000..cbc9c3b1e9
--- /dev/null
+++ b/modules/gui/qt/maininterface/detached_video_window.cpp
@@ -0,0 +1,247 @@
+/*****************************************************************************
+ * Copyright (C) 2020 VLC authors and VideoLAN
+ *
+ * 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 "detached_video_window.hpp"
+#include "widgets/native/customwidgets.hpp"               // qtEventToVLCKey, QVLCStackedWidget
+
+#if defined (QT5_HAS_X11)
+# include <X11/Xlib.h>
+# include <QX11Info>
+# if defined(QT5_HAS_XCB)
+#  include <xcb/xproto.h>
+# endif
+#endif
+#ifdef QT5_HAS_WAYLAND
+# include QPNI_HEADER
+#endif
+
+#include <QWindow>
+#include <QScreen>
+
+#if defined(_WIN32)
+#include <qpa/qplatformnativeinterface.h>
+#endif
+
+#include <vlc_vout_window.h>
+#include "compositor.hpp"
+
+DetachedVideoWindow::DetachedVideoWindow(intf_thread_t *p_intf,
+                                         vout_window_t *p_wnd,
+                                         QWidget *parent)
+    : QWidget(parent)
+    , m_intf(p_intf)
+    , m_voutWindow(p_wnd)
+{
+    m_cursorTimer = new QTimer( this );
+    m_cursorTimer->setSingleShot( true );
+    connect( m_cursorTimer, &QTimer::timeout, this, &DetachedVideoWindow::hideCursor);
+    m_cursorTimeout = var_InheritInteger( m_intf, "mouse-hide-timeout" );
+}
+
+QSize DetachedVideoWindow::physicalSize() const
+{
+#ifdef QT5_HAS_X11
+    if ( QX11Info::isPlatformX11() )
+    {
+        Display *p_x_display = QX11Info::display();
+        Window x_window = this->winId();
+        XWindowAttributes x_attributes;
+
+        XGetWindowAttributes( p_x_display, x_window, &x_attributes );
+
+        return QSize( x_attributes.width, x_attributes.height );
+    }
+#endif
+#if defined(_WIN32)
+    HWND hwnd;
+    RECT rect;
+
+    QWindow *window = windowHandle();
+    hwnd = static_cast<HWND>(QGuiApplication::platformNativeInterface()->nativeResourceForWindow("handle", window));
+
+    GetClientRect(hwnd, &rect);
+
+    return QSize( rect.right, rect.bottom );
+#endif
+
+    QSize current_size = size();
+    current_size *= devicePixelRatioF();
+    return current_size;
+}
+
+void DetachedVideoWindow::showFSOnScreen(QString screenName, QWindow* interfaceWindow)
+{
+    auto screenList = QGuiApplication::screens();
+    auto it = std::find_if(screenList.begin(), screenList.end(), [&screenName](QScreen* screen) {
+        return screen->name() == screenName;
+    });
+    if (it == screenList.end())
+    {
+        //target screen not found, show it fullscreen anyway
+        showFullScreen();
+        return;
+    }
+
+    QWindow* window = windowHandle();
+    assert(window);
+    window->setScreen(*it);
+
+    showFullScreen();
+
+    //move the interface if it is on the destination screen
+    if (!interfaceWindow)
+        return;
+
+    QScreen* currentInterfaceScreen = interfaceWindow->screen();
+    if (screenList.count() > 1 && currentInterfaceScreen == *it)
+    {
+        auto availableScreenIt = std::find_if(screenList.begin(), screenList.end(), [currentInterfaceScreen](QScreen* screen) {
+            return screen != currentInterfaceScreen;
+        });
+        if (availableScreenIt != screenList.end())
+        {
+            QScreen* newInterfaceScreen = *availableScreenIt;
+            interfaceWindow->setScreen(newInterfaceScreen);
+            interfaceWindow->setFramePosition(newInterfaceScreen->geometry().topLeft());
+            interfaceWindow->resize(qMin(interfaceWindow->width(), newInterfaceScreen->size().width()),
+                                     qMin(interfaceWindow->height(), newInterfaceScreen->size().height()));
+        }
+    }
+
+}
+
+void DetachedVideoWindow::reportSize()
+{
+    if( !m_voutWindow )
+    {
+        msg_Info(m_intf, "no size report, no m_voutWindow");
+        return;
+    }
+    msg_Info(m_intf, "report size");
+
+    QSize size = physicalSize();
+    vout_window_ReportSize( m_voutWindow, size.width(), size.height() );
+}
+
+void DetachedVideoWindow::resizeEvent( QResizeEvent *event )
+{
+    QWidget::resizeEvent( event );
+    QMetaObject::invokeMethod(this,  &DetachedVideoWindow::reportSize, Qt::QueuedConnection);
+}
+
+void DetachedVideoWindow::hideCursor()
+{
+    setCursor( Qt::BlankCursor );
+}
+
+void DetachedVideoWindow::showCursor()
+{
+    setCursor( Qt::ArrowCursor );
+    m_cursorTimer->start( m_cursorTimeout );
+}
+
+int DetachedVideoWindow::qtMouseButton2VLC( Qt::MouseButton qtButton )
+{
+    if( m_voutWindow == NULL )
+        return -1;
+    switch( qtButton )
+    {
+        case Qt::LeftButton:
+            return 0;
+        case Qt::RightButton:
+            return 2;
+        case Qt::MiddleButton:
+            return 1;
+        default:
+            return -1;
+    }
+}
+
+void DetachedVideoWindow::mouseReleaseEvent( QMouseEvent *event )
+{
+    int vlc_button = qtMouseButton2VLC( event->button() );
+    if( vlc_button >= 0 )
+    {
+        vout_window_ReportMouseReleased( m_voutWindow, vlc_button );
+        showCursor();
+        event->accept();
+    }
+    else
+        event->ignore();
+}
+
+void DetachedVideoWindow::mousePressEvent( QMouseEvent* event )
+{
+    int vlc_button = qtMouseButton2VLC( event->button() );
+    if( vlc_button >= 0 )
+    {
+        vout_window_ReportMousePressed( m_voutWindow, vlc_button );
+        showCursor();
+        event->accept();
+    }
+    else
+        event->ignore();
+}
+
+void DetachedVideoWindow::mouseMoveEvent( QMouseEvent *event )
+{
+    if( m_voutWindow != NULL )
+    {
+        QPointF current_pos = event->localPos();
+
+        current_pos *= devicePixelRatioF();
+
+        vout_window_ReportMouseMoved( m_voutWindow, current_pos.x(), current_pos.y() );
+        showCursor();
+        event->accept();
+    }
+    else
+        event->ignore();
+}
+
+void DetachedVideoWindow::mouseDoubleClickEvent( QMouseEvent *event )
+{
+    int vlc_button = qtMouseButton2VLC( event->button() );
+    if( vlc_button >= 0 )
+    {
+        vout_window_ReportMouseDoubleClick( m_voutWindow, vlc_button );
+        showCursor();
+        event->accept();
+    }
+    else
+        event->ignore();
+}
+
+void DetachedVideoWindow::keyPressEvent(QKeyEvent* e)
+{
+    int vlck = qtEventToVLCKey( e );
+    if( vlck > 0 )
+    {
+        var_SetInteger(vlc_object_instance(m_intf), "key-pressed", vlck);
+        e->accept();
+    }
+    else
+        e->ignore();
+
+}
+
+void DetachedVideoWindow::closeEvent(QCloseEvent* e)
+{
+    emit windowClosed();
+    e->ignore();
+}
diff --git a/modules/gui/qt/maininterface/detached_video_window.hpp b/modules/gui/qt/maininterface/detached_video_window.hpp
new file mode 100644
index 0000000000..0646e14b7c
--- /dev/null
+++ b/modules/gui/qt/maininterface/detached_video_window.hpp
@@ -0,0 +1,75 @@
+/*****************************************************************************
+ * Copyright (C) 2020 VLC authors and VideoLAN
+ *
+ * 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 DETACHEDVIDEOWINDOW_H
+#define DETACHEDVIDEOWINDOW_H
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "maininterface/main_interface.hpp" /* Interface integration */
+#include <QWidget>
+#include <QTimer>
+
+class DetachedVideoWindow : public QWidget
+{
+    Q_OBJECT
+
+public:
+    explicit DetachedVideoWindow(intf_thread_t *p_intf, vout_window_t* p_wnd, QWidget *parent = nullptr);
+
+
+    virtual void resizeEvent( QResizeEvent *event ) override;
+    virtual void mousePressEvent(QMouseEvent *) override;
+    virtual void mouseMoveEvent(QMouseEvent *) override;
+    virtual void mouseReleaseEvent(QMouseEvent *) override;
+    virtual void mouseDoubleClickEvent(QMouseEvent *) override;
+    virtual void keyPressEvent(QKeyEvent *) override;
+    virtual void closeEvent(QCloseEvent *) override;
+
+    virtual QSize physicalSize() const;
+
+    /**
+     * @brief showFSOnScreen show fullscreen on screen named @a screenName,
+     *        if @a interfaceWindow window is on target screen it will be moved
+     *        to another window
+     * @param screenName
+     * @param interfaceWindow
+     */
+    void showFSOnScreen( QString screenName, QWindow* interfaceWindow );
+
+signals:
+    void windowClosed();
+
+public slots:
+    void hideCursor();
+    void showCursor();
+
+private:
+    int qtMouseButton2VLC( Qt::MouseButton qtButton );
+    void reportSize();
+
+    intf_thread_t* m_intf = nullptr;
+    vout_window_t* m_voutWindow = nullptr;
+
+    QTimer* m_cursorTimer = nullptr;
+    int m_cursorTimeout;
+};
+
+#endif // DETACHEDVIDEOWINDOW_H
-- 
2.25.1



More information about the vlc-devel mailing list