help: default the contextual layer off, and carry the help into the chooser

The contextual help was on by default, so a first run met a window with a "?"
beside every surface it had not asked to have explained; `contextual_help` now
defaults to false and the layer is asked for from the Help menu, from the
chooser's new help menu, or with Ctrl+H.

The source chooser runs before `App` exists, which makes it the window a user
who does not know how to start is looking at, so it now carries the same three
help affordances the window's Help view does: Documentation (the manual is
another process and needs nothing of the app), Enable contextual help (a row
whose check *is* the setting, written to the file the app reads a moment
later), and Guided tour. The tour is drawn on the app's own window, so the
chooser can only record the wish: it sets `Config::tour_pending` -- the value
`main()` owns and hands to both `choose_source()` and `run_ui()` -- and
`on_activate()` starts it once the window is up and laid out, through its own
callback so the readings can tell a request from the first-run auto-start.
The rows are the window's own `menu_button()`/`menu_toggle()`; `install_css()`
therefore runs from `choose_source()` (it is idempotent now) so the popover
gets the `.udpscope-menu` rules before it is shown.

Opening the manual could also fail with a message that blamed the handler
whatever was missing. `help_installed_path()` now resolves `help:<id>` the way
the specification does and the failure alert says which of the two it is: with
the set installed it names the viewer, without it it names the identifier, the
expected installed path and the install command. `show_help()` gained an
optional reporter, which `UDPSCOPE_PROBE_HELP_MS` uses for a new reading --
`[help] launch attempted= done= ok= error='' installed=` -- since a successful
launch leaves no window of ours to observe.

Tested: clean --clean-first build, three warnings as documented; test-ui 13/13
and test-help pass; no Gtk-CRITICAL in the help, helpui and chooser runs.
This commit is contained in:
Martino Ferrari committed 2026-10-14 17:22:03 +02:00
1 parent e140642ed0
commit d8a79b96ba
15 files changed
+461 -66

No files matched your search

