Change behaviour of --update

- Bool option to overwrite config file
- Set scaling mode, too
This commit is contained in:
Candifloss 2025-12-20 15:07:28 +05:30
parent 4da3fe8358
commit 736e258d25
4 changed files with 82 additions and 85 deletions

View File

@ -7,51 +7,64 @@ Configuration is optional, and the app exits immediately after setting the wallp
## Features ## Features
* Simple CLI usage - Simple CLI usage
* Optional config file - Optional config file
* Two image scaling modes: **Fill** and **Stretch** - Two image scaling modes: **Fill** and **Stretch**
* Minimal dependencies - Minimal dependencies
* X11 only (Wayland not supported) - X11 only (Wayland not supported)
--- ---
## Usage ## Usage
### Set wallpaper once (no config change) `icing` can be used in two ways.
1. Specify a wallpaper explicitly as an argument
```sh ```sh
icing --set /path/to/image.png icing --set /path/to/image.png
``` ```
Sets the wallpaper immediately but does **not** update the config file.
### Update config and set wallpaper Sets the wallpaper immediately without modifying the config file.
```sh 2. Use the config file
icing --update /path/to/image.png
```
* Writes the image path to the config file
* Sets the wallpaper immediately
* Future runs of `icing` will reuse this image
### Use config only
```sh ```sh
icing icing
``` ```
Uses the image path and settings from the config file. Run without arguments to apply the wallpaper defined in the config file.
Fails if no config exists. Fails if no config exists.
### Optional arguments See below for config instructions.
### Additional options
#### `--mode`
Use the `--mode` option to specify the image scaling mode.
```sh ```sh
--mode fill|stretch icing --set /path/to/image.png --mode fill
``` ```
Overrides the default or configured scaling mode (see below). Overrides the default or configured scaling mode (see below).
#### `--update`
Use the `--update` flag to persist the new settings to the config file.
```sh
icing --set /path/to/image.png --update
icing --set /path/to/image.png --mode stretch --update
```
- Sets the wallpaper
- Writes the settings to the config file
- Future runs of `icing` will reuse these settings
## Configuration ## Configuration
Config file location: Config file location:
@ -110,31 +123,31 @@ Optionally move it to your `$PATH` (for example `/usr/bin/`) if desired.
## Requirements ## Requirements
* X11 (Xorg) - X11 (Xorg)
* A window manager - A window manager
* Rust (for building) - Rust (for building)
## Future plans ## Future plans
* Multi-monitor support via `--monitor <MONITOR>` - Multi-monitor support via `--monitor <MONITOR>`
```sh ```sh
icing --monitor HDMI-1 --set image.png icing --monitor HDMI-1 --set image.png
icing --monitor HDMI-2 --set image2.jpg --mode stretch icing --monitor HDMI-2 --set image2.jpg --mode stretch
``` ```
* Probably not: - Probably not:
* Additional scaling modes (unless they make sense) - Additional scaling modes (unless they make sense)
* Wayland support - Wayland support
## Notes ## Notes
* `icing` does not run in the background - `icing` does not run in the background
* No daemon, no config watcher - No daemon, no config watcher
* Intended to be called explicitly (startup scripts, keybindings, etc.) - Intended to be called explicitly (startup scripts, keybindings, etc.)
--- ---

View File

