Skip to content
Cody-will edited this page Sep 20, 2026 · 4 revisions

Overview and Key Features

Related Files:

  • README.md
  • Cargo.toml

Related Pages:

  • Installation, Configuration, and Usage
  • Architecture and Data Flow
  • Wallpaper, Theme, and Bar Workflow
Relevant source files

The following files were used as context for generating this wiki page:

Overview and Key Features

rice is a small Rust CLI designed to orchestrate wallpapers, theming, and basic session helpers for a Hyprland desktop environment. It centralizes common tasks—such as cycling wallpapers, running wallust, restarting waybar, and starting user sessions—behind a single binary and a simple command-line interface that is intended for use in window manager keybindings.
Sources: README.md:1-59

The core of rice is a set of cohesive modules that handle configuration, filesystem paths, wallpaper backends, theming, bar control, session startup, persistent state, notifications, and command execution. The top-level CLI routes user commands into these modules, which then coordinate to update both the visual wallpaper and associated system components.
Sources: src/main.rs:1-26, src/cli.rs:1-39, src/wall/mod.rs:1-35, src/theme.rs:1-33, src/bar.rs:1-23


High-Level Architecture

Sources: src/main.rs:1-64, src/cli.rs:1-39, src/config.rs:1-40, src/wall/mod.rs:1-102, src/wall/backend.rs:1-27, src/session.rs:1-30, src/state.rs:1-53, src/notifications.rs:1-55, src/paths.rs:1-63, src/cmd.rs:1-18, README.md:1-120

At a high level, rice consists of:

  • A CLI front-end that exposes subcommands for wallpaper, bar, and session operations.
  • A configuration subsystem stored in TOML under ~/.config/rice/config.toml.
  • A wallpaper subsystem that lists images, steps forward/backward, and applies changes via backends.
  • A theme subsystem that runs an external theming command (e.g., wallust) and optionally restarts the bar.
  • A bar subsystem that restarts the configured status bar.
  • A session subsystem that spawns configured applications and restores the last wallpaper.
  • A state subsystem that maintains the last wallpaper and backend in JSON under ~/.cache/rice/state.json.
  • A notifications subsystem to display desktop notifications about success/failure.
  • A paths helper module to resolve config/cache locations and expand ~.
  • A generic command runner to execute external binaries.

Top-Level Component Diagram

graph TD
  Main["main.rs"]
  Cli["cli.rs"]
  Config["config.rs"]
  Paths["paths.rs"]
  Wall["wall/mod.rs"]
  Backend["wall/backend.rs"]
  Theme["theme.rs"]
  Bar["bar.rs"]
  Session["session.rs"]
  State["state.rs"]
  Notify["notifications.rs"]
  Cmd["cmd.rs"]

  Main --> Cli
  Main --> Config
  Main --> Wall
  Main --> Bar
  Main --> Session
  Main --> Notify

  Config --> Paths
  Config --> Theme
  Config --> Bar
  Config --> Session
  Config --> Notify

  Wall --> Config
  Wall --> State
  Wall --> Theme
  Wall --> Backend

  Backend --> Cmd

  Theme --> Paths
  Theme --> Cmd
  Theme --> Bar

  Bar --> Cmd

  Session --> Config
  Session --> Wall

  State --> Paths

  Notify --> Paths
Loading

This diagram shows how the main entrypoint and configuration sit at the center of the system, coordinating interactions between wallpaper, theme, bar, session, state, notifications, and command execution.
Sources: src/main.rs:1-64, src/config.rs:1-40, src/wall/mod.rs:1-35, src/wall/backend.rs:1-27, src/theme.rs:1-33, src/bar.rs:1-23, src/session.rs:1-30, src/state.rs:1-53, src/notifications.rs:1-55, src/paths.rs:1-63, src/cmd.rs:1-18


CLI and Command Routing

Sources: src/cli.rs:1-39, src/main.rs:1-64, README.md:16-33

The CLI exposes three primary top-level commands—wall, bar, and session—each with specific subcommands:

Top-level command Subcommand Effect (high-level)
wall next Step to next wallpaper and apply theme/state
wall prev Step to previous wallpaper and apply theme/state
wall start Restore last wallpaper (or first) and apply theme/state
bar restart Restart the configured bar (default waybar)
session start Spawn configured session apps, then start wallpaper

Sources: src/cli.rs:1-39, src/wall/mod.rs:59-102, src/bar.rs:18-23, src/session.rs:19-30, README.md:16-33

CLI Types

