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"