fixed event/live transition

This commit is contained in:
Martino Ferrari committed 2026-10-13 23:37:49 +02:00
1 parent bb99be5889
commit 881b52748e
9 files changed
+314 -2

No files matched your search

+70
View File
@@ -3107,6 +3107,62 @@ gboolean rowmenu_probe_step(gpointer user) {
return G_SOURCE_REMOVE;
}
/// The live view's own settings, taken just before a file view is opened over them, so that every
/// way back out can be read against what was there. The trigger is read under the lock and its
/// channel by *name*: a file view rebuilds the channel list, so an index means nothing on the way
/// back. The probe keeps its own copy rather than asking the restore path for one -- a reading taken
/// from the mechanism under test asserts nothing.
void capture_live_expectation(App& a) {
a.dbg_live_window = a.rows->time_window();
a.dbg_live_trigger_on =
a.trigger_toggle != nullptr &&
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(a.trigger_toggle)) != FALSE;
std::lock_guard<std::mutex> lock(a.model->mutex());
const TriggerConfig& tc = a.model->trigger();
a.dbg_live_level = tc.condition.level;
a.dbg_live_trigger_channel = tc.channel >= 0 && tc.channel < int(a.model->channels().size())
? a.model->channels()[std::size_t(tc.channel)].name
: std::string();
}
/// What came back when a file view was left: every setting the live view had before it opened, read
/// against the expectation the probe captured itself. Four of the five readings are a *pair* on
/// purpose -- a file view overwrites the window, the trigger mode, the trigger's channel and its
/// level, so a line where the two halves of a pair disagree names the one that was not put back.
/// `pinned` is the fifth and has no pair: a file pins the axis to the event's span, and going live
/// must leave the axis following again, so the only passing reading is 0.
void report_live_restored(App& a, const char* what) {
std::string channel;
double level = 0.0;
bool enabled = false;
bool armed = false;
{
std::lock_guard<std::mutex> lock(a.model->mutex());
const TriggerConfig& tc = a.model->trigger();
enabled = tc.enabled;
armed = tc.armed;
level = tc.condition.level;
if (tc.channel >= 0 && tc.channel < int(a.model->channels().size())) {
channel = a.model->channels()[std::size_t(tc.channel)].name;
}
}
std::fprintf(stderr,
"[events] live restored (%s): window=%.6f (want %.6f) trigger=%d (want %d) "
"channel='%s' (want '%s') level=%.6g (want %.6g) enabled=%d armed=%d pinned=%d "
"held=%d mode=%d pending=%d gen=%u/%u\n",
what, a.rows->time_window(), a.dbg_live_window,
a.trigger_toggle != nullptr &&
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(a.trigger_toggle))
? 1
: 0,
a.dbg_live_trigger_on ? 1 : 0, channel.c_str(), a.dbg_live_trigger_channel.c_str(),
level, a.dbg_live_level, enabled ? 1 : 0, armed ? 1 : 0,
a.rows->window_pinned() ? 1 : 0, a.event_held ? 1 : 0,
static_cast<int>(a.model->display_mode()), a.live_restore_pending ? 1 : 0,
a.model->generation(), a.live_restore_generation);
std::fflush(stderr);
}
void events_probe_next(App& a, int step, guint delay_ms) {
a.dbg_events_step = step;
g_timeout_add(delay_ms, events_probe_step, &a);
@@ -3227,6 +3283,7 @@ gboolean events_probe_step(gpointer user) {
// says whether opening the event framed it: with the same window there would be nothing to tell
// "framed" from "untouched".
apply_time_window(*a, 0.5);
capture_live_expectation(*a);
GtkListBoxRow* row = gtk_list_box_get_row_at_index(GTK_LIST_BOX(a->events_list), 0);
// Selected *and* remembered, because what the activation must not do is rebuild the list:
// a selection the user made for a comparison, and the row object itself, are what a
@@ -3312,6 +3369,7 @@ gboolean events_probe_step(gpointer user) {
std::fprintf(stderr, "[events] live again: replaying=%d waveform=%d\n", a->replaying ? 1 : 0,
a->waveform_name.empty() ? 0 : 1);
report_live_restored(*a, "after replay");
// The pane's *other* precondition, through the real switch, in both trigger states: disabling
// recording has to take the button and the pane with it, and arming the trigger afterwards must not
// bring back a pane over an empty cache.
@@ -3360,6 +3418,10 @@ gboolean events_group_probe_step(gpointer user) {
a->events_compare != nullptr && gtk_widget_get_sensitive(a->events_compare) ? 1 : 0,
a->events_accumulate != nullptr && gtk_widget_get_sensitive(a->events_accumulate) ? 1
: 0);
// The live settings this leg will be read against, taken *here* rather than inherited from the
// replay leg: a group is a second, independent way into a file view, and its way back has to put
// back what was on screen when the button was pressed.
capture_live_expectation(*a);
if (a->events_compare != nullptr) g_signal_emit_by_name(a->events_compare, "clicked");
// Read one step later: a rebuilt row's traces are bound by the next *frame*, so a reading taken in
// the same handler as the click reads the frame before the bind.
@@ -3502,6 +3564,14 @@ gboolean events_group_probe_step(gpointer user) {
std::fprintf(stderr, "[events] group left: replaying=%d kind=%d waveform=%d\n", a->replaying ? 1 : 0,
static_cast<int>(a->group_kind), a->waveform_name.empty() ? 0 : 1);
std::fflush(stderr);
// The restore is not this handler's: it waits for the restarted client's first CONFIG, so it is a
// *later tick* that performs it. Reading here would read the frame before the stream came back.
events_group_probe_next(*a, 61, 900);
return G_SOURCE_REMOVE;
}
if (a->dbg_events_step == 61) {
report_live_restored(*a, "after a group");
return G_SOURCE_REMOVE;
}