#[derive(Parser)]
#[command(name = "rice", about = "Hyprland helpers")]
pub struct Cli {
    #[command(subcommand)]
    pub command: Command,
}

The Command enum further branches into Wall, Bar, and Session variants, each carrying a more specific action enum (WallAction, BarAction, SessionAction).
Sources: src/cli.rs:1-39

Main Dispatch Flow

The main function parses the CLI and matches on command to dispatch into module-specific functions:

fn main() -> Result<()> {
    let result = match Cli::parse().command {
        Command::Wall { action } => match action {
            WallAction::Next => wall::next(),
            WallAction::Prev => wall::prev(),
            WallAction::Start => wall::start(),
        },
        Command::Bar { action } => match action {
            BarAction::Restart => bar::restart(&Config::load()?),
        },
        Command::Session { action } => match action {
            SessionAction::Start => session::start(),
        }
    };

    match result {
        Ok(()) => {
            if let Ok(cfg) = config::Config::load() {
                notifications::success(&cfg, "Wallpaper updated");
            }
            Ok(())
        },
        Err(e) => {
            if let Ok(cfg) = config::Config::load() {
                notifications::error(&cfg, &format!("Update failed: {e:#}"));
            }
            eprintln!("{e:#}");
            std::process::exit(1);
        }
    }
}

The logic:

  1. Parse arguments into Cli.
  2. Invoke the appropriate function in wall, bar, or session.
  3. On success, optionally show a success notification ("Wallpaper updated").
  4. On error, show an error notification and exit with status 1.

Sources: src/main.rs:8-64

CLI Call Sequence Diagram

sequenceDiagram
  autonumber

  participant U as User
  participant Shell as Shell
  participant Bin as rice (main)
  participant Cli as CLI Parser
  participant Wall as wall module
  participant Bar as bar module
  participant Sess as session module
  participant Cfg as Config
  participant Notif as Notifications

  U->>Shell: run "rice wall next"
  Shell->>+Bin: exec rice
  Bin->>+Cli: parse args
  Cli-->>-Bin: Command::Wall(Next)

  alt wall command
    Bin->>+Wall: next()
    Wall-->>-Bin: Result
  else bar command
    Bin->>+Cfg: Config::load()
    Cfg-->>-Bin: Config
    Bin->>+Bar: restart(&Config)
    Bar-->>-Bin: Result
  else session command
    Bin->>+Sess: start()
    Sess-->>-Bin: Result
  end

  alt Result Ok
    Bin->>+Cfg: Config::load()
    Cfg-->>-Bin: Config
    Bin->>+Notif: success("Wallpaper updated")
    Notif-->>-Bin: (shown/ignored)
    Bin-->>Shell: exit 0
  else Result Err
    Bin->>+Cfg: Config::load()
    Cfg-->>-Bin: Config
    Bin->>+Notif: error("Update failed: ...")
    Notif-->>-Bin: (shown/ignored)
    Bin-->>Shell: exit 1
  end
Loading

This sequence shows how rice processes a user command from the shell, dispatches it to the appropriate module, then uses config and notifications for reporting.
Sources: src/main.rs:8-64, src/cli.rs:1-39, src/notifications.rs:33-55, src/config.rs:18-40


Configuration and Filesystem Layout

Sources: src/config.rs:1-40, src/paths.rs:1-63, src/state.rs:1-53, src/notifications.rs:1-32, README.md:45-111

Filesystem Paths

paths.rs centralizes all filesystem location logic and ~ expansion:

Function Path / Behavior
project_dirs XDG dirs for qualifier rice (config and cache)
config_dir ~/.config/rice
cache_dir ~/.cache/rice
config_file ~/.config/rice/config.toml
icon_file ~/.config/rice/icon.png
state_file ~/.cache/rice/state.json
ensure_dir mkdir -p style directory creation
expand_tilde Expand leading ~ using $HOME

Sources: src/paths.rs:15-63

expand_tilde supports:

  • ~ → $HOME
  • ~/something → $HOME/something
  • Other paths returned unchanged.

Sources: src/paths.rs:43-63

Config Loading and Defaults

The Config struct is deserialized from TOML and enriched with default values from embedded example config:

const DEFAULT: &str = include_str!("../examples/config.toml");

#[derive(Deserialize, Debug)]
pub struct Config {
    pub wallpaper_dir: PathBuf,
    pub backend: String,
    pub sort: String,
    pub extensions: Vec<String>,
    pub theme: Theme,
    pub bar: Bar,
    pub session: Session,
    pub notifications: Notifications,
}

