diff --git a/bread-polkit/src/identity.rs b/bread-polkit/src/identity.rs index e92e395..0dd0496 100644 --- a/bread-polkit/src/identity.rs +++ b/bread-polkit/src/identity.rs @@ -37,7 +37,7 @@ pub fn users_from_uids(uids: &[u32], passwd: &str) -> Vec { } /// Prefer the process's own uid when it is in `users`, otherwise the first. -pub fn pick_user<'a>(users: &'a [UnixUser], current_uid: Option) -> Option<&'a UnixUser> { +pub fn pick_user(users: &[UnixUser], current_uid: Option) -> Option<&UnixUser> { if let Some(uid) = current_uid { if let Some(user) = users.iter().find(|u| u.uid == uid) { return Some(user); diff --git a/bread-theme/src/gtk.rs b/bread-theme/src/gtk.rs index 43e450d..e4ffeda 100644 --- a/bread-theme/src/gtk.rs +++ b/bread-theme/src/gtk.rs @@ -10,6 +10,10 @@ use std::rc::Rc; use crate::Palette; +/// Per-widget app-CSS builder: given the resolved palette for the widget's +/// monitor, produce the app stylesheet to layer on top of the theme CSS. +type AppCssBuilder = Rc String>; + /// Above APPLICATION (600) so we beat [`apply_shared`], below USER (800) /// so `apply_user_css` still wins. const BIND_PRIORITY: u32 = gtk4::STYLE_PROVIDER_PRIORITY_USER - 10; @@ -162,7 +166,7 @@ struct WidgetBind { output: String, theme: CssProvider, app: Option, - app_build: Option String>>, + app_build: Option, /// Keep the directory monitor + child model alive for this widget. _watch: Option, } @@ -284,7 +288,7 @@ fn watch_root_children(widget: >k4::Widget) -> gio::ListModel { fn bind_window_inner( widget: >k4::Widget, output: &str, - app_build: Option String>>, + app_build: Option, ) { let key = widget_key(widget); let palette = crate::load_palette_for(output); @@ -387,7 +391,7 @@ where bind_window_inner(widget.as_ref(), output, Some(Rc::new(build))); } -fn attach_enter_monitor(widget: >k4::Widget, build: Option String>>) { +fn attach_enter_monitor(widget: >k4::Widget, build: Option) { let Some(native) = widget.native() else { return; }; @@ -408,7 +412,7 @@ fn attach_enter_monitor(widget: >k4::Widget, build: Option String>>) { +fn bind_auto(native: >k4::Native, build: Option) { let widget = native.upcast_ref::().clone(); let apply = { diff --git a/bread-theme/src/lib.rs b/bread-theme/src/lib.rs index f9f2300..a9ab77c 100644 --- a/bread-theme/src/lib.rs +++ b/bread-theme/src/lib.rs @@ -330,7 +330,8 @@ pub fn stylesheet_resolved(p: &Palette) -> String { /// named colors cannot leak the wrong monitor's accent. pub(crate) fn resolve_color_names(css: &str, p: &Palette) -> String { let mut pairs: Vec<(&str, String)> = color_pairs(p).into_iter().collect(); - pairs.sort_by(|a, b| b.0.len().cmp(&a.0.len())); + // Longest name first, so `@on-bg` is replaced before `@bg` can match its tail. + pairs.sort_by_key(|(name, _)| std::cmp::Reverse(name.len())); let mut out = css.to_string(); for (name, value) in pairs { out = out.replace(&format!("@{name}"), &value); @@ -544,8 +545,10 @@ mod tests { #[test] fn stylesheet_resolved_inlines_color4_and_drops_named_refs_in_rules() { - let mut p = Palette::default(); - p.color4 = "#7aa2f7".into(); + let p = Palette { + color4: "#7aa2f7".into(), + ..Default::default() + }; let css = stylesheet_resolved(&p); assert!(css.contains("#7aa2f7"), "color4 must appear as hex: {css}"); // Rule bodies must not keep named colors — GTK display-global diff --git a/bread-theme/src/output.rs b/bread-theme/src/output.rs index 5389277..1b1f9f4 100644 --- a/bread-theme/src/output.rs +++ b/bread-theme/src/output.rs @@ -185,10 +185,7 @@ pub fn palette_from_image(path: &Path) -> std::io::Result { Ok(s) => s, }; if !status.success() { - return Err(std::io::Error::new( - std::io::ErrorKind::Other, - format!("wal failed with {status}"), - )); + return Err(std::io::Error::other(format!("wal failed with {status}"))); } let json_path = [ @@ -299,9 +296,11 @@ mod tests { #[test] fn write_output_palette_roundtrips_color4() { with_runtime_dir(|_| { - let mut p = Palette::default(); - p.color4 = "#7aa2f7".into(); - p.background = "#ffffff".into(); + let p = Palette { + color4: "#7aa2f7".into(), + background: "#ffffff".into(), + ..Default::default() + }; write_output_palette("HDMI-A-1", &p).unwrap(); let loaded = load_palette_for("HDMI-A-1"); assert_eq!(loaded.color4, "#7aa2f7"); diff --git a/bread-utils/src/singleton.rs b/bread-utils/src/singleton.rs index 6809747..0fd3610 100644 --- a/bread-utils/src/singleton.rs +++ b/bread-utils/src/singleton.rs @@ -80,6 +80,9 @@ pub fn try_acquire(app: &str) -> std::io::Result { .read(true) .write(true) .create(true) + // Never truncate on open: an existing lock file may be held by a live + // instance. We only clear it (`set_len(0)`) *after* winning the lock. + .truncate(false) .open(&path)?; match file.try_lock() {