From c9913834f2f142abe999db0972efed2e8a55ef13 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 9 May 2025 14:16:12 -0600 Subject: [PATCH] Cleanup config handling --- Cargo.lock | 29 +++++++---- Cargo.toml | 4 ++ daemon/Cargo.toml | 1 + daemon/src/lib.rs | 122 +++++++++++++++++++++++----------------------- src/greeter.rs | 84 +++++++++++++++---------------- src/locker.rs | 79 +++++++++++++++++++----------- 6 files changed, 177 insertions(+), 142 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5cb5b01..0f005a0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1081,10 +1081,19 @@ dependencies = [ "libm", ] +[[package]] +name = "cosmic-applets-config" +version = "0.1.0" +source = "git+https://github.com/pop-os/cosmic-applets#edaf5b994e5bd6c78e9e395ebfa4f53c631faeae" +dependencies = [ + "cosmic-config", + "serde", +] + [[package]] name = "cosmic-bg-config" version = "0.1.0" -source = "git+https://github.com/pop-os/cosmic-bg#d41c8506ed5c44afd51f74bdb56f620e1dec1ffc" +source = "git+https://github.com/pop-os/cosmic-bg#1da843a63656cf58b373a4823c15326be448b24e" dependencies = [ "colorgrad", "cosmic-config", @@ -1110,7 +1119,7 @@ dependencies = [ [[package]] name = "cosmic-comp-config" version = "0.1.0" -source = "git+https://github.com/pop-os/cosmic-comp#99bbd10168aed50a24db730cf20eb778e072c5e4" +source = "git+https://github.com/pop-os/cosmic-comp#a57f4a84664b36a661509d9fe58f6940a774e34a" dependencies = [ "cosmic-config", "input", @@ -1120,7 +1129,7 @@ dependencies = [ [[package]] name = "cosmic-config" version = "0.1.0" -source = "git+https://github.com/pop-os/libcosmic#67df54f38390eda8180b55b55b0fe9825894a62a" +source = "git+https://github.com/pop-os/libcosmic#c8c650c0410258bb8cd5321bb93845979c7260a4" dependencies = [ "atomicwrites", "calloop 0.14.2", @@ -1143,7 +1152,7 @@ dependencies = [ [[package]] name = "cosmic-config-derive" version = "0.1.0" -source = "git+https://github.com/pop-os/libcosmic#67df54f38390eda8180b55b55b0fe9825894a62a" +source = "git+https://github.com/pop-os/libcosmic#c8c650c0410258bb8cd5321bb93845979c7260a4" dependencies = [ "quote", "syn 1.0.109", @@ -1185,6 +1194,7 @@ dependencies = [ "chrono", "chrono-tz", "clap_lex", + "cosmic-applets-config", "cosmic-bg-config", "cosmic-comp-config", "cosmic-config", @@ -1231,6 +1241,7 @@ dependencies = [ name = "cosmic-greeter-daemon" version = "0.1.0" dependencies = [ + "cosmic-applets-config", "cosmic-bg-config", "cosmic-comp-config", "cosmic-config", @@ -2067,9 +2078,9 @@ dependencies = [ [[package]] name = "freedesktop-desktop-entry" -version = "0.7.10" +version = "0.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2258b98a780699da05c858682498ceaf3942013d7d93ca7584e26fbacc58f2d9" +checksum = "cbcb2951884fd80c5b3093ce762bebcc4ec351fadff3c253f9d09cb91917ddd2" dependencies = [ "gettext-rs", "log", @@ -2625,7 +2636,7 @@ dependencies = [ [[package]] name = "iced_core" version = "0.14.0-dev" -source = "git+https://github.com/pop-os/libcosmic#67df54f38390eda8180b55b55b0fe9825894a62a" +source = "git+https://github.com/pop-os/libcosmic#c8c650c0410258bb8cd5321bb93845979c7260a4" dependencies = [ "bitflags 2.9.0", "bytes", @@ -2649,7 +2660,7 @@ dependencies = [ [[package]] name = "iced_futures" version = "0.14.0-dev" -source = "git+https://github.com/pop-os/libcosmic#67df54f38390eda8180b55b55b0fe9825894a62a" +source = "git+https://github.com/pop-os/libcosmic#c8c650c0410258bb8cd5321bb93845979c7260a4" dependencies = [ "futures", "iced_core", @@ -4048,7 +4059,7 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" dependencies = [ - "proc-macro-crate 3.3.0", + "proc-macro-crate 1.3.1", "proc-macro2", "quote", "syn 2.0.100", diff --git a/Cargo.toml b/Cargo.toml index 67e6795..4bfafce 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,6 +16,7 @@ icu = { version = "1.5.0", features = [ ] } chrono-tz = "0.10" chrono = { version = "0.4", features = ["unstable-locales"] } +cosmic-applets-config.workspace = true cosmic-bg-config.workspace = true cosmic-comp-config.workspace = true cosmic-config = { workspace = true, features = ["calloop", "macro"] } @@ -103,6 +104,9 @@ serde = "1" tokio = "1.39.1" zbus = "4" +[workspace.dependencies.cosmic-applets-config] +git = "https://github.com/pop-os/cosmic-applets" +default-features = false [workspace.dependencies.cosmic-bg-config] git = "https://github.com/pop-os/cosmic-bg" diff --git a/daemon/Cargo.toml b/daemon/Cargo.toml index 7e827f5..41fc1ab 100644 --- a/daemon/Cargo.toml +++ b/daemon/Cargo.toml @@ -6,6 +6,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +cosmic-applets-config.workspace = true cosmic-bg-config.workspace = true cosmic-comp-config.workspace = true cosmic-config.workspace = true diff --git a/daemon/src/lib.rs b/daemon/src/lib.rs index 89391d7..ac0b92f 100644 --- a/daemon/src/lib.rs +++ b/daemon/src/lib.rs @@ -1,58 +1,67 @@ -use cosmic_config::{ConfigGet, CosmicConfigEntry}; -use std::{fs, path::Path}; +use cosmic_config::CosmicConfigEntry; +use std::{ + collections::BTreeMap, + fs, + path::{Path, PathBuf}, +}; -pub use cosmic_bg_config::{Color, Source}; +pub use cosmic_applets_config::time::TimeAppletConfig; +pub use cosmic_bg_config::{state::State as BgState, Color, Source as BgSource}; pub use cosmic_comp_config::{CosmicCompConfig, XkbConfig}; pub use cosmic_theme::Theme; -#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)] +#[derive(Clone, Debug, Default, serde::Deserialize, serde::Serialize)] pub struct UserData { pub uid: u32, pub name: String, - pub full_name_opt: Option, + pub full_name: String, pub icon_opt: Option>, pub theme_opt: Option, - pub wallpapers_opt: Option>, + pub bg_state: BgState, + pub bg_path_data: BTreeMap>, pub xkb_config_opt: Option, - pub clock_military_time_opt: Option, + pub time_applet_config: TimeAppletConfig, } impl UserData { - pub fn full_name_or_name(&self) -> &str { - if let Some(full_name) = &self.full_name_opt { - if !full_name.is_empty() { - return full_name.as_str(); - } - } - self.name.as_str() - } - - pub fn load_wallpapers_as_user(&mut self, wallpaper_state: &cosmic_bg_config::state::State) { - let mut wallpaper_datas = Vec::new(); - for (output, source) in wallpaper_state.wallpapers.iter() { + pub fn load_wallpapers_as_user(&mut self) { + //TODO: reload changed background files? + self.bg_path_data.retain(|path, _| { + self.bg_state + .wallpapers + .iter() + .any(|(_, source)| match source { + BgSource::Path(source_path) => source_path == path, + _ => false, + }) + }); + for (_, source) in self.bg_state.wallpapers.iter() { match source { - Source::Path(path) => match fs::read(&path) { - Ok(bytes) => { - wallpaper_datas.push((output.clone(), WallpaperData::Bytes(bytes))); + //TODO: do not reread duplicate paths, cache data by path? + BgSource::Path(path) => { + if !self.bg_path_data.contains_key(path) { + match fs::read(&path) { + Ok(bytes) => { + self.bg_path_data.insert(path.clone(), bytes); + } + Err(err) => { + log::error!("failed to read wallpaper {:?}: {:?}", path, err); + } + } } - Err(err) => { - log::error!("failed to read wallpaper {:?}: {:?}", path, err); - } - }, - Source::Color(color) => { - wallpaper_datas.push((output.clone(), WallpaperData::Color(color.clone()))); } + // Other types not supported + _ => {} } } - self.wallpapers_opt = Some(wallpaper_datas); } pub fn load_config_as_user(&mut self) { self.icon_opt = None; self.theme_opt = None; - self.wallpapers_opt = None; + self.bg_state = Default::default(); self.xkb_config_opt = None; - self.clock_military_time_opt = None; + self.time_applet_config = Default::default(); //TODO: use accountsservice? //IMPORTANT: This file is owned by root and safe to read (it won't be a link to /etc/shadow for example) @@ -106,25 +115,21 @@ impl UserData { } //TODO: fallback to background config if background state is not set? - let mut wallpaper_state_opt = None; match cosmic_bg_config::state::State::state() { Ok(helper) => match cosmic_bg_config::state::State::get_entry(&helper) { Ok(state) => { - wallpaper_state_opt = Some(state); + self.bg_state = state; } Err((errs, state)) => { log::error!("failed to load cosmic-bg state: {:?}", errs); - wallpaper_state_opt = Some(state); + self.bg_state = state; } }, Err(err) => { log::error!("failed to create cosmic-bg state helper: {:?}", err); } } - - if let Some(wallpaper_state) = wallpaper_state_opt { - self.load_wallpapers_as_user(&wallpaper_state); - } + self.load_wallpapers_as_user(); match cosmic_config::Config::new("com.system76.CosmicComp", CosmicCompConfig::VERSION) { Ok(config_handler) => match CosmicCompConfig::get_entry(&config_handler) { @@ -141,13 +146,15 @@ impl UserData { } }; - match cosmic_config::Config::new("com.system76.CosmicAppletTime", 1) { - Ok(config_handler) => match config_handler.get("military_time") { - Ok(value) => { - self.clock_military_time_opt = Some(value); + match cosmic_config::Config::new("com.system76.CosmicAppletTime", TimeAppletConfig::VERSION) + { + Ok(config_handler) => match TimeAppletConfig::get_entry(&config_handler) { + Ok(config) => { + self.time_applet_config = config; } - Err(err) => { - log::error!("failed to load military time config: {:?}", err); + Err((errs, config)) => { + log::error!("failed to load time applet config: {:?}", errs); + self.time_applet_config = config; } }, Err(err) => { @@ -162,25 +169,20 @@ impl UserData { impl From for UserData { fn from(user: pwd::Passwd) -> Self { + let mut full_name = user + .gecos + .as_ref() + .and_then(|gecos| gecos.split(',').next()) + .map(|x| x.to_string()) + .unwrap_or_default(); + if full_name.is_empty() { + full_name = user.name.clone(); + } Self { uid: user.uid, name: user.name.clone(), - full_name_opt: user - .gecos - .as_ref() - .and_then(|gecos| gecos.split(',').next()) - .map(|x| x.to_string()), - icon_opt: None, - theme_opt: None, - wallpapers_opt: None, - xkb_config_opt: None, - clock_military_time_opt: None, + full_name, + ..Default::default() } } } - -#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)] -pub enum WallpaperData { - Bytes(Vec), - Color(Color), -} diff --git a/src/greeter.rs b/src/greeter.rs index 17253c0..a58add4 100644 --- a/src/greeter.rs +++ b/src/greeter.rs @@ -33,7 +33,7 @@ use cosmic::{ }; use cosmic_comp_config::CosmicCompConfig; use cosmic_greeter_config::Config as CosmicGreeterConfig; -use cosmic_greeter_daemon::{UserData, WallpaperData}; +use cosmic_greeter_daemon::{BgSource, UserData}; use greetd_ipc::Request; use std::{ collections::{HashMap, hash_map}, @@ -432,12 +432,8 @@ impl App { let military_time = self .selected_username .data_idx - .and_then(|i| { - self.flags - .user_datas - .get(i) - .and_then(|user| user.clock_military_time_opt) - }) + .and_then(|i| self.flags.user_datas.get(i)) + .map(|user_data| user_data.time_applet_config.military_time) .unwrap_or_default(); let date_time_column = self.time.date_time_widget(military_time); @@ -639,11 +635,9 @@ impl App { None => {} } column = column.push( - widget::container(widget::text::title4( - user_data.full_name_or_name(), - )) - .width(Length::Fill) - .align_x(alignment::Horizontal::Center), + widget::container(widget::text::title4(&user_data.full_name)) + .width(Length::Fill) + .align_x(alignment::Horizontal::Center), ); } } @@ -834,42 +828,46 @@ impl App { } }; - if let Some(wallpapers) = &user_data.wallpapers_opt { - for (output, surface_id) in self.surface_ids.iter() { - if self.surface_images.contains_key(surface_id) { - continue; - } + for (_output, surface_id) in self.surface_ids.iter() { + if self.surface_images.contains_key(surface_id) { + continue; + } - let output_name = match self.surface_names.get(surface_id) { - Some(some) => some, - None => continue, - }; + let Some(output_name) = self.surface_names.get(surface_id) else { + continue; + }; - log::info!("updating wallpaper for {:?}", output_name); + log::info!("updating wallpaper for {:?}", output_name); - for (wallpaper_output_name, wallpaper_data) in wallpapers.iter() { - if wallpaper_output_name == output_name { - match wallpaper_data { - WallpaperData::Bytes(bytes) => { - self.surface_images - .insert(*surface_id, image::Handle::from_bytes(bytes.clone())); - - //TODO: what to do about duplicates? - break; - } - WallpaperData::Color(color) => { - //TODO: support color sources - log::warn!( - "output {}: unsupported source {:?}", - output.id(), - color - ); + for (wallpaper_output_name, wallpaper_source) in user_data.bg_state.wallpapers.iter() { + if wallpaper_output_name == output_name { + match wallpaper_source { + BgSource::Path(path) => { + match user_data.bg_path_data.get(path) { + Some(bytes) => { + let image = widget::image::Handle::from_bytes(bytes.clone()); + self.surface_images.insert(*surface_id, image); + //TODO: what to do about duplicates? + } + None => { + log::warn!( + "output {}: failed to find wallpaper data for source {:?}", + output_name, + path + ); + } } + break; + } + BgSource::Color(color) => { + //TODO: support color sources + log::warn!("output {}: unsupported source {:?}", output_name, color); } } } } } + // From cosmic-applet-input-sources if let Some(keyboard_layouts) = &self.flags.layouts_opt { if let Some(xkb_config) = &user_data.xkb_config_opt { @@ -964,15 +962,11 @@ impl cosmic::Application for App { core.window.show_minimize = false; core.window.use_template = false; - //TODO: use full_name_opt + //TODO: use full_name? let mut usernames: Vec<_> = flags .user_datas .iter() - .map(|x| { - let name = x.name.clone(); - let full_name = x.full_name_opt.clone().unwrap_or_else(|| name.clone()); - (name, full_name) - }) + .map(|x| (x.name.clone(), x.full_name.clone())) .collect(); usernames.sort_by(|a, b| a.1.cmp(&b.1)); diff --git a/src/locker.rs b/src/locker.rs index 913843e..96fc4e4 100644 --- a/src/locker.rs +++ b/src/locker.rs @@ -22,7 +22,8 @@ use cosmic::{ iced_runtime::core::window::Id as SurfaceId, widget, }; -use cosmic_greeter_daemon::{UserData, WallpaperData}; +use cosmic_config::CosmicConfigEntry; +use cosmic_greeter_daemon::{BgSource, TimeAppletConfig, UserData}; use std::time::Duration; use std::{ any::TypeId, @@ -194,6 +195,7 @@ pub enum Message { SessionLockEvent(SessionLockEvent), Channel(mpsc::Sender), BackgroundState(cosmic_bg_config::state::State), + TimeAppletConfig(TimeAppletConfig), Focus(SurfaceId), Inhibit(Arc), NetworkIcon(Option<&'static str>), @@ -264,11 +266,7 @@ impl App { window_width }; let left_element = { - let military_time = self - .flags - .user_data - .clock_military_time_opt - .unwrap_or_default(); + let military_time = self.flags.user_data.time_applet_config.military_time; let date_time_column = self.time.date_time_widget(military_time); let mut status_row = widget::row::with_capacity(2).padding(16.0).spacing(12.0); @@ -336,11 +334,9 @@ impl App { } column = column.push( - widget::container(widget::text::title4( - self.flags.user_data.full_name_or_name(), - )) - .width(Length::Fill) - .align_x(alignment::Horizontal::Center), + widget::container(widget::text::title4(&self.flags.user_data.full_name)) + .width(Length::Fill) + .align_x(alignment::Horizontal::Center), ); match &self.prompt_opt { @@ -421,7 +417,9 @@ impl App { //TODO: cache wallpapers by source? fn update_wallpapers(&mut self) { - for (output, surface_id) in self.surface_ids.iter() { + let user_data = &self.flags.user_data; + + for (_output, surface_id) in self.surface_ids.iter() { if self.surface_images.contains_key(surface_id) { continue; } @@ -432,22 +430,29 @@ impl App { log::info!("updating wallpaper for {:?}", output_name); - let Some(wallpapers) = &self.flags.user_data.wallpapers_opt else { - continue; - }; - - for (wallpaper_output_name, wallpaper_data) in wallpapers.iter() { + for (wallpaper_output_name, wallpaper_source) in user_data.bg_state.wallpapers.iter() { if wallpaper_output_name == output_name { - match wallpaper_data { - WallpaperData::Bytes(bytes) => { - let image = widget::image::Handle::from_bytes(bytes.clone()); - self.surface_images.insert(*surface_id, image); - //TODO: what to do about duplicates? + match wallpaper_source { + BgSource::Path(path) => { + match user_data.bg_path_data.get(path) { + Some(bytes) => { + let image = widget::image::Handle::from_bytes(bytes.clone()); + self.surface_images.insert(*surface_id, image); + //TODO: what to do about duplicates? + } + None => { + log::warn!( + "output {}: failed to find wallpaper data for source {:?}", + output_name, + path + ); + } + } break; } - WallpaperData::Color(color) => { + BgSource::Color(color) => { //TODO: support color sources - log::warn!("output {}: unsupported source {:?}", output.id(), color); + log::warn!("output {}: unsupported source {:?}", output_name, color); } } } @@ -837,13 +842,16 @@ impl cosmic::Application for App { Message::Channel(value_tx) => { self.value_tx_opt = Some(value_tx); } - Message::BackgroundState(background_state) => { - self.flags - .user_data - .load_wallpapers_as_user(&background_state); + Message::BackgroundState(bg_state) => { + eprintln!("{:#?}", bg_state); + self.flags.user_data.bg_state = bg_state; + self.flags.user_data.load_wallpapers_as_user(); self.surface_images.clear(); self.update_wallpapers(); } + Message::TimeAppletConfig(config) => { + self.flags.user_data.time_applet_config = config; + } Message::Inhibit(inhibit) => { self.inhibit_opt = Some(inhibit); } @@ -1031,6 +1039,21 @@ impl cosmic::Application for App { }), ); + struct TimeAppletSubscription; + subscriptions.push( + cosmic_config::config_subscription( + TypeId::of::(), + "com.system76.CosmicAppletTime".into(), + TimeAppletConfig::VERSION, + ) + .map(|res| { + if !res.errors.is_empty() { + log::info!("errors loading background state: {:?}", res.errors); + } + Message::TimeAppletConfig(res.config) + }), + ); + #[cfg(feature = "logind")] { subscriptions.push(crate::logind::subscription());