From 94697c1af004980a71a7902aa84058e3c29a69e4 Mon Sep 17 00:00:00 2001 From: evgeny Date: Tue, 20 Oct 2026 16:27:17 +0200 Subject: [PATCH] Preserve desktop catalogue watches across chat selection --- tools/chatgui/transport/stream_bridge.cpp | 34 ++++++++++++++--------- tools/chatgui/transport/stream_bridge.h | 3 +- 2 files changed, 23 insertions(+), 14 deletions(-) diff --git a/tools/chatgui/transport/stream_bridge.cpp b/tools/chatgui/transport/stream_bridge.cpp index 13c1f7b8..e68d1532 100644 --- a/tools/chatgui/transport/stream_bridge.cpp +++ b/tools/chatgui/transport/stream_bridge.cpp @@ -1,5 +1,7 @@ #include "stream_bridge.h" #include +#include +#include extern "C" { #include "../../../lib/debug_config.h" @@ -15,17 +17,22 @@ struct Bridge { std::mutex lock; // Ограничивает lifetime managers для callers GUI/workers. UTUN_INSTANCE* inst = nullptr; posted_task* pending = nullptr; - uint64_t watch = 0; - bool watchPending = false; + std::map watches; + std::set watchChanges; stream_viewers* viewers = nullptr; stream_publisher* publisher = nullptr; } bridge; void watch(void*) { std::lock_guard guard(bridge.lock); - bridge.pending = nullptr; bridge.watchPending = false; - if (stream_watch_sources(bridge.inst, bridge.watch) != STREAM_OK) - DEBUG_ERROR(DEBUG_CATEGORY_STREAM, "desktop source watch failed group=%llx", (unsigned long long)bridge.watch); + bridge.pending = nullptr; + for (auto owner : bridge.watchChanges) { + uint64_t group = bridge.watches.at(owner); + if (stream_watch_sources(bridge.inst, group, owner) != STREAM_OK) + DEBUG_ERROR(DEBUG_CATEGORY_STREAM, "desktop source watch failed group=%llx", (unsigned long long)group); + if (!group) bridge.watches.erase(owner); + } + bridge.watchChanges.clear(); } } @@ -39,11 +46,11 @@ bool gui_stream_attach(UTUN_INSTANCE* inst) { stream_publisher_destroy(bridge.publisher); bridge.publisher = nullptr; return false; } bridge.inst = inst; - if (bridge.watchPending) { - bridge.watchPending = false; - if (stream_watch_sources(inst, bridge.watch) != STREAM_OK) - DEBUG_ERROR(DEBUG_CATEGORY_STREAM, "desktop initial source watch failed group=%llx", (unsigned long long)bridge.watch); + for (const auto& [owner, group] : bridge.watches) { + if (stream_watch_sources(inst, group, owner) != STREAM_OK) + DEBUG_ERROR(DEBUG_CATEGORY_STREAM, "desktop initial source watch failed group=%llx", (unsigned long long)group); } + bridge.watchChanges.clear(); DEBUG_INFO(DEBUG_CATEGORY_STREAM, "desktop stream bridge attached"); return true; } @@ -51,14 +58,15 @@ void gui_stream_detach(UTUN_INSTANCE* inst) { std::lock_guard guard(bridge.lock); if (!inst || bridge.inst != inst) return; if (bridge.pending) uasync_cancel_post(inst->ua, bridge.pending); - stream_watch_sources(inst, 0); bridge.pending = nullptr; + for (const auto& [owner, group] : bridge.watches) stream_watch_sources(inst, 0, owner); + bridge.pending = nullptr; stream_viewers_destroy(bridge.viewers); bridge.viewers = nullptr; stream_publisher_destroy(bridge.publisher); bridge.publisher = nullptr; - bridge.inst = nullptr; bridge.watchPending = bridge.watch != 0; + bridge.inst = nullptr; bridge.watchChanges.clear(); DEBUG_INFO(DEBUG_CATEGORY_STREAM, "desktop stream bridge detached"); } -bool gui_stream_watch(uint64_t group) { +bool gui_stream_watch(uint64_t group, uint64_t owner) { std::lock_guard guard(bridge.lock); if (bridge.inst && !bridge.pending) { auto* task = static_cast(u_calloc(1, sizeof(posted_task))); @@ -66,7 +74,7 @@ bool gui_stream_watch(uint64_t group) { task->callback = watch; bridge.pending = task; uasync_post_reserved(bridge.inst->ua, task); } - bridge.watch = group; bridge.watchPending = true; return true; + bridge.watches[owner] = group; bridge.watchChanges.insert(owner); return true; } bool gui_stream_open(uint64_t id, uint64_t group, uint64_t source, uint64_t epoch) { diff --git a/tools/chatgui/transport/stream_bridge.h b/tools/chatgui/transport/stream_bridge.h index 6cfc284f..5c92a8ed 100644 --- a/tools/chatgui/transport/stream_bridge.h +++ b/tools/chatgui/transport/stream_bridge.h @@ -23,7 +23,8 @@ struct StreamRecord { bool gui_stream_attach(UTUN_INSTANCE* inst); void gui_stream_detach(UTUN_INSTANCE* inst); -bool gui_stream_watch(uint64_t group); +/* owner=0 — выбранный чат; окно многопросмотра держит свой ненулевой owner. group=0 снимает только его. */ +bool gui_stream_watch(uint64_t group, uint64_t owner = 0); bool gui_stream_open(uint64_t id, uint64_t group, uint64_t source, uint64_t epoch); void gui_stream_stop(uint64_t id); bool gui_stream_pull(uint64_t id, StreamRecord& record, int64_t position = -1,