diff --git a/patches/xdph-close-session-on-window-close.patch b/patches/xdph-close-session-on-window-close.patch new file mode 100644 index 0000000..f128d8d --- /dev/null +++ b/patches/xdph-close-session-on-window-close.patch @@ -0,0 +1,44 @@ +--- 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); diff --git a/settings/hyprland.nix b/settings/hyprland.nix index 13a60bb..bcfe3b7 100644 --- a/settings/hyprland.nix +++ b/settings/hyprland.nix @@ -11,6 +11,11 @@ in programs.hyprland = { enable = true; xwayland.enable = true; + # Closing a window that's being shared ends the share (Discord stops the + # stream) instead of streaming its last frame forever. + portalPackage = pkgs.xdg-desktop-portal-hyprland.overrideAttrs (old: { + patches = (old.patches or [ ]) ++ [ ../patches/xdph-close-session-on-window-close.patch ]; + }); }; # Let Hyprland show the session menu for a short power-key press instead