Sources: src/config.rs:1-17

Loading logic:

  1. Compute config path.
  2. If missing, create parent dir and write the embedded default TOML content.
  3. Read file into string.
  4. Deserialize TOML into Config.
  5. Expand wallpaper_dir ~ using paths::expand_tilde.
pub fn load() -> Result<Config> {
    let path = paths::config_file()?;

    if !path.exists() {
        let parent = path.parent().context("Config path has no parent")?;
        paths::ensure_dir(parent)?;
        std::fs::write(&path, DEFAULT)
            .with_context(|| format!("failed to write {}", path.display()))?;
    }

    let raw = std::fs::read_to_string(&path)
        .with_context(|| format!("failed to read {}", path.display()))?;

    let mut cfg: Config = toml::from_str::<Config>(&raw)
        .with_context(|| format!("failed to parse {}", path.display()))?;

    cfg.wallpaper_dir = paths::expand_tilde(&cfg.wallpaper_dir);

    Ok(cfg)
}

Sources: src/config.rs:19-40

The README documents example configuration keys and their meanings:

wallpaper_dir = "~/Pictures/walls"
backend = "hyprpaper"    # hyprpaper | swww | none
sort = "name"
extensions = ["jpg", "jpeg", "png", "webp"]

[theme]
enable = true
command = "wallust"
args = []                 # apply() should call: wallust run <image>

[bar]
restart_on_theme = true
command = "waybar"

[session]
exec = ["waybar", "swaync"]

Sources: README.md:90-116

Persistent State

The State struct holds runtime state across invocations:

#[derive(Serialize, Deserialize, Debug)]
#[serde(default)]
pub struct State {
    pub wallpaper: Option<PathBuf>,
    pub backend: Option<String>,
}

Sources: src/state.rs:7-19

Load and save semantics:

  • load():
    • If state.json doesn’t exist, return default State with None values.
    • Otherwise, read JSON and deserialize.
  • save():
    • Ensure parent directory exists.
    • Serialize to pretty JSON.
    • Write to state.json.

Sources: src/state.rs:21-53


Wallpaper Management

Sources: src/wall/mod.rs:1-102, src/wall/backend.rs:1-27, src/config.rs:1-40, src/state.rs:1-53, src/theme.rs:1-33

The wallpaper subsystem includes:

  • Listing candidate images from the configured directory.
  • Stepping forward/backward through the list.
  • Restoring last wallpaper.
  • Applying wall changes via backend commands.
  • Triggering theme application and bar restart.

Image Listing

list_images collects valid image files from cfg.wallpaper_dir:

fn list_images(cfg: &Config) -> Result<Vec<PathBuf>> {
    let dir = &cfg.wallpaper_dir;
    let mut images: Vec<PathBuf> = fs::read_dir(dir)?
        .filter_map(|res| res.ok())
        .map(|entry| entry.path())
        .filter(|path| {
            path.is_file() && path.extension().map_or(false, |ext| cfg.is_valid_img(&ext.to_string_lossy().to_lowercase()))
        })
        .collect();

    if images.is_empty() {
        bail!("no wallpapers in {}", dir.display());
    }

    if cfg.sort == "name" {
        images.sort();
    }

    Ok(images)
}

Sources: src/wall/mod.rs:8-35, src/config.rs:42-48

Config::is_valid_img checks whether the image extension belongs to the configured extensions list:

pub fn is_valid_img(&self, img_ext: &str) -> bool {
    self.extensions.contains(&img_ext.to_string())
}

Sources: src/config.rs:42-48

Stepping Between Wallpapers

The step function encapsulates the next/prev logic:

fn step(delta: isize) -> Result<()> {
    let cfg = Config::load()?;
    let mut state = State::load()?;
    let images = list_images(&cfg)?;
    let n = images.len() as isize;

    let idx = state.wallpaper
        .as_ref()
        .and_then(|cur| images.iter().position(|p| p == cur))
        .unwrap_or(0) as isize;

    let next = (idx + delta).rem_euclid(n) as usize;
    let backend = state.backend
        .as_deref()
        .unwrap_or(cfg.backend.as_str());

    backend::set(&images[next], backend)?;
    theme::apply(&images[next], &cfg)?;
    state.wallpaper = Some(images[next].clone());
    state.backend = Some(backend.to_string());
    state.save()?;
    println!("{}", images[next].display());
    Ok(())
}

Sources: src/wall/mod.rs:37-59

