ask which source to open when --server is absent
The chooser runs before ScopeModel exists, so declining costs no buffer and no socket. UDPSCOPE_PROBE_SOURCES=1 prints what the discovery found and exits, before gtk_init(), so the list is checkable with no display.
This commit is contained in:
1 parent
9ae059db1b
commit
0be3feecc5
6 files changed
+91
No files matched your search
@@ -67,6 +67,7 @@ Config parse_args(int argc, char** argv) {
|
||||
std::exit(0);
|
||||
} else if (a == "--server" || a.rfind("--server=", 0) == 0) {
|
||||
c.server = value_of(argc, argv, i, "--server");
|
||||
c.server_specified = true;
|
||||
} else if (a == "--port" || a.rfind("--port=", 0) == 0) {
|
||||
const std::string v = value_of(argc, argv, i, "--port");
|
||||
const long p = std::strtol(v.c_str(), nullptr, 10);
|
||||
|
||||
@@ -16,6 +16,11 @@ struct Config {
|
||||
std::string multicast; ///< Empty selects unicast.
|
||||
std::string interface_addr; ///< Local IPv4 to join the group on; empty = default route.
|
||||
|
||||
/// Whether `--server` was given. Absent, the application asks which source to open rather
|
||||
/// than silently taking the default above -- so this is "did the user choose", not "is
|
||||
/// `server` valid". The default stays a usable value for every other path.
|
||||
bool server_specified = false;
|
||||
|
||||
/// Size of *each* of the two sample buffers, in megabytes. The application
|
||||
/// always allocates two identical buffers (spec item 1).
|
||||
double buffer_mb = 200.0;
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "config.hpp"
|
||||
#include "model.hpp"
|
||||
#include "plot_host.hpp"
|
||||
#include "source_dialog.hpp"
|
||||
#include "ui.hpp"
|
||||
|
||||
#include <cstdio>
|
||||
@@ -19,6 +20,10 @@ int main(int argc, char** argv) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
// No `--server` means the user has not said which source to open, so ask. Before the model:
|
||||
// declining must cost no buffer and no socket, and nothing below has to cope with "no source".
|
||||
if (!cfg.server_specified && !udpscope::choose_source(cfg)) return 0;
|
||||
|
||||
udpscope::ScopeModel model(cfg);
|
||||
udpscope::RowSet rows;
|
||||
rows.set_row_count(cfg.plots);
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// SPDX-FileCopyrightText: 2026 Martino Ferrari
|
||||
|
||||
#include "source_dialog.hpp"
|
||||
|
||||
#include "layout_store.hpp"
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace udpscope {
|
||||
namespace {
|
||||
|
||||
/// A chooser row's source becomes the connection to open. The interface comes along with the
|
||||
/// group: it is the local address the join happens on, so storing one without the other would
|
||||
/// reconnect to the right group on the wrong path.
|
||||
[[maybe_unused]] void apply_source(Config& cfg, const KnownSource& src) {
|
||||
cfg.server = src.host;
|
||||
cfg.port = src.port;
|
||||
cfg.multicast = src.multicast;
|
||||
cfg.interface_addr = src.interface_addr;
|
||||
}
|
||||
|
||||
/// One line per known source on stderr, in the style of the probes in `ui.cpp`.
|
||||
void report_sources(const std::vector<KnownSource>& known) {
|
||||
std::fprintf(stderr, "[sources] %zu known:", known.size());
|
||||
for (const KnownSource& s : known) {
|
||||
std::fprintf(stderr, " %s:%u plots=%d signals=%d", s.host.c_str(), s.port, s.rows, s.signals);
|
||||
if (!s.multicast.empty()) std::fprintf(stderr, " multicast=%s", s.multicast.c_str());
|
||||
if (!s.interface_addr.empty()) {
|
||||
std::fprintf(stderr, " interface=%s", s.interface_addr.c_str());
|
||||
}
|
||||
std::fprintf(stderr, " |");
|
||||
}
|
||||
std::fprintf(stderr, "\n");
|
||||
std::fflush(stderr);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool choose_source(Config& cfg) {
|
||||
const std::vector<KnownSource> known = known_sources();
|
||||
|
||||
// The discovery half, checkable with no display at all: this returns before `gtk_init()`, so
|
||||
// it asserts what the list found without needing an X server or a GL context. False means the
|
||||
// caller exits 0, which is what "list and exit" wants.
|
||||
if (g_getenv("UDPSCOPE_PROBE_SOURCES") != nullptr) {
|
||||
report_sources(known);
|
||||
return false;
|
||||
}
|
||||
|
||||
gtk_init();
|
||||
(void)cfg;
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace udpscope
|
||||
@@ -0,0 +1,19 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// SPDX-FileCopyrightText: 2026 Martino Ferrari
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "config.hpp"
|
||||
|
||||
namespace udpscope {
|
||||
|
||||
/// Asks which data source to open: a list of the sources with a stored session, and a form for a
|
||||
/// new one. Returns true with `cfg`'s connection fields filled in, or false if the user declined
|
||||
/// -- in which case `cfg` is untouched and the caller should exit.
|
||||
///
|
||||
/// Runs *before* `ScopeModel` exists, so declining costs no buffer and no socket. It drives its
|
||||
/// own `gtk_init()` and nested `GMainLoop`; `run_ui()`'s `GtkApplication` comes afterwards in the
|
||||
/// same process, which works because `gtk_init()` is idempotent.
|
||||
bool choose_source(Config& cfg);
|
||||
|
||||
} // namespace udpscope
|
||||
Reference in new issue
Block a user