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

+15 -1
View File
@@ -4,6 +4,7 @@
#include <gtk/gtk.h>
#include <cstddef>
#include <functional>
#include <string>
namespace udpscope {
@@ -23,7 +24,20 @@ const char* about_icon_name();
/// window of our own. `parent` is the window the launch is attributed to (and the one an
/// error is reported on); the viewer is a separate process, so nothing here can be closed
/// with `close_help_windows()`.
void show_help(GtkWindow* parent);
///
/// `done`, when the caller gives one, is called with the *launch*'s outcome: whether the
/// `help:` URI was handed to a viewer, and the error text when it was not. It says nothing
/// about the viewer itself — that process may fail for its own reasons and this side cannot
/// see them — so it is the self-check's reading of the path and not a promise that a window
/// appeared. The failure alert is shown either way; the callback is an extra, not instead.
void show_help(GtkWindow* parent, std::function<void(bool ok, const std::string& error)> done = {});
/// Where `help:<id>` resolves to on this system: the first of `$XDG_DATA_HOME/help/<lang>/<id>/`
/// and `$XDG_DATA_DIRS/help/<lang>/<id>/` that holds an `index.page`, or an empty string when no
/// such directory does. This is the specification's own resolution, and the distinction a launch
/// failure turns on: a missing *document* (install it) and a missing *handler* (install a viewer)
/// are different problems with different fixes, and only the file system can tell them apart.
std::string help_installed_path();
/// What UDPSCOPE_PROBE_HELP_MS reports about the manual *in the tree*. `topics` is the
/// number of `<id>.page` files other than `index.page`, and `index` says whether