Gaussian blur applied at texture load time when `background_blur` is set in moonset.toml. Blur runs once, result is shared across monitors.
189 lines
6.6 KiB
Rust
189 lines
6.6 KiB
Rust
// ABOUTME: Configuration loading for the session power menu.
|
|
// ABOUTME: Reads moonset.toml for wallpaper settings with fallback hierarchy.
|
|
|
|
use serde::Deserialize;
|
|
use std::fs;
|
|
use std::path::{Path, PathBuf};
|
|
|
|
const MOONARCH_WALLPAPER: &str = "/usr/share/moonarch/wallpaper.jpg";
|
|
|
|
/// Default config search paths: system-wide, then user-specific.
|
|
fn default_config_paths() -> Vec<PathBuf> {
|
|
let mut paths = vec![PathBuf::from("/etc/moonset/moonset.toml")];
|
|
if let Some(config_dir) = dirs::config_dir() {
|
|
paths.push(config_dir.join("moonset").join("moonset.toml"));
|
|
}
|
|
paths
|
|
}
|
|
|
|
/// Power menu configuration.
|
|
#[derive(Debug, Clone, Default, Deserialize)]
|
|
pub struct Config {
|
|
pub background_path: Option<String>,
|
|
pub background_blur: Option<f32>,
|
|
}
|
|
|
|
/// Load config from TOML files. Later paths override earlier ones.
|
|
pub fn load_config(config_paths: Option<&[PathBuf]>) -> Config {
|
|
let default_paths = default_config_paths();
|
|
let paths = config_paths.unwrap_or(&default_paths);
|
|
|
|
let mut merged = Config::default();
|
|
for path in paths {
|
|
if let Ok(content) = fs::read_to_string(path) {
|
|
if let Ok(parsed) = toml::from_str::<Config>(&content) {
|
|
if parsed.background_path.is_some() {
|
|
merged.background_path = parsed.background_path;
|
|
}
|
|
if parsed.background_blur.is_some() {
|
|
merged.background_blur = parsed.background_blur;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
merged
|
|
}
|
|
|
|
/// Resolve the wallpaper path using the fallback hierarchy.
|
|
///
|
|
/// Priority: config background_path > Moonarch system default > gresource fallback.
|
|
pub fn resolve_background_path(config: &Config) -> PathBuf {
|
|
resolve_background_path_with(config, Path::new(MOONARCH_WALLPAPER))
|
|
}
|
|
|
|
/// Resolve with configurable moonarch wallpaper path (for testing).
|
|
pub fn resolve_background_path_with(config: &Config, moonarch_wallpaper: &Path) -> PathBuf {
|
|
// User-configured path
|
|
if let Some(ref bg) = config.background_path {
|
|
let path = PathBuf::from(bg);
|
|
if path.is_file() {
|
|
return path;
|
|
}
|
|
}
|
|
|
|
// Moonarch ecosystem default
|
|
if moonarch_wallpaper.is_file() {
|
|
return moonarch_wallpaper.to_path_buf();
|
|
}
|
|
|
|
// GResource fallback path (loaded from compiled resources at runtime)
|
|
let prefix = crate::GRESOURCE_PREFIX;
|
|
PathBuf::from(format!("{prefix}/wallpaper.jpg"))
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn default_config_has_none_background() {
|
|
let config = Config::default();
|
|
assert!(config.background_path.is_none());
|
|
assert!(config.background_blur.is_none());
|
|
}
|
|
|
|
#[test]
|
|
fn load_config_returns_default_when_no_files_exist() {
|
|
let paths = vec![PathBuf::from("/nonexistent/moonset.toml")];
|
|
let config = load_config(Some(&paths));
|
|
assert!(config.background_path.is_none());
|
|
}
|
|
|
|
#[test]
|
|
fn load_config_reads_background_path() {
|
|
let dir = tempfile::tempdir().unwrap();
|
|
let conf = dir.path().join("moonset.toml");
|
|
fs::write(&conf, "background_path = \"/custom/wallpaper.jpg\"\n").unwrap();
|
|
let paths = vec![conf];
|
|
let config = load_config(Some(&paths));
|
|
assert_eq!(config.background_path.as_deref(), Some("/custom/wallpaper.jpg"));
|
|
}
|
|
|
|
#[test]
|
|
fn load_config_reads_background_blur() {
|
|
let dir = tempfile::tempdir().unwrap();
|
|
let conf = dir.path().join("moonset.toml");
|
|
fs::write(&conf, "background_blur = 20.0\n").unwrap();
|
|
let paths = vec![conf];
|
|
let config = load_config(Some(&paths));
|
|
assert_eq!(config.background_blur, Some(20.0));
|
|
}
|
|
|
|
#[test]
|
|
fn load_config_blur_override() {
|
|
let dir = tempfile::tempdir().unwrap();
|
|
let conf1 = dir.path().join("first.toml");
|
|
let conf2 = dir.path().join("second.toml");
|
|
fs::write(&conf1, "background_blur = 10.0\n").unwrap();
|
|
fs::write(&conf2, "background_blur = 25.0\n").unwrap();
|
|
let paths = vec![conf1, conf2];
|
|
let config = load_config(Some(&paths));
|
|
assert_eq!(config.background_blur, Some(25.0));
|
|
}
|
|
|
|
#[test]
|
|
fn load_config_later_paths_override_earlier() {
|
|
let dir = tempfile::tempdir().unwrap();
|
|
let conf1 = dir.path().join("first.toml");
|
|
let conf2 = dir.path().join("second.toml");
|
|
fs::write(&conf1, "background_path = \"/first.jpg\"\n").unwrap();
|
|
fs::write(&conf2, "background_path = \"/second.jpg\"\n").unwrap();
|
|
let paths = vec![conf1, conf2];
|
|
let config = load_config(Some(&paths));
|
|
assert_eq!(config.background_path.as_deref(), Some("/second.jpg"));
|
|
}
|
|
|
|
#[test]
|
|
fn load_config_skips_missing_files() {
|
|
let dir = tempfile::tempdir().unwrap();
|
|
let conf = dir.path().join("exists.toml");
|
|
fs::write(&conf, "background_path = \"/exists.jpg\"\n").unwrap();
|
|
let paths = vec![PathBuf::from("/nonexistent.toml"), conf];
|
|
let config = load_config(Some(&paths));
|
|
assert_eq!(config.background_path.as_deref(), Some("/exists.jpg"));
|
|
}
|
|
|
|
#[test]
|
|
fn resolve_uses_config_path_when_file_exists() {
|
|
let dir = tempfile::tempdir().unwrap();
|
|
let wallpaper = dir.path().join("custom.jpg");
|
|
fs::write(&wallpaper, "fake").unwrap();
|
|
let config = Config {
|
|
background_path: Some(wallpaper.to_str().unwrap().to_string()),
|
|
..Config::default()
|
|
};
|
|
assert_eq!(
|
|
resolve_background_path_with(&config, Path::new("/nonexistent")),
|
|
wallpaper
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn resolve_ignores_config_path_when_file_missing() {
|
|
let config = Config {
|
|
background_path: Some("/nonexistent/wallpaper.jpg".to_string()),
|
|
..Config::default()
|
|
};
|
|
let result = resolve_background_path_with(&config, Path::new("/nonexistent"));
|
|
// Falls through to gresource fallback
|
|
assert!(result.to_str().unwrap().contains("moonset"));
|
|
}
|
|
|
|
#[test]
|
|
fn resolve_uses_moonarch_wallpaper_as_second_fallback() {
|
|
let dir = tempfile::tempdir().unwrap();
|
|
let moonarch_wp = dir.path().join("wallpaper.jpg");
|
|
fs::write(&moonarch_wp, "fake").unwrap();
|
|
let config = Config::default();
|
|
assert_eq!(resolve_background_path_with(&config, &moonarch_wp), moonarch_wp);
|
|
}
|
|
|
|
#[test]
|
|
fn resolve_uses_gresource_fallback_as_last_resort() {
|
|
let config = Config::default();
|
|
let result = resolve_background_path_with(&config, Path::new("/nonexistent"));
|
|
assert!(result.to_str().unwrap().contains("wallpaper.jpg"));
|
|
}
|
|
}
|