diff --git a/Cargo.lock b/Cargo.lock index 9e0d4e4..f754ff4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1776,6 +1776,7 @@ dependencies = [ "image", "infer", "jxl-oxide", + "notify", "tokio", "tracing", "walkdir", diff --git a/cosmic-settings/src/pages/desktop/wallpaper/config.rs b/cosmic-settings/src/pages/desktop/wallpaper/config.rs index 7ab6978..733e537 100644 --- a/cosmic-settings/src/pages/desktop/wallpaper/config.rs +++ b/cosmic-settings/src/pages/desktop/wallpaper/config.rs @@ -120,6 +120,30 @@ impl Config { #[must_use] pub fn default_folder() -> PathBuf { + // Check user directories first + if let Some(home) = env::var_os("HOME") { + let home_path = PathBuf::from(home); + + // Check ~/.local/share/backgrounds (XDG standard) + let local_backgrounds = home_path.join(".local/share/backgrounds"); + if local_backgrounds.exists() { + return local_backgrounds; + } + + // Check ~/Images + let images_dir = home_path.join("Images"); + if images_dir.exists() { + return images_dir; + } + + // Check ~/Pictures + let pictures_dir = home_path.join("Pictures"); + if pictures_dir.exists() { + return pictures_dir; + } + } + + // Check system directories if let Some(data_dirs) = env::var_os("XDG_DATA_DIRS") && let Some(data_dirs) = data_dirs.to_str() { diff --git a/cosmic-settings/src/subscription/wallpapers.rs b/cosmic-settings/src/subscription/wallpapers.rs index b424219..532c73f 100644 --- a/cosmic-settings/src/subscription/wallpapers.rs +++ b/cosmic-settings/src/subscription/wallpapers.rs @@ -1,9 +1,13 @@ use std::path::PathBuf; +use std::time::Duration; use cosmic::iced::futures::channel::mpsc::Sender; use cosmic::iced::futures::{SinkExt, StreamExt, future}; use cosmic::iced::{Subscription, stream}; use image::{ImageBuffer, Rgba}; +use notify::{Config, Event, RecommendedWatcher, RecursiveMode, Watcher}; +use tokio::sync::mpsc; +use tokio::time; #[derive(Clone, Debug)] /// Event emitted by the wallpaper subscription @@ -35,9 +39,72 @@ pub fn wallpapers(current_dir: PathBuf) -> cosmic::iced::Subscription) -> anyhow::Result<()> { + let (event_tx, event_rx) = std::sync::mpsc::channel(); + + let mut watcher: RecommendedWatcher = RecommendedWatcher::new( + move |res: Result| { + if let Ok(event) = res { + // Only send reload for relevant events + if matches!( + event.kind, + notify::EventKind::Create(_) | notify::EventKind::Modify(_) | notify::EventKind::Remove(_) + ) { + let _ = event_tx.send(event); + } + } + }, + Config::default().with_poll_interval(Duration::from_secs(1)), + )?; + + watcher.watch(¤t_dir, RecursiveMode::Recursive)?; + + tokio::spawn(async move { + let mut debounce_timer = None; + loop { + match event_rx.recv() { + Ok(_) => { + // Debounce: wait 500ms before reloading to avoid multiple rapid events + if debounce_timer.is_none() { + let tx_clone = tx.clone(); + debounce_timer = Some(tokio::spawn(async move { + time::sleep(Duration::from_millis(500)).await; + let _ = tx_clone.send(()); + })); + } + } + Err(_) => break, + } + } + }); + + Ok(()) +} + async fn inner(tx: Sender, current_dir: PathBuf) -> anyhow::Result<()> { tx.clone().send(WallpaperEvent::Loading).await?; + // Load initial wallpapers + load_wallpapers(&tx, current_dir.clone()).await?; + tx.clone().send(WallpaperEvent::Loaded).await?; + + // Set up file watcher for automatic reload + let (reload_tx, mut reload_rx) = mpsc::channel::<()>(1); + + // Spawn watcher in background + let _ = spawn_watcher(current_dir.clone(), reload_tx); + + // Watch for reload signals + while let Some(_) = reload_rx.recv().await { + tracing::debug!("Reloading wallpapers due to directory change"); + load_wallpapers(&tx, current_dir.clone()).await?; + } + + Ok(()) +} + +async fn load_wallpapers(tx: &Sender, current_dir: PathBuf) -> anyhow::Result<()> { let mut stream = cosmic_settings_wallpaper::load_each_from_path(current_dir).await; while let Some((path, display, selection)) = stream.next().await { @@ -54,7 +121,5 @@ async fn inner(tx: Sender, current_dir: PathBuf) -> anyhow::Resu } } - tx.clone().send(WallpaperEvent::Loaded).await?; - Ok(()) } diff --git a/pages/wallpapers/Cargo.toml b/pages/wallpapers/Cargo.toml index b148edb..6dea7dd 100644 --- a/pages/wallpapers/Cargo.toml +++ b/pages/wallpapers/Cargo.toml @@ -22,3 +22,4 @@ jxl-oxide = { version = "0.12.5", features = ["image"] } tokio = { workspace = true, features = ["sync"] } tracing = "0.1.44" walkdir = "=2.5.0" +notify = "8.2.0"