File indexing completed on 2024-11-10 04:57:37

0001 /*
0002     SPDX-FileCopyrightText: 2017 Marco Martin <notmart@gmail.com>
0003     SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
0004     SPDX-FileCopyrightText: 2023 Kai Uwe Broulik <kde@broulik.de>
0005 
0006     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0007 */
0008 
0009 #include "display.h"
0010 #include "xdgforeign_v2_p.h"
0011 
0012 #include <QUuid>
0013 
0014 namespace KWin
0015 {
0016 static const quint32 s_exporterVersion = 1;
0017 static const quint32 s_importerVersion = 1;
0018 
0019 XdgExportedSurface::XdgExportedSurface(SurfaceInterface *surface)
0020     : QObject()
0021     , m_handle(QUuid::createUuid().toString(QUuid::WithoutBraces))
0022     , m_surface(surface)
0023 {
0024     connect(m_surface, &QObject::destroyed, this, &XdgExportedSurface::handleSurfaceDestroyed);
0025 }
0026 
0027 QString XdgExportedSurface::handle() const
0028 {
0029     return m_handle;
0030 }
0031 
0032 SurfaceInterface *XdgExportedSurface::surface() const
0033 {
0034     return m_surface;
0035 }
0036 
0037 void XdgExportedSurface::handleSurfaceDestroyed()
0038 {
0039     delete this;
0040 }
0041 
0042 XdgForeignV2InterfacePrivate::XdgForeignV2InterfacePrivate(Display *display, XdgForeignV2Interface *_q)
0043     : q(_q)
0044     , exporter(new XdgExporterV2Interface(display, _q))
0045     , importer(new XdgImporterV2Interface(display, _q))
0046 {
0047 }
0048 
0049 XdgForeignV2Interface::XdgForeignV2Interface(Display *display, QObject *parent)
0050     : QObject(parent)
0051     , d(new XdgForeignV2InterfacePrivate(display, this))
0052 {
0053 }
0054 
0055 XdgForeignV2Interface::~XdgForeignV2Interface()
0056 {
0057 }
0058 
0059 SurfaceInterface *XdgForeignV2Interface::transientFor(SurfaceInterface *surface)
0060 {
0061     return d->importer->transientFor(surface);
0062 }
0063 
0064 XdgExportedSurface *XdgForeignV2Interface::exportSurface(SurfaceInterface *surface)
0065 {
0066     return d->exporter->exportSurface(surface);
0067 }
0068 
0069 XdgExporterV2Interface::XdgExporterV2Interface(Display *display, XdgForeignV2Interface *foreign)
0070     : QObject(foreign)
0071     , QtWaylandServer::zxdg_exporter_v2(*display, s_exporterVersion)
0072 {
0073 }
0074 
0075 XdgExportedSurface *XdgExporterV2Interface::exportedSurface(const QString &handle) const
0076 {
0077     return m_exportedSurfaces.value(handle);
0078 }
0079 
0080 XdgExportedSurface *XdgExporterV2Interface::exportSurface(SurfaceInterface *surface)
0081 {
0082     auto *exported = new XdgExportedSurface(surface);
0083     addExported(exported);
0084     return exported;
0085 }
0086 
0087 void XdgExporterV2Interface::addExported(XdgExportedSurface *exported)
0088 {
0089     const QString handle = exported->handle();
0090     connect(exported, &XdgExportedSurface::destroyed, this, [this, handle] {
0091         m_exportedSurfaces.remove(handle);
0092     });
0093     m_exportedSurfaces[handle] = exported;
0094 }
0095 
0096 void XdgExporterV2Interface::zxdg_exporter_v2_destroy(Resource *resource)
0097 {
0098     wl_resource_destroy(resource->handle);
0099 }
0100 
0101 void XdgExporterV2Interface::zxdg_exporter_v2_export_toplevel(Resource *resource, uint32_t id, wl_resource *surface_resource)
0102 {
0103     SurfaceInterface *surface = SurfaceInterface::get(surface_resource);
0104     if (!surface) {
0105         wl_resource_post_error(resource->handle, 0, "Invalid  surface");
0106         return;
0107     }
0108 
0109     wl_resource *exportedResource = wl_resource_create(resource->client(), &zxdg_exported_v2_interface, resource->version(), id);
0110     if (!exportedResource) {
0111         wl_client_post_no_memory(resource->client());
0112         return;
0113     }
0114 
0115     XdgExportedV2Interface *exported = new XdgExportedV2Interface(surface, exportedResource);
0116     addExported(exported);
0117 
0118     exported->send_handle(exported->handle());
0119 }
0120 
0121 XdgImporterV2Interface::XdgImporterV2Interface(Display *display, XdgForeignV2Interface *foreign)
0122     : QObject(foreign)
0123     , QtWaylandServer::zxdg_importer_v2(*display, s_importerVersion)
0124     , m_foreign(foreign)
0125 {
0126 }
0127 
0128 SurfaceInterface *XdgImporterV2Interface::transientFor(SurfaceInterface *surface)
0129 {
0130     auto it = m_parents.constFind(surface);
0131     if (it == m_parents.constEnd()) {
0132         return nullptr;
0133     }
0134     return (*it)->surface();
0135 }
0136 
0137 void XdgImporterV2Interface::zxdg_importer_v2_destroy(Resource *resource)
0138 {
0139     wl_resource_destroy(resource->handle);
0140 }
0141 
0142 void XdgImporterV2Interface::zxdg_importer_v2_import_toplevel(Resource *resource, uint32_t id, const QString &handle)
0143 {
0144     wl_resource *importedResource = wl_resource_create(resource->client(), &zxdg_imported_v2_interface, resource->version(), id);
0145     if (!importedResource) {
0146         wl_client_post_no_memory(resource->client());
0147         return;
0148     }
0149 
0150     // If there is no exported surface with the specified handle, we must still create an
0151     // inert xdg_imported object and send the destroyed event right afterwards.
0152     XdgExportedSurface *exported = m_foreign->d->exporter->exportedSurface(handle);
0153     if (!exported) {
0154         auto imported = new XdgDummyImportedV2Interface(importedResource);
0155         imported->send_destroyed();
0156         return;
0157     }
0158 
0159     XdgImportedV2Interface *imported = new XdgImportedV2Interface(exported, importedResource);
0160 
0161     connect(imported, &XdgImportedV2Interface::childChanged, this, [this, imported](SurfaceInterface *child) {
0162         link(imported, child);
0163 
0164         // child surface destroyed
0165         connect(child, &QObject::destroyed, this, [this, child]() {
0166             unlink(nullptr, child);
0167         });
0168     });
0169 
0170     // surface no longer imported
0171     connect(imported, &XdgImportedV2Interface::destroyed, this, [this, imported]() {
0172         unlink(imported, nullptr);
0173     });
0174 }
0175 
0176 void XdgImporterV2Interface::link(XdgImportedV2Interface *parent, SurfaceInterface *child)
0177 {
0178     // remove any previous association
0179     auto it = m_children.find(parent);
0180     if (it != m_children.end()) {
0181         m_parents.remove(*it);
0182         m_children.erase(it);
0183     }
0184 
0185     m_parents[child] = parent;
0186     m_children[parent] = child;
0187 
0188     Q_EMIT m_foreign->transientChanged(child, parent->surface());
0189 }
0190 
0191 void XdgImporterV2Interface::unlink(XdgImportedV2Interface *parent, SurfaceInterface *child)
0192 {
0193     if (parent) {
0194         // If the parent endpoint is unlinked, the transientChanged() signal will indicate
0195         // the orphaned child.
0196         auto it = m_children.find(parent);
0197         if (it != m_children.end()) {
0198             SurfaceInterface *child = *it;
0199             m_parents.remove(*it);
0200             m_children.erase(it);
0201             Q_EMIT m_foreign->transientChanged(child, nullptr);
0202         }
0203     } else if (child) {
0204         // If the child endpoint is unlinked, the transientChanged() signal will indicate
0205         // what parent has lost a child.
0206         auto it = m_parents.find(child);
0207         if (it != m_parents.end()) {
0208             XdgImportedV2Interface *parent = *it;
0209             m_children.remove(*it);
0210             m_parents.erase(it);
0211             Q_EMIT m_foreign->transientChanged(nullptr, parent->surface());
0212         }
0213     }
0214 }
0215 
0216 XdgExportedV2Interface::XdgExportedV2Interface(SurfaceInterface *surface, wl_resource *resource)
0217     : XdgExportedSurface(surface)
0218     , QtWaylandServer::zxdg_exported_v2(resource)
0219 {
0220 }
0221 
0222 void XdgExportedV2Interface::zxdg_exported_v2_destroy(Resource *resource)
0223 {
0224     wl_resource_destroy(resource->handle);
0225 }
0226 
0227 void XdgExportedV2Interface::zxdg_exported_v2_destroy_resource(Resource *resource)
0228 {
0229     delete this;
0230 }
0231 
0232 XdgDummyImportedV2Interface::XdgDummyImportedV2Interface(wl_resource *resource)
0233     : QtWaylandServer::zxdg_imported_v2(resource)
0234 {
0235 }
0236 
0237 void XdgDummyImportedV2Interface::zxdg_imported_v2_destroy(Resource *resource)
0238 {
0239     wl_resource_destroy(resource->handle);
0240 }
0241 
0242 void XdgDummyImportedV2Interface::zxdg_imported_v2_destroy_resource(Resource *resource)
0243 {
0244     delete this;
0245 }
0246 
0247 XdgImportedV2Interface::XdgImportedV2Interface(XdgExportedSurface *exported, wl_resource *resource)
0248     : QtWaylandServer::zxdg_imported_v2(resource)
0249     , m_exported(exported)
0250 {
0251     connect(exported, &XdgExportedSurface::destroyed, this, &XdgImportedV2Interface::handleExportedDestroyed);
0252 }
0253 
0254 SurfaceInterface *XdgImportedV2Interface::child() const
0255 {
0256     return m_child;
0257 }
0258 
0259 SurfaceInterface *XdgImportedV2Interface::surface() const
0260 {
0261     return m_exported->surface();
0262 }
0263 
0264 void XdgImportedV2Interface::zxdg_imported_v2_set_parent_of(Resource *resource, wl_resource *surface)
0265 {
0266     SurfaceInterface *surf = SurfaceInterface::get(surface);
0267 
0268     if (!surf) {
0269         return;
0270     }
0271 
0272     m_child = surf;
0273     Q_EMIT childChanged(surf);
0274 }
0275 
0276 void XdgImportedV2Interface::zxdg_imported_v2_destroy(Resource *resource)
0277 {
0278     wl_resource_destroy(resource->handle);
0279 }
0280 
0281 void XdgImportedV2Interface::zxdg_imported_v2_destroy_resource(Resource *resource)
0282 {
0283     delete this;
0284 }
0285 
0286 void XdgImportedV2Interface::handleExportedDestroyed()
0287 {
0288     send_destroyed();
0289     delete this;
0290 }
0291 
0292 }
0293 
0294 #include "moc_xdgforeign_v2.cpp"
0295 #include "moc_xdgforeign_v2_p.cpp"