#include "protocols/XDGForeignV2.hpp" #include "managers/TokenManager.hpp" #include "protocols/XDGShell.hpp" #include "xdg-foreign-unstable-v2.hpp" #include #include #include #include #include #include #include "protocols/core/Compositor.hpp" CXDGExportedResourceV2::CXDGExportedResourceV2(SP resource, SP toplevel, const std::string& handle) : m_resource(resource), m_toplevel(toplevel), m_handle(handle) { if UNLIKELY (!good()) return; m_resource->setData(this); m_resource->sendHandle(handle.c_str()); m_listeners.topLevelDestroyed = toplevel->m_events.destroy.listen([this] { m_topLevelDestroyed = true; m_listeners.topLevelDestroyed.reset(); m_events.destroy.emit(); }); m_resource->setOnDestroy([this](CZxdgExportedV2*) { PROTO::xdgForeignExporter->destroyExported(this); }); m_resource->setDestroy([this](CZxdgExportedV2*) { PROTO::xdgForeignExporter->destroyExported(this); }); } CXDGExportedResourceV2::~CXDGExportedResourceV2() { if (!m_topLevelDestroyed) m_events.destroy.emit(); } bool CXDGExportedResourceV2::good() const { return m_resource->resource(); } WP CXDGExportedResourceV2::xdgSurf() const { return m_toplevel; } std::string_view CXDGExportedResourceV2::handle() const { return m_handle; } CXDGForeignExporterProtocolV2::CXDGForeignExporterProtocolV2(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) {} static SP xdgToplevelFromWlSurface(wl_resource* surface) { const auto wlSurf = CWLSurfaceResource::fromResource(surface); if (!wlSurf || !wlSurf->m_role || wlSurf->m_role->role() != SURFACE_ROLE_XDG_SHELL) return nullptr; const auto xdgSurfResource = sc(wlSurf->m_role.get())->m_xdgSurface.lock(); if (!xdgSurfResource || xdgSurfResource->m_toplevel.expired()) return nullptr; return xdgSurfResource->m_toplevel.lock(); } void CXDGForeignExporterProtocolV2::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { const auto RESOURCE = m_exporters.emplace_back(makeUnique(client, ver, id)).get(); if UNLIKELY (!RESOURCE->resource()) { wl_client_post_no_memory(client); m_exporters.pop_back(); return; } RESOURCE->setExportToplevel([this](CZxdgExporterV2* exporter, uint32_t id, wl_resource* surface) { auto TOPLEVEL = xdgToplevelFromWlSurface(surface); if (!TOPLEVEL) { exporter->error(zxdgExporterV2Error::ZXDG_EXPORTER_V2_ERROR_INVALID_SURFACE, "surface must be an xdg_toplevel"); return; } const std::string HANDLE = g_pTokenManager->getRandomUUID(); const auto [ELM, EMPLACED] = m_exported.emplace(HANDLE, makeShared(makeShared(exporter->client(), exporter->version(), id), TOPLEVEL, HANDLE)); // This should only happen if we have our generated handles collide. if UNLIKELY (!EMPLACED) { wl_client_post_no_memory(exporter->client()); return; } if UNLIKELY (!ELM->second->good()) { wl_client_post_no_memory(exporter->client()); destroyExported(ELM->second.get()); } }); RESOURCE->setDestroy([this](CZxdgExporterV2* e) { onExporterDestroyed(e); }); RESOURCE->setOnDestroy([this](CZxdgExporterV2* e) { onExporterDestroyed(e); }); } SP CXDGForeignExporterProtocolV2::getExported(const std::string& handle) const { return m_exported.contains(handle) ? m_exported.at(handle) : nullptr; } void CXDGForeignExporterProtocolV2::onExporterDestroyed(CZxdgExporterV2* exporter) { std::erase_if(m_exporters, [exporter](const auto& other) { return exporter == other.get(); }); } void CXDGForeignExporterProtocolV2::destroyExported(CXDGExportedResourceV2* r) { PROTO::xdgForeignExporter->m_exported.erase(r->m_handle); } CXDGImportedResourceV2::CXDGImportedResourceV2(SP imported, SP exported, const std::string& handle) : m_resource(imported), m_exported(exported), m_handle(handle) { if UNLIKELY (!good()) return; m_resource->setData(this); m_resource->setSetParentOf([this](CZxdgImportedV2* r, wl_resource* surf) { if (m_invalid) return; const auto CHILDTOPLEVEL = xdgToplevelFromWlSurface(surf); if (!CHILDTOPLEVEL) { m_resource->error(zxdgImportedV2Error::ZXDG_IMPORTED_V2_ERROR_INVALID_SURFACE, "surface must be an xdg_toplevel"); return; } if LIKELY (auto exportedTopLevel = m_exported->xdgSurf(); !exportedTopLevel.expired()) CHILDTOPLEVEL->setNewParent(exportedTopLevel.lock()); }); if (exported) m_listeners.exportedDestroyed = exported->m_events.destroy.listen([this]() { invalidate(); }); m_resource->setDestroy([this](CZxdgImportedV2*) { PROTO::xdgForeignImporter->destroyImported(this); }); m_resource->setOnDestroy([this](CZxdgImportedV2*) { PROTO::xdgForeignImporter->destroyImported(this); }); if (m_exported.expired()) invalidate(); } CXDGImportedResourceV2::~CXDGImportedResourceV2() {} bool CXDGImportedResourceV2::good() const { return m_resource->resource(); } void CXDGImportedResourceV2::invalidate() { if (m_invalid) return; m_invalid = true; if (!m_destroyedSent && m_resource && m_resource->resource()) { m_destroyedSent = true; m_resource->sendDestroyed(); } } CXDGForeignImporterProtocolV2::CXDGForeignImporterProtocolV2(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { ; } void CXDGForeignImporterProtocolV2::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { const auto RESOURCE = m_importers.emplace_back(makeUnique(client, ver, id)).get(); if UNLIKELY (!RESOURCE->resource()) { wl_client_post_no_memory(client); m_importers.pop_back(); return; } RESOURCE->setImportToplevel([this](CZxdgImporterV2* importer, uint32_t id, const char* _handle) { const std::string HANDLE = _handle; auto exported = PROTO::xdgForeignExporter->getExported(HANDLE); auto imported = m_imports.emplace_back(makeUnique(makeShared(importer->client(), importer->version(), id), exported, HANDLE)).get(); if UNLIKELY (!imported->good()) { wl_client_post_no_memory(importer->client()); m_imports.pop_back(); return; } }); RESOURCE->setDestroy([this](CZxdgImporterV2* r) { onImporterDestroyed(r); }); RESOURCE->setOnDestroy([this](CZxdgImporterV2* r) { onImporterDestroyed(r); }); } void CXDGForeignImporterProtocolV2::onImporterDestroyed(CZxdgImporterV2* importer) { std::erase_if(m_importers, [importer](const auto& other) { return importer == other.get(); }); } void CXDGForeignImporterProtocolV2::destroyImported(CXDGImportedResourceV2* imported) { std::erase_if(m_imports, [imported](const auto& other) { return imported == other.get(); }); }