feat: the preferences are a UI file, applying as they change
src/ui/preferences.ui is an AdwPreferencesDialog whose rows are libadwaita's own -- AdwEntryRow, AdwSpinRow, AdwSwitchRow, AdwComboRow, AdwButtonRow -- instead of a label and a bare GtkEntry in a GtkBox. There is no Apply button: a row applies as it changes, which is what those widgets are designed around, and [prefs-probe] reads the settings file back after every change. The folder chooser is cancellable now, so a picker still open when the dialog closes cannot write into a row that is gone; the cancellable is also how the probe takes the cancel path without a mouse. Two traps cost a run each and are recorded in docs/claude/invariants-gtk-and-chrome.md: an AdwDialog is not a GtkWindow (it cannot parent a GtkFileDialog, and in floating mode it adds a native surface to gtk_window_get_toplevels() that is neither a widget nor a window), and a .ui that is not listed in the GResource is a Gtk-ERROR at runtime rather than a build failure -- which is exactly what the probe opening every window is for.
This commit is contained in:
1 parent
0e256764d5
commit
4c56172005
11 files changed
+403
-247
No files matched your search
+7
-10
@@ -123,13 +123,10 @@ void chooser_finish(Chooser& c, bool chosen) {
|
||||
c.form = nullptr; // before the destroy, so the `close-request` handler cannot re-enter
|
||||
gtk_window_destroy(GTK_WINDOW(w));
|
||||
}
|
||||
// The preferences window is transient for the chooser, so it has to go first: a window destroyed
|
||||
// with a transient still up is the lifetime this project has already got wrong once.
|
||||
if (c.prefs.window != nullptr) {
|
||||
GtkWidget* w = c.prefs.window;
|
||||
c.prefs.window = nullptr;
|
||||
gtk_window_destroy(GTK_WINDOW(w));
|
||||
}
|
||||
// The preferences go first: they are presented *on* this window, and a dialog still up when its
|
||||
// window is destroyed is the lifetime this project has got wrong once already. `prefs_close()` is
|
||||
// `adw_dialog_close()`, and the form's own `closed` handler clears it.
|
||||
ui_impl::prefs_close(c.prefs);
|
||||
if (c.window != nullptr) {
|
||||
GtkWidget* w = c.window;
|
||||
c.window = nullptr; // before the destroy: `close-request` must not re-enter this
|
||||
@@ -628,9 +625,9 @@ gboolean pick_probe(gpointer user) {
|
||||
// open: the pick below destroys the chooser with it still up, which is the lifetime at risk.
|
||||
if (g_getenv("UDPSCOPE_PROBE_CHOOSER_PREFS") != nullptr) {
|
||||
open_chooser_preferences(c);
|
||||
std::fprintf(stderr, "[sources] prefs: opened=%d apply=%d\n", c.prefs.window != nullptr ? 1 : 0,
|
||||
c.prefs.apply != nullptr ? 1 : 0);
|
||||
ui_impl::prefs_probe_fill_and_apply(c.prefs);
|
||||
std::fprintf(stderr, "[sources] prefs: opened=%d rows=%d\n", c.prefs.dialog != nullptr ? 1 : 0,
|
||||
c.prefs.dir_row != nullptr ? 1 : 0);
|
||||
ui_impl::prefs_probe_change(c.prefs);
|
||||
const Settings back = load_settings();
|
||||
std::fprintf(stderr,
|
||||
"[sources] prefs: dir=%s keep=%d rel=%d theme=%s cfg_relative=%d\n",
|
||||
|
||||
Reference in new issue
Block a user