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: 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
*/
@ -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

View file

@ -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

View file

@ -1,6 +1,7 @@
/*
SPDX-FileCopyrightText: 2017 Marco Martin <notmart@gmail.com>
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
*/
@ -11,6 +12,8 @@
#include <qwayland-server-xdg-foreign-unstable-v2.h>
#include <QPointer>
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<QString, XdgExportedV2Interface *> m_exportedSurfaces;
void addExported(XdgExportedSurface *exported);
QHash<QString, XdgExportedSurface *> m_exportedSurfaces;
};
class XdgImporterV2Interface : public QObject, public QtWaylandServer::zxdg_importer_v2
@ -67,24 +73,16 @@ private:
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
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<SurfaceInterface> m_child;
protected:

View file

@ -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);

View file

@ -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.
*/