+43 -10
View File
@@ -730,7 +730,11 @@ same session twice). Connector settings are stored even for a configuration with
which is why those rows exist at all. The app's
menu has **Configurations…**: the same list for the running source, with *Save this session* —
a name and a note — and a delete button per row. Opening one saves the current session first, so
switching is never the gesture that loses what it switches from.
switching is never the gesture that loses what it switches from. Beside **Preferences…** the chooser
also carries a **help menu** with the window's three help entries — the manual, the contextual-help
toggle and the guided tour — because the chooser is shown to exactly the user who has not started yet
and does not know how to; the tour is started by the app once its window is up (see
[the help section](#the-help-submenu-the-contextual-help-and-the-guided-tour)).
A session written before configurations existed is imported on first use as the configuration
named `default`: copied into the directory, remembered as active, and the old file renamed to
@@ -901,14 +905,32 @@ button is a sibling of the heading's title, not an overlay on its corner, for th
toolbar's icons are not overlaid either: an overlay child sits *on* whatever is under it, and the
one surface whose corner is free (the plot) is the one that uses one.
**Off means gone, not greyed.** The toggle removes the buttons rather than disabling them, and
which buttons exist is decided by a data key rather than a list of pointers, so the math editor --
whose heading is created afresh every time it opens -- cannot leave a stale pointer behind. The
setting is `contextual_help` in `settings.toml`, written by
**Off means gone, not greyed, and off is the default.** The toggle removes the buttons rather than
disabling them, and which buttons exist is decided by a data key rather than a list of pointers, so
the math editor -- whose heading is created afresh every time it opens -- cannot leave a stale
pointer behind. The setting is `contextual_help` in `settings.toml`, written by
`Settings`/`load_settings()`/`save_settings()`: the same file, the same three functions and the same
`~/.config/udpscope/settings.toml` the Preferences dialog writes. The dialog's own rows start from
`load_settings()`, so a save from there carries the two help keys through untouched; the Help menu's
row is the only place that states `contextual_help`, which is why the row's check *is* the setting.
`~/.config/udpscope/settings.toml` the Preferences dialog writes. **A fresh install has no such key
and the default is `false`**, so a first run shows the window as anyone would expect it and the layer
is asked for -- from the Help menu, from the source chooser's own help menu, or with `Ctrl+H`. The
dialog's own rows start from `load_settings()`, so a save from there carries the two help keys
through untouched; the Help menu's row is the only place in the *window* that states `contextual_help`
(which is why the row's check *is* the setting), and the chooser's row states it too, before any
window exists.
**The source chooser carries the same three affordances, because it is shown to exactly the user who
has not started yet.** Its header bar has a help `GtkMenuButton` beside *Preferences*, whose rows are
the window's own `menu_button()`/`menu_toggle()` -- the same shape, and the same `.udpscope-menu`
stylesheet, whose rules `choose_source()` installs before building them since the app installs them
later. *Documentation* opens the manual directly (it is another process and needs nothing of the app),
*Enable contextual help* writes the settings file the app reads a moment later, and *Guided tour*
cannot start anything -- the tour is drawn on the app's window, which does not exist yet -- so it sets
**`Config::tour_pending`**, the value `main()` owns and hands to both the chooser and the front end
(`open_waveform` crosses the same way). Half a second and a half after the window is up, the same
delay the first-run auto-start uses, the pending request starts the tour; it sets `tour_requested`
rather than `tour_auto_started`, so the readings say which of the two it was. The chooser's rows show
**no accelerators** -- the window prints `F1`/`Ctrl+T` because the window binds them, and this dialog
binds none.
**The guided tour is five steps on a `GtkOverlay`** inserted above the window's content: the plot,
the side panel, the trigger, the signals and the status line. There is no popover anywhere in it and
@@ -2439,7 +2461,14 @@ identifier `org.udpscope.app` is the desktop file's own basename, so it is the `
GApplication id and the install directory at once. The set is installed by an `install()` rule to
`share/help/C/org.udpscope.app/` — the path the freedesktop Help System Specification's `help:` URI
resolves — and `show_help()` hands `help:org.udpscope.app` to whatever the desktop registered for the
scheme (Yelp on GNOME), reporting a launch failure with an alert rather than failing silently.
scheme (Yelp on GNOME), reporting a launch failure with an alert rather than failing silently. That
alert says **which** thing is missing, because the two have different fixes: `help_installed_path()`
looks for the document under `$XDG_DATA_HOME/help/<lang>/org.udpscope.app/` then
`$XDG_DATA_DIRS/help/<lang>/org.udpscope.app/`, so with the set installed the alert names the missing
*viewer* (`yelp`), and without it the alert names the identifier, the expected installed path and the
install command — `cmake --install build --prefix ~/.local`, which writes
`~/.local/share/help/C/org.udpscope.app/`. A build tree has neither the installed copy nor a
`help:` handler, and **either is enough to make `F1` do nothing**; that is the failure this names.
`cmake --build build --target test-help` checks the set the way `test-ui` checks the `.ui` files:
`yelp-check`'s offline subcommands (links, media, orphans, ids) and a `yelp-build html` render;
`yelp-check validate` is left out because it fetches the Mallard RelaxNG schema over the network.
@@ -2447,7 +2476,11 @@ scheme (Yelp on GNOME), reporting a launch failure with an alert rather than fai
(GTK4 has to be forced to the Cairo renderer or X11 reads the surface back blank).
`UDPSCOPE_PROBE_HELP_MS` asserts the set is *present in the tree* — its
`[help] topics=… index=… figures=…` reading — rather than parsing pages, since they are files now
and not resources. Mallard is translatable with `itstool`, but only the `C` set is authored here.
and not resources, and it **launches the manual too**: `[help] launch attempted=1 done=1 ok=1
error='' installed=/home/…/.local/share/help/C/org.udpscope.app` is the reading, `ok=1` meaning the
`help:` URI reached a registered handler and not that a window appeared (Yelp is another process and
cannot map one headlessly). Mallard is translatable with `itstool`, but only the `C` set is authored
here.
**The status bar is two tiers.** The bar itself shows one glance line: the activity badge, the
display state (one word from a fixed set — `connecting`, `live`, `paused`, `armed`, `capturing`,