From 5e58558dd36031433d4a8d8e70c71206c3f1f8f4 Mon Sep 17 00:00:00 2001 From: Breadway Date: Wed, 17 Jun 2026 12:53:35 +0800 Subject: [PATCH 1/2] =?UTF-8?q?bread-theme=200.2.8:=20fix=20live=20reload?= =?UTF-8?q?=20=E2=80=94=20watch=20the=20dir,=20not=20the=20file?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The stylesheet is written with write-tmp-then-rename (atomic), which replaces the inode. A monitor on the file itself caught the first replace then went deaf (inotify reports DELETE_SELF and never re-arms), so `bread-theme reload` updated the file but no running GUI ever recoloured. Monitor the parent directory and filter for the stylesheet filename instead — that fires on every reload. Verified against a real atomic-rename write (event arrives as Renamed with the new name in other_file, so match both file and other_file). --- bread-theme/src/gtk.rs | 39 +++++++++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/bread-theme/src/gtk.rs b/bread-theme/src/gtk.rs index bc68dc2..aab7d01 100644 --- a/bread-theme/src/gtk.rs +++ b/bread-theme/src/gtk.rs @@ -26,6 +26,33 @@ fn reload_app() { } } +/// Watch the shared stylesheet for changes and run `reload` when it's rewritten. +/// +/// `bread-theme` writes the file with write-tmp-then-rename (atomic), which +/// *replaces the inode*. A monitor on the file itself dies after the first +/// replace (inotify reports DELETE_SELF and never re-arms), so we monitor the +/// parent *directory* and filter for the stylesheet's filename — that fires +/// reliably on every reload. Returns the monitor (keep it alive to stay armed). +fn watch_theme_file(reload: fn()) -> Option { + let target = crate::shared_css_path(); + let dir = target.parent()?; + // The dir must exist to be monitored; `bread-theme generate` makes it at + // login, but create it here too so a GUI started first still arms the watch. + let _ = std::fs::create_dir_all(dir); + let monitor = gio::File::for_path(dir) + .monitor_directory(gio::FileMonitorFlags::WATCH_MOVES, gio::Cancellable::NONE) + .ok()?; + monitor.connect_changed(move |_, file, other, _event| { + // The rename lands as an event whose file (or move destination) is the + // stylesheet. Match either to catch both CREATED/CHANGED and MOVED_IN. + let is_target = |f: &gio::File| f.path().as_deref() == Some(target.as_path()); + if is_target(file) || other.is_some_and(is_target) { + reload(); + } + }); + Some(monitor) +} + /// Apply an app's *own* stylesheet and keep it live across palette changes. /// /// `build` is called now to produce the app-specific CSS, and again every time @@ -47,11 +74,7 @@ pub fn apply_app_css String + 'static>(build: F) { if cell.borrow().is_some() { return; } - let file = gio::File::for_path(crate::shared_css_path()); - if let Ok(monitor) = file.monitor_file(gio::FileMonitorFlags::NONE, gio::Cancellable::NONE) { - monitor.connect_changed(|_, _, _, _| reload_app()); - *cell.borrow_mut() = Some(monitor); - } + *cell.borrow_mut() = watch_theme_file(reload_app); }); } @@ -68,11 +91,7 @@ pub fn apply_shared() { if cell.borrow().is_some() { return; } - let file = gio::File::for_path(crate::shared_css_path()); - if let Ok(monitor) = file.monitor_file(gio::FileMonitorFlags::NONE, gio::Cancellable::NONE) { - monitor.connect_changed(|_, _, _, _| reload_shared()); - *cell.borrow_mut() = Some(monitor); - } + *cell.borrow_mut() = watch_theme_file(reload_shared); }); } From 10f62fb1a62fc5ca4eab90ae5e1bfc8cd9bf9fc9 Mon Sep 17 00:00:00 2001 From: Breadway Date: Wed, 17 Jun 2026 22:55:12 +0800 Subject: [PATCH 2/2] feat: add breadpaper to ecosystem registry --- registry/bread-ecosystem.toml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/registry/bread-ecosystem.toml b/registry/bread-ecosystem.toml index 530f938..96887cb 100644 --- a/registry/bread-ecosystem.toml +++ b/registry/bread-ecosystem.toml @@ -36,3 +36,8 @@ description = "Profile-aware Wi-Fi state machine with Tailscale integration" name = "breadpad" repo = "Breadway/breadpad" description = "Quick-capture scratchpad and note viewer with AI classification" + +[[products]] +name = "breadpaper" +repo = "Breadway/breadpaper" +description = "Wallpaper manager for the bread desktop"