diff --git a/modules/gui/qt/Makefile.am b/modules/gui/qt/Makefile.am index daabd5e5508ec58959662bf2abce9148d22e4724..4426d1abe4149bb6e2277a0398ea9fe5dc0a1e8f 100644 --- a/modules/gui/qt/Makefile.am +++ b/modules/gui/qt/Makefile.am @@ -993,6 +993,7 @@ libqml_module_maininterface_a_CPPFLAGS = $(libqt_plugin_la_CPPFLAGS) libqml_module_maininterface_a_QML = \ maininterface/qml/BannerSources.qml \ maininterface/qml/MainInterface.qml \ + maininterface/qml/MainInterfaceLayerShell.qml \ maininterface/qml/MainViewLoader.qml \ maininterface/qml/MainDisplay.qml \ maininterface/qml/MainGridView.qml \ diff --git a/modules/gui/qt/maininterface/mainui.cpp b/modules/gui/qt/maininterface/mainui.cpp index 94ec5d756cbb1ba30a437587c6d261f04016c869..680979e34299d776a77a8270d18bae61c4ade448 100644 --- a/modules/gui/qt/maininterface/mainui.cpp +++ b/modules/gui/qt/maininterface/mainui.cpp @@ -115,7 +115,28 @@ bool MainUI::setup(QQmlEngine* engine) engine->addImageProvider(QStringLiteral("svgcolor"), new SVGColorImageImageProvider()); engine->addImageProvider(QStringLiteral("vlcaccess"), new VLCAccessImageProvider()); - m_component = new QQmlComponent(engine, QStringLiteral("qrc:/qt/qml/VLC/MainInterface/MainInterface.qml"), QQmlComponent::PreferSynchronous, engine); + // NOTE: Starting with Qt 6.5, `QQmlComponent` accepts `QAnyStringView`. + constexpr QLatin1String mainInterface {"qrc:/qt/qml/VLC/MainInterface/MainInterface.qml"}; + constexpr QLatin1String mainInterfaceLayerShell {"qrc:/qt/qml/VLC/MainInterface/MainInterfaceLayerShell.qml"}; + + const bool useLayerShell = [this]() { + assert(qGuiApp); + if (qGuiApp->platformName().startsWith(QLatin1String("wayland")) && + m_mainCtx->isInterfaceAlwaysOnTop() && + var_InheritBool(m_intf, "embedded-video")) + return true; + return false; + }(); + + m_component = new QQmlComponent(engine, useLayerShell ? mainInterfaceLayerShell : mainInterface, QQmlComponent::PreferSynchronous, engine); + + if (useLayerShell && m_component->isError()) + { + // fallback for missing org.kde.layershell or other errors + delete m_component; // `QQmlComponent` does not seem to allow changing the source URL. + m_component = new QQmlComponent(engine, mainInterface, QQmlComponent::PreferSynchronous, engine); + } + if (m_component->isLoading()) { msg_Warn(m_intf, "component is still loading"); diff --git a/modules/gui/qt/maininterface/qml/MainInterfaceLayerShell.qml b/modules/gui/qt/maininterface/qml/MainInterfaceLayerShell.qml new file mode 100644 index 0000000000000000000000000000000000000000..88ab977b81458e16cef9a8e2293a15b473d90f7b --- /dev/null +++ b/modules/gui/qt/maininterface/qml/MainInterfaceLayerShell.qml @@ -0,0 +1,36 @@ +/***************************************************************************** + * Copyright (C) 2025 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. + *****************************************************************************/ +import QtQuick +import QtQuick.Window + +import VLC.MainInterface + +import org.kde.layershell as LayerShell + +MainInterface { + Window.onWindowChanged: { + if (Window.window) { + console.warn("Attempting to use layer shell, most features available with xdg shell will not be available.") + Window.window.LayerShell // at this point, QML engine should create the attached layer shell + if (MainCtx.interfaceAlwaysOnTop) { + // Video always on top: + Window.window.LayerShell.Window.layer = LayerShell.Window.LayerTop + } + } + } +} diff --git a/modules/gui/qt/meson.build b/modules/gui/qt/meson.build index 6c6b3dbac48f32607561789852faf539a3c5e59c..6f4ce7f6ba7f8ba16388cd3a17c2d1c775ff25a1 100644 --- a/modules/gui/qt/meson.build +++ b/modules/gui/qt/meson.build @@ -593,6 +593,7 @@ qml_modules += { 'sources': files( 'maininterface/qml/BannerSources.qml', 'maininterface/qml/MainInterface.qml', + 'maininterface/qml/MainInterfaceLayerShell.qml', 'maininterface/qml/MainViewLoader.qml', 'maininterface/qml/MainDisplay.qml', 'maininterface/qml/MainGridView.qml',