Skip to content

session management and hyprland integration

Cody-will edited this page Sep 20, 2026 · 1 revision

Session Management and Hyprland Integration

Related Files:

  • README.md
  • src/session.rs
  • src/wall/mod.rs
  • src/config.rs
  • src/cmd.rs

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:

Session Management and Hyprland Integration

Introduction

The rice project is a small Rust CLI designed to orchestrate wallpapers, theming, bar restarts, and session startup for a Hyprland desktop environment. It exposes subcommands that can be bound directly to Hyprland keybinds, enabling a single binary to handle wallpaper changes, wallust theme application, waybar restarts, and application session startup.
Sources: README.md:1-80

Session management and Hyprland integration in rice center around the session command (rice session start), the wall commands (rice wall next|prev|start), and their use inside a Hyprland configuration or scripting environment. These pieces work together through shared configuration, persistent state, and small command invocations to provide a consistent, theme-aware desktop session.
Sources: README.md:80-160, src/session.rs:1-34, src/wall/mod.rs:1-113, src/main.rs:1-61


High-Level Architecture

Sources: src/main.rs:1-61, src/cli.rs:1-43, README.md:80-160

At a high level, Hyprland keybinds (or hooks) invoke rice subcommands. These subcommands load configuration and state, modify wallpapers or start applications, optionally apply themes and restart the bar, and finally persist new state and emit notifications.

Major Components Overview

Component Responsibility
CLI (Cli, Command) Parse rice command line into wall, bar, and session subcommands and actions.
session module Start a session by spawning configured applications and then restoring the last wallpaper.
wall module List images, compute next/previous/current wallpaper, call backend to set it, apply theme, and persist state.
wall::backend Abstract the wallpaper backend (hyprpaper, swww, none) via command invocations.
config module Load and parse TOML config, provide runtime configuration (including session, bar, theme, notifications).
state module Load and save last wallpaper and backend in JSON under ~/.cache/rice/state.json.
theme module Run theme command (e.g. wallust), then optionally restart the bar.
bar module Restart bar process (waybar by default) safely.
paths module Resolve and create config/cache paths and expand ~.
cmd module Run external commands with error handling.
notifications module Show desktop notifications for success/failure using notify-rust.

Sources: src/cli.rs:1-43, src/session.rs:1-34, src/wall/mod.rs:1-113, src/wall/backend.rs:1-30, src/config.rs:1-53, src/state.rs:1-63, src/theme.rs:1-44, src/bar.rs:1-27, src/paths.rs:1-63, src/cmd.rs:1-17, src/notifications.rs:1-54

Top-Down Flow from Hyprland

The typical Hyprland integration is illustrated in the README, where hooks and keybinds are wired to rice commands.
Sources: README.md:120-160

graph TD
  HStart["Hyprland<br/>startup"] --> HExec1["Start<br/>hyprpaper"]
  HStart --> HExec2["Run<br/>rice session start"]

  HBindNext["Key SUPER+W"] --> RWallNext["Command<br/>rice wall next"]
  HBindPrev["Key SUPER+SHIFT+W"] --> RWallPrev["Command<br/>rice wall prev"]
  HBindBar["Key SUPER+R"] --> RBarRestart["Command<br/>rice bar restart"]
Loading

Sources: README.md:120-160


CLI and Entry Point

Sources: src/cli.rs:1-43, src/main.rs:1-61

Command-Line Interface

The CLI is defined via clap with three primary subcommands: Wall, Bar, and Session. Each has its own set of actions.
Sources: src/cli.rs:1-43

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

#[derive(Subcommand)]
pub enum Command {
    Wall {
        #[command(subcommand)]
        action: WallAction,
    },
    Bar {
        #[command(subcommand)]
        action: BarAction,
    },
    Session {
        #[command(subcommand)]
        action: SessionAction,
    },
}

Sources: src/cli.rs:1-23

Supported actions:

Command Action Behavior (high-level)
wall Next Set next wallpaper, apply theme, update state.
wall Prev Set previous wallpaper, apply theme, update state.
wall Start Restore last wallpaper (or first) and apply theme.
bar Restart Kill and restart configured bar.
session Start Spawn configured apps, then run wall start.

Sources: src/cli.rs:24-43, src/wall/mod.rs:49-113, src/bar.rs:18-27, src/session.rs:1-34

Main Function Control Flow

main dispatches on the parsed command and centralizes notification behavior for success and error.
Sources: src/main.rs:1-61

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);
        }
    }
}

Sources: src/main.rs:9-61

This behavior ensures:

  • Every subcommand returns a Result<()>.
  • On Ok(()), a success notification is shown if enabled.
  • On Err(e), an error notification is shown and process exits with status 1.

Session Management

Sources: src/session.rs:1-34, src/config.rs:1-53, src/wall/mod.rs:84-113

Session Configuration Model

The Session configuration is part of the global Config and contains a list of applications to spawn when starting a session.
Sources: src/session.rs:1-18, src/config.rs:15-29

#[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-18

In the Config struct:

#[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:15-26

Session Start Flow

session::start is the central function that implements session startup.
Sources: src/session.rs:20-34

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:20-34

Key behaviors:

  1. Load configuration via Config::load().
  2. Iterate over cfg.session.exec and spawn each program.
  3. After spawning all applications, call wall::start() to restore the last wallpaper (and theme/bar as configured).
  4. Return success or propagate errors with context.

This creates a tight coupling between the session initialization and wallpaper restoration, ensuring a consistent look whenever a session starts.

Session Start Sequence Diagram

sequenceDiagram
  autonumber
  participant H as actor Hyprland
  participant R as control rice(main)
  participant C as control Config
  participant S as control Session
  participant W as control Wall
  participant B as control Backend

  H->>+R: rice session start
  R->>+S: session::start()
  S->>+C: Config::load()
  C-->>-S: Config
  loop for each exec in cfg.session.exec
    S->>+S: spawn(exec)
    S-->>-S: child process
  end
  S->>+W: wall::start()
  W->>+C: Config::load()
  C-->>-W: Config
  W->>+W: State::load()
  W-->>-W: State
  W->>+B: backend::set(path, backend)
  B-->>-W: Result
  W-->>-S: Result
  S-->>-R: Result
  R->>+C: Config::load()
  C-->>-R: Config
  R->>R: notifications::success(...)
  R-->>-H: exit 0
Loading

Sources: src/session.rs:20-34, src/wall/mod.rs:84-113, src/config.rs:29-53, src/wall/backend.rs:1-22, src/main.rs:9-61


Wallpaper Management and State Persistence

Sources: src/wall/mod.rs:1-113, src/state.rs:1-63, src/config.rs:29-53

Wallpaper Listing and Selection

wall::list_images collects valid wallpapers from the configured directory and applies simple name-based sorting when requested.
Sources: src/wall/mod.rs:7-33

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:7-33, src/config.rs:55-60

The is_valid_img helper on Config checks extensions against the configured whitelist:
Sources: src/config.rs:55-60

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

Next/Previous Wallpaper Logic

wall::next and wall::prev delegate to step(delta) which computes the next index using modular arithmetic and updates state and theme.
Sources: src/wall/mod.rs:35-65

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:35-65

Public functions:

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

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

Sources: src/wall/mod.rs:67-73

Index Wrapping

Tests verify forward and backward wrapping behavior for a 3-element list using .rem_euclid.
Sources: src/wall/mod.rs:115-127

#[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);
}

Restoring Wallpaper on Session Start

wall::start is used both independently (rice wall start) and from session::start. It picks a wallpaper based on saved state or falls back to the first available image.
Sources: src/wall/mod.rs:75-113

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:75-113

State Model and Persistence

The state is a simple JSON file containing the last wallpaper path and backend name.
Sources: src/state.rs:1-63

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

Sources: src/state.rs:7-15

Location is resolved via paths::state_file (e.g. ~/.cache/rice/state.json on Linux).
Sources: src/paths.rs:31-40

pub fn state_file() -> Result<PathBuf> {
    Ok(cache_dir()?.join("state.json"))
}

State load and save logic:

pub fn load() -> Result<State> {
    let path = paths::state_file()?;

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

    let state = serde_json::from_str(&raw)
        .with_context(|| format!("failed for parse {}", path.display()))?;

    Ok(state)
}

pub fn save(&self) -> Result<()> {
    let path = paths::state_file()?;
    let parent = path.parent().context("Path does not have a parent")?;
    
    paths::ensure_dir(parent)?;

    let json = serde_json::to_string_pretty(self).context("failed to serialize state")?;
    
    std::fs::write(&path, json)
        .with_context(|| format!("failed to write {}", path.display()))?;

    Ok(())
}

Sources: src/state.rs:19-49

Wallpaper and State Flow Diagram

graph TD
  Cmd["wall command"] --> LoadCfg["Config::load()"]
  Cmd --> LoadState["State::load()"]
  LoadCfg --> ListImg["list_images(cfg)"]
  ListImg --> SelectImg["Select<br/>current/next/prev"]
  LoadState --> SelectImg
  SelectImg --> BackendSet["backend::set(path, backend)"]
  BackendSet --> ThemeApply["theme::apply(path, cfg)"]
  ThemeApply --> UpdateState["Update<br/>State fields"]
  UpdateState --> SaveState["State::save()"]
  SaveState --> Done["Print path<br/>and return"]
Loading

Sources: src/wall/mod.rs:7-65, src/wall/mod.rs:75-113, src/state.rs:19-49, src/theme.rs:23-44, src/wall/backend.rs:1-22


Wallpaper Backend Integration

Sources: src/wall/backend.rs:1-30, src/cmd.rs:1-17, src/config.rs:15-26

The wall::backend module abstracts over the actual wallpaper setting mechanism by mapping a backend string to a specific external command invocation.

Backend Dispatch

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-22

Backends:

Backend string Behavior
"hyprpaper" Run hyprctl hyprpaper wallpaper "eDP-1, {img_path}".
"swww" Run swww img {img_path}.
"none" Do nothing; skip wallpaper command.
other Error: unknown backend {backend}.

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

Command Execution Helper

cmd::run encapsulates spawning an external binary and checking its exit status.
Sources: src/cmd.rs:1-17

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-17

This is used by backend::set, theme::apply, and bar::restart.

Backend Selection

The backend used is tracked both in configuration and state:

In step (next/prev):

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

Sources: src/wall/mod.rs:47-52

In start:

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

Sources: src/wall/mod.rs:95-99


Configuration and Paths

Sources: src/config.rs:1-60, src/paths.rs:1-63, README.md:80-120

Config File Lifecycle

On first run, Config::load() will create ~/.config/rice/config.toml from the embedded default if it does not exist.
Sources: src/config.rs:29-53

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:29-53

Paths and XDG Integration

paths uses directories::ProjectDirs to resolve config and cache directories for the rice application.
Sources: src/paths.rs:1-63

Key helpers:

Function Description
config_dir() Returns ~/.config/rice.
cache_dir() Returns ~/.cache/rice.
config_file() Returns ~/.config/rice/config.toml.
icon_file() Returns ~/.config/rice/icon.png.
state_file() Returns ~/.cache/rice/state.json.
ensure_dir(p) mkdir -p equivalent on the given directory path.
expand_tilde(p) Expands ~ or ~/... using $HOME when available.

Sources: src/paths.rs:13-63

Example:

pub fn expand_tilde(path: &Path) -> PathBuf {
    let raw = path.to_string_lossy();

    if raw == "~" {
        return home_dir().unwrap_or_else(|| PathBuf::from(raw.as_ref()));
    }

    if let Some(rest) = raw.strip_prefix("~/") {
        let mut home = home_dir().unwrap_or_else(|| PathBuf::from("~"));
        home.push(rest);
        return home;
    }

    path.to_path_buf()
}

Sources: src/paths.rs:45-63


Theme Application and Bar Restart

Sources: src/theme.rs:1-44, src/bar.rs:1-27, src/config.rs:15-26, README.md:40-70

Theme Configuration

The Theme struct defines how theming is applied after a wallpaper change.
Sources: src/theme.rs:1-21, src/config.rs:15-26

#[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-21

README example configuration:

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

Sources: README.md:40-70

Theme Application Logic

theme::apply is called after successfully setting the wallpaper.
Sources: src/theme.rs:23-44, src/wall/mod.rs:35-65, src/wall/mod.rs:75-113

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:23-44

This function:

  1. Honors cfg.theme.enable.
  2. Builds command arguments as ["run", <image_path>, ...extra_args].
  3. Calls the configured theme command via cmd::run.
  4. If cfg.bar.restart_on_theme is true, calls bar::restart(cfg).

Bar Restart Behavior

bar::restart uses pkill on the configured bar command, then spawns a new instance.
Sources: src/bar.rs:1-27

#[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(),
        }
    } 
}

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:1-27

README example configuration:

[bar]
restart_on_theme = true
command = "waybar"

Sources: README.md:40-70


Notifications and User Feedback

Sources: src/notifications.rs:1-54, src/main.rs:9-61, src/paths.rs:13-40

Notifications Configuration

Notification preferences are part of the global Config:
Sources: src/notifications.rs:7-21, src/config.rs:15-26

#[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-21

Notification Flow

main calls notifications::success or notifications::error based on subcommand results.
Sources: src/main.rs:26-61

notifications ensures an icon file exists and then displays a desktop notification via notify-rust.
Sources: src/notifications.rs:23-54

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)
}

fn show(body: &str, urgency: Urgency) {
    let Ok(icon) = ensure_icon() else { return };
    let Some(icon) = icon.to_str() else { return };
    let _ = Notification::new()
        .appname("rice")
        .summary("rice")
        .body(body)
        .icon(icon)
        .urgency(urgency)
        .show();
}

Sources: src/notifications.rs:23-44

Public 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:46-54


Hyprland Integration Patterns

Sources: README.md:120-160, src/cli.rs:1-43, src/session.rs:20-34, src/wall/mod.rs:67-113, src/bar.rs:18-27

The README shows how rice is intended to be called from Hyprland, particularly the session and wall commands.
Sources: README.md:120-160

Example Hyprland integration:

hl.on("hyprland.start", function()
  hl.exec_cmd("hyprpaper")
  hl.exec_cmd("rice session start")
end)

hl.bind("SUPER + W",         hl.dsp.exec_cmd("rice wall next"))
hl.bind("SUPER + SHIFT + W", hl.dsp.exec_cmd("rice wall prev"))
hl.bind("SUPER + R",         hl.dsp.exec_cmd("rice bar restart"))

Sources: README.md:120-160

Key patterns:

  • On Hyprland start:
    • Start wallpaper backend (hyprpaper) separately.
    • Call rice session start to spawn the configured session apps and restore wallpaper.
  • Bind keys to rice wall next / prev to cycle wallpapers.
  • Bind a key to rice bar restart to manually restart bar if needed (in addition to automatic restarts triggered by theme changes).

Hyprland Integration Diagram

graph TD
  HyprStart["Hyprland<br/>start"] --> StartBackend["exec hyprpaper"]
  HyprStart --> StartSession["exec rice session start"]

  KeyNext["SUPER+W"] --> CmdNext["rice wall next"]
  KeyPrev["SUPER+SHIFT+W"] --> CmdPrev["rice wall prev"]
  KeyBar["SUPER+R"] --> CmdBar["rice bar restart"]
Loading

Sources: README.md:120-160


Configuration Summary for Session and Integration

Based on README example and module definitions, relevant configuration sections:

Section Key Type Default (if any) Role in Session/Integration
root wallpaper_dir PathBuf from example config Directory for wallpapers.
root backend String from example config Default wallpaper backend (hyprpaper/swww).
root sort String from example config "name" triggers filename sorting.
root extensions Vec<String> from example config Valid wallpaper file extensions.
[theme] enable bool true Toggle theme application on wallpaper change.
[theme] command String "wallust" Theme command binary.
[theme] args Option<Vec<String>> None Extra args appended after run <image>.
[bar] restart_on_theme bool true Whether to restart bar after theme apply.
[bar] command String "waybar" Bar command to restart.
[session] exec Vec<String> ["waybar","swaync","discord"] Apps started by rice session start.
[notifications] on_success bool false Show notification on success.
[notifications] on_error bool true Show notification on error.

Sources: src/config.rs:15-26, src/session.rs:1-18, src/theme.rs:1-21, src/bar.rs:1-16, src/notifications.rs:7-21, README.md:40-70


Conclusion

Session management and Hyprland integration in rice are built around a small set of cohesive modules and commands:

  • rice session start orchestrates starting user applications and restoring wallpapers.
  • rice wall next|prev|start manage wallpaper selection, backend invocation, theme application, bar restarts, and persistent state updates.
  • Configuration and state are clearly separated via TOML and JSON files in XDG directories, resolved by the paths module.
  • External components (Hyprland, wallpaper backends, theming tools, bar, desktop notifications) are integrated via small, well-defined command calls encapsulated in helper modules.

Together, these pieces provide a straightforward yet flexible way to manage a Hyprland-based desktop session through a single CLI entry point that can be easily wired to Hyprland startup hooks and keybindings.
Sources: README.md:1-80, src/session.rs:1-34, src/wall/mod.rs:1-113, src/theme.rs:23-44, src/bar.rs:1-27, src/notifications.rs:23-54, src/main.rs:9-61

Clone this wiki locally