@ -6,8 +6,8 @@ use std::path::PathBuf;
#[derive(Debug)] #[derive(Debug)]
pub struct Args { pub struct Args {
pub set: Option<PathBuf>, pub set: Option<PathBuf>,
pub update: Option<PathBuf>, pub update: bool,
pub mode: Option<String>, // parsed now, used later pub mode: Option<String>,
} }
impl Args { impl Args {
@ -15,11 +15,12 @@ impl Args {
let mut args = Arguments::from_env(); let mut args = Arguments::from_env();
let set = args.opt_value_from_str("--set")?; let set = args.opt_value_from_str("--set")?;
let update = args.opt_value_from_str("--update")?;
let mode = args.opt_value_from_str("--mode")?; let mode = args.opt_value_from_str("--mode")?;
let update = args.contains("--update");
if set.is_some() && update.is_some() { // --update is only meaningful if --set is provided
bail!("--set and --update cannot be used together"); if update && set.is_none() {
bail!("--update requires --set");
} }
// Fail if unknown arguments are present // Fail if unknown arguments are present

View File

@ -24,18 +24,19 @@ impl Config {
Ok(config) Ok(config)
} }
/// Update config with image specifeid by CLI arg /// Persist wallpaper settings to config.
pub fn update_background_image(&self, new_path: &str) -> Result<()> { pub fn write(background_image: &str, mode: Option<&str>) -> Result<()> {
let path = config_path()?; let path = config_path()?;
let updated = toml::to_string(&Config { let config = Config {
background_image: new_path.to_string(), background_image: background_image.to_string(),
mode: self.mode.clone(), mode: mode.map(str::to_string),
})?; };
let serialized = toml::to_string(&config)?;
fs::create_dir_all(path.parent().expect("config path has parent"))?; fs::create_dir_all(path.parent().expect("config path has parent"))?;
fs::write(&path, serialized)
fs::write(&path, updated)
.with_context(|| format!("Failed to write config file: {}", path.display()))?; .with_context(|| format!("Failed to write config file: {}", path.display()))?;
Ok(()) Ok(())

View File

@ -17,50 +17,22 @@ pub fn resolve_wallpaper(
// Avoids moving `config`, allows to: // Avoids moving `config`, allows to:
// - read values multiple times // - read values multiple times
// - decide later whether we need to write a new config // - decide later whether we need to write a new config
let cfg_ref = config.as_ref(); let cfg = config.as_ref();
// Resolve wallpaper image path by precedence: // Resolve wallpaper image path by precedence:
// 1. args (`--set`, `--update`): Use path from args. // 1. args (`--set`, `--update`): Use path from args.
// 2. config: Use path from config. // 2. config: Use path from config.
let path = match (&args.set, &args.update) { let path = if let Some(path) = &args.set {
// Case: arg `--set`: One-shot wallpaper change. Not persistent. // Case: arg `--set`: One-shot wallpaper change. Not persistent.
(Some(path), None) => path.clone(),
// Case: arg `--update`. Persist wallpaper path to config (create if missing), then apply it.
(None, Some(path)) => {
// Use existing config if present.
// Otherwise, create a minimal temporary config only for writing.
// Avoids moving or cloning the original config, keeps ownership simple.
let cfg = match cfg_ref {
Some(cfg) => cfg,
None => &config::Config {
background_image: String::new(),
mode: None,
},
};
// Write to config.
cfg.update_background_image(
path.to_str()
// Unsupported path format.
.ok_or_else(|| anyhow::anyhow!("Non-UTF8 path"))?,
)?;
path.clone() path.clone()
} } else {
// Case: No args. Fallback to config file. // Case: No args. Fallback to config file.
(None, None) => { let cfg = cfg.ok_or_else(|| {
let cfg = cfg_ref.ok_or_else(|| {
// No CLI args and no valid config. // No CLI args and no valid config.
anyhow::anyhow!("No or invalid image path specified in config or args.") anyhow::anyhow!("No or invalid image settings specified in config or args.")
})?; })?;
// Successfully loaded.
cfg.background_image.clone().into() cfg.background_image.clone().into()
}
// Case: Both args `--set` & `--update`. This case is already rejected during argument parsing.
_ => unreachable!(),
}; };
// Resolve scaling mode by precedence: // Resolve scaling mode by precedence:
@ -72,7 +44,7 @@ pub fn resolve_wallpaper(
mode_arg mode_arg
.parse::<wallpaper::ScalingMode>() .parse::<wallpaper::ScalingMode>()
.with_context(|| "Invalid wallpaper mode in CLI")? .with_context(|| "Invalid wallpaper mode in CLI")?
} else if let Some(cfg) = cfg_ref { } else if let Some(cfg) = cfg {
if let Some(mode_str) = &cfg.mode { if let Some(mode_str) = &cfg.mode {
// Config-specified mode // Config-specified mode
mode_str mode_str
@ -83,9 +55,19 @@ pub fn resolve_wallpaper(
wallpaper::ScalingMode::Fill wallpaper::ScalingMode::Fill
} }
} else { } else {
// No CLI and no config default // No CLI and no config -> default
wallpaper::ScalingMode::Fill wallpaper::ScalingMode::Fill
}; };
// Persist if requested
if args.update {
config::Config::write(
path.to_str()
// Unsupported path format.
.ok_or_else(|| anyhow::anyhow!("Non-UTF8 path"))?,
args.mode.as_deref().or(cfg.and_then(|c| c.mode.as_deref())),
)?;
}
Ok(WallpaperSettings { path, mode }) Ok(WallpaperSettings { path, mode })
} }