From 5fae9a944ed341f94263eec516c03c347f543e4b Mon Sep 17 00:00:00 2001 From: Vlad Zahorodnii Date: Thu, 20 Jul 2023 12:47:14 +0300 Subject: [PATCH] wayland: Implement xdg-shell v5 In v5, the xdg_toplevel.wm_capabilities event had been introduced which specifies a list of actions allowed by the compositors. Mainly useful to client-side decorated apps. --- src/wayland/xdgshell_interface.cpp | 28 +++++++++++++++++++++++++++- src/wayland/xdgshell_interface.h | 14 ++++++++++++++ src/xdgshellwindow.cpp | 29 +++++++++++++++++++++++++++++ src/xdgshellwindow.h | 3 +++ 4 files changed, 73 insertions(+), 1 deletion(-) diff --git a/src/wayland/xdgshell_interface.cpp b/src/wayland/xdgshell_interface.cpp index 38c3ade79b..c5de3c9a24 100644 --- a/src/wayland/xdgshell_interface.cpp +++ b/src/wayland/xdgshell_interface.cpp @@ -16,7 +16,7 @@ namespace KWaylandServer { -static const int s_version = 4; +static const int s_version = 5; XdgShellInterfacePrivate::XdgShellInterfacePrivate(XdgShellInterface *shell) : q(shell) @@ -595,6 +595,32 @@ void XdgToplevelInterface::sendConfigureBounds(const QSize &size) } } +void XdgToplevelInterface::sendWmCapabilities(Capabilities capabilities) +{ + if (d->resource()->version() < XDG_TOPLEVEL_WM_CAPABILITIES_SINCE_VERSION) { + return; + } + // Note that the capabilities listed in the event must be an array of uint32_t. + + uint32_t capabilitiesData[4] = {0}; + int i = 0; + + if (capabilities & Capability::WindowMenu) { + capabilitiesData[i++] = QtWaylandServer::xdg_toplevel::wm_capabilities_window_menu; + } + if (capabilities & Capability::Maximize) { + capabilitiesData[i++] = QtWaylandServer::xdg_toplevel::wm_capabilities_maximize; + } + if (capabilities & Capability::FullScreen) { + capabilitiesData[i++] = QtWaylandServer::xdg_toplevel::wm_capabilities_fullscreen; + } + if (capabilities & Capability::Minimize) { + capabilitiesData[i++] = QtWaylandServer::xdg_toplevel::wm_capabilities_minimize; + } + + d->send_wm_capabilities(QByteArray::fromRawData(reinterpret_cast(capabilitiesData), sizeof(uint32_t) * i)); +} + XdgToplevelInterface *XdgToplevelInterface::get(::wl_resource *resource) { if (auto toplevelPrivate = resource_cast(resource)) { diff --git a/src/wayland/xdgshell_interface.h b/src/wayland/xdgshell_interface.h index 3331b3a935..b4369a5a48 100644 --- a/src/wayland/xdgshell_interface.h +++ b/src/wayland/xdgshell_interface.h @@ -224,6 +224,14 @@ public: }; Q_ENUM(ResizeAnchor) + enum class Capability { + WindowMenu = 0x1, + Maximize = 0x2, + FullScreen = 0x4, + Minimize = 0x8, + }; + Q_DECLARE_FLAGS(Capabilities, Capability) + /** * Constructs an XdgToplevelInterface for the given xdg-surface \a surface. */ @@ -297,6 +305,11 @@ public: */ void sendConfigureBounds(const QSize &size); + /** + * Sends an event to the client specifying allowed actions by the compositor. + */ + void sendWmCapabilities(Capabilities capabilities); + /** * Returns the XdgToplevelInterface for the specified wayland resource object \a resource. */ @@ -585,5 +598,6 @@ private: } // namespace KWaylandServer Q_DECLARE_OPERATORS_FOR_FLAGS(KWaylandServer::XdgToplevelInterface::States) +Q_DECLARE_OPERATORS_FOR_FLAGS(KWaylandServer::XdgToplevelInterface::Capabilities) Q_DECLARE_METATYPE(KWaylandServer::XdgToplevelInterface::State) Q_DECLARE_METATYPE(KWaylandServer::XdgToplevelInterface::States) diff --git a/src/xdgshellwindow.cpp b/src/xdgshellwindow.cpp index f83d2653a8..ec769b86ef 100644 --- a/src/xdgshellwindow.cpp +++ b/src/xdgshellwindow.cpp @@ -643,6 +643,12 @@ bool XdgToplevelWindow::supportsWindowRules() const return true; } +void XdgToplevelWindow::applyWindowRules() +{ + WaylandWindow::applyWindowRules(); + updateCapabilities(); +} + void XdgToplevelWindow::closeWindow() { if (isCloseable()) { @@ -1120,11 +1126,13 @@ void XdgToplevelWindow::handlePongReceived(quint32 serial) void XdgToplevelWindow::handleMaximumSizeChanged() { + updateCapabilities(); Q_EMIT maximizeableChanged(isMaximizable()); } void XdgToplevelWindow::handleMinimumSizeChanged() { + updateCapabilities(); Q_EMIT maximizeableChanged(isMaximizable()); } @@ -1207,6 +1215,7 @@ void XdgToplevelWindow::initialize() configureDecoration(); scheduleConfigure(); updateColorScheme(); + updateCapabilities(); setupWindowManagementInterface(); m_isInitialized = true; @@ -1234,6 +1243,26 @@ void XdgToplevelWindow::updateFullScreenMode(bool set) Q_EMIT fullScreenChanged(); } +void XdgToplevelWindow::updateCapabilities() +{ + KWaylandServer::XdgToplevelInterface::Capabilities caps = KWaylandServer::XdgToplevelInterface::Capability::WindowMenu; + + if (isMaximizable()) { + caps.setFlag(KWaylandServer::XdgToplevelInterface::Capability::Maximize); + } + if (isFullScreenable()) { + caps.setFlag(KWaylandServer::XdgToplevelInterface::Capability::FullScreen); + } + if (isMinimizable()) { + caps.setFlag(KWaylandServer::XdgToplevelInterface::Capability::Minimize); + } + + if (m_capabilities != caps) { + m_capabilities = caps; + m_shellSurface->sendWmCapabilities(caps); + } +} + QString XdgToplevelWindow::preferredColorScheme() const { if (m_paletteInterface) { diff --git a/src/xdgshellwindow.h b/src/xdgshellwindow.h index 09d7057d72..1ea53bf539 100644 --- a/src/xdgshellwindow.h +++ b/src/xdgshellwindow.h @@ -150,6 +150,7 @@ public: void invalidateDecoration() override; QString preferredColorScheme() const override; bool supportsWindowRules() const override; + void applyWindowRules() override; bool takeFocus() override; bool wantsInput() const override; bool dockWantsInput() const override; @@ -209,6 +210,7 @@ private: void configureXdgDecoration(DecorationMode decorationMode); void configureServerDecoration(DecorationMode decorationMode); void clearDecoration(); + void updateCapabilities(); QPointer m_appMenuInterface; QPointer m_paletteInterface; @@ -218,6 +220,7 @@ private: KWaylandServer::XdgToplevelInterface::States m_nextStates; KWaylandServer::XdgToplevelInterface::States m_acknowledgedStates; KWaylandServer::XdgToplevelInterface::States m_initialStates; + KWaylandServer::XdgToplevelInterface::Capabilities m_capabilities; QMap m_pings; MaximizeMode m_maximizeMode = MaximizeRestore; MaximizeMode m_requestedMaximizeMode = MaximizeRestore;