--- a/src/portals/Screencopy.cpp +++ b/src/portals/Screencopy.cpp @@ -625,6 +625,19 @@ return m_sState.toplevel; } +// A shared window went away: close its sessions like other portals do, so the +// app's track ends instead of streaming the last frame forever. +void CScreencopyPortal::onToplevelClosed(CCZwlrForeignToplevelHandleV1* handle) { + for (auto& s : m_vSessions) { + if (!s->session || s->selection.type != TYPE_WINDOW || s->selection.windowHandle.get() != handle) + continue; + + Debug::log(LOG, "[screencopy] Shared window closed, closing session {}", s->sessionHandle.c_str()); + s->session->object->emitSignal("Closed").onInterface(sdbus::InterfaceName{"org.freedesktop.impl.portal.Session"}); + s->session->onDestroy(); + } +} + CScreencopyPortal::SSession* CScreencopyPortal::getSession(sdbus::ObjectPath& path) { for (auto& s : m_vSessions) { if (s->sessionHandle == path) --- a/src/portals/Screencopy.hpp +++ b/src/portals/Screencopy.hpp @@ -113,6 +113,7 @@ void startFrameCopy(SSession* pSession); void queueNextShareFrame(SSession* pSession); bool hasToplevelCapabilities(); + void onToplevelClosed(CCZwlrForeignToplevelHandleV1* handle); std::unique_ptr m_pPipewire; --- a/src/shared/ToplevelManager.cpp +++ b/src/shared/ToplevelManager.cpp @@ -18,6 +18,9 @@ handle->setClosed([this](CCZwlrForeignToplevelHandleV1* r) { Debug::log(TRACE, "[toplevel] toplevel at {} closed", (void*)this); + if (g_pPortalManager->m_sPortals.screencopy) + g_pPortalManager->m_sPortals.screencopy->onToplevelClosed(r); + std::erase_if(g_pPortalManager->m_sHelpers.toplevel->m_vToplevels, [&](const auto& e) { return e.get() == this; }); if (g_pPortalManager->m_sHelpers.toplevelMapping) g_pPortalManager->m_sHelpers.toplevelMapping->m_muAddresses.erase(this->handle);