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.
This commit is contained in:
Kai Uwe Broulik 2023-11-23 23:28:24 +01:00 committed by Vlad Zahorodnii
parent 2b868edb9e
commit 9b7718459e
5 changed files with 99 additions and 38 deletions

View file

@ -1,6 +1,7 @@
/* /*
SPDX-FileCopyrightText: 2017 Marco Martin <notmart@gmail.com> SPDX-FileCopyrightText: 2017 Marco Martin <notmart@gmail.com>
SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org> SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
SPDX-FileCopyrightText: 2023 Kai Uwe Broulik <kde@broulik.de>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL 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_exporterVersion = 1;
static const quint32 s_importerVersion = 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) XdgForeignV2InterfacePrivate::XdgForeignV2InterfacePrivate(Display *display, XdgForeignV2Interface *_q)
: q(_q) : q(_q)
, exporter(new XdgExporterV2Interface(display, _q)) , exporter(new XdgExporterV2Interface(display, _q))
@ -37,17 +61,38 @@ SurfaceInterface *XdgForeignV2Interface::transientFor(SurfaceInterface *surface)
return d->importer->transientFor(surface); return d->importer->transientFor(surface);
} }
XdgExportedSurface *XdgForeignV2Interface::exportSurface(SurfaceInterface *surface)
{
return d->exporter->exportSurface(surface);
}
XdgExporterV2Interface::XdgExporterV2Interface(Display *display, XdgForeignV2Interface *foreign) XdgExporterV2Interface::XdgExporterV2Interface(Display *display, XdgForeignV2Interface *foreign)
: QObject(foreign) : QObject(foreign)
, QtWaylandServer::zxdg_exporter_v2(*display, s_exporterVersion) , 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); 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) void XdgExporterV2Interface::zxdg_exporter_v2_destroy(Resource *resource)
{ {
wl_resource_destroy(resource->handle); wl_resource_destroy(resource->handle);
@ -68,15 +113,9 @@ void XdgExporterV2Interface::zxdg_exporter_v2_export_toplevel(Resource *resource
} }
XdgExportedV2Interface *exported = new XdgExportedV2Interface(surface, exportedResource); XdgExportedV2Interface *exported = new XdgExportedV2Interface(surface, exportedResource);
const QString handle = QUuid::createUuid().toString(); addExported(exported);
// a surface not exported anymore exported->send_handle(exported->handle());
connect(exported, &XdgExportedV2Interface::destroyed, this, [this, handle]() {
m_exportedSurfaces.remove(handle);
});
m_exportedSurfaces[handle] = exported;
exported->send_handle(handle);
} }
XdgImporterV2Interface::XdgImporterV2Interface(Display *display, XdgForeignV2Interface *foreign) 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 // 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. // 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) { if (!exported) {
auto imported = new XdgDummyImportedV2Interface(importedResource); auto imported = new XdgDummyImportedV2Interface(importedResource);
imported->send_destroyed(); imported->send_destroyed();
@ -175,15 +214,9 @@ void XdgImporterV2Interface::unlink(XdgImportedV2Interface *parent, SurfaceInter
} }
XdgExportedV2Interface::XdgExportedV2Interface(SurfaceInterface *surface, wl_resource *resource) XdgExportedV2Interface::XdgExportedV2Interface(SurfaceInterface *surface, wl_resource *resource)
: QtWaylandServer::zxdg_exported_v2(resource) : XdgExportedSurface(surface)
, m_surface(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) void XdgExportedV2Interface::zxdg_exported_v2_destroy(Resource *resource)
@ -196,11 +229,6 @@ void XdgExportedV2Interface::zxdg_exported_v2_destroy_resource(Resource *resourc
delete this; delete this;
} }
void XdgExportedV2Interface::handleSurfaceDestroyed()
{
delete this;
}
XdgDummyImportedV2Interface::XdgDummyImportedV2Interface(wl_resource *resource) XdgDummyImportedV2Interface::XdgDummyImportedV2Interface(wl_resource *resource)
: QtWaylandServer::zxdg_imported_v2(resource) : QtWaylandServer::zxdg_imported_v2(resource)
{ {
@ -216,11 +244,11 @@ void XdgDummyImportedV2Interface::zxdg_imported_v2_destroy_resource(Resource *re
delete this; delete this;
} }
XdgImportedV2Interface::XdgImportedV2Interface(XdgExportedV2Interface *exported, wl_resource *resource) XdgImportedV2Interface::XdgImportedV2Interface(XdgExportedSurface *exported, wl_resource *resource)
: QtWaylandServer::zxdg_imported_v2(resource) : QtWaylandServer::zxdg_imported_v2(resource)
, m_exported(exported) , m_exported(exported)
{ {
connect(exported, &QObject::destroyed, this, &XdgImportedV2Interface::handleExportedDestroyed); connect(exported, &XdgExportedSurface::destroyed, this, &XdgImportedV2Interface::handleExportedDestroyed);
} }
SurfaceInterface *XdgImportedV2Interface::child() const SurfaceInterface *XdgImportedV2Interface::child() const

View file

@ -16,6 +16,23 @@ class Display;
class SurfaceInterface; class SurfaceInterface;
class XdgForeignV2InterfacePrivate; 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. * 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 * a process can export a surface to be identifiable by a server-wide unique
@ -39,6 +56,13 @@ public:
*/ */
SurfaceInterface *transientFor(SurfaceInterface *surface); 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: Q_SIGNALS:
/** /**
* A surface got a new imported transient parent * A surface got a new imported transient parent

View file

@ -1,6 +1,7 @@
/* /*
SPDX-FileCopyrightText: 2017 Marco Martin <notmart@gmail.com> SPDX-FileCopyrightText: 2017 Marco Martin <notmart@gmail.com>
SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org> SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
SPDX-FileCopyrightText: 2023 Kai Uwe Broulik <kde@broulik.de>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/ */
@ -11,6 +12,8 @@
#include <qwayland-server-xdg-foreign-unstable-v2.h> #include <qwayland-server-xdg-foreign-unstable-v2.h>
#include <QPointer>
namespace KWin namespace KWin
{ {
class XdgExportedV2Interface; class XdgExportedV2Interface;
@ -35,14 +38,17 @@ class XdgExporterV2Interface : public QObject, public QtWaylandServer::zxdg_expo
public: public:
XdgExporterV2Interface(Display *display, XdgForeignV2Interface *foreign); XdgExporterV2Interface(Display *display, XdgForeignV2Interface *foreign);
XdgExportedV2Interface *exportedSurface(const QString &handle); XdgExportedSurface *exportedSurface(const QString &handle) const;
XdgExportedSurface *exportSurface(SurfaceInterface *surface);
protected: protected:
void zxdg_exporter_v2_destroy(Resource *resource) override; void zxdg_exporter_v2_destroy(Resource *resource) override;
void zxdg_exporter_v2_export_toplevel(Resource *resource, uint32_t id, wl_resource *surface) override; void zxdg_exporter_v2_export_toplevel(Resource *resource, uint32_t id, wl_resource *surface) override;
private: private:
QHash<QString, XdgExportedV2Interface *> m_exportedSurfaces; void addExported(XdgExportedSurface *exported);
QHash<QString, XdgExportedSurface *> m_exportedSurfaces;
}; };
class XdgImporterV2Interface : public QObject, public QtWaylandServer::zxdg_importer_v2 class XdgImporterV2Interface : public QObject, public QtWaylandServer::zxdg_importer_v2
@ -67,24 +73,16 @@ private:
QHash<XdgImportedV2Interface *, SurfaceInterface *> m_children; // parent->child hash QHash<XdgImportedV2Interface *, SurfaceInterface *> 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 Q_OBJECT
public: public:
explicit XdgExportedV2Interface(SurfaceInterface *surface, wl_resource *resource); explicit XdgExportedV2Interface(SurfaceInterface *surface, wl_resource *resource);
SurfaceInterface *surface();
protected: protected:
void zxdg_exported_v2_destroy(Resource *resource) override; void zxdg_exported_v2_destroy(Resource *resource) override;
void zxdg_exported_v2_destroy_resource(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 class XdgDummyImportedV2Interface : public QtWaylandServer::zxdg_imported_v2
@ -101,7 +99,7 @@ class XdgImportedV2Interface : public QObject, QtWaylandServer::zxdg_imported_v2
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit XdgImportedV2Interface(XdgExportedV2Interface *exported, wl_resource *resource); explicit XdgImportedV2Interface(XdgExportedSurface *exported, wl_resource *resource);
SurfaceInterface *child() const; SurfaceInterface *child() const;
SurfaceInterface *surface() const; SurfaceInterface *surface() const;
@ -113,7 +111,7 @@ private Q_SLOTS:
void handleExportedDestroyed(); void handleExportedDestroyed();
private: private:
XdgExportedV2Interface *m_exported; XdgExportedSurface *m_exported;
QPointer<SurfaceInterface> m_child; QPointer<SurfaceInterface> m_child;
protected: protected:

View file

@ -510,6 +510,11 @@ SurfaceInterface *WaylandServer::findForeignTransientForSurface(SurfaceInterface
return m_XdgForeign->transientFor(surface); return m_XdgForeign->transientFor(surface);
} }
XdgExportedSurface *WaylandServer::exportAsForeign(SurfaceInterface *surface)
{
return m_XdgForeign->exportSurface(surface);
}
void WaylandServer::initWorkspace() void WaylandServer::initWorkspace()
{ {
auto inputPanelV1Integration = new InputPanelV1Integration(this); auto inputPanelV1Integration = new InputPanelV1Integration(this);

View file

@ -36,6 +36,7 @@ class PlasmaVirtualDesktopManagementInterface;
class PlasmaWindowManagementInterface; class PlasmaWindowManagementInterface;
class OutputDeviceV2Interface; class OutputDeviceV2Interface;
class OutputManagementV2Interface; class OutputManagementV2Interface;
class XdgExportedSurface;
class XdgForeignV2Interface; class XdgForeignV2Interface;
class XdgOutputManagerV1Interface; class XdgOutputManagerV1Interface;
class DrmClientBufferIntegration; class DrmClientBufferIntegration;
@ -153,6 +154,11 @@ public:
*/ */
SurfaceInterface *findForeignTransientForSurface(SurfaceInterface *surface); SurfaceInterface *findForeignTransientForSurface(SurfaceInterface *surface);
/**
* Exports a surface with the foreign protocol
*/
XdgExportedSurface *exportAsForeign(SurfaceInterface *surface);
/** /**
* @returns file descriptor for Xwayland to connect to. * @returns file descriptor for Xwayland to connect to.
*/ */