Key behavior:

  • Loads configuration and current state.
  • Finds the index of the current wallpaper in the sorted list (default 0 if not found).
  • Uses rem_euclid for wraparound at both ends.
  • Falls back to cfg.backend if state’s backend is absent.
  • Delegates setting the wallpaper to backend::set.
  • Applies theming via theme::apply.
  • Updates and persists state.
  • Prints the selected path to stdout.

next and prev are thin wrappers:

pub fn next() -> Result<()> {
    step(1)
}

pub fn prev() -> Result<()> {
    step(-1)
}

Sources: src/wall/mod.rs:61-69

Two tests verify wraparound behavior:

#[cfg(test)]
mod tests {

    #[test]
    fn wrap_next_from_last() {
        let n: isize = 3;
        let idx: isize = 2;
        assert_eq!((idx + 1).rem_euclid(n) as usize, 0);
    }

    #[test]
    fn wrap_prev_from_first() {
        let n: isize = 3;
        let idx: isize = 0;
        assert_eq!((idx + -1).rem_euclid(n) as usize, 2);
    }
}

Sources: src/wall/mod.rs:81-101

Start Command (Restore Last Wallpaper)

The start function restores the last used wallpaper or falls back to the first image:

pub fn start() -> Result<()> {
    let cfg = Config::load()?;
    let mut state = State::load()?;
    let images = list_images(&cfg)?;

    let path = state.wallpaper
        .as_ref()
        .and_then(|cur| images.iter().find(|p| *p == cur))
        .unwrap_or(&images[0])
        .clone();

    let backend = state.backend
        .as_deref()
        .unwrap_or(cfg.backend.as_str())
        .to_string();

    backend::set(&path, &backend)?;
    theme::apply(&path, &cfg)?;
    state.wallpaper = Some(path.clone());
    state.backend = Some(backend);
    state.save()?;
    println!("{}", path.display());
    Ok(())
}

Sources: src/wall/mod.rs:71-79, src/wall/mod.rs:102-120

Behavior:

  • Attempts to find state.wallpaper in the current list.
  • If missing, selects the first image.
  • Chooses backend from state or config.
  • Calls backend and theme, then persists state.

Backend Integration

wall/backend.rs abstracts over the wallpaper backend:

pub fn set(path: &Path, backend: &str) -> Result<()> {
    let img_path = path.to_str().context("wallpaper path is not valid utf-8")?;
    match backend {
        "hyprpaper" => cmd::run("hyprctl", &["hyprpaper", "wallpaper", &format!("eDP-1, {img_path}")]),
        "swww" => cmd::run("swww", &["img", img_path]),
        "none" => Ok(()),
        _ => bail!("unkown backend {backend}"),
    }
}

Sources: src/wall/backend.rs:1-18

Supported backend values (as seen in README and code):

  • "hyprpaper": uses hyprctl hyprpaper wallpaper eDP-1, <path>
  • "swww": uses swww img <path>
  • "none": skip wallpaper change
  • Other values cause an error.

Sources: src/wall/backend.rs:1-18, README.md:93-97


Theme Application and Bar Integration

Sources: src/theme.rs:1-33, src/bar.rs:1-23, src/config.rs:1-17, README.md:93-105

Theme Configuration and Defaults

Theme struct:

#[derive(Deserialize, Debug)]
#[serde(default)]
pub struct Theme {
    enable: bool,
    command: String,
    args: Option<Vec<String>>
}

impl Default for Theme {
    fn default() -> Self {
        Self {
            enable: true,
            command: "wallust".into(),
            args: None,
        }
    }
}

Sources: src/theme.rs:1-18

Default behavior:

  • Theming is enabled by default.
  • Uses wallust as command.
  • No extra arguments unless specified.

Bar struct:

#[derive(Deserialize, Debug)]
#[serde(default)]
pub struct Bar {
    pub restart_on_theme: bool,
    pub command: String,
}

impl Default for Bar {
    fn default() -> Self {
        Self {
            restart_on_theme: true,
            command: "waybar".into(),
        }
    }
}

Sources: src/bar.rs:1-17

Applying Theme

theme::apply is called after wallpaper changes:

pub fn apply(path: &Path, cfg: &Config) -> Result<()> {
    if !cfg.theme.enable {
        return Ok(());
    }

    let p = paths::expand_tilde(path);

    let img = p
        .to_str()
        .context("wallpaper path is not valid utf-8")?;

    let mut args: Vec<String> = vec!["run".into(), img.to_string()];
    if let Some(extra) = &cfg.theme.args {
        args.extend(extra.iter().cloned());
    }

    let args_ref: Vec<&str> = args.iter().map(String::as_str).collect();
    cmd::run(&cfg.theme.command, &args_ref)?;
    if cfg.bar.restart_on_theme {
        crate::bar::restart(cfg)?;
    }
    Ok(())
}

