bread-theme: fix per-monitor colour-theming leaks (define-color, bind lifecycle, watch arming) #7
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "fix/per-monitor-colour-leaks"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Fixes the six bread-ecosystem findings from the multi-monitor audit: per-monitor accent colours leaking across a multi-output Hyprland desktop.
Per-finding checklist
stylesheet_resolvedstill emits@define-color— FIXED. The per-bind variant now strips every@define-colorline; its rule bodies are already fully hex, so the block was pure liability.@define-coloris stylesheet-global in GTK4, so keeping it meant every per-monitor bind/reload clobbered the display-global@accent/@bg/@on-*with that monitor's palette, and any CSS parsed afterwards in another window (apply_shared,apply_app_css,apply_user_css) resolved against whichever monitor bound last. The display-globalstylesheet()/render()sheet keeps its block. Existing regression test tightened to assert the block is absent; new test guards the display-global sheet still carries it.ENTER_HOOKEDnever cleaned up on destroy — FIXED. It's keyed byGdkSurfacepointer while the sibling sets are keyed by widget pointer, soensure_destroy_cleanupnever removed it. Now awidget -> surfacemapping (ENTER_SURFACE) is recorded at hook time and the unifiedforget_bind(singleconnect_destroy, also folding in the previously-separateMAP_HOOKEDcleanup) clears the enter hook by its real key.watch_root_children(root's direct children only) replaced withhook_subtree: recursively observes every current container and, from insideitems-changed, re-walks the whole bound tree and hooks any newly-spliced-in containers. Child-models are owned by theWidgetBindso they drop together on destroy. The existingconnect_mapfull-subtree re-attach is kept for the whole-window-remap case. Note: this registers oneobserve_children+ signal per container at bind time — O(widgets in tree), which the audit explicitly sanctioned; acceptable for the window sizes involved.sanitize_outputcollisions — FIXED. Replaced the everything-to-_mapping with percent-encoding of every byte outside[A-Za-z0-9._-]. Injective, soa/banda:bcan no longer share one palette/CSS file. Real Hyprland connector names are unaffected (already keep-set only); files are session-scoped and regenerated at login.ensure_themes_watchand theapply_shared/apply_app_csswatchers storedNoneon amonitor_directoryfailure and were only re-armed as a side effect of another bind — so a bind-once consumer (bread-polkit) lost per-monitor reload for the session. Newarm_or_retryhelper: bounded lazy retry (5 attempts, 2s apart), guarded so a burst of binds doesn't each spawn a timer..cssevents underthemes/; a write of onlypalettes/<out>.jsonleft bound windows stale (third-party tooling — the CLI writes both). Now also watchespalettes/for.json; the reload path re-reads the JSON viaload_palette_forregardless, so reacting to either file is correct (a paired write reloads twice, harmlessly).forget_bind's surface-keyed cleanup (#2), the css/json reload routing (#6), and watch arming (#5); plus one#[ignore]d display+GTK test covering the deep-subtree re-attach and bind lifecycle (#2/#3).Test notes
cargo build --workspace/--features gtk: clean.cargo clippy --workspace --all-targetsand--features gtkwith-D warnings: clean.cargo test --workspaceandcargo test --workspace --features gtk: all pass (notebread-polkitpullsbread-themewith thegtkfeature, so the newgtk.rstests run under a plaincargo test --workspacetoo).#[ignore]d test needs a GDK display and callsgtk4::init(), which binds GTK to a single thread for the process and acquires the thread-default glib main context — running it in the shared test binary deadlocks theshell::hotreloadtests (they pump that context forFileMonitorevents). It still compiles on every build and passes when run alone:cargo test -p bread-theme --features gtk -- --ignoredCI wiring (not changed here)
.forgejo/workflows/dev-bread-theme.ymlonly runscargo build ... --bin bread-theme— nocargo test, and nothing with--features gtk. So none of bread-theme's tests (new or old) run in CI today; onlybakeryhas acargo teststep. Worth wiring acargo test -p bread-theme --features gtkstep (it needs system GTK4 on the runner, plus a headless display or the#[ignore]skip covers it), but that's left as a separate change to the workflow files.View command line instructions
Checkout
From your project repository, check out a new branch and test the changes.Merge
Merge the changes and update on Forgejo.Warning: The "Autodetect manual merge" setting is not enabled for this repository, you will have to mark this pull request as manually merged afterwards.