/* SPDX-FileCopyrightText: 2017 Marco Martin SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ #include "xdgforeign_interface.h" #include "xdgforeign_v2_interface_p.h" #include "display.h" #include "global_p.h" #include "resource_p.h" #include "surface_interface_p.h" #include "wayland-xdg-foreign-unstable-v2-server-protocol.h" #include #include namespace KWayland { namespace Server { class Q_DECL_HIDDEN XdgExporterUnstableV2Interface::Private : public Global::Private { public: Private(XdgExporterUnstableV2Interface *q, Display *d, XdgForeignInterface *foreignInterface); XdgForeignInterface *foreignInterface; QHash exportedSurfaces; private: void bind(wl_client *client, uint32_t version, uint32_t id) override; static void unbind(wl_resource *resource); static Private *cast(wl_resource *r) { return reinterpret_cast(wl_resource_get_user_data(r)); } static void destroyCallback(wl_client *client, wl_resource *resource); static void exportCallback(wl_client *client, wl_resource *resource, uint32_t id, wl_resource * surface); XdgExporterUnstableV2Interface *q; static const struct zxdg_exporter_v2_interface s_interface; static const quint32 s_version; }; const quint32 XdgExporterUnstableV2Interface::Private::s_version = 1; #ifndef K_DOXYGEN const struct zxdg_exporter_v2_interface XdgExporterUnstableV2Interface::Private::s_interface = { destroyCallback, exportCallback }; #endif XdgExporterUnstableV2Interface::XdgExporterUnstableV2Interface(Display *display, XdgForeignInterface *parent) : Global(new Private(this, display, parent), parent) { } XdgExporterUnstableV2Interface::~XdgExporterUnstableV2Interface() {} XdgExporterUnstableV2Interface::Private *XdgExporterUnstableV2Interface::d_func() const { return reinterpret_cast(d.data()); } XdgExportedUnstableV2Interface *XdgExporterUnstableV2Interface::exportedSurface(const QString &handle) { Q_D(); auto it = d->exportedSurfaces.constFind(handle); if (it != d->exportedSurfaces.constEnd()) { return it.value(); } return nullptr; } void XdgExporterUnstableV2Interface::Private::destroyCallback(wl_client *client, wl_resource *resource) { Q_UNUSED(client) Q_UNUSED(resource) } void XdgExporterUnstableV2Interface::Private::exportCallback(wl_client *client, wl_resource *resource, uint32_t id, wl_resource * surface) { auto s = cast(resource); QPointer e = new XdgExportedUnstableV2Interface(s->q, surface); e->create(s->display->getConnection(client), wl_resource_get_version(resource), id); if (!e->resource()) { wl_resource_post_no_memory(resource); delete e; return; } const QString handle = QUuid::createUuid().toString(); //a surface not exported anymore connect(e.data(), &XdgExportedUnstableV2Interface::unbound, s->q, [s, handle]() { s->exportedSurfaces.remove(handle); emit s->q->surfaceUnexported(handle); }); //if the surface dies before this, this dies too connect(SurfaceInterface::get(surface), &Resource::unbound, s->q, [s, e, handle]() { if (e) { e->deleteLater(); } s->exportedSurfaces.remove(handle); emit s->q->surfaceUnexported(handle); }); s->exportedSurfaces[handle] = e; zxdg_exported_v2_send_handle(e->resource(), handle.toUtf8().constData()); emit s->q->surfaceExported(handle, e); } XdgExporterUnstableV2Interface::Private::Private(XdgExporterUnstableV2Interface *q, Display *d,XdgForeignInterface *foreignInterface) : Global::Private(d, &zxdg_exporter_v2_interface, s_version) , foreignInterface(foreignInterface) , q(q) { } void XdgExporterUnstableV2Interface::Private::bind(wl_client *client, uint32_t version, uint32_t id) { auto c = display->getConnection(client); wl_resource *resource = c->createResource(&zxdg_exporter_v2_interface, qMin(version, s_version), id); if (!resource) { wl_client_post_no_memory(client); return; } wl_resource_set_implementation(resource, &s_interface, this, unbind); // TODO: should we track? } void XdgExporterUnstableV2Interface::Private::unbind(wl_resource *resource) { Q_UNUSED(resource) // TODO: implement? } class Q_DECL_HIDDEN XdgImporterUnstableV2Interface::Private : public Global::Private { public: Private(XdgImporterUnstableV2Interface *q, Display *d, XdgForeignInterface *foreignInterface); XdgForeignInterface *foreignInterface; QHash importedSurfaces; //child->parent hash QHash parents; //parent->child hash QHash children; private: void bind(wl_client *client, uint32_t version, uint32_t id) override; static void unbind(wl_resource *resource); static Private *cast(wl_resource *r) { return reinterpret_cast(wl_resource_get_user_data(r)); } static void destroyCallback(wl_client *client, wl_resource *resource); static void importCallback(wl_client *client, wl_resource *resource, uint32_t id, const char * handle); XdgImporterUnstableV2Interface *q; static const struct zxdg_importer_v2_interface s_interface; static const quint32 s_version; }; const quint32 XdgImporterUnstableV2Interface::Private::s_version = 1; #ifndef K_DOXYGEN const struct zxdg_importer_v2_interface XdgImporterUnstableV2Interface::Private::s_interface = { destroyCallback, importCallback }; #endif XdgImporterUnstableV2Interface::XdgImporterUnstableV2Interface(Display *display, XdgForeignInterface *parent) : Global(new Private(this, display, parent), parent) { } XdgImporterUnstableV2Interface::~XdgImporterUnstableV2Interface() { } XdgImportedUnstableV2Interface *XdgImporterUnstableV2Interface::importedSurface(const QString &handle) { Q_D(); auto it = d->importedSurfaces.constFind(handle); if (it != d->importedSurfaces.constEnd()) { return it.value(); } return nullptr; } SurfaceInterface *XdgImporterUnstableV2Interface::transientFor(SurfaceInterface *surface) { Q_D(); auto it = d->parents.constFind(surface); if (it == d->parents.constEnd()) { return nullptr; } return SurfaceInterface::get((*it)->parentResource()); } XdgImporterUnstableV2Interface::Private *XdgImporterUnstableV2Interface::d_func() const { return reinterpret_cast(d.data()); } void XdgImporterUnstableV2Interface::Private::destroyCallback(wl_client *client, wl_resource *resource) { Q_UNUSED(client) Q_UNUSED(resource) } void XdgImporterUnstableV2Interface::Private::importCallback(wl_client *client, wl_resource *resource, uint32_t id, const char *h) { auto s = cast(resource); Q_ASSERT(s->foreignInterface); const QString handle = QString::fromUtf8(h); XdgExportedUnstableV2Interface *exp = s->foreignInterface->d->exporter->exportedSurface(handle); if (!exp) { zxdg_imported_v2_send_destroyed(resource); return; } wl_resource *surface = exp->parentResource(); if (!surface) { zxdg_imported_v2_send_destroyed(resource); return; } QPointer imp = new XdgImportedUnstableV2Interface(s->q, surface); imp->create(s->display->getConnection(client), wl_resource_get_version(resource), id); //surface no longer exported connect(exp, &XdgExportedUnstableV2Interface::unbound, s->q, [s, imp, handle]() { //imp valid when the exported is deleted before the imported if (imp) { zxdg_imported_v2_send_destroyed(imp->resource()); imp->deleteLater(); } s->importedSurfaces.remove(handle); emit s->q->surfaceUnimported(handle); }); connect(imp.data(), &XdgImportedUnstableV2Interface::childChanged, s->q, [s, imp](SurfaceInterface *child) { //remove any previous association auto it = s->children.find(imp); if (it != s->children.end()) { s->parents.remove(*it); s->children.erase(it); } s->parents[child] = imp; s->children[imp] = child; SurfaceInterface *parent = SurfaceInterface::get(imp->parentResource()); emit s->q->transientChanged(child, parent); //child surface destroyed connect(child, &Resource::unbound, s->q, [s, child]() { auto it = s->parents.find(child); if (it != s->parents.end()) { KWayland::Server::XdgImportedUnstableV2Interface* parent = *it; s->children.remove(*it); s->parents.erase(it); emit s->q->transientChanged(nullptr, SurfaceInterface::get(parent->parentResource())); } }); }); //surface no longer imported connect(imp.data(), &XdgImportedUnstableV2Interface::unbound, s->q, [s, handle, imp]() { s->importedSurfaces.remove(handle); emit s->q->surfaceUnimported(handle); auto it = s->children.find(imp); if (it != s->children.end()) { KWayland::Server::SurfaceInterface* child = *it; s->parents.remove(*it); s->children.erase(it); emit s->q->transientChanged(child, nullptr); } }); if (!imp->resource()) { wl_resource_post_no_memory(resource); delete imp; return; } s->importedSurfaces[handle] = imp; emit s->q->surfaceImported(handle, imp); } XdgImporterUnstableV2Interface::Private::Private(XdgImporterUnstableV2Interface *q, Display *d, XdgForeignInterface *foreignInterface) : Global::Private(d, &zxdg_importer_v2_interface, s_version) , foreignInterface(foreignInterface) , q(q) { } void XdgImporterUnstableV2Interface::Private::bind(wl_client *client, uint32_t version, uint32_t id) { auto c = display->getConnection(client); wl_resource *resource = c->createResource(&zxdg_importer_v2_interface, qMin(version, s_version), id); if (!resource) { wl_client_post_no_memory(client); return; } wl_resource_set_implementation(resource, &s_interface, this, unbind); // TODO: should we track? } void XdgImporterUnstableV2Interface::Private::unbind(wl_resource *resource) { Q_UNUSED(resource) // TODO: implement? } class Q_DECL_HIDDEN XdgExportedUnstableV2Interface::Private : public Resource::Private { public: Private(XdgExportedUnstableV2Interface *q, XdgExporterUnstableV2Interface *c, wl_resource *parentResource); ~Private(); private: XdgExportedUnstableV2Interface *q_func() { return reinterpret_cast(q); } static const struct zxdg_exported_v2_interface s_interface; }; #ifndef K_DOXYGEN const struct zxdg_exported_v2_interface XdgExportedUnstableV2Interface::Private::s_interface = { resourceDestroyedCallback }; #endif XdgExportedUnstableV2Interface::XdgExportedUnstableV2Interface(XdgExporterUnstableV2Interface *parent, wl_resource *parentResource) : Resource(new Private(this, parent, parentResource)) { } XdgExportedUnstableV2Interface::~XdgExportedUnstableV2Interface() {} XdgExportedUnstableV2Interface::Private *XdgExportedUnstableV2Interface::d_func() const { return reinterpret_cast(d.data()); } XdgExportedUnstableV2Interface::Private::Private(XdgExportedUnstableV2Interface *q, XdgExporterUnstableV2Interface *c, wl_resource *parentResource) : Resource::Private(q, c, parentResource, &zxdg_exported_v2_interface, &s_interface) { } XdgExportedUnstableV2Interface::Private::~Private() {} class Q_DECL_HIDDEN XdgImportedUnstableV2Interface::Private : public Resource::Private { public: Private(XdgImportedUnstableV2Interface *q, XdgImporterUnstableV2Interface *c, wl_resource *parentResource); ~Private(); QPointer parentOf; private: static void setParentOfCallback(wl_client *client, wl_resource *resource, wl_resource * surface); XdgImportedUnstableV2Interface *q_func() { return reinterpret_cast(q); } static const struct zxdg_imported_v2_interface s_interface; }; #ifndef K_DOXYGEN const struct zxdg_imported_v2_interface XdgImportedUnstableV2Interface::Private::s_interface = { resourceDestroyedCallback, setParentOfCallback }; #endif XdgImportedUnstableV2Interface::XdgImportedUnstableV2Interface(XdgImporterUnstableV2Interface *parent, wl_resource *parentResource) : Resource(new Private(this, parent, parentResource)) { } XdgImportedUnstableV2Interface::~XdgImportedUnstableV2Interface() {} XdgImportedUnstableV2Interface::Private *XdgImportedUnstableV2Interface::d_func() const { return reinterpret_cast(d.data()); } SurfaceInterface *XdgImportedUnstableV2Interface::child() const { Q_D(); return d->parentOf.data(); } void XdgImportedUnstableV2Interface::Private::setParentOfCallback(wl_client *client, wl_resource *resource, wl_resource * surface) { Q_UNUSED(client) auto s = cast(resource); SurfaceInterface *surf = SurfaceInterface::get(surface); if (!surf) { return; } s->parentOf = surf; emit s->q_func()->childChanged(surf); } XdgImportedUnstableV2Interface::Private::Private(XdgImportedUnstableV2Interface *q, XdgImporterUnstableV2Interface *c, wl_resource *parentResource) : Resource::Private(q, c, parentResource, &zxdg_imported_v2_interface, &s_interface) { } XdgImportedUnstableV2Interface::Private::~Private() {} } }