Sources: src/theme.rs:20-33

Key behavior:

  • No-op if theme.enable is false.
  • Ensures ~ expansion on the wallpaper path.
  • Constructs command arguments starting with "run" and image path, then appends extra args if configured.
  • Executes the theme command via cmd::run.
  • If bar.restart_on_theme is true, calls bar::restart.

Bar Restart

bar::restart restarts the configured bar process:

pub fn restart(cfg: &Config) -> Result<()> {
    cmd::run("pkill", &[&cfg.bar.command])?;
    std::process::Command::new(&cfg.bar.command)
        .spawn()
        .with_context(|| format!("failed to start {}", cfg.bar.command))?;
    Ok(())
}

Sources: src/bar.rs:19-23

Steps:

  1. Use pkill to terminate existing bar processes by command name.
  2. Spawn a new bar process.
  3. Propagate errors with context.

Theme and Bar Flow Diagram

graph TD
  Step["wall step()"]
  ThemeApply["theme::apply()"]
  Expand["expand_tilde()"]
  BuildArgs["build theme args"]
  RunTheme["cmd::run(theme cmd)"]
  RestartCheck["bar.restart_on_theme?"]
  BarRestart["bar::restart()"]
  Pkill["cmd::run(\"pkill\")"]
  SpawnBar["spawn bar"]

  Step --> ThemeApply
  ThemeApply --> Expand
  ThemeApply --> BuildArgs
  BuildArgs --> RunTheme
  RunTheme --> RestartCheck
  RestartCheck --> BarRestart
  BarRestart --> Pkill
  BarRestart --> SpawnBar
Loading

This shows how a wallpaper change flows into theme application and optional bar restart.
Sources: src/wall/mod.rs:37-59, src/theme.rs:20-33, src/bar.rs:19-23, src/paths.rs:43-63, src/cmd.rs:1-18


Session Management

Sources: src/session.rs:1-30, src/config.rs:1-17, src/wall/mod.rs:71-79,102-120

The session feature allows starting a collection of user-defined applications and then restoring the wallpaper.

Session Configuration and Defaults

Session struct:

#[derive(Deserialize, Debug)]
#[serde(default)]
pub struct Session {
    pub exec: Vec<String>,
}

impl Default for Session {
    fn default() -> Self {
        Self {
            exec: vec!["waybar".into(), "swaync".into(), "discord".into()],
        }
    }
}

Sources: src/session.rs:1-15

The README’s example:

[session]
exec = ["waybar", "swaync"]

Sources: README.md:104-109

Starting a Session

session::start:

pub fn start() -> Result<()> {
    let cfg = Config::load()?;

    for exec in cfg.session.exec {
        std::process::Command::new(&exec)
            .spawn()
            .with_context(|| format!("failed to start {exec}"))?;
    };

    crate::wall::start()?;
    Ok(())
}

Sources: src/session.rs:17-30

Behavior:

  1. Loads configuration.
  2. Iterates through session.exec list, spawning each command as a separate process.
  3. Calls wall::start to restore the last wallpaper (and theme/bar accordingly).

Session Flow Diagram

graph TD
  SessCmd["session::start()"]
  LoadCfg["Config::load()"]
  ForEachExec["for each exec in cfg.session.exec"]
  SpawnCmd["spawn process"]
  WallStart["wall::start()"]
  RestoreWall["restore wallpaper"]
  ApplyTheme["apply theme + bar"]

  SessCmd --> LoadCfg
  LoadCfg --> ForEachExec
  ForEachExec --> SpawnCmd
  ForEachExec --> WallStart
  WallStart --> RestoreWall
  WallStart --> ApplyTheme
Loading

This flow illustrates how the session command orchestrates application startup followed by wallpaper and theme restoration.
Sources: src/session.rs:17-30, src/wall/mod.rs:71-79,102-120, src/theme.rs:20-33


Notifications

Sources: src/notifications.rs:1-55, src/main.rs:26-64, src/paths.rs:25-39

Notifications provide feedback on command success or failure.

Configuration and Defaults

Notifications struct:

#[derive(Serialize, Deserialize, Debug)]
#[serde(default)]
pub struct Notifications {
    pub on_success: bool,
    pub on_error: bool,
}

