[vlc-commits] [Git][videolan/vlc][master] 9 commits: qt: introduce CSD menu
Steve Lhomme (@robUx4)
gitlab at videolan.org
Thu Nov 21 10:05:17 UTC 2024
Steve Lhomme pushed to branch master at VideoLAN / VLC
Commits:
7986a170 by Pierre Lamot at 2024-11-21T09:28:37+00:00
qt: introduce CSD menu
this menu is usually shown by window manager as contextual menu in the topbar
- - - - -
1470c852 by Pierre Lamot at 2024-11-21T09:28:37+00:00
qml: use CSDMenu to handle clicks in the CSD bar and on the banner icon
- - - - -
2a04c86e by Pierre Lamot at 2024-11-21T09:28:37+00:00
qml: lock the topbar when the CSD menu is visible
- - - - -
0d908dc1 by Pierre Lamot at 2024-11-21T09:28:37+00:00
qt: remove setSystemMenuButton from the CSDButtonModel
behavior is now handled by CSDMenu
- - - - -
33f214a5 by Pierre Lamot at 2024-11-21T09:28:37+00:00
qt: move DummyWidget out of compositor X11 util
compositor_x11_utils no longer depends on Qt and can be reused in other modules
- - - - -
f112486e by Pierre Lamot at 2024-11-21T09:28:37+00:00
qt: fix XCB_DAMAGE cflags
- - - - -
61deb09b by Pierre Lamot at 2024-11-21T09:28:37+00:00
qt: add csdmenu module for X11
- - - - -
9bd833f3 by Pierre Lamot at 2024-11-21T09:28:37+00:00
qt: add CSD menu module for wayland
- - - - -
62ff2e00 by Pierre Lamot at 2024-11-21T09:28:37+00:00
qt: add csdmenu module for windows
- - - - -
28 changed files:
- modules/gui/qt/Makefile.am
- modules/gui/qt/maininterface/compositor_wayland_module.c
- modules/gui/qt/maininterface/compositor_wayland_module.h
- modules/gui/qt/maininterface/compositor_x11.cpp
- modules/gui/qt/maininterface/compositor_x11.hpp
- modules/gui/qt/maininterface/compositor_x11_utils.cpp
- modules/gui/qt/maininterface/compositor_x11_utils.hpp
- modules/gui/qt/maininterface/mainctx_win32.cpp
- modules/gui/qt/maininterface/mainui.cpp
- + modules/gui/qt/maininterface/qt_wayland_plugin.c
- + modules/gui/qt/maininterface/qt_x11_plugin.c
- modules/gui/qt/meson.build
- modules/gui/qt/player/qml/TopBar.qml
- modules/gui/qt/qt.cpp
- modules/gui/qt/util/csdbuttonmodel.cpp
- modules/gui/qt/util/csdbuttonmodel.hpp
- + modules/gui/qt/util/csdmenu.cpp
- + modules/gui/qt/util/csdmenu.hpp
- + modules/gui/qt/util/csdmenu_module.h
- + modules/gui/qt/util/csdmenu_wayland.c
- + modules/gui/qt/util/csdmenu_wayland.h
- + modules/gui/qt/util/csdmenu_win32.c
- + modules/gui/qt/util/csdmenu_win32.h
- + modules/gui/qt/util/csdmenu_x11.cpp
- + modules/gui/qt/util/csdmenu_x11.h
- modules/gui/qt/widgets/qml/BannerCone.qml
- modules/gui/qt/widgets/qml/CSDTitlebarTapNDrapHandler.qml
- po/POTFILES.in
Changes:
=====================================
modules/gui/qt/Makefile.am
=====================================
@@ -296,6 +296,7 @@ libqt_plugin_la_SOURCES = \
util/covergenerator.hpp \
util/imageluminanceextractor.cpp util/imageluminanceextractor.hpp \
util/csdbuttonmodel.cpp util/csdbuttonmodel.hpp \
+ util/csdmenu.cpp util/csdmenu.hpp \
util/imagehelper.cpp util/imagehelper.hpp \
util/keyhelper.cpp util/keyhelper.hpp \
util/listcache.hxx util/listcache.hpp \
@@ -470,6 +471,7 @@ nodist_libqt_plugin_la_SOURCES = \
util/vlcaccess_image_provider.moc.cpp \
util/imageluminanceextractor.moc.cpp \
util/csdbuttonmodel.moc.cpp \
+ util/csdmenu.moc.cpp \
util/keyhelper.moc.cpp \
util/listcache.moc.cpp \
util/locallistcacheloader.moc.cpp \
@@ -531,7 +533,9 @@ libqt_plugin_la_SOURCES += \
maininterface/compositor_win7.hpp \
style/windowsthemeprovider.cpp \
maininterface/win32windoweffects_module.cpp \
- maininterface/win32windoweffects_module.hpp
+ maininterface/win32windoweffects_module.hpp \
+ util/csdmenu_win32.c \
+ util/csdmenu_win32.h
nodist_libqt_plugin_la_SOURCES += maininterface/mainctx_win32.moc.cpp \
maininterface/compositor_win7.moc.cpp
@@ -559,7 +563,7 @@ if HAVE_XCB_DAMAGE
if HAVE_XCB_XFIXES
libqt_plugin_la_CXXFLAGS += -DQT_HAS_X11_COMPOSITOR \
- $(QT_X11_CFLAGS) $(XCB_RENDER_CFLAGS) $(XCB_COMPOSITE_CFLAGS) $(XLCB_DAMAGE_CFLAGS) $(XCB_XFIXES_CFLAGS)
+ $(QT_X11_CFLAGS) $(XCB_RENDER_CFLAGS) $(XCB_COMPOSITE_CFLAGS) $(XCB_DAMAGE_CFLAGS) $(XCB_XFIXES_CFLAGS)
libqt_plugin_la_LIBADD += $(QT_X11_LIBS) $(XCB_RENDER_LIBS) $(XCB_COMPOSITE_LIBS) $(XCB_DAMAGE_LIBS) $(XCB_XFIXES_LIBS)
@@ -579,8 +583,24 @@ nodist_libqt_plugin_la_SOURCES += \
maininterface/compositor_x11.moc.cpp \
maininterface/compositor_x11_renderclient.moc.cpp \
maininterface/compositor_x11_renderwindow.moc.cpp \
- maininterface/compositor_x11_uisurface.moc.cpp \
- maininterface/compositor_x11_utils.moc.cpp
+ maininterface/compositor_x11_uisurface.moc.cpp
+
+#extra X11 features
+
+libqt_x11_plugin_la_CXXFLAGS = $(AM_CXXFLAGS) $(XCB_CFLAGS) $(XCB_RENDER_CFLAGS) $(XCB_COMPOSITE_CFLAGS) $(XCB_DAMAGE_CFLAGS) $(XCB_XFIXES_CFLAGS)
+libqt_x11_plugin_la_LIBADD = $(XCB_LIBS) $(XCB_RENDER_LIBS) $(XCB_COMPOSITE_LIBS) $(XCB_DAMAGE_LIBS) $(XCB_XFIXES_LIBS)
+libqt_x11_plugin_la_SOURCES = \
+ maininterface/qt_x11_plugin.c \
+ maininterface/compositor_x11_utils.hpp \
+ maininterface/compositor_x11_utils.cpp \
+ util/csdmenu_module.h \
+ util/csdmenu_x11.cpp \
+ util/csdmenu_x11.h
+
+if ENABLE_QT
+gui_LTLIBRARIES += libqt_x11_plugin.la
+endif
+
endif
endif
@@ -605,6 +625,7 @@ nodist_libqt_plugin_la_SOURCES += \
libqt_wayland_plugin_la_CFLAGS = $(AM_CFLAGS) $(WAYLAND_CLIENT_CFLAGS)
libqt_wayland_plugin_la_LIBADD = $(WAYLAND_CLIENT_LIBS)
libqt_wayland_plugin_la_SOURCES = \
+ maininterface/qt_wayland_plugin.c \
maininterface/compositor_wayland_module.c \
maininterface/compositor_wayland_module.h
@@ -612,9 +633,16 @@ libqt_wayland_plugin_la_SOURCES = \
#if WAYLAND_SCANNER
libqt_wayland_plugin_la_CFLAGS += -DQT_HAS_WAYLAND_PROTOCOLS -I$(builddir)/maininterface
+libqt_wayland_plugin_la_SOURCES += \
+ util/csdmenu_wayland.c \
+ util/csdmenu_wayland.h \
+ util/csdmenu_module.h
+
nodist_libqt_wayland_plugin_la_SOURCES = \
maininterface/viewporter-client-protocol.h \
- maininterface/viewporter-protocol.c
+ maininterface/viewporter-protocol.c \
+ maininterface/xdg-shell-client-protocol.h \
+ maininterface/xdg-shell-protocol.c
BUILT_SOURCES += $(nodist_libqt_wayland_plugin_la_SOURCES)
@@ -627,6 +655,12 @@ maininterface/viewporter-protocol.c: \
maininterface/viewporter-client-protocol.h
$(AM_V_GEN)$(WAYLAND_SCANNER) private-code $< $@
+maininterface/xdg-shell-client-protocol.h: $(WAYLAND_PROTOCOLS)/stable/xdg-shell/xdg-shell.xml Makefile.am
+ $(AM_V_GEN)$(WAYLAND_SCANNER) client-header $< $@
+
+maininterface/xdg-shell-protocol.c: $(WAYLAND_PROTOCOLS)/stable/xdg-shell/xdg-shell.xml Makefile.am
+ $(AM_V_GEN)$(WAYLAND_SCANNER) private-code $< $@
+
#endif
#endif
=====================================
modules/gui/qt/maininterface/compositor_wayland_module.c
=====================================
@@ -286,7 +286,7 @@ error:
return false;
}
-static int Open(vlc_object_t* p_this)
+int OpenCompositor(vlc_object_t* p_this)
{
qtwayland_t* obj = (qtwayland_t*)p_this;
@@ -323,10 +323,3 @@ static int Open(vlc_object_t* p_this)
return VLC_SUCCESS;
}
-
-vlc_module_begin()
- set_shortname(N_("QtWayland"))
- set_description(N_(" calls for compositing with Qt"))
- set_capability("qtwayland", 10)
- set_callback(Open)
-vlc_module_end()
=====================================
modules/gui/qt/maininterface/compositor_wayland_module.h
=====================================
@@ -43,5 +43,6 @@ typedef struct qtwayland_t
void (*close)(struct qtwayland_t*);
} qtwayland_t;
+int OpenCompositor(vlc_object_t* p_this);
#endif // COMPOSITOR_WAYLAND_MODULE_H
=====================================
modules/gui/qt/maininterface/compositor_x11.cpp
=====================================
@@ -258,3 +258,36 @@ QQuickItem * CompositorX11::activeFocusItem() const /* override */
{
return m_qmlView->activeFocusItem();
}
+
+///////// DummyNativeWidget
+
+DummyNativeWidget::DummyNativeWidget(QWidget* parent, Qt::WindowFlags f)
+ : QWidget(parent, f)
+{
+ setAttribute(Qt::WA_NativeWindow, true);
+ setAttribute(Qt::WA_OpaquePaintEvent, true);
+ setAttribute(Qt::WA_PaintOnScreen, true);
+ setAttribute(Qt::WA_MouseTracking, true);
+ setAttribute(Qt::WA_TranslucentBackground, false);
+ QWindow* w = window()->windowHandle();
+ assert(w);
+ /*
+ * force the window not to have an alpha channel, the parent window
+ * may have an alpha channel and child widget would inhertit the format
+ * even if we set Qt::WA_TranslucentBackground to false. having an alpha
+ * in this surface would lead to the video begin semi-tranparent.
+ */
+ QSurfaceFormat format = w->format();
+ format.setAlphaBufferSize(0);
+ w->setFormat(format);
+}
+
+DummyNativeWidget::~DummyNativeWidget()
+{
+
+}
+
+QPaintEngine* DummyNativeWidget::paintEngine() const
+{
+ return nullptr;
+}
=====================================
modules/gui/qt/maininterface/compositor_x11.hpp
=====================================
@@ -22,6 +22,8 @@
#include "videosurface.hpp"
#include <memory>
+#include <QWidget>
+
#include <xcb/xcb.h>
class QObject;
@@ -68,6 +70,18 @@ private:
std::unique_ptr<CompositorX11RenderWindow> m_renderWindow;
};
+class DummyNativeWidget : public QWidget
+{
+ Q_OBJECT
+public:
+ DummyNativeWidget(QWidget* parent = nullptr, Qt::WindowFlags f = Qt::WindowFlags());
+ virtual ~DummyNativeWidget();
+
+ //override paintEnging to suppress warning
+ QPaintEngine* paintEngine() const override;
+};
+
+
}
#endif // COMPOSITORX11_HPP
=====================================
modules/gui/qt/maininterface/compositor_x11_utils.cpp
=====================================
@@ -15,44 +15,17 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
-#include <xcb/xfixes.h>
-#include <vlc_cxx_helpers.hpp>
-#include "compositor_x11_utils.hpp"
-
-#include <QWindow>
+#include <vector>
+#include <algorithm>
+#include <cstring>
-namespace vlc {
-
-DummyNativeWidget::DummyNativeWidget(QWidget* parent, Qt::WindowFlags f)
- : QWidget(parent, f)
-{
- setAttribute(Qt::WA_NativeWindow, true);
- setAttribute(Qt::WA_OpaquePaintEvent, true);
- setAttribute(Qt::WA_PaintOnScreen, true);
- setAttribute(Qt::WA_MouseTracking, true);
- setAttribute(Qt::WA_TranslucentBackground, false);
- QWindow* w = window()->windowHandle();
- assert(w);
- /*
- * force the window not to have an alpha channel, the parent window
- * may have an alpha channel and child widget would inhertit the format
- * even if we set Qt::WA_TranslucentBackground to false. having an alpha
- * in this surface would lead to the video begin semi-tranparent.
- */
- QSurfaceFormat format = w->format();
- format.setAlphaBufferSize(0);
- w->setFormat(format);
-}
+#include <vlc_cxx_helpers.hpp>
-DummyNativeWidget::~DummyNativeWidget()
-{
+#include <xcb/xfixes.h>
-}
+#include "compositor_x11_utils.hpp"
-QPaintEngine* DummyNativeWidget::paintEngine() const
-{
- return nullptr;
-}
+namespace vlc {
bool queryExtension(xcb_connection_t* conn, const char* name, uint8_t* first_event_out, uint8_t* first_error_out)
{
@@ -133,10 +106,10 @@ void setTransparentForMouseEvent(xcb_connection_t* conn, xcb_window_t window)
//see https://specifications.freedesktop.org/wm-spec/wm-spec-latest.html#idm45894597940912
bool wmScreenHasCompositor(xcb_connection_t* conn, int screen)
{
- QByteArray propName("_NET_WM_CM_S");
- propName += QByteArray::number(screen);
+ std::string propName("_NET_WM_CM_S");
+ propName += std::to_string(screen);
- xcb_atom_t atom = getInternAtom(conn, propName.constData());
+ xcb_atom_t atom = getInternAtom(conn, propName.c_str());
if (atom == 0)
return false;
=====================================
modules/gui/qt/maininterface/compositor_x11_utils.hpp
=====================================
@@ -19,26 +19,12 @@
#define COMPOSITOR_X11_UTILS_HPP
#include <memory>
-#include <QWidget>
-
#include <xcb/xcb.h>
#include <xcb/render.h>
#include <xcb/composite.h>
-
namespace vlc {
-class DummyNativeWidget : public QWidget
-{
- Q_OBJECT
-public:
- DummyNativeWidget(QWidget* parent = nullptr, Qt::WindowFlags f = Qt::WindowFlags());
- virtual ~DummyNativeWidget();
-
- //override paintEnging to suppress warning
- QPaintEngine* paintEngine() const override;
-};
-
template<typename T, typename R, R RELEASE>
class X11Resource {
public:
=====================================
modules/gui/qt/maininterface/mainctx_win32.cpp
=====================================
@@ -117,103 +117,6 @@ HWND WinId( QWindow *windowHandle )
return 0;
}
-
-bool isWindowFixedSize(const QWindow *window)
-{
- if (window->flags() & Qt::MSWindowsFixedSizeDialogHint)
- return true;
-
- const auto minSize = window->minimumSize();
- const auto maxSize = window->maximumSize();
-
- return minSize.isValid() && maxSize.isValid() && minSize == maxSize;
-}
-
-
-class WinSystemMenuButton : public SystemMenuButton
-{
-public:
- WinSystemMenuButton(QWindow *window, QObject *parent)
- : SystemMenuButton {parent}
- , m_window {window}
- {
- connect(this, &CSDButton::clicked, this, &WinSystemMenuButton::handleClick);
- connect(this, &CSDButton::doubleClicked, this, &WinSystemMenuButton::handleDoubleClick);
- }
-
- void showSystemMenu(const QPoint &windowpos) override
- {
- HWND hwnd = (HWND)m_window->winId();
- HMENU hmenu = ::GetSystemMenu(hwnd, FALSE);
- if (!hmenu)
- return;
-
- // Tweak the menu items according to the current window status.
- const auto winState = m_window->windowStates();
- const bool maxOrFull = (winState.testFlag(Qt::WindowMaximized) || winState.testFlag(Qt::WindowFullScreen));
- const bool fixedSize = isWindowFixedSize(m_window);
-
- EnableMenuItem(hmenu, SC_MOVE, (MF_BYCOMMAND | (!maxOrFull ? MFS_ENABLED : MFS_DISABLED)));
- EnableMenuItem(hmenu, SC_SIZE, (MF_BYCOMMAND | ((!maxOrFull && !fixedSize) ? MFS_ENABLED : MFS_DISABLED)));
-
- EnableMenuItem(hmenu, SC_RESTORE, (MF_BYCOMMAND | ((maxOrFull && !fixedSize) ? MFS_ENABLED : MFS_DISABLED)));
- EnableMenuItem(hmenu, SC_MINIMIZE, (MF_BYCOMMAND | MFS_ENABLED));
- EnableMenuItem(hmenu, SC_MAXIMIZE, (MF_BYCOMMAND | ((!maxOrFull && !fixedSize) ? MFS_ENABLED : MFS_DISABLED)));
- EnableMenuItem(hmenu, SC_CLOSE, (MF_BYCOMMAND | MFS_ENABLED));
-
- // map pos to screen points and convert according to device DPR, required on HI-DPI displays
- const auto screenPoints = m_window->mapToGlobal(windowpos) * m_window->devicePixelRatio();
-
- const auto alignment = (QGuiApplication::isRightToLeft() ? TPM_RIGHTALIGN : TPM_LEFTALIGN);
-
- // show menu
- emit systemMenuVisibilityChanged(true);
-
- const int action = TrackPopupMenu(hmenu, (TPM_RETURNCMD | alignment)
- , screenPoints.x(), screenPoints.y()
- , 0, hwnd, nullptr);
-
- // unlike native system menu which sends WM_SYSCOMMAND, TrackPopupMenu sends WM_COMMAND
- // imitate native system menu by sending the action manually as WM_SYSCOMMAND
- PostMessageW(hwnd, WM_SYSCOMMAND, action, 0);
-
- emit systemMenuVisibilityChanged(false);
- }
-
-private:
- // target window
- QWindow *m_window = {};
-
- // used to reject click() incase a doubleClick() is followed
- bool m_triggerSystemMenu = false;
-
- void handleClick()
- {
- // delay the show of sytem menu to check if this 'click' is
- // a double click, 'm_triggerSystemMenu' is used to reject the
- // queued 'showSystemMenu' call in case this is a double click
-
- m_triggerSystemMenu = true;
- QTimer::singleShot(100, this, [this]()
- {
- if (!m_triggerSystemMenu)
- return;
-
- // show system menu 'margin' below the rect
- constexpr QPoint margin {0, 4};
- showSystemMenu(rect().bottomLeft() + margin);
- });
- }
-
- void handleDoubleClick()
- {
- // reject any queued showSystemMenu call
- m_triggerSystemMenu = false;
-
- m_window->close();
- }
-};
-
class CSDWin32EventHandler : public QObject, public QAbstractNativeEventFilter
{
public:
@@ -827,9 +730,6 @@ InterfaceWindowHandlerWin32::InterfaceWindowHandlerWin32(qt_intf_t *_p_intf, Mai
m_disableVolumeKeys = disable;
});
- auto systemMenuButton = std::make_shared<WinSystemMenuButton>(mainCtx->intfMainWindow(), nullptr);
- mainCtx->csdButtonModel()->setSystemMenuButton(systemMenuButton);
-
QApplication::instance()->installNativeEventFilter(this);
}
=====================================
modules/gui/qt/maininterface/mainui.cpp
=====================================
@@ -33,6 +33,7 @@
#include "playlist/playlist_model.hpp"
#include "playlist/playlist_controller.hpp"
+#include "util/csdmenu.hpp"
#include "util/item_key_event_filter.hpp"
#include "util/imageluminanceextractor.hpp"
#include "util/keyhelper.hpp"
@@ -182,8 +183,8 @@ void MainUI::registerQMLTypes()
qmlRegisterUncreatableType<VLCVarChoiceModel>(uri, versionMajor, versionMinor, "VLCVarChoiceModel", "generic variable with choice model" );
qmlRegisterUncreatableType<CSDButton>(uri, versionMajor, versionMinor, "CSDButton", "");
qmlRegisterUncreatableType<CSDButtonModel>(uri, versionMajor, versionMinor, "CSDButtonModel", "has CSD buttons and provides for communicating CSD events between UI and backend");
+ qmlRegisterTypesAndRevisions<CSDMenu>( uri, versionMajor);
qmlRegisterUncreatableType<NavigationAttached>( uri, versionMajor, versionMinor, "Navigation", "Navigation is only available via attached properties");
-
qmlRegisterModule(uri, versionMajor, versionMinor);
qmlProtectModule(uri, versionMajor);
}
=====================================
modules/gui/qt/maininterface/qt_wayland_plugin.c
=====================================
@@ -0,0 +1,35 @@
+/*****************************************************************************
+ * Copyright (C) 2024 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 "compositor_wayland_module.h"
+
+#ifdef QT_HAS_WAYLAND_PROTOCOLS
+#include "util/csdmenu_wayland.h"
+#endif
+
+vlc_module_begin()
+ set_shortname(N_("QtWayland"))
+ set_description(N_(" calls for compositing with Qt"))
+ set_capability("qtwayland", 10)
+ set_callback(OpenCompositor)
+#ifdef QT_HAS_WAYLAND_PROTOCOLS
+add_submodule()
+ set_capability("qtcsdmenu", 10)
+ set_callbacks(WaylandCSDMenuOpen, WaylandCSDMenuClose)
+#endif
+vlc_module_end()
=====================================
modules/gui/qt/maininterface/qt_x11_plugin.c
=====================================
@@ -0,0 +1,25 @@
+/*****************************************************************************
+ * Copyright (C) 2024 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 "util/csdmenu_x11.h"
+
+vlc_module_begin()
+ set_shortname(N_("QtX11"))
+ set_description(N_("Qt extra X11 features"))
+ set_capability("qtcsdmenu", 10)
+ set_callback(X11CSDMenuOpen)
+vlc_module_end()
=====================================
modules/gui/qt/meson.build
=====================================
@@ -128,6 +128,7 @@ moc_headers = files(
'util/color_svg_image_provider.hpp',
'util/vlcaccess_image_provider.hpp',
'util/csdbuttonmodel.hpp',
+ 'util/csdmenu.hpp',
'util/imageluminanceextractor.hpp',
'util/keyhelper.hpp',
'util/listcache.hpp',
@@ -431,6 +432,8 @@ some_sources = files(
'util/covergenerator.hpp',
'util/csdbuttonmodel.cpp',
'util/csdbuttonmodel.hpp',
+ 'util/csdmenu.cpp',
+ 'util/csdmenu.hpp',
'util/imageluminanceextractor.cpp',
'util/imageluminanceextractor.hpp',
'util/imagehelper.cpp',
@@ -507,6 +510,8 @@ if host_system == 'windows'
'maininterface/compositor_win7.cpp',
'maininterface/compositor_win7.hpp',
'style/windowsthemeprovider.cpp',
+ 'util/csdmenu_win32.c',
+ 'util/csdmenu_win32.h',
)
if cdata.has('HAVE_DCOMP_H')
@@ -1056,6 +1061,23 @@ if qt6_dep.found()
endif
endif
+ if (xcb_dep.found() and xcb_render_dep.found() and xcb_xfixes_dep.found())
+
+ vlc_modules += {
+ 'name' : 'qt_x11',
+ 'include_directories' : qt_include_dir,
+ 'sources' : files(
+ 'maininterface/qt_x11_plugin.c',
+ 'maininterface/compositor_x11_utils.hpp',
+ 'maininterface/compositor_x11_utils.cpp',
+ 'util/csdmenu_module.h',
+ 'util/csdmenu_x11.cpp',
+ 'util/csdmenu_x11.h'
+ ),
+ 'dependencies' : [xcb_dep, xcb_render_dep, xcb_xfixes_dep]
+ }
+ endif
+
# TODO support qmlcachegen
vlc_modules += {
=====================================
modules/gui/qt/player/qml/TopBar.qml
=====================================
@@ -198,6 +198,14 @@ FocusScope{
anchors.fill: parent
active: root.showCSD
source: "qrc:///qt/qml/VLC/Widgets/CSDTitlebarTapNDrapHandler.qml"
+
+ Connections {
+ target: tapNDrag.item
+ enabled: tapNDrag.status === Loader.Ready
+ function onCsdMenuVisibleChanged() {
+ root.requestLockUnlockAutoHide(tapNDrag.item.csdMenuVisible)
+ }
+ }
}
// Components -
@@ -276,13 +284,7 @@ FocusScope{
color: theme.accent
- Connections {
- target: logo.button
-
- function onSystemMenuVisibilityChanged() {
- root.requestLockUnlockAutoHide(visible)
- }
- }
+ onCsdMenuVisibleChanged: root.requestLockUnlockAutoHide(csdMenuVisible)
}
}
=====================================
modules/gui/qt/qt.cpp
=====================================
@@ -72,6 +72,7 @@ extern "C" char **environ;
#ifdef _WIN32
# include "maininterface/mainctx_win32.hpp"
#include "maininterface/win32windoweffects_module.hpp"
+#include "util/csdmenu_win32.h"
#else
# include "maininterface/mainctx.hpp" /* MainCtx creation */
#endif
@@ -469,6 +470,11 @@ vlc_module_begin ()
set_description( "Provides window effects on Windows." )
set_capability( "qtwindoweffects", 10 )
set_callback( QtWin32WindowEffectsOpen )
+ add_submodule ()
+ add_shortcut( "QtWin32CSDMenu" )
+ set_description( "Provides csd menu on Windows." )
+ set_capability( "qtcsdmenu", 10 )
+ set_callback( QtWin32CSDMenuOpen )
#endif
add_submodule()
set_capability("qt theme provider", 1)
=====================================
modules/gui/qt/util/csdbuttonmodel.cpp
=====================================
@@ -127,16 +127,6 @@ QList<CSDButton *> CSDButtonModel::windowCSDButtons() const
return m_windowCSDButtons;
}
-CSDButton *CSDButtonModel::systemMenuButton() const
-{
- return m_systemMenuButton.get();
-}
-
-void CSDButtonModel::setSystemMenuButton(std::shared_ptr<SystemMenuButton> button)
-{
- m_systemMenuButton = std::move(button);
-}
-
void CSDButtonModel::minimizeButtonClicked()
{
=====================================
modules/gui/qt/util/csdbuttonmodel.hpp
=====================================
@@ -90,21 +90,6 @@ private:
bool m_externalPressed = false;
};
-
-class SystemMenuButton : public CSDButton
-{
- Q_OBJECT
-
-public:
- SystemMenuButton(QObject *parent = nullptr) : CSDButton {SystemMenuButton::SystemMenu, parent} {}
-
- Q_INVOKABLE virtual void showSystemMenu(const QPoint &windowpos) = 0;
-
-signals:
- void systemMenuVisibilityChanged(bool visible);
-};
-
-
class MainCtx;
@@ -113,17 +98,10 @@ class CSDButtonModel : public QObject
Q_OBJECT
Q_PROPERTY(QList<CSDButton *> windowCSDButtons READ windowCSDButtons CONSTANT)
- Q_PROPERTY(CSDButton *systemMenuButton READ systemMenuButton CONSTANT)
-
public:
CSDButtonModel(MainCtx *mainCtx, QObject *parent = nullptr);
QList<CSDButton *> windowCSDButtons() const;
- CSDButton *systemMenuButton() const;
-
- // set by internal implmentation
- // all the actions are also handled by implementation
- void setSystemMenuButton(std::shared_ptr<SystemMenuButton> button);
private slots:
void minimizeButtonClicked();
@@ -135,9 +113,6 @@ private:
// CSD window action buttons i.e minimize, maximize, close
QList<CSDButton *> m_windowCSDButtons;
-
- // sysmenu button, available on windows only
- std::shared_ptr<SystemMenuButton> m_systemMenuButton = nullptr;
};
=====================================
modules/gui/qt/util/csdmenu.cpp
=====================================
@@ -0,0 +1,323 @@
+/*****************************************************************************
+ * Copyright (C) 2024 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 "csdmenu.hpp"
+
+#include <QApplication>
+#include <QAction>
+#include <QWindow>
+
+#ifdef QT_GUI_PRIVATE
+#include <QtGui/qpa/qplatformnativeinterface.h>
+#include <QtGui/qpa/qplatformwindow.h>
+#include <QtGui/qpa/qplatformwindow_p.h>
+#endif
+
+#include "maininterface/mainctx.hpp"
+#include "util/csdmenu_module.h"
+#include "menus/menus.hpp"
+
+#include <vlc_common.h>
+#include <vlc_modules.h>
+
+struct xdg_surface;
+
+namespace {
+
+//vlc module callback
+static int csdMenuInfoOpen(void *func, bool forced, va_list ap)
+{
+ VLC_UNUSED(forced);
+ qt_csd_menu_open open = reinterpret_cast<qt_csd_menu_open>(func);
+ qt_csd_menu_t* obj = va_arg(ap, qt_csd_menu_t*);
+ qt_csd_menu_info* info = va_arg(ap, qt_csd_menu_info*);
+ return open(obj, info);
+}
+
+bool isWindowFixedSize(const QWindow *window)
+{
+ if (window->flags() & Qt::MSWindowsFixedSizeDialogHint)
+ return true;
+
+ const auto minSize = window->minimumSize();
+ const auto maxSize = window->maximumSize();
+
+ return minSize.isValid() && maxSize.isValid() && minSize == maxSize;
+}
+
+}
+
+class CSDMenuPrivate
+{
+ Q_DECLARE_PUBLIC(CSDMenu)
+public:
+
+ CSDMenuPrivate(CSDMenu* parent)
+ : q_ptr(parent)
+ {
+ const QString& platform = qApp->platformName();;
+ if (platform == QLatin1String("windows") || platform == QLatin1String("direct2d"))
+ m_plateform = QT_CSD_PLATFORM_WINDOWS;
+ else if (platform.startsWith( QLatin1String("wayland")))
+ m_plateform = QT_CSD_PLATFORM_WAYLAND;
+ else if (platform == QLatin1String("xcb"))
+ m_plateform = QT_CSD_PLATFORM_X11;
+ }
+
+ static void notifyMenuVisible(void* data, bool visible)
+ {
+ auto that = static_cast<CSDMenuPrivate*>(data);
+ that->m_menuVisible = visible;
+ emit that->q_func()->menuVisibleChanged(visible);
+ }
+
+ void fallbackMenu(QPoint pos)
+ {
+ auto menu = new VLCMenu(m_ctx->getIntf());
+ menu->setAttribute(Qt::WA_DeleteOnClose);
+
+ QObject::connect(menu, &QMenu::aboutToShow, q_ptr, [this](){
+ notifyMenuVisible(this, true);
+ });
+
+ QObject::connect(menu, &QMenu::aboutToHide, q_ptr, [this](){
+ notifyMenuVisible(this, false);
+ });
+
+ QWindow::Visibility visibility = m_ctx->interfaceVisibility();
+ QAction* action;
+ action = menu->addAction(qtr("Restore"));
+ action->setEnabled(visibility != QWindow::Windowed);
+ action->connect(action, &QAction::triggered, q_ptr, [this]() {
+ m_ctx->requestInterfaceNormal();
+ });
+ action = menu->addAction(qtr("Minimize"));
+ action->connect(action, &QAction::triggered, q_ptr, [this]() {
+ m_ctx->requestInterfaceMinimized();
+ });
+ action = menu->addAction(qtr("Maximized"));
+ action->setEnabled(visibility != QWindow::Maximized);
+ action->connect(action, &QAction::triggered, q_ptr, [this]() {
+ m_ctx->requestInterfaceMaximized();
+ });
+ action = menu->addAction(qtr("Always on top"));
+ action->setCheckable(true);
+ action->setChecked(m_ctx->isInterfaceAlwaysOnTop());
+ action->connect(action, &QAction::triggered, q_ptr, [this](bool checked) {
+ m_ctx->setInterfaceAlwaysOnTop(checked);
+ });
+ action = menu->addAction(qtr("Close"));
+ action->connect(action, &QAction::triggered, q_ptr, [this]() {
+ m_ctx->intfMainWindow()->close();
+ });
+
+ /* Ideally we should allow moving and resizing the window through startSystemXXX
+ * But, startSystemXXX is usually active from a mouse press until a mouse release,
+ * so calling it from a menu is broken with some desktop environments
+ */
+
+ menu->popup(pos);
+ }
+
+ void loadModule()
+ {
+ QWindow* window = m_ctx->intfMainWindow();
+ assert(window);
+
+ qt_csd_menu_info info = {};
+ info.platform = QT_CSD_PLATFORM_UNKNOWN;
+#ifdef _WIN32
+ if (m_plateform == QT_CSD_PLATFORM_WINDOWS)
+ {
+ info.platform = QT_CSD_PLATFORM_WINDOWS;
+ };
+#else
+#ifdef QT_GUI_PRIVATE
+ if (m_plateform == QT_CSD_PLATFORM_X11)
+ {
+ QPlatformNativeInterface* native = qApp->platformNativeInterface();
+ info.platform = QT_CSD_PLATFORM_X11;
+ info.data.x11.rootwindow = reinterpret_cast<intptr_t>(native->nativeResourceForIntegration(QByteArrayLiteral("rootwindow")));
+ info.data.x11.connection = reinterpret_cast<struct xcb_connection_t*>(native->nativeResourceForIntegration(QByteArrayLiteral("connection")));
+ }
+
+#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)
+ if (m_plateform == QT_CSD_PLATFORM_WAYLAND)
+ {
+ info.platform = QT_CSD_PLATFORM_WAYLAND;
+
+ auto appNative = qApp->nativeInterface<QNativeInterface::QWaylandApplication>();
+ auto windowNative = window->nativeInterface<QNativeInterface::Private::QWaylandWindow>();
+
+ info.data.wayland.display = appNative->display();
+ info.data.wayland.toplevel = windowNative->surfaceRole<xdg_toplevel>();
+ }
+#endif // QT 6.5
+#endif // QT_GUI_PRIVATE
+#endif // _WIN32
+ info.isRtl = QGuiApplication::isRightToLeft();
+
+ info.userData = this;
+ info.notifyMenuVisible = ¬ifyMenuVisible;
+
+ m_systemMenuState = UNAVAILABLE;
+ m_systemMenu = vlc_object_create<qt_csd_menu_t>(m_ctx->getIntf());
+ if (!m_systemMenu)
+ return;
+ m_module = vlc_module_load(vlc_object_logger(m_systemMenu), "qtcsdmenu", nullptr, false, &csdMenuInfoOpen, m_systemMenu, &info);
+ if (!m_module)
+ {
+ vlc_object_delete(m_systemMenu);
+ m_systemMenu = nullptr;
+ return;
+ }
+ m_systemMenuState = AVAILABLE;
+ }
+
+ void unloadModule()
+ {
+ if (m_module)
+ {
+ module_unneed(m_systemMenu, m_module);
+ m_module = nullptr;
+ }
+ if (m_systemMenu)
+ {
+ vlc_object_delete(m_systemMenu);
+ m_systemMenu = nullptr;
+ }
+ m_systemMenuState = CSDMenuPrivate::NEED_INITIALISATION;
+ }
+
+ enum {
+ NEED_INITIALISATION,
+ UNAVAILABLE,
+ AVAILABLE
+ } m_systemMenuState = NEED_INITIALISATION;
+
+ module_t* m_module = nullptr;
+ qt_csd_menu_t* m_systemMenu = nullptr;
+
+ qt_csd_menu_platform m_plateform = QT_CSD_PLATFORM_UNKNOWN;
+ MainCtx* m_ctx = nullptr;
+ bool m_menuVisible = false;
+
+ CSDMenu* q_ptr;
+};
+
+CSDMenu::CSDMenu(QObject* parent)
+ : QObject(parent)
+ , d_ptr(new CSDMenuPrivate(this))
+{
+}
+
+CSDMenu::~CSDMenu()
+{
+ Q_D(CSDMenu);
+ d->unloadModule();
+}
+
+MainCtx* CSDMenu::getCtx() const
+{
+ Q_D(const CSDMenu);
+ return d->m_ctx;
+}
+
+void CSDMenu::setCtx(MainCtx* ctx)
+{
+ Q_D(CSDMenu);
+
+ if (d->m_ctx == ctx)
+ return;
+ d->m_ctx = ctx;
+ emit ctxChanged(ctx);
+}
+
+bool CSDMenu::getMenuVisible() const
+{
+ Q_D(const CSDMenu);
+ return d->m_menuVisible;
+}
+
+void CSDMenu::popup(const QPoint &pos)
+{
+ Q_D(CSDMenu);
+
+ assert(d->m_ctx);
+
+ QWindow* window = d->m_ctx->intfMainWindow();
+ assert(window);
+
+ if (d->m_systemMenuState == CSDMenuPrivate::NEED_INITIALISATION)
+ d->loadModule();
+
+ if (d->m_systemMenuState == CSDMenuPrivate::AVAILABLE) {
+ assert(d->m_systemMenu);
+
+ qreal qtDpr = window->devicePixelRatio();
+ QPlatformWindow* nativeWindow = window->handle();
+ qreal nativeDpr = nativeWindow->devicePixelRatio();
+
+ qt_csd_menu_event event = {};
+ event.platform = QT_CSD_PLATFORM_UNKNOWN;
+ event.x = (pos.x() * qtDpr) / nativeDpr;
+ event.y = (pos.y() * qtDpr) / nativeDpr;
+
+ const auto winState = window->windowStates();
+ int windowFlags = (winState.testFlag(Qt::WindowMaximized) ? QT_CSD_WINDOW_MAXIMIZED : 0)
+ | (winState.testFlag(Qt::WindowFullScreen) ? QT_CSD_WINDOW_FULLSCREEN : 0)
+ | (winState.testFlag(Qt::WindowMinimized) ? QT_CSD_WINDOW_MINIMIZED: 0)
+ | (isWindowFixedSize(window) ? QT_CSD_WINDOW_FIXED_SIZE : 0);
+
+ event.windowState = static_cast<qt_csd_menu_window_state>(windowFlags);
+
+#ifdef _WIN32
+ if (d->m_plateform == QT_CSD_PLATFORM_WINDOWS)
+ {
+ event.platform = QT_CSD_PLATFORM_WINDOWS;
+ event.data.win32.hwnd = reinterpret_cast<void*>(window->winId());
+ }
+#else
+
+#ifdef QT_GUI_PRIVATE
+ if (d->m_plateform == QT_CSD_PLATFORM_X11)
+ {
+ event.platform = QT_CSD_PLATFORM_X11;
+ event.data.x11.window = window->winId();
+ }
+
+#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)
+ if (d->m_plateform == QT_CSD_PLATFORM_WAYLAND)
+ {
+ event.platform = QT_CSD_PLATFORM_WAYLAND;
+ auto appNative = qApp->nativeInterface<QNativeInterface::QWaylandApplication>();
+ assert(appNative);
+ event.data.wayland.seat = appNative->lastInputSeat();
+ event.data.wayland.serial = appNative->lastInputSerial();
+ }
+#endif // Qt 6.5
+#endif // QT_GUI_PRIVATE
+#endif // _WIN32
+
+ bool ret = d->m_systemMenu->popup(d->m_systemMenu, &event);
+ if (ret)
+ return;
+ }
+
+ d->fallbackMenu(pos);
+}
+
=====================================
modules/gui/qt/util/csdmenu.hpp
=====================================
@@ -0,0 +1,57 @@
+/*****************************************************************************
+ * Copyright (C) 2024 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 CSDMENU_HPP
+#define CSDMENU_HPP
+
+#include <QQmlEngine>
+#include <QMenu>
+
+Q_MOC_INCLUDE("maininterface/mainctx.hpp")
+class MainCtx;
+
+class CSDMenuPrivate;
+class CSDMenu : public QObject
+{
+ Q_OBJECT
+ QML_ELEMENT
+
+ Q_PROPERTY(MainCtx* ctx READ getCtx WRITE setCtx NOTIFY ctxChanged FINAL)
+ Q_PROPERTY(bool menuVisible READ getMenuVisible NOTIFY menuVisibleChanged FINAL)
+
+public:
+ explicit CSDMenu(QObject* parent = nullptr);
+ ~CSDMenu();
+
+public:
+ Q_INVOKABLE void popup(const QPoint &windowpos);
+
+ MainCtx* getCtx() const;
+ void setCtx(MainCtx* ctx);
+
+ bool getMenuVisible() const;
+
+signals:
+ void ctxChanged(MainCtx*);
+ void menuVisibleChanged(bool);
+
+protected:
+ QScopedPointer<CSDMenuPrivate> d_ptr;
+ Q_DECLARE_PRIVATE(CSDMenu)
+};
+
+#endif // CSDMENU_HPP
=====================================
modules/gui/qt/util/csdmenu_module.h
=====================================
@@ -0,0 +1,91 @@
+#ifndef QTCSDMENU_MODULE_H
+#define QTCSDMENU_MODULE_H
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <vlc_common.h>
+#include <vlc_plugin.h>
+#include <vlc_objects.h>
+
+#include <stdint.h>
+
+struct xcb_connection_t;
+
+struct wl_display;
+struct wl_seat;
+struct xdg_toplevel;
+
+typedef enum {
+ QT_CSD_PLATFORM_UNKNOWN,
+ QT_CSD_PLATFORM_WAYLAND,
+ QT_CSD_PLATFORM_X11,
+ QT_CSD_PLATFORM_WINDOWS
+} qt_csd_menu_platform;
+
+typedef enum {
+ QT_CSD_WINDOW_FULLSCREEN = (1 << 0),
+ QT_CSD_WINDOW_MAXIMIZED = (1 << 1),
+ QT_CSD_WINDOW_MINIMIZED = (1 << 2),
+ QT_CSD_WINDOW_FIXED_SIZE = (1 << 3)
+} qt_csd_menu_window_state;
+
+
+typedef void (*notifyMenuVisibleCallback)(void* userData, bool visible);
+
+//information about the window, plateform dependent
+typedef struct {
+ qt_csd_menu_platform platform;
+ union {
+ struct {
+ struct xcb_connection_t* connection;
+ uint32_t rootwindow;
+ } x11;
+ struct {
+ struct wl_display* display;
+ struct xdg_toplevel* toplevel;
+ } wayland;
+ struct {
+ void* hwnd;
+ } windows;
+ } data;
+
+ //is the UI rtl or ltr
+ bool isRtl;
+
+ //callback called to notify that the menu is visible/hidden
+ notifyMenuVisibleCallback notifyMenuVisible;
+ //user data passed to callbacks
+ void* userData;
+} qt_csd_menu_info;
+
+typedef struct {
+ qt_csd_menu_platform platform;
+ union {
+ struct {
+ struct wl_seat* seat;
+ uint32_t serial;
+ } wayland;
+ struct {
+ uint32_t window;
+ } x11;
+ struct {
+ void* hwnd;
+ } win32;
+ } data;
+ int x;
+ int y;
+ qt_csd_menu_window_state windowState;
+} qt_csd_menu_event;
+
+typedef struct qt_csd_menu_t {
+ struct vlc_object_t obj;
+ void* p_sys;
+
+ bool (*popup)(struct qt_csd_menu_t* menu, qt_csd_menu_event* event);
+} qt_csd_menu_t;
+
+typedef int (*qt_csd_menu_open)(qt_csd_menu_t* obj, qt_csd_menu_info* info);
+
+#endif // QTCSDMENU_MODULE_H
=====================================
modules/gui/qt/util/csdmenu_wayland.c
=====================================
@@ -0,0 +1,127 @@
+/*****************************************************************************
+ * Copyright (C) 2024 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 "csdmenu_wayland.h"
+
+#include <assert.h>
+#include <wayland-client.h>
+#include "xdg-shell-client-protocol.h"
+
+typedef struct {
+ struct wl_display* display;
+ struct wl_event_queue* queue;
+ struct xdg_wm_base *wm_base;
+ struct xdg_toplevel *toplevel;
+ bool supportWindowMenu;
+} csd_menu_priv_t;
+
+static void csd_registry_global_cb(void* data, struct wl_registry* registry,
+ uint32_t id, const char* iface, uint32_t version)
+{
+ qt_csd_menu_t* obj = (qt_csd_menu_t*)data;
+ csd_menu_priv_t* sys = (csd_menu_priv_t*)obj->p_sys;
+
+ if (!strcmp(iface, "xdg_wm_base")) {
+ sys->wm_base = (struct xdg_wm_base*)wl_registry_bind(registry, id, &xdg_wm_base_interface, version);
+ }
+}
+
+static void csd_registry_global_remove_cb(void* data, struct wl_registry* registry, uint32_t id)
+{
+ VLC_UNUSED(data);
+ VLC_UNUSED(registry);
+ VLC_UNUSED(id);
+}
+
+static const struct wl_registry_listener csd_registry_cbs = {
+ csd_registry_global_cb,
+ csd_registry_global_remove_cb,
+};
+
+static bool CSDMenuPopup(qt_csd_menu_t* p_this, qt_csd_menu_event* event)
+{
+ csd_menu_priv_t* sys = (csd_menu_priv_t*)p_this->p_sys;
+ assert (event->platform == QT_CSD_PLATFORM_WAYLAND);
+
+ if (!sys->supportWindowMenu)
+ return false;
+
+ xdg_toplevel_show_window_menu(sys->toplevel, event->data.wayland.seat, event->data.wayland.serial, event->x, event->y);
+
+ return true;
+}
+
+void WaylandCSDMenuClose(vlc_object_t* obj)
+{
+ qt_csd_menu_t* menu = (qt_csd_menu_t*)obj;
+ csd_menu_priv_t* sys = (csd_menu_priv_t*)menu->p_sys;
+ if (sys->wm_base)
+ xdg_wm_base_destroy(sys->wm_base);
+ if (sys->queue)
+ wl_event_queue_destroy(sys->queue);
+}
+
+int WaylandCSDMenuOpen(qt_csd_menu_t* p_this, qt_csd_menu_info* info)
+{
+ if (info->platform != QT_CSD_PLATFORM_WAYLAND) {
+ return VLC_EGENERIC;
+ }
+
+ if (info->data.wayland.display == NULL || info->data.wayland.toplevel == NULL) {
+ msg_Warn(p_this, "wayland display or surface not provided");
+ return VLC_EGENERIC;
+ }
+
+ csd_menu_priv_t* sys = (csd_menu_priv_t*)vlc_obj_calloc(p_this, 1, sizeof(csd_menu_priv_t));
+ if (!sys)
+ return VLC_ENOMEM;
+
+ p_this->p_sys = sys;
+
+ sys->display = info->data.wayland.display;
+
+ sys->queue = wl_display_create_queue(sys->display);
+ void* wrapper = wl_proxy_create_wrapper(sys->display);
+ wl_proxy_set_queue((struct wl_proxy*)wrapper, sys->queue);
+
+ struct wl_registry* registry = wl_display_get_registry((struct wl_display*)wrapper);
+ wl_proxy_wrapper_destroy(wrapper);
+
+ wl_registry_add_listener(registry, &csd_registry_cbs, p_this);
+ wl_display_roundtrip_queue(sys->display, sys->queue);
+
+ wl_registry_destroy(registry);
+
+ if (!sys->wm_base) {
+ msg_Dbg(p_this, "wm_base not found");
+ goto error;
+ }
+
+ sys->toplevel = info->data.wayland.toplevel;
+
+ //module functions
+ p_this->popup = CSDMenuPopup;
+
+ return VLC_SUCCESS;
+
+error:
+ p_this->p_sys = NULL;
+ WaylandCSDMenuClose(VLC_OBJECT(p_this));
+ vlc_obj_free(p_this, sys);
+ return VLC_EGENERIC;
+}
+
=====================================
modules/gui/qt/util/csdmenu_wayland.h
=====================================
@@ -0,0 +1,26 @@
+/*****************************************************************************
+ * Copyright (C) 2024 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 CSDMENU_WAYLAND_HPP
+#define CSDMENU_WAYLAND_HPP
+
+#include "csdmenu_module.h"
+
+int WaylandCSDMenuOpen(qt_csd_menu_t* obj, qt_csd_menu_info* info);
+void WaylandCSDMenuClose(vlc_object_t* obj);
+
+#endif // CSDMENU_WAYLAND_HPP
=====================================
modules/gui/qt/util/csdmenu_win32.c
=====================================
@@ -0,0 +1,92 @@
+/*****************************************************************************
+ * Copyright (C) 2024 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 <windows.h>
+#include <winuser.h>
+#include <assert.h>
+#include "csdmenu_win32.h"
+
+typedef struct
+{
+ bool isRtl;
+ notifyMenuVisibleCallback notifyMenuVisible;
+ void* userData;
+} qt_csd_menu_priv_t;
+
+static bool Popup(struct qt_csd_menu_t* menu, qt_csd_menu_event* event)
+{
+ qt_csd_menu_priv_t* sys = (qt_csd_menu_priv_t*)menu->p_sys;
+
+ assert(event->platform == QT_CSD_PLATFORM_WINDOWS);
+
+ HWND hwnd = event->data.win32.hwnd;
+ HMENU hmenu = GetSystemMenu(hwnd, FALSE);
+ if (!hmenu)
+ return false;
+
+ // Tweak the menu items according to the current window status.
+ const bool maxOrFull = event->windowState & (QT_CSD_WINDOW_FULLSCREEN | QT_CSD_WINDOW_MAXIMIZED);
+ const bool fixedSize = event->windowState & QT_CSD_WINDOW_FIXED_SIZE;
+
+ EnableMenuItem(hmenu, SC_MOVE, (MF_BYCOMMAND | (!maxOrFull ? MFS_ENABLED : MFS_DISABLED)));
+ EnableMenuItem(hmenu, SC_SIZE, (MF_BYCOMMAND | ((!maxOrFull && !fixedSize) ? MFS_ENABLED : MFS_DISABLED)));
+
+ EnableMenuItem(hmenu, SC_RESTORE, (MF_BYCOMMAND | ((maxOrFull && !fixedSize) ? MFS_ENABLED : MFS_DISABLED)));
+ EnableMenuItem(hmenu, SC_MINIMIZE, (MF_BYCOMMAND | MFS_ENABLED));
+ EnableMenuItem(hmenu, SC_MAXIMIZE, (MF_BYCOMMAND | ((!maxOrFull && !fixedSize) ? MFS_ENABLED : MFS_DISABLED)));
+ EnableMenuItem(hmenu, SC_CLOSE, (MF_BYCOMMAND | MFS_ENABLED));
+
+
+ const unsigned alignment = sys->isRtl ? TPM_RIGHTALIGN : TPM_LEFTALIGN;
+
+ // show menu
+
+ if (sys->notifyMenuVisible)
+ sys->notifyMenuVisible(sys->userData, true);
+
+ const int action = TrackPopupMenu(hmenu, (TPM_RETURNCMD | alignment)
+ , event->x, event->y
+ , 0, hwnd, NULL);
+
+ // unlike native system menu which sends WM_SYSCOMMAND, TrackPopupMenu sends WM_COMMAND
+ // imitate native system menu by sending the action manually as WM_SYSCOMMAND
+ PostMessageW(hwnd, WM_SYSCOMMAND, action, 0);
+
+ if (sys->notifyMenuVisible)
+ sys->notifyMenuVisible(sys->userData, false);
+
+ return true;
+}
+
+int QtWin32CSDMenuOpen(qt_csd_menu_t* p_this, qt_csd_menu_info* info)
+{
+ if (info->platform != QT_CSD_PLATFORM_WINDOWS)
+ return VLC_EGENERIC;
+
+ qt_csd_menu_priv_t* sys = vlc_obj_malloc(p_this, sizeof(qt_csd_menu_priv_t));
+ if (!sys)
+ return VLC_ENOMEM;
+
+ sys->isRtl = info->isRtl;
+
+ sys->notifyMenuVisible = info->notifyMenuVisible;
+ sys->userData = info->userData;
+
+ p_this->p_sys = sys;
+ p_this->popup = Popup;
+ return VLC_SUCCESS;
+}
=====================================
modules/gui/qt/util/csdmenu_win32.h
=====================================
@@ -0,0 +1,33 @@
+/*****************************************************************************
+ * Copyright (C) 2024 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 CSDMENU_WIN32_H
+#define CSDMENU_WIN32_H
+
+#include "csdmenu_module.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int QtWin32CSDMenuOpen(qt_csd_menu_t* obj, qt_csd_menu_info* info);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CSDMENU_WIN32_H
=====================================
modules/gui/qt/util/csdmenu_x11.cpp
=====================================
@@ -0,0 +1,93 @@
+/*****************************************************************************
+ * Copyright (C) 2024 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 "csdmenu_x11.h"
+#include <cassert>
+#include "maininterface/compositor_x11_utils.hpp"
+
+typedef struct {
+ xcb_connection_t* connection;
+ xcb_atom_t gtkShowWindowMenuAtom;
+ xcb_window_t rootWindow;
+} csd_menu_priv_t;
+
+extern "C" {
+
+static bool CSDMenuPopup(qt_csd_menu_t* p_this, qt_csd_menu_event* event)
+{
+ csd_menu_priv_t* sys = static_cast<csd_menu_priv_t*>(p_this->p_sys);
+
+ assert(event->platform == QT_CSD_PLATFORM_X11);
+
+ xcb_client_message_event_t x11event;
+ x11event.response_type = XCB_CLIENT_MESSAGE;
+ x11event.type = sys->gtkShowWindowMenuAtom;
+ x11event.window = event->data.x11.window;
+ x11event.sequence = 0;
+ x11event.format = 32;
+ x11event.data.data32[0] = 0; //device id ignored
+ x11event.data.data32[1] = event->x;
+ x11event.data.data32[2] = event->y;
+ x11event.data.data32[3] = 0;
+ x11event.data.data32[4] = 0;
+
+ // ungrab pointer to allow the window manager to grab them
+ xcb_ungrab_pointer(sys->connection, XCB_CURRENT_TIME);
+ xcb_send_event(sys->connection, false, sys->rootWindow, XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY, reinterpret_cast<const char*>(&x11event));
+ return true;
+}
+
+int X11CSDMenuOpen(qt_csd_menu_t* p_this, qt_csd_menu_info* info)
+{
+ if (info->platform != QT_CSD_PLATFORM_X11) {
+ return VLC_EGENERIC;
+ }
+
+ if (info->data.x11.connection == NULL || info->data.x11.rootwindow == 0) {
+ msg_Warn(p_this, "X11 connection or root window missing");
+ return VLC_EGENERIC;
+ }
+
+ csd_menu_priv_t* sys = (csd_menu_priv_t*)vlc_obj_calloc(p_this, 1, sizeof(csd_menu_priv_t));
+ if (!sys)
+ return VLC_ENOMEM;
+
+ sys->connection = info->data.x11.connection;
+ sys->rootWindow = info->data.x11.rootwindow;
+
+ sys->gtkShowWindowMenuAtom = vlc::getInternAtom(sys->connection, "_GTK_SHOW_WINDOW_MENU");
+
+ if (sys->gtkShowWindowMenuAtom == 0)
+ goto error;
+
+ if (!vlc::wmNetSupport(sys->connection, info->data.x11.rootwindow, sys->gtkShowWindowMenuAtom))
+ goto error;
+
+
+ //module functions
+ p_this->popup = CSDMenuPopup;
+ p_this->p_sys = sys;
+
+ return VLC_SUCCESS;
+
+error:
+ p_this->p_sys = NULL;
+ vlc_obj_free(p_this, sys);
+ return VLC_EGENERIC;
+}
+
+}
=====================================
modules/gui/qt/util/csdmenu_x11.h
=====================================
@@ -0,0 +1,33 @@
+/*****************************************************************************
+ * Copyright (C) 2024 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 CSD_MENU_X11_H
+#define CSD_MENU_X11_H
+
+#include "csdmenu_module.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int X11CSDMenuOpen(qt_csd_menu_t* obj, qt_csd_menu_info* info);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CSD_MENU_X11_H
=====================================
modules/gui/qt/widgets/qml/BannerCone.qml
=====================================
@@ -27,8 +27,8 @@ import VLC.Util
Image {
id: root
- property var button: MainCtx.csdButtonModel.systemMenuButton
required property color color
+ property alias csdMenuVisible: csdMenu.menuVisible
sourceSize.width: VLCStyle.icon_normal
sourceSize.height: VLCStyle.icon_normal
@@ -39,41 +39,39 @@ Image {
focus: false
- Loader {
- anchors.fill: root
- enabled: MainCtx.clientSideDecoration && root.button
-
- sourceComponent: MouseArea {
- onClicked: { root.button.click() }
- onDoubleClicked: { root.button.doubleClick() }
-
- Connections {
- // don't target MouseArea for position since we
- // need position updates of cone, inresepect of BannerSources
- // to correctly track cone's global position
- target: root
-
- // handles VLCStyle.scale changes
- function onXChanged() { Qt.callLater(root.updateRect) }
- function onYChanged() { Qt.callLater(root.updateRect) }
- function onWidthChanged() { Qt.callLater(root.updateRect) }
- function onHeightChanged() { Qt.callLater(root.updateRect) }
- }
+ TapHandler {
+ enabled: MainCtx.clientSideDecoration
+
+ gesturePolicy: TapHandler.WithinBounds
- Connections {
- target: VLCStyle
+ onSingleTapped: (eventPoint, button) => {
+ if (button === Qt.LeftButton){
+ doubleTapFilter.start()
+ }
+ }
- // handle window resize
- function onAppWidthChanged() { Qt.callLater(root.updateRect) }
- function onAppHeightChanged() { Qt.callLater(root.updateRect) }
+ onDoubleTapped: (eventPoint, button) => {
+ if (button === Qt.LeftButton) {
+ doubleTapFilter.stop()
+ MainCtx.intfMainWindow.close()
}
}
}
- function updateRect() {
- const rect = root.mapToItem(null, 0, 0, width, height)
+ CSDMenu {
+ id: csdMenu
+ ctx: MainCtx
+ }
+
+ //SingleTapped is always notified, perform the action only if the double tap doesn't occur
+ Timer {
+ id: doubleTapFilter
- if (button)
- button.rect = rect
+ interval: VLCStyle.duration_short
+
+ onTriggered: {
+ //popup below the widget
+ csdMenu.popup(root.mapToGlobal(0, root.height + VLCStyle.margin_xxsmall))
+ }
}
}
=====================================
modules/gui/qt/widgets/qml/CSDTitlebarTapNDrapHandler.qml
=====================================
@@ -18,20 +18,18 @@
//CSD is only supported on Qt 5.15
import QtQuick
-import QtQuick.Window
import VLC.MainInterface
Item {
+ property alias csdMenuVisible: csdMenu.menuVisible
+
TapHandler {
acceptedButtons: Qt.LeftButton | Qt.RightButton
onSingleTapped: (eventPoint, button) => {
if (button & Qt.RightButton) {
- const systemButton = MainCtx.csdButtonModel.systemMenuButton
- if (systemButton) {
- systemButton.showSystemMenu(eventPoint.position)
- }
+ csdMenu.popup(parent.mapToGlobal(eventPoint.position.x, eventPoint.position.y))
}
}
@@ -65,4 +63,8 @@ Item {
}
}
+ CSDMenu {
+ id: csdMenu
+ ctx: MainCtx
+ }
}
=====================================
po/POTFILES.in
=====================================
@@ -884,6 +884,7 @@ modules/gui/qt/qt.hpp
modules/gui/qt/util/color_scheme_model.cpp
modules/gui/qt/util/covergenerator.cpp
modules/gui/qt/util/covergenerator.hpp
+modules/gui/qt/util/csdmenu.cpp
modules/gui/qt/util/imagehelper.cpp
modules/gui/qt/util/imagehelper.hpp
modules/gui/qt/util/qt_dirs.cpp
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/63f076b59416262a860724c3ea638e5079bccc19...62ff2e006c63f691e635f2dada66161f30d207b5
--
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/63f076b59416262a860724c3ea638e5079bccc19...62ff2e006c63f691e635f2dada66161f30d207b5
You're receiving this email because of your account on code.videolan.org.
VideoLAN code repository instance
More information about the vlc-commits
mailing list