- C 73.7%
- C++ 25.3%
- CMake 1%
|
|
||
|---|---|---|
| docs | ||
| extra | ||
| include | ||
| LICENSES | ||
| protocols | ||
| src | ||
| .gitignore | ||
| AGENTS.md | ||
| CMakeLists.txt | ||
| config.toml | ||
| LICENSE | ||
| README.md | ||
Zurin
A modular Wayland compositor with Dwindle tiling layout and TOML-based runtime configuration.
Features
- Dwindle Layout: Smart binary tree tiling with cursor-aware window placement
- Directional Control:
focusdir,swapwindowand keyboardresizeactivefor keyboard-driven layouts - Runtime Configuration: TOML-based configuration with functional hot-reload (keybinds, appearance, wallpaper and input settings are reapplied live on save) and
zurin -tvalidation - Window Rules: match by app id substring or regex, title regex, floating geometry, monitor by name, opacity, borders, gaps and fullscreen
- Per-window Opacity: global active/inactive opacity, rule overrides and runtime
setopacity/IPC control - Keybind Submaps: named modes (
[keybinds.resize]) with a safe Escape exit - Modular Architecture: Focus on scalability and customization
- Screencast with Consent: PipeWire screen sharing through the XDG Desktop Portal with a user consent menu and source selection (entire screen, output or window), including an optional "always allow" permission store
- Interactive Screenshot: Region/window/output capture (bound to
Super+Shift+S) with clipboard integration - Wallpaper Modes: fill/fit/tile/center drawing modes with live reload of both path and mode
- Hardened IPC: Non-blocking Unix-socket control interface (
zbus) with peer authentication, per-client timeouts, runtime commands (dispatch,reload,gaps,opacity, …) and a JSON event stream (zbus subscribe)
Documentation
Full reference in docs/:
- Building and running — dependencies, CMake options, sessions, config validation
- Configuration — every TOML table with defaults and examples
- Actions — complete action reference for keybinds, gestures and
zbus dispatch - IPC — commands, events,
subscribeand examples - Architecture — module map, scene layers, dwindle tree, internals
Dependencies
Required
| Package | Version | Description |
|---|---|---|
| wlroots | 0.19+ | Wayland compositor library |
| wayland | 1.21+ | Wayland protocol libraries |
| wayland-protocols | 1.32+ | Wayland protocol definitions |
| xkbcommon | 1.5+ | Keyboard handling library |
| libinput | 1.21+ | Input device handling |
| pixman | 0.42+ | Pixel manipulation library |
| libdrm | 2.4+ | Direct Rendering Manager |
| libpipewire | 0.3+ | Audio/Video processing graph |
| libsystemd | - | System and Service Manager library |
Optional
| Package | Description |
|---|---|
| xcb, xcb-icccm | Required for XWayland support |
Runtime
These tools are configured by default but can be changed in config.toml.
| Tool | Description |
|---|---|
| kitty | Default terminal emulator |
Build Tools
- CMake 3.16+
- pkg-config
- GCC or Clang with C11 support
- wayland-scanner
Building
# Create build directory
mkdir build && cd build
# Configure (RELEASE)
cmake ..
# Configure (DEBUG)
cmake -DDEBUG_MODE=ON ..
# Configure (with XWayland support)
cmake -DENABLE_XWAYLAND=ON ..
# Build
make -j$(nproc)
# Install
sudo make install
Running
zurin
Configuration
Edit config.toml in the project directory or ~/.config/zurin/config.toml.
Validate changes without restarting the session with:
zurin -t # checks the resolved config
zurin -t -c file # checks a specific file
The complete reference (all tables, defaults and examples) is in
docs/configuration.md.
Default Keybinds
| Keybind | Action |
|---|---|
| Super+Q | Open terminal (kitty) |
| Super+P | Open launcher (wmenu) |
| Super+Shift+S | Screenshot region |
| Super+Tab | Close window |
| Super+(1-0) | Switch workspace |
| Super+Shift+(1-0) | Move to workspace |
| Super+Shift+M | Quit |
| Super+Mouse Left | Move window |
| Super+Mouse Right | Resize window |
All keybinds are configurable in config.toml ([keybinds] and
[keybinds.mouse]). Directional focus/swap, keyboard resize, opacity and
keybind submaps are available as actions — see
docs/actions.md for the full list with examples.
Window rules and opacity
Rules match by app id (substring key or app_id regex) and can set floating
state, workspace, monitor (by name), size/position/center, opacity, borders,
gaps and fullscreen:
[rules]
"gimp" = { floating = true, size = [1200, 800], center = true }
"kitty" = { border = false, gaps = false, opacity = 0.95 }
See docs/configuration.md#rules.
Input
[settings.input]
natural_scroll = false
accel_speed = 0.0
accel_profile = "adaptive"
invert_buttons = false
Appearance
Wallpaper rendering mode is set with wallpaper_mode under [settings.appearance]:
| Value | Mode |
|---|---|
| 0 | fill (default) |
| 1 | fit |
| 2 | tile |
| 3 | center |
The wallpaper path and mode are watched on config reload: changing either one respawns the wallpaper client live.
Screenshot
The screenshot actions can be bound to any keybind via the [keybinds] table:
"Super+Shift+S" = "screenshot region" # interactive region selection
"Super+Shift+W" = "screenshot window" # focused window
"Super+Shift+O" = "screenshot output" # focused output
region opens an interactive selection overlay (slurp style); the captured image is copied to the clipboard. Super+Shift+S is bound to screenshot region by default.
Portal consent menu
When an app requests screen sharing, Zurin shows a consent menu and, for window sources, an interactive window picker. The menu entry under [apps] must point to a dmenu-compatible picker:
[apps]
menu = "fuzzel --dmenu" # or "wmenu"
The picker reads the options from stdin and prints the selection to stdout.
IPC
Zurin exposes a control socket at $XDG_RUNTIME_DIR/zurin.sock. The zbus client is the supported way to talk to it:
zbus workspaces # List active workspaces (JSON)
zbus workspace set N # Switch to workspace N (or next|prev)
zbus monitors # List connected monitors (JSON)
zbus clients # List open windows (JSON)
zbus apps # List configured applications (JSON)
zbus open <app_name> # Launch an application from [apps]
zbus close <id> # Close a specific window
zbus focus <id|next|prev|left|right|up|down>
zbus show-focus # Show details of the focused window (JSON)
zbus version # Compositor and protocol version
zbus status # Runtime status (mode, layout, gaps, …)
zbus dispatch <action> … # Run any keybind action (see docs/actions.md)
zbus spawn <command> # Run a shell command detached
zbus reload # Reload the TOML config
zbus gaps set <in> <out> # Runtime gaps (gaps reset restores the TOML values)
zbus opacity <id|active> <v> # Per-window opacity (opacity reset <id> too)
zbus move <id> <monitor> # Move a window to another monitor
zbus monitor focus <name> # Focus a monitor
zbus screenshot region|window|output
zbus subscribe [event...] streams JSON events (workspace, focus, open,
close, title, urgent, state, mode, monitor) on a persistent connection —
ideal for status bars and scripts:
zbus subscribe workspace focus
{"event":"workspace_changed","monitor":"eDP-1","workspace":3}
{"event":"client_focused","id":"0x...","title":"kitty","appid":"kitty"}
The socket is created with mode 0600 and every connection is verified with SO_PEERCRED (only the same UID is accepted), so a foreign local user cannot drive the compositor even if the socket path leaks. Full protocol reference: docs/ipc.md.
License
See LICENSES/ directory:
LICENSE.dwl— dwl (GPL-3.0)LICENSE.wlroots— wlroots (MIT)LICENSE.tomlc99— tomlc99 TOML parser (MIT)LICENSE.stb— stb_image (public domain / MIT dual-licensed; used under the public-domain terms)
Contributing
Contributions are welcome! Please submit a pull request and open an issue for bug reports and feature requests.