impl Default for Notifications {
    fn default() -> Self {
        Self {
            on_success: false,
            on_error: true,
        }
    }
}

Sources: src/notifications.rs:7-20

By default:

  • Success notifications are disabled.
  • Error notifications are enabled.

Icon Handling

ensure_icon writes a bundled PNG to the config directory if needed:

const ICON: &[u8] = include_bytes!("../assets/rice-notify.png");

fn ensure_icon() -> Result<PathBuf> {
    let path = crate::paths::icon_file()?;
    if !path.exists() {
        if let Some(dir) = path.parent() {
            crate::paths::ensure_dir(dir)?;
        }
        std::fs::write(&path, ICON)
            .with_context(|| format!("failed to write {}", path.display()))?;
    }
    Ok(path)
}

Sources: src/notifications.rs:1-6, src/notifications.rs:22-32, src/paths.rs:31-39

show uses notify_rust::Notification to display a desktop notification with the icon, app name, summary, body, and urgency.
Sources: src/notifications.rs:34-43

Success and Error Helpers

pub fn success(cfg: &Config, body: &str) {
    if cfg.notifications.on_success {
        show(body, Urgency::Low);
    }
}

pub fn error(cfg: &Config, body: &str) {
    if cfg.notifications.on_error {
        show(body, Urgency::Normal);
    }
}

Sources: src/notifications.rs:45-55

These are used in main after command execution:

  • On success, success(&cfg, "Wallpaper updated").
  • On error, error(&cfg, &format!("Update failed: {e:#}")).

Sources: src/main.rs:26-64


Command Execution Utility

Sources: src/cmd.rs:1-18, src/wall/backend.rs:1-18, src/theme.rs:20-33, src/bar.rs:19-23

cmd::run provides a common wrapper for running external commands:

pub fn run(bin: &str, args: &[&str]) -> Result<()> {
    let status = Command::new(bin)
        .args(args)
        .status()
        .with_context(|| format!("failed to start {bin}"))?;

    if !status.success() {
        bail!("{bin} exited with {status}");
    }

    Ok(())
}

Sources: src/cmd.rs:1-18

It is used in:

  • wall/backend.rs for hyprpaper, swww, and pkill.
  • theme.rs for the theming command.
  • bar.rs to kill existing bar processes.

This centralization ensures consistent error handling and messaging for subprocess execution.
Sources: src/wall/backend.rs:1-18, src/theme.rs:20-33, src/bar.rs:19-23


Key Features Summary

Sources: README.md:16-59,90-116, src/wall/mod.rs:1-102, src/wall/backend.rs:1-18, src/theme.rs:1-33, src/bar.rs:1-23, src/session.rs:1-30, src/state.rs:1-53, src/notifications.rs:1-55, src/config.rs:1-48

Feature Description Primary Modules
Wallpaper cycling Next/previous wallpaper selection with wraparound and persistent state wall/mod.rs, state.rs, config.rs
Wallpaper backend abstraction Support for hyprpaper, swww, or none via a common interface wall/backend.rs, cmd.rs
Theming integration Optional theming command (default wallust) executed after wallpaper changes theme.rs, config.rs
Bar restart on theme Optional bar restart (default waybar) after theme application bar.rs, config.rs, theme.rs
Session startup Launch configured applications and then restore the wallpaper session.rs, wall/mod.rs, config.rs
Config auto-generation Auto-creates ~/.config/rice/config.toml from embedded example if missing config.rs, paths.rs, examples/config.toml (embedded)
State persistence Stores last wallpaper and backend in ~/.cache/rice/state.json state.rs, paths.rs
Notifications Configurable success/error desktop notifications with embedded icon notifications.rs, paths.rs, main.rs
CLI entrypoint rice wall ..., rice bar restart, rice session start for keybind usage main.rs, cli.rs, README.md

Conclusion

rice provides a focused, modular CLI for managing wallpapers, theming, bar restarts, and session startup within a Hyprland desktop. Through clear separation of concerns—configuration, filesystem paths, wallpaper backends, theming, bar control, session orchestration, state persistence, notifications, and subprocess execution—it offers a simple yet extensible foundation that can be controlled entirely via a small set of CLI subcommands suitable for window manager keybindings.
Sources: README.md:16-59, src/main.rs:1-64, src/wall/mod.rs:1-102, src/theme.rs:1-33, src/session.rs:1-30, src/bar.rs:1-23, src/state.rs:1-53, src/notifications.rs:1-55

Clone this wiki locally