Pixel-perfect, CSS-themed, configuration-driven bar for the Niri Wayland compositor.
- Linux + Wayland only (Niri WM). No X11/macOS/Windows.
- GTK4 +
gtk4-layer-shell. - Rust toolchain (stable).
- Optional (for wallpaper switching):
swww(recommended) orswaybginstalled and running. - Optional (for battery/power):
powerprofilesctlfor power profile switching.
cargo build --release
./target/release/niri-barEdit niri-bar.yaml. Key sections:
application.theme: one ofwombat,solarized,dracula(default:wombat).application.modules: global module defaults (use YAML anchors/aliases).application.layouts: reusable layout profiles (columns → modules + overflow policy).application.monitors: list of regex-matched monitors withenabled,layout,modulesoverrides.
Example (excerpt):
application:
theme: wombat
modules:
clock: &clock_default { format: "%a %b %d, %Y @ %H:%M:%S", tooltip: true }
layouts:
three_column: &layout_three
columns:
left: { modules: ["workspaces"], overflow: hide }
center: { modules: ["window_title"], overflow: hide }
right: { modules: ["clock", "battery", "system"], overflow: kebab }
monitors:
- match: ".*"
enabled: true
layout: { <<: *layout_three }- Themes live in
themes/(wombat.css,solarized.css,dracula.css). - Every monitor/column/module gets stable CSS classes/ids for granular styling.
- Hot-reload: editing
niri-bar.yamlor any CSS inthemes/updates the bar immediately.
- GTK homogeneous layout ensures equal spacing and perfect centering (odd: exact center, even: symmetric).
- Column names are for CSS only; renderer uses order/count.
- Per-column overflow:
hide(crop) orkebab(dropdown popover for overflowed items).
Modules are loaded via a registry by name (e.g., clock → bar.module.clock).
clock: singleformatstring, updates every 1s independently.window_title: shows focused window title via Niri IPC state.workspaces: buttons per workspace; click to focus; wheel to next/prev;scroll_wraparoundsupported; optionalshow_wallpaperfor button thumbnails.battery: shows charge % + icon; optional power profile dropdown (requirespowerprofilesctl); pulse animation.tray: system tray icons (StatusNotifierHost) with right-click menus; supports swww/swaybg providers.
Configured in application.wallpapers:
default: fallback wallpaper path.by_workspace: map workspace name/index to specific paths (e.g.,"1","dev").special_cmd: custom command with${current_workspace_image}substitution.- Automatically switches wallpaper on workspace focus using: special_cmd → swww → swaybg → none.
- Default file:
~/.local/share/niri-bar/niri-bar.log.
- All tests live under
tests/; none inline insrc/*unless critical. - Validate the real
niri-bar.yamlagainstsrc/niri-bar-yaml.schema.json.
cargo test -- --test-threads=1
# Style & lint
cargo fmt -- --check
cargo clippy -- -D warnings- One persistent read socket (event stream), one short-lived write socket per request (no batching).
- State cached in a central bus consumed by UI modules on the GTK thread.
- Ensure Niri is running (Wayland) and
$NIRI_SOCKETis set by the compositor. - If nothing appears: check logs, validate YAML (
cargo test -- tests/config_tests.rs).
See the wiki/ folder for detailed architecture, configuration, theming, IPC, hot-reload, testing, and logging docs.