Change behaviour of --update
- Bool option to overwrite config file - Set scaling mode, too
This commit is contained in:
parent
4da3fe8358
commit
736e258d25
79
README.md
79
README.md
@ -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.)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
11
src/args.rs
11
src/args.rs
@ -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
|
||||||
|
|||||||
@ -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(())
|
||||||
|
|||||||
@ -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(),
|
path.clone()
|
||||||
|
} else {
|
||||||
// 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()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 settings specified in config or args.")
|
||||||
anyhow::anyhow!("No or invalid image path 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 })
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user