diff --git a/src/wayland/CMakeLists.txt b/src/wayland/CMakeLists.txt index 7c4b3d9e5e..a700bfef0c 100644 --- a/src/wayland/CMakeLists.txt +++ b/src/wayland/CMakeLists.txt @@ -180,6 +180,11 @@ ecm_add_qtwayland_server_protocol_kde(WaylandProtocols_xml BASENAME kde-lockscreen-overlay-v1 ) +ecm_add_qtwayland_server_protocol_kde(WaylandProtocols_xml + PROTOCOL ${WaylandProtocols_DATADIR}/unstable/xwayland-keyboard-grab/xwayland-keyboard-grab-unstable-v1.xml + BASENAME xwayland-keyboard-grab-unstable-v1 +) + target_sources(kwin PRIVATE abstract_data_source.cpp abstract_drop_handler.cpp @@ -250,6 +255,7 @@ target_sources(kwin PRIVATE xdgforeign_v2_interface.cpp xdgoutput_v1_interface.cpp xdgshell_interface.cpp + xwaylandkeyboardgrab_v1_interface.cpp ) if(CMAKE_SYSTEM_NAME MATCHES "Linux") diff --git a/src/wayland/xwaylandkeyboardgrab_v1_interface.cpp b/src/wayland/xwaylandkeyboardgrab_v1_interface.cpp new file mode 100644 index 0000000000..46e9306c6f --- /dev/null +++ b/src/wayland/xwaylandkeyboardgrab_v1_interface.cpp @@ -0,0 +1,111 @@ +/* + SPDX-FileCopyrightText: 2022 David Redondo + + SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL +*/ + +#include "xwaylandkeyboardgrab_v1_interface.h" + +#include + +#include "display.h" +#include "seat_interface.h" +#include "surface_interface.h" + +constexpr int version = 1; + +namespace KWaylandServer +{ + +class XWaylandKeyboardGrabManagerV1InterfacePrivate : QtWaylandServer::zwp_xwayland_keyboard_grab_manager_v1 +{ +public: + XWaylandKeyboardGrabManagerV1InterfacePrivate(Display *display, XWaylandKeyboardGrabManagerV1Interface *q); + XWaylandKeyboardGrabManagerV1Interface *const q; + QHash, XWaylandKeyboardGrabV1Interface *> m_grabs; + +protected: + void zwp_xwayland_keyboard_grab_manager_v1_destroy(Resource *resource) override; + void zwp_xwayland_keyboard_grab_manager_v1_grab_keyboard(Resource *resource, uint32_t id, wl_resource *surface, wl_resource *seat) override; +}; + +class XWaylandKeyboardGrabV1InterfacePrivate : QtWaylandServer::zwp_xwayland_keyboard_grab_v1 +{ +public: + XWaylandKeyboardGrabV1InterfacePrivate(XWaylandKeyboardGrabV1Interface *q, wl_resource *resource); + XWaylandKeyboardGrabV1Interface *const q; + +protected: + void zwp_xwayland_keyboard_grab_v1_destroy(Resource *resource) override; + void zwp_xwayland_keyboard_grab_v1_destroy_resource(Resource *resource) override; +}; + +XWaylandKeyboardGrabManagerV1InterfacePrivate::XWaylandKeyboardGrabManagerV1InterfacePrivate(Display *display, XWaylandKeyboardGrabManagerV1Interface *q) + : zwp_xwayland_keyboard_grab_manager_v1(*display, version) + , q(q) +{ +} + +void XWaylandKeyboardGrabManagerV1InterfacePrivate::zwp_xwayland_keyboard_grab_manager_v1_destroy(Resource *resource) +{ + wl_resource_destroy(resource->handle); +} + +void XWaylandKeyboardGrabManagerV1InterfacePrivate::zwp_xwayland_keyboard_grab_manager_v1_grab_keyboard(Resource *resource, uint32_t id, wl_resource *surface, wl_resource *seat) +{ + wl_resource *keyboardGrab = wl_resource_create(resource->client(), &zwp_xwayland_keyboard_grab_v1_interface, version, id); + if (!keyboardGrab) { + wl_client_post_no_memory(resource->client()); + return; + } + const auto surfaceInterface = SurfaceInterface::get(surface); + const auto seatInterface = SeatInterface::get(seat); + auto grab = new XWaylandKeyboardGrabV1Interface(keyboardGrab); + QObject::connect(grab, &QObject::destroyed, q, [this, surfaceInterface, seatInterface] { + m_grabs.remove({surfaceInterface, seatInterface}); + }); + m_grabs.insert({SurfaceInterface::get(surface), SeatInterface::get(seat)}, grab); +} + +XWaylandKeyboardGrabManagerV1Interface::XWaylandKeyboardGrabManagerV1Interface(Display *display, QObject *parent) + : QObject(parent) + , d(std::make_unique(display, this)) +{ +} + +XWaylandKeyboardGrabManagerV1Interface::~XWaylandKeyboardGrabManagerV1Interface() +{ +} + +bool XWaylandKeyboardGrabManagerV1Interface::hasGrab(SurfaceInterface *surface, SeatInterface *seat) const +{ + return d->m_grabs.contains({surface, seat}); +} + +XWaylandKeyboardGrabV1InterfacePrivate::XWaylandKeyboardGrabV1InterfacePrivate(XWaylandKeyboardGrabV1Interface *q, wl_resource *resource) + : zwp_xwayland_keyboard_grab_v1(resource) + , q(q) +{ +} + +void XWaylandKeyboardGrabV1InterfacePrivate::zwp_xwayland_keyboard_grab_v1_destroy(Resource *resource) +{ + wl_resource_destroy(resource->handle); +} + +void XWaylandKeyboardGrabV1InterfacePrivate::zwp_xwayland_keyboard_grab_v1_destroy_resource(Resource *resource) +{ + Q_UNUSED(resource) + delete q; +} + +XWaylandKeyboardGrabV1Interface::XWaylandKeyboardGrabV1Interface(wl_resource *resource) + : d(std::make_unique(this, resource)) +{ +} + +XWaylandKeyboardGrabV1Interface::~XWaylandKeyboardGrabV1Interface() +{ +} + +} diff --git a/src/wayland/xwaylandkeyboardgrab_v1_interface.h b/src/wayland/xwaylandkeyboardgrab_v1_interface.h new file mode 100644 index 0000000000..f44c6dce75 --- /dev/null +++ b/src/wayland/xwaylandkeyboardgrab_v1_interface.h @@ -0,0 +1,51 @@ +/* + SPDX-FileCopyrightText: 2022 David Redondo + + SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL +*/ + +#pragma once + +#include "kwin_export.h" + +#include + +#include + +struct wl_resource; + +namespace KWaylandServer +{ + +class Display; +class SeatInterface; +class SurfaceInterface; +class XWaylandKeyboardGrabV1InterfacePrivate; +class XWaylandKeyboardGrabManagerV1InterfacePrivate; + +class KWIN_EXPORT XWaylandKeyboardGrabManagerV1Interface : public QObject +{ + Q_OBJECT +public: + explicit XWaylandKeyboardGrabManagerV1Interface(Display *display, QObject *parent = nullptr); + ~XWaylandKeyboardGrabManagerV1Interface() override; + bool hasGrab(SurfaceInterface *surface, SeatInterface *seat) const; + +private: + friend class XWaylandKeyboardGrabManagerV1InterfacePrivate; + std::unique_ptr d; +}; + +class KWIN_EXPORT XWaylandKeyboardGrabV1Interface : public QObject +{ + Q_OBJECT +public: + ~XWaylandKeyboardGrabV1Interface() override; + +private: + friend class XWaylandKeyboardGrabManagerV1InterfacePrivate; + XWaylandKeyboardGrabV1Interface(wl_resource *resource); + std::unique_ptr d; +}; + +} diff --git a/src/wayland_server.cpp b/src/wayland_server.cpp index 1a41761efb..c469599976 100644 --- a/src/wayland_server.cpp +++ b/src/wayland_server.cpp @@ -61,6 +61,7 @@ #include "wayland/xdgforeign_v2_interface.h" #include "wayland/xdgoutput_v1_interface.h" #include "wayland/xdgshell_interface.h" +#include "wayland/xwaylandkeyboardgrab_v1_interface.h" #include "waylandoutput.h" #include "workspace.h" #include "x11window.h" @@ -154,6 +155,10 @@ public: return false; } + if (client != waylandServer()->xWaylandConnection() && interfaceName == "zwp_xwayland_keyboard_grab_manager_v1") { + return false; + } + if (!interfacesBlackList.contains(interfaceName)) { return true; } @@ -462,6 +467,7 @@ bool WaylandServer::init(InitializationFlags flags) new SubCompositorInterface(m_display, m_display); m_XdgForeign = new XdgForeignV2Interface(m_display, m_display); m_inputMethod = new InputMethodV1Interface(m_display, m_display); + m_xWaylandKeyboardGrabManager = new XWaylandKeyboardGrabManagerV1Interface(m_display, m_display); auto activation = new KWaylandServer::XdgActivationV1Interface(m_display, this); auto init = [this, activation] { @@ -755,7 +761,12 @@ bool WaylandServer::isKeyboardShortcutsInhibited() const auto surface = seat()->focusedKeyboardSurface(); if (surface) { auto inhibitor = keyboardShortcutsInhibitManager()->findInhibitor(surface, seat()); - return inhibitor && inhibitor->isActive(); + if (inhibitor && inhibitor->isActive()) { + return true; + } + if (m_xWaylandKeyboardGrabManager->hasGrab(surface, seat())) { + return true; + } } return false; } diff --git a/src/wayland_server.h b/src/wayland_server.h index ccbb9f608c..d9440112b8 100644 --- a/src/wayland_server.h +++ b/src/wayland_server.h @@ -49,6 +49,7 @@ class TabletManagerV2Interface; class KeyboardShortcutsInhibitManagerV1Interface; class XdgDecorationManagerV1Interface; class PrimarySelectionDeviceManagerV1Interface; +class XWaylandKeyboardGrabManagerV1Interface; } namespace KWin @@ -289,6 +290,7 @@ private: KWaylandServer::PrimaryOutputV1Interface *m_primary = nullptr; XdgActivationV1Integration *m_xdgActivationIntegration = nullptr; KWaylandServer::PrimarySelectionDeviceManagerV1Interface *m_primarySelectionDeviceManager = nullptr; + KWaylandServer::XWaylandKeyboardGrabManagerV1Interface *m_xWaylandKeyboardGrabManager = nullptr; QList m_windows; InitializationFlags m_initFlags; QHash m_waylandOutputs;