File indexing completed on 2024-05-19 16:35:32

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