From c604d629174fa8c44ca9e90f5abf2b52df065c4f Mon Sep 17 00:00:00 2001 From: Martino Ferrari Date: Sun, 4 Oct 2026 00:04:52 +0200 Subject: [PATCH] session file records how the source was reached A session is named _.toml, which cannot say whether that source was multicast or which interface it joined on, so a chooser row could not reconnect to one. Both go in the top block: a bare key after a [[table]] header belongs to that table, which is how the enabled key was lost once. --- src/layout_store.cpp | 9 +++++++++ src/layout_store.hpp | 6 ++++++ 2 files changed, 15 insertions(+) diff --git a/src/layout_store.cpp b/src/layout_store.cpp index c6fbcad..6ef03df 100644 --- a/src/layout_store.cpp +++ b/src/layout_store.cpp @@ -242,6 +242,10 @@ bool load_layout(const std::string& path, LayoutState& out) { plot_count = std::max(0, std::stoi(value)); } catch (...) { } + } else if (key == "multicast") { + st.multicast = strip_quote(value); + } else if (key == "interface") { + st.interface_addr = strip_quote(value); } } else if (section == Section::Plot && !st.rows.empty()) { if (key == "signals") { @@ -325,6 +329,11 @@ bool save_layout(const std::string& path, const LayoutState& state) { o << "# udpscope session layout (written by the app; safe to edit)\n"; if (state.window_s > 0.0) o << "window_s = " << state.window_s << "\n"; o << "plots = " << state.rows.size() << "\n"; + // Top level, before any table, for the same reason as `enabled` below. + if (!state.multicast.empty()) o << "multicast = " << toml_escape(state.multicast) << "\n"; + if (!state.interface_addr.empty()) { + o << "interface = " << toml_escape(state.interface_addr) << "\n"; + } // Top level, before any table. Emitted after the `[[calibration]]` tables it belonged to the last // of them -- a bare key after a header is that table's key in TOML -- so the parser, correctly, // never saw it and a session's enable state was silently lost. diff --git a/src/layout_store.hpp b/src/layout_store.hpp index b70bfd6..fa9f5c5 100644 --- a/src/layout_store.hpp +++ b/src/layout_store.hpp @@ -37,6 +37,12 @@ struct LayoutState { /// identity here, because a CONFIG renumbers the channels. std::vector enabled; + /// How this source was reached, so the startup chooser can reconnect to it exactly. The file is + /// named `_.toml` and that name can say neither of these. Empty `multicast` is + /// unicast; empty `interface_addr` is the default route. + std::string multicast; + std::string interface_addr; + /// The derived channels, graphs and all: the editor's work is part of the session, not of the /// process. A graph is stored as one string per node so the file stays in this store's TOML /// subset (tables, string arrays, scalars) rather than growing a nested-table parser for it; see