diff --git a/src/server/xdgforeign_v2_interface.cpp b/src/server/xdgforeign_v2_interface.cpp index 645ebb7..4f296ab 100644 --- a/src/server/xdgforeign_v2_interface.cpp +++ b/src/server/xdgforeign_v2_interface.cpp @@ -1,462 +1,466 @@ /**************************************************************************** Copyright 2017 Marco Martin This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . ****************************************************************************/ #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 DOXYGEN_SHOULD_SKIP_THIS 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 DOXYGEN_SHOULD_SKIP_THIS 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 DOXYGEN_SHOULD_SKIP_THIS 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 DOXYGEN_SHOULD_SKIP_THIS 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() {} } } diff --git a/src/server/xdgoutput_interface.cpp b/src/server/xdgoutput_interface.cpp index 82c9dfd..7794021 100644 --- a/src/server/xdgoutput_interface.cpp +++ b/src/server/xdgoutput_interface.cpp @@ -1,307 +1,307 @@ /**************************************************************************** Copyright 2018 David Edmundson This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . ****************************************************************************/ #include "xdgoutput_interface.h" #include "display.h" #include "global_p.h" #include "resource_p.h" #include "output_interface.h" #include namespace KWayland { namespace Server { class XdgOutputManagerInterface::Private : public Global::Private { public: Private(XdgOutputManagerInterface *q, Display *d); QHash outputs; 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 getXdgOutputCallback(wl_client *client, wl_resource *resource, uint32_t id, wl_resource * output); XdgOutputManagerInterface *q; static const struct zxdg_output_manager_v1_interface s_interface; static const quint32 s_version; }; const quint32 XdgOutputManagerInterface::Private::s_version = 1; #ifndef DOXYGEN_SHOULD_SKIP_THIS const struct zxdg_output_manager_v1_interface XdgOutputManagerInterface::Private::s_interface = { destroyCallback, getXdgOutputCallback }; #endif class XdgOutputV1Interface: public Resource { public: XdgOutputV1Interface(XdgOutputManagerInterface *parent, wl_resource *parentResource); ~XdgOutputV1Interface(); void setLogicalSize(const QSize &size); void setLogicalPosition(const QPoint &pos); void done(); private: class Private; }; class XdgOutputInterface::Private { public: void resourceConnected(XdgOutputV1Interface *resource); void resourceDisconnected(XdgOutputV1Interface *resource); QPoint pos; QSize size; bool doneOnce = false; QList resources; }; XdgOutputManagerInterface::XdgOutputManagerInterface(Display *display, QObject *parent) - : Global(new XdgOutputManagerInterface::Private(this, display)) + : Global(new XdgOutputManagerInterface::Private(this, display), parent) { } XdgOutputManagerInterface::~XdgOutputManagerInterface() {} XdgOutputInterface* XdgOutputManagerInterface::createXdgOutput(OutputInterface *output, QObject *parent) { Q_D(); if (!d->outputs.contains(output)) { auto xdgOutput = new XdgOutputInterface(parent); d->outputs[output] = xdgOutput; //as XdgOutput lifespan is managed by user, delete our mapping when either //it or the relevant Output gets deleted connect(output, &QObject::destroyed, this, [this, output]() { Q_D(); d->outputs.remove(output); }); connect(xdgOutput, &QObject::destroyed, this, [this, output]() { Q_D(); d->outputs.remove(output); }); } return d->outputs[output]; } XdgOutputManagerInterface::Private* XdgOutputManagerInterface::d_func() const { return reinterpret_cast(d.data()); } void XdgOutputManagerInterface::Private::destroyCallback(wl_client *client, wl_resource *resource) { Q_UNUSED(client) wl_resource_destroy(resource); } void XdgOutputManagerInterface::Private::getXdgOutputCallback(wl_client *client, wl_resource *resource, uint32_t id, wl_resource * outputResource) { auto d = cast(resource); auto output = OutputInterface::get(outputResource); if (!output) { // output client is requesting XdgOutput for an Output that doesn't exist return; } if (!d->outputs.contains(output)) { return; //server hasn't created an XdgOutput for this output yet, give the client nothing } auto iface = new XdgOutputV1Interface(d->q, resource); iface->create(d->display->getConnection(client), wl_resource_get_version(resource), id); if (!iface->resource()) { wl_resource_post_no_memory(resource); delete iface; return; } auto xdgOutput = d->outputs[output]; xdgOutput->d->resourceConnected(iface); connect(iface, &XdgOutputV1Interface::unbound, xdgOutput, [xdgOutput, iface]() { xdgOutput->d->resourceDisconnected(iface); }); } XdgOutputManagerInterface::Private::Private(XdgOutputManagerInterface *q, Display *d) : Global::Private(d, &zxdg_output_manager_v1_interface, s_version) , q(q) { } void XdgOutputManagerInterface::Private::bind(wl_client *client, uint32_t version, uint32_t id) { auto c = display->getConnection(client); wl_resource *resource = c->createResource(&zxdg_output_manager_v1_interface, qMin(version, s_version), id); if (!resource) { wl_client_post_no_memory(client); return; } wl_resource_set_implementation(resource, &s_interface, this, unbind); } void XdgOutputManagerInterface::Private::unbind(wl_resource *resource) { Q_UNUSED(resource) } XdgOutputInterface::XdgOutputInterface(QObject *parent): QObject(parent), d(new XdgOutputInterface::Private) { } XdgOutputInterface::~XdgOutputInterface() {} void XdgOutputInterface::setLogicalSize(const QSize &size) { if (size == d->size) { return; } d->size = size; for(auto resource: d->resources) { resource->setLogicalSize(size); } } QSize XdgOutputInterface::logicalSize() const { return d->size; } void XdgOutputInterface::setLogicalPosition(const QPoint &pos) { if (pos == d->pos) { return; } d->pos = pos; for(auto resource: d->resources) { resource->setLogicalPosition(pos); } } QPoint XdgOutputInterface::logicalPosition() const { return d->pos; } void XdgOutputInterface::done() { d->doneOnce = true; for(auto resource: d->resources) { resource->done(); } } void XdgOutputInterface::Private::resourceConnected(XdgOutputV1Interface *resource) { resource->setLogicalPosition(pos); resource->setLogicalSize(size); if (doneOnce) { resource->done(); } resources << resource; } void XdgOutputInterface::Private::resourceDisconnected(XdgOutputV1Interface *resource) { resources.removeOne(resource); } class XdgOutputV1Interface::Private : public Resource::Private { public: Private(XdgOutputV1Interface *q, XdgOutputManagerInterface *c, wl_resource *parentResource); ~Private(); private: XdgOutputV1Interface *q_func() { return reinterpret_cast(q); } static const struct zxdg_output_v1_interface s_interface; }; XdgOutputV1Interface::XdgOutputV1Interface(XdgOutputManagerInterface *parent, wl_resource *parentResource) :Resource(new XdgOutputV1Interface::Private(this, parent, parentResource)) {} XdgOutputV1Interface::~XdgOutputV1Interface() {} void XdgOutputV1Interface::setLogicalSize(const QSize &size) { if (!d->resource) { return; } zxdg_output_v1_send_logical_size(d->resource, size.width(), size.height()); } void XdgOutputV1Interface::setLogicalPosition(const QPoint &pos) { if (!d->resource) { return; } zxdg_output_v1_send_logical_position(d->resource, pos.x(), pos.y()); } void XdgOutputV1Interface::done() { if (!d->resource) { return; } zxdg_output_v1_send_done(d->resource); } #ifndef DOXYGEN_SHOULD_SKIP_THIS const struct zxdg_output_v1_interface XdgOutputV1Interface::Private::s_interface = { resourceDestroyedCallback }; #endif XdgOutputV1Interface::Private::Private(XdgOutputV1Interface *q, XdgOutputManagerInterface *c, wl_resource *parentResource) : Resource::Private(q, c, parentResource, &zxdg_output_v1_interface, &s_interface) { } XdgOutputV1Interface::Private::~Private() { if (resource) { wl_resource_destroy(resource); resource = nullptr; } } } }