source: capability panels as side-stack pages, with a probe for the path

This commit is contained in:
Martino Ferrari committed 2026-10-31 20:18:28 +01:00
1 parent 79c33b25c5
commit 5cee00aaee
6 files changed
+209 -3

No files matched your search

+93
View File
@@ -6,6 +6,8 @@
// automated check, and they are code of their own -- a third of what used to be `ui.cpp` -- so they
// live in a translation unit of their own.
#include "source/probe_source.hpp"
#include "source/registry.hpp"
#include "ui_app.hpp"
#include <sys/stat.h>
@@ -1887,6 +1889,97 @@ gboolean side_tab_probe(gpointer user) {
return G_SOURCE_REMOVE;
}
namespace {
std::uint64_t g_source_kinds_before = 0;
}
/// Phase two: the command the Poke button posted must have been run by `poll()` on the producer.
gboolean source_kinds_probe_report(gpointer user) {
App* a = static_cast<App*>(user);
if (a->window == nullptr) return G_SOURCE_REMOVE;
const ProbeSource* src = a->acq != nullptr ? dynamic_cast<const ProbeSource*>(a->acq->source())
: nullptr;
const std::uint64_t after = src != nullptr ? src->commands_applied() : 0;
std::fprintf(stderr, "[source-kinds] command: before=%" G_GUINT64_FORMAT " after=%" G_GUINT64_FORMAT
" drained=%d\n",
g_source_kinds_before, after, after == g_source_kinds_before + 1 ? 1 : 0);
std::fflush(stderr);
return G_SOURCE_REMOVE;
}
/// What the registry offers and what a source kind brings: the kinds, each config form's
/// round trip, the panel page (insensitive while disconnected, still present), and a posted command.
gboolean source_kinds_probe(gpointer user) {
App* a = static_cast<App*>(user);
if (a->window == nullptr) return G_SOURCE_REMOVE;
std::string ids;
for (const SourceKind* k : kinds()) ids += (ids.empty() ? "" : ",") + k->id();
std::fprintf(stderr, "[source-kinds] kinds=%s\n", ids.c_str());
// Each kind's form must hand back what it was given.
const auto sample = [](const std::string& id) {
SourceConfig c;
if (id == "udps") {
c.set("server", "10.0.0.5");
c.set("port", "9001");
c.set("multicast", "239.1.2.3");
c.set("interface", "10.0.0.9");
} else if (id == "probe") {
c.set("rate", "750");
}
return c;
};
for (const SourceKind* k : kinds()) {
ConfigForm f = k->make_config_form();
const SourceConfig in = sample(k->id());
f.write(in);
const SourceConfig out = f.read();
bool same = !in.empty();
for (const auto& kv : in.items()) same = same && out.get(kv.first) == kv.second;
std::fprintf(stderr, "[source-kinds] form %s: round_trip=%d valid=%d\n", k->id().c_str(),
same ? 1 : 0, f.valid() ? 1 : 0);
// The rows were never parented; sink and release them so the form leaves nothing behind.
for (GtkWidget* row : f.rows) {
g_object_ref_sink(row);
g_object_unref(row);
}
}
// The panel page: built, insensitive while disconnected, present either way.
const SourcePanelPage* page = a->source_panels.empty() ? nullptr : &a->source_panels.front();
const auto report = [&](const char* state) {
const bool present =
page != nullptr && a->side_stack != nullptr &&
adw_view_stack_get_child_by_name(ADW_VIEW_STACK(a->side_stack), page->name.c_str()) !=
nullptr;
std::fprintf(stderr, "[source-kinds] panel %s: panels=%zu present=%d sensitive=%d\n", state,
a->source_panels.size(), present ? 1 : 0,
page != nullptr && gtk_widget_get_sensitive(page->content) ? 1 : 0);
};
apply_source_panels(*a, false);
report("disconnected");
apply_source_panels(*a, true);
report("connected");
// The probe kind has no datagrams, so the packet-capture button stays disabled, and is still there.
std::fprintf(stderr, "[source-kinds] capture button: present=%d sensitive=%d\n",
a->capture_button != nullptr ? 1 : 0,
a->capture_button != nullptr && gtk_widget_get_sensitive(a->capture_button) ? 1 : 0);
// Click the panel's button: it posts a command, and a later `poll()` runs it.
ProbeSource* src = a->acq != nullptr ? dynamic_cast<ProbeSource*>(a->acq->source()) : nullptr;
g_source_kinds_before = src != nullptr ? src->commands_applied() : 0;
if (page != nullptr) {
if (GtkWidget* poke = gtk_widget_get_last_child(page->content)) {
g_signal_emit_by_name(poke, "clicked");
}
}
std::fflush(stderr);
g_timeout_add(500, source_kinds_probe_report, a);
return G_SOURCE_REMOVE;
}
gboolean pan_probe(gpointer user) {
App* a = static_cast<App*>(user);
if (a->window == nullptr || a->rows->row_count() <= 0) return G_SOURCE_REMOVE;