#window-manager #tiling-window-manager #river #wayland #config

app orilla-run

TOML-configurable binary for running orilla, a tiling WM for River

1 unstable release

Uses new Rust 2024

0.1.0 Mar 6, 2026

#380 in GUI

GPL-3.0-only

125KB
3K SLoC

orilla

Rust builds.sr.ht status todo.sr.ht wiki

orilla is a Rust-based window manager for the river Wayland compositor.

Inspired by XMonad, it exists for a simple reason: layout is ergonomics. How your tools are arranged affects how well you can use them.

(too much) more: https://man.sr.ht/~hokiegeek/orilla/#philosophy

features

  • Dynamic tiling for river, configured in Rust.
  • Composable layouts with predictable keyboard-driven navigation.
  • Strong integration with river protocol behavior and seat/input handling.
  • Two entry points: code-first orilla library and TOML-based orilla-run.

Would you like to know more?: https://man.sr.ht/~hokiegeek/orilla/roadmap.md

crates

This repo is split into two crates:

  • orilla (crates/orilla): the core library crate and primary interface for building your window manager config in Rust.
  • orilla-run (crates/orilla-run): a convenience binary that loads a simple TOML config and runs orilla, useful for bootstrapping into orilla.

how to get started

Use the cargo-generate template to scaffold a code-first orilla config:

# generate it
cargo install cargo-generate
cargo generate --git https://git.sr.ht/~hokiegeek/orilla.git --subfolder template --name my-orilla

# build it
cd my-orilla
cargo build --release

Then:

  1. Edit src/main.rs in your generated project to match your keybindings and layout preferences.
  2. Add this to ~/.config/river/init: <location of your file>/my-orilla/target/release/my-orilla &

configuration

orilla is configured in Rust. Your generated project is just a normal Rust binary that builds an Orilla instance, sets options, registers keybindings, and calls run().

A minimal example:

use orilla::prelude::*;

fn main() {
    let tags: Vec<char> = "1234567890".chars().collect();
    let mut wm = orilla::Orilla::new()
        .layouts(layout_set![layouts::Tall::new(), layouts::Full])
        .borders(Borders::new(2, "#9e9e9e80").focused("#008080e6").urgent((3, "#ff0000")))
        .tags(tags.iter().map(|&t| t.to_string()).collect())
        .keys(vec![
            Keybinding::new(Mods::Super, 'm', action::focus_primary()),
            Keybinding::new(Mods::Super, 'n', action::focus_next()),
            Keybinding::new(Mods::Super, 'e', action::focus_prev()),
            Keybinding::new(Mods::Super | Mods::Shift, 'c', action::close()),
            Keybinding::new(Mods::Super, keysyms::space, action::cycle_layout()),
            Keybinding::new(Mods::Super, 't', action::spawn("fuzzel")),
            Keybinding::new(Mods::Super, keysyms::Return, action::spawn("foot")),

            // Bindings related to the 'Tall' layout
            Keybinding::new(Mods::Super, keysyms::comma, action::message(Tall::IncMainCount)),
            Keybinding::new(Mods::Super, keysyms::period, action::message(Tall::DecMainCount)),
            Keybinding::new(Mods::Super, 'h', action::message(Tall::ShrinkMain)),
            Keybinding::new(Mods::Super, 'l', action::message(Tall::GrowMain)),
            Keybinding::new(Mods::Super, 'm', action::message(Tall::FocusMain)),
        ]
        .into_iter())
        .chain(tags.iter().map(|&tag| Keybinding::new(Mods::Super, tag, action::switch_tag(tag.to_string()))))
        .chain(tags.iter().map(|&t| Keybinding::new(Mods::Super | Mods::Shift, t, action::shift_tag(t.to_string()))))
        .collect());

    if let Err(e) = wm.run() {
        eprintln!("orilla failed: {e}");
        std::process::exit(1);
    }
}

Dig deeper: https://man.sr.ht/~hokiegeek/orilla/configuration.md

Dependencies

~13–22MB
~352K SLoC