From 9b7718459efa593f50a35b535121badc390984db Mon Sep 17 00:00:00 2001 From: Kai Uwe Broulik Date: Thu, 23 Nov 2023 23:28:24 +0100 Subject: [PATCH] xdgforeign: Allow exporting surfaces internally Without a client asking for it. This way we can send a surface to another helper application, such as the window killer. An ExportedSurface wrapper class is introduced which represents an exported surface in a windowing-system independent way. --- src/wayland/xdgforeign_v2.cpp | 78 ++++++++++++++++++++++++----------- src/wayland/xdgforeign_v2.h | 24 +++++++++++ src/wayland/xdgforeign_v2_p.h | 24 +++++------ src/wayland_server.cpp | 5 +++ src/wayland_server.h | 6 +++ 5 files changed, 99 insertions(+), 38 deletions(-) diff --git a/src/wayland/xdgforeign_v2.cpp b/src/wayland/xdgforeign_v2.cpp index cf24d3f7db..e30ed5ba2b 100644 --- a/src/wayland/xdgforeign_v2.cpp +++ b/src/wayland/xdgforeign_v2.cpp @@ -1,6 +1,7 @@ /* SPDX-FileCopyrightText: 2017 Marco Martin SPDX-FileCopyrightText: 2021 Vlad Zahorodnii + SPDX-FileCopyrightText: 2023 Kai Uwe Broulik SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ @@ -15,6 +16,29 @@ namespace KWin static const quint32 s_exporterVersion = 1; static const quint32 s_importerVersion = 1; +XdgExportedSurface::XdgExportedSurface(SurfaceInterface *surface) + : QObject() + , m_handle(QUuid::createUuid().toString()) + , m_surface(surface) +{ + connect(m_surface, &QObject::destroyed, this, &XdgExportedSurface::handleSurfaceDestroyed); +} + +QString XdgExportedSurface::handle() const +{ + return m_handle; +} + +SurfaceInterface *XdgExportedSurface::surface() const +{ + return m_surface; +} + +void XdgExportedSurface::handleSurfaceDestroyed() +{ + delete this; +} + XdgForeignV2InterfacePrivate::XdgForeignV2InterfacePrivate(Display *display, XdgForeignV2Interface *_q) : q(_q) , exporter(new XdgExporterV2Interface(display, _q)) @@ -37,17 +61,38 @@ SurfaceInterface *XdgForeignV2Interface::transientFor(SurfaceInterface *surface) return d->importer->transientFor(surface); } +XdgExportedSurface *XdgForeignV2Interface::exportSurface(SurfaceInterface *surface) +{ + return d->exporter->exportSurface(surface); +} + XdgExporterV2Interface::XdgExporterV2Interface(Display *display, XdgForeignV2Interface *foreign) : QObject(foreign) , QtWaylandServer::zxdg_exporter_v2(*display, s_exporterVersion) { } -XdgExportedV2Interface *XdgExporterV2Interface::exportedSurface(const QString &handle) +XdgExportedSurface *XdgExporterV2Interface::exportedSurface(const QString &handle) const { return m_exportedSurfaces.value(handle); } +XdgExportedSurface *XdgExporterV2Interface::exportSurface(SurfaceInterface *surface) +{ + auto *exported = new XdgExportedSurface(surface); + addExported(exported); + return exported; +} + +void XdgExporterV2Interface::addExported(XdgExportedSurface *exported) +{ + const QString handle = exported->handle(); + connect(exported, &XdgExportedSurface::destroyed, this, [this, handle] { + m_exportedSurfaces.remove(handle); + }); + m_exportedSurfaces[handle] = exported; +} + void XdgExporterV2Interface::zxdg_exporter_v2_destroy(Resource *resource) { wl_resource_destroy(resource->handle); @@ -68,15 +113,9 @@ void XdgExporterV2Interface::zxdg_exporter_v2_export_toplevel(Resource *resource } XdgExportedV2Interface *exported = new XdgExportedV2Interface(surface, exportedResource); - const QString handle = QUuid::createUuid().toString(); + addExported(exported); - // a surface not exported anymore - connect(exported, &XdgExportedV2Interface::destroyed, this, [this, handle]() { - m_exportedSurfaces.remove(handle); - }); - - m_exportedSurfaces[handle] = exported; - exported->send_handle(handle); + exported->send_handle(exported->handle()); } XdgImporterV2Interface::XdgImporterV2Interface(Display *display, XdgForeignV2Interface *foreign) @@ -110,7 +149,7 @@ void XdgImporterV2Interface::zxdg_importer_v2_import_toplevel(Resource *resource // If there is no exported surface with the specified handle, we must still create an // inert xdg_imported object and send the destroyed event right afterwards. - XdgExportedV2Interface *exported = m_foreign->d->exporter->exportedSurface(handle); + XdgExportedSurface *exported = m_foreign->d->exporter->exportedSurface(handle); if (!exported) { auto imported = new XdgDummyImportedV2Interface(importedResource); imported->send_destroyed(); @@ -175,15 +214,9 @@ void XdgImporterV2Interface::unlink(XdgImportedV2Interface *parent, SurfaceInter } XdgExportedV2Interface::XdgExportedV2Interface(SurfaceInterface *surface, wl_resource *resource) - : QtWaylandServer::zxdg_exported_v2(resource) - , m_surface(surface) + : XdgExportedSurface(surface) + , QtWaylandServer::zxdg_exported_v2(resource) { - connect(surface, &QObject::destroyed, this, &XdgExportedV2Interface::handleSurfaceDestroyed); -} - -SurfaceInterface *XdgExportedV2Interface::surface() -{ - return m_surface; } void XdgExportedV2Interface::zxdg_exported_v2_destroy(Resource *resource) @@ -196,11 +229,6 @@ void XdgExportedV2Interface::zxdg_exported_v2_destroy_resource(Resource *resourc delete this; } -void XdgExportedV2Interface::handleSurfaceDestroyed() -{ - delete this; -} - XdgDummyImportedV2Interface::XdgDummyImportedV2Interface(wl_resource *resource) : QtWaylandServer::zxdg_imported_v2(resource) { @@ -216,11 +244,11 @@ void XdgDummyImportedV2Interface::zxdg_imported_v2_destroy_resource(Resource *re delete this; } -XdgImportedV2Interface::XdgImportedV2Interface(XdgExportedV2Interface *exported, wl_resource *resource) +XdgImportedV2Interface::XdgImportedV2Interface(XdgExportedSurface *exported, wl_resource *resource) : QtWaylandServer::zxdg_imported_v2(resource) , m_exported(exported) { - connect(exported, &QObject::destroyed, this, &XdgImportedV2Interface::handleExportedDestroyed); + connect(exported, &XdgExportedSurface::destroyed, this, &XdgImportedV2Interface::handleExportedDestroyed); } SurfaceInterface *XdgImportedV2Interface::child() const diff --git a/src/wayland/xdgforeign_v2.h b/src/wayland/xdgforeign_v2.h index 8c394a778d..9832565e2d 100644 --- a/src/wayland/xdgforeign_v2.h +++ b/src/wayland/xdgforeign_v2.h @@ -16,6 +16,23 @@ class Display; class SurfaceInterface; class XdgForeignV2InterfacePrivate; +class KWIN_EXPORT XdgExportedSurface : public QObject +{ + Q_OBJECT + +public: + XdgExportedSurface(SurfaceInterface *surface); + + QString handle() const; + SurfaceInterface *surface() const; + +private: + void handleSurfaceDestroyed(); + + const QString m_handle; + SurfaceInterface *m_surface; +}; + /** * This class encapsulates the server side logic of the XdgForeign protocol. * a process can export a surface to be identifiable by a server-wide unique @@ -39,6 +56,13 @@ public: */ SurfaceInterface *transientFor(SurfaceInterface *surface); + /** + * Exports the given surface without creating a Wayland interface object. + * @param surface The surface to export + * @return The handle, this can then be passed to other clients. + */ + XdgExportedSurface *exportSurface(SurfaceInterface *surface); + Q_SIGNALS: /** * A surface got a new imported transient parent diff --git a/src/wayland/xdgforeign_v2_p.h b/src/wayland/xdgforeign_v2_p.h index 13b7f20d78..2ec764af37 100644 --- a/src/wayland/xdgforeign_v2_p.h +++ b/src/wayland/xdgforeign_v2_p.h @@ -1,6 +1,7 @@ /* SPDX-FileCopyrightText: 2017 Marco Martin SPDX-FileCopyrightText: 2021 Vlad Zahorodnii + SPDX-FileCopyrightText: 2023 Kai Uwe Broulik SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ @@ -11,6 +12,8 @@ #include +#include + namespace KWin { class XdgExportedV2Interface; @@ -35,14 +38,17 @@ class XdgExporterV2Interface : public QObject, public QtWaylandServer::zxdg_expo public: XdgExporterV2Interface(Display *display, XdgForeignV2Interface *foreign); - XdgExportedV2Interface *exportedSurface(const QString &handle); + XdgExportedSurface *exportedSurface(const QString &handle) const; + XdgExportedSurface *exportSurface(SurfaceInterface *surface); protected: void zxdg_exporter_v2_destroy(Resource *resource) override; void zxdg_exporter_v2_export_toplevel(Resource *resource, uint32_t id, wl_resource *surface) override; private: - QHash m_exportedSurfaces; + void addExported(XdgExportedSurface *exported); + + QHash m_exportedSurfaces; }; class XdgImporterV2Interface : public QObject, public QtWaylandServer::zxdg_importer_v2 @@ -67,24 +73,16 @@ private: QHash m_children; // parent->child hash }; -class XdgExportedV2Interface : public QObject, public QtWaylandServer::zxdg_exported_v2 +class XdgExportedV2Interface : public XdgExportedSurface, public QtWaylandServer::zxdg_exported_v2 { Q_OBJECT public: explicit XdgExportedV2Interface(SurfaceInterface *surface, wl_resource *resource); - SurfaceInterface *surface(); - protected: void zxdg_exported_v2_destroy(Resource *resource) override; void zxdg_exported_v2_destroy_resource(Resource *resource) override; - -private Q_SLOTS: - void handleSurfaceDestroyed(); - -private: - SurfaceInterface *m_surface; }; class XdgDummyImportedV2Interface : public QtWaylandServer::zxdg_imported_v2 @@ -101,7 +99,7 @@ class XdgImportedV2Interface : public QObject, QtWaylandServer::zxdg_imported_v2 { Q_OBJECT public: - explicit XdgImportedV2Interface(XdgExportedV2Interface *exported, wl_resource *resource); + explicit XdgImportedV2Interface(XdgExportedSurface *exported, wl_resource *resource); SurfaceInterface *child() const; SurfaceInterface *surface() const; @@ -113,7 +111,7 @@ private Q_SLOTS: void handleExportedDestroyed(); private: - XdgExportedV2Interface *m_exported; + XdgExportedSurface *m_exported; QPointer m_child; protected: diff --git a/src/wayland_server.cpp b/src/wayland_server.cpp index aa8790c7ae..c2b4d2ddcc 100644 --- a/src/wayland_server.cpp +++ b/src/wayland_server.cpp @@ -510,6 +510,11 @@ SurfaceInterface *WaylandServer::findForeignTransientForSurface(SurfaceInterface return m_XdgForeign->transientFor(surface); } +XdgExportedSurface *WaylandServer::exportAsForeign(SurfaceInterface *surface) +{ + return m_XdgForeign->exportSurface(surface); +} + void WaylandServer::initWorkspace() { auto inputPanelV1Integration = new InputPanelV1Integration(this); diff --git a/src/wayland_server.h b/src/wayland_server.h index 2fc59755ee..26a1ec1daa 100644 --- a/src/wayland_server.h +++ b/src/wayland_server.h @@ -36,6 +36,7 @@ class PlasmaVirtualDesktopManagementInterface; class PlasmaWindowManagementInterface; class OutputDeviceV2Interface; class OutputManagementV2Interface; +class XdgExportedSurface; class XdgForeignV2Interface; class XdgOutputManagerV1Interface; class DrmClientBufferIntegration; @@ -153,6 +154,11 @@ public: */ SurfaceInterface *findForeignTransientForSurface(SurfaceInterface *surface); + /** + * Exports a surface with the foreign protocol + */ + XdgExportedSurface *exportAsForeign(SurfaceInterface *surface); + /** * @returns file descriptor for Xwayland to connect to. */