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:
1 parent
e140642ed0
commit
d8a79b96ba
15 files changed
+461
-66
No files matched your search
+37
-4
@@ -4444,16 +4444,33 @@ UiShortcuts ui_shortcut_rows(const char* path) {
|
||||
return out;
|
||||
}
|
||||
|
||||
/// Prints the manual launch's outcome, which arrives in a callback (the launch is asynchronous and
|
||||
/// the viewer is another process) -- so the line is written from a timer a moment later rather than
|
||||
/// from `help_probe`. `done=0` is a launch that never called back, which is a reading of its own.
|
||||
gboolean help_launch_report(gpointer user) {
|
||||
App* a = static_cast<App*>(user);
|
||||
const std::string installed = help_installed_path();
|
||||
std::fprintf(stderr, "[help] launch attempted=%d done=%d ok=%d error='%s' installed=%s\n",
|
||||
a->dbg_help_launch_attempted ? 1 : 0, a->dbg_help_launch_done ? 1 : 0,
|
||||
a->dbg_help_launch_ok ? 1 : 0, a->dbg_help_launch_error.c_str(),
|
||||
installed.empty() ? "(not found)" : installed.c_str());
|
||||
std::fflush(stderr);
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
gboolean help_probe(gpointer user) {
|
||||
App* a = static_cast<App*>(user);
|
||||
const HelpReport report = help_self_check();
|
||||
const std::string session =
|
||||
layout_path(a->model->config().server, a->model->config().port);
|
||||
|
||||
// The manual is not opened here: it lives in another process (Yelp, through the `help:` URI)
|
||||
// and neither it nor this box can draw a window for it, so there is nothing to open, read
|
||||
// back or close. `help_self_check()` above is the assertion -- the set is on disk where the
|
||||
// build says it is. The two AdwDialogs below are still built, read and closed for real.
|
||||
// The manual is *launched* here and read no further: it opens in another process (Yelp, through
|
||||
// the `help:` URI) and neither it nor this box can draw a window for it, so there is nothing to
|
||||
// read back or close. `help_self_check()` above is the assertion on the *set* being on disk where
|
||||
// the build says it is; the launch is the assertion on the *path*, and its outcome is reported by
|
||||
// `help_launch_report()` once the launch's callback has run. The failure alert the callback shows
|
||||
// is deliberately left up -- it is what a user sees, and the probe must not report a failure as a
|
||||
// silence. The two AdwDialogs below are still built, read and closed for real.
|
||||
show_about(GTK_WINDOW(a->window), session);
|
||||
show_shortcuts(GTK_WINDOW(a->window));
|
||||
// Read while it is open: the icon is the point of the dialog carrying one, and
|
||||
@@ -4461,6 +4478,18 @@ gboolean help_probe(gpointer user) {
|
||||
const std::string about_icon = about_icon_name();
|
||||
close_help_windows();
|
||||
|
||||
// The manual's path: on a successful launch no window is left behind, so this cannot be observed
|
||||
// any other way; `show_help()`'s reporter is the only hook that runs on that path.
|
||||
a->dbg_help_launch_attempted = true;
|
||||
a->dbg_help_launch_done = false;
|
||||
a->dbg_help_launch_ok = false;
|
||||
a->dbg_help_launch_error.clear();
|
||||
show_help(GTK_WINDOW(a->window), [a](bool ok, const std::string& error) {
|
||||
a->dbg_help_launch_done = true;
|
||||
a->dbg_help_launch_ok = ok;
|
||||
a->dbg_help_launch_error = error;
|
||||
});
|
||||
|
||||
int accel_count = 0;
|
||||
int gesture_count = 0;
|
||||
(void)app_accels(&accel_count);
|
||||
@@ -4479,6 +4508,10 @@ gboolean help_probe(gpointer user) {
|
||||
build_info::kCommit, build_info::kTimestamp, config_dir().c_str(),
|
||||
about_icon.c_str());
|
||||
std::fflush(stderr);
|
||||
// The launch's outcome needs its callback to have run; a moment is enough for a local
|
||||
// `g_app_info_launch_default_for_uri()`, and `done=0` in the line is how a launch that never
|
||||
// called back reads.
|
||||
g_timeout_add(600, help_launch_report, a);
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user