A tiling window manager for the River Wayland compositor, written in Python.
nix run github:pinpox/river-pwm
The script automatically detects if you're running inside another compositor:
WAYLAND_DISPLAY or DISPLAY is set): Opens River in a windowpwm --help
Options:
--terminal, -t TEXT Terminal emulator (default: foot)
--launcher, -l TEXT Application launcher (default: fuzzel)
--gap, -g INTEGER Gap between windows in pixels (default: 4)
--border-width, -b INTEGER Border width in pixels (default: 2)
All bindings use Alt as the modifier key.
| Binding | Action |
|---|---|
Alt+Return | Spawn terminal |
Alt+D | Spawn launcher |
Alt+Q | Close focused window |
Alt+Shift+Q | Quit window manager |
| Binding | Action |
|---|---|
Alt+J / Alt+Down | Focus next window |
Alt+K / Alt+Up | Focus previous window |
Alt+Shift+J | Swap with next window |
Alt+Shift+K | Swap with previous window |
Alt+Shift+Return | Promote focused window to master |
| Binding | Action |
|---|---|
Alt+Space | Cycle to next layout |
Alt+Shift+Space | Cycle to previous layout |
Alt+F | Toggle fullscreen |
| Binding | Action |
|---|---|
Alt+1-9 | Switch to workspace 1-9 |
Alt+Shift+1-9 | Move window to workspace 1-9 |
Cycle through layouts with Alt+Space / Alt+Shift+Space.
river-pwm/
├── flake.nix # Nix flake for building
├── __init__.py # Package exports
├── __main__.py # Entry point
├── protocol.py # Wayland protocol definitions
├── connection.py # Wayland socket handling
├── objects.py # Window, Output, Seat objects
├── manager.py # Core WindowManager class
├── layout.py # Layout algorithms
└── riverwm.py # Complete WM implementation
from pwm import RiverWM, RiverConfig, Modifiers
# Create custom configuration
config = RiverConfig(
terminal='alacritty',
launcher='wofi',
gap=8,
border_width=3,
mod=Modifiers.MOD4, # Use Super instead of Alt
)
# Create and run window manager
wm = RiverWM(config)
wm.run()
from pwm import Layout, LayoutGeometry, Area, Window
class MyLayout(Layout):
@property
def name(self) -> str:
return "my-layout"
def calculate(self, windows: list[Window], area: Area) -> dict[Window, LayoutGeometry]:
result = {}
# ... implement layout logic ...
return result
This implementation uses the following River protocols:
river-window-management-v1: Core window managementriver-xkb-bindings-v1: Keyboard bindingsriver-layer-shell-v1: Layer shell integrationThe project uses Nix flakes for reproducible builds. The flake provides:
packages.pwm: The pwm window manager binarypackages.river: River compositor 0.4.x (from upstream)packages.river-pwm: Smart launcher script (auto-detects nested/bare-metal mode)Note: The flake includes River 0.4.x for convenience, but River is developed separately by the River project.
ISC License (same as River).
pwm is created by pinpox as a window manager for the River Wayland compositor.
River itself is developed by Isaac Freund and the River contributors.
53 commits
Python
96.3%
Nix
3.2%
A tiling window manager for the River Wayland compositor, written in Python.
nix run github:pinpox/river-pwm
The script automatically detects if you're running inside another compositor:
WAYLAND_DISPLAY or DISPLAY is set): Opens River in a windowpwm --help
Options:
--terminal, -t TEXT Terminal emulator (default: foot)
--launcher, -l TEXT Application launcher (default: fuzzel)
--gap, -g INTEGER Gap between windows in pixels (default: 4)
--border-width, -b INTEGER Border width in pixels (default: 2)
All bindings use Alt as the modifier key.
| Binding | Action |
|---|---|
Alt+Return | Spawn terminal |
Alt+D | Spawn launcher |
Alt+Q | Close focused window |
Alt+Shift+Q | Quit window manager |
| Binding | Action |
|---|---|
Alt+J / Alt+Down | Focus next window |
Alt+K / Alt+Up | Focus previous window |
Alt+Shift+J | Swap with next window |
Alt+Shift+K | Swap with previous window |
Alt+Shift+Return | Promote focused window to master |
| Binding | Action |
|---|---|
Alt+Space | Cycle to next layout |
Alt+Shift+Space | Cycle to previous layout |
Alt+F | Toggle fullscreen |
| Binding | Action |
|---|---|
Alt+1-9 | Switch to workspace 1-9 |
Alt+Shift+1-9 | Move window to workspace 1-9 |
Cycle through layouts with Alt+Space / Alt+Shift+Space.
river-pwm/
├── flake.nix # Nix flake for building
├── __init__.py # Package exports
├── __main__.py # Entry point
├── protocol.py # Wayland protocol definitions
├── connection.py # Wayland socket handling
├── objects.py # Window, Output, Seat objects
├── manager.py # Core WindowManager class
├── layout.py # Layout algorithms
└── riverwm.py # Complete WM implementation
from pwm import RiverWM, RiverConfig, Modifiers
# Create custom configuration
config = RiverConfig(
terminal='alacritty',
launcher='wofi',
gap=8,
border_width=3,
mod=Modifiers.MOD4, # Use Super instead of Alt
)
# Create and run window manager
wm = RiverWM(config)
wm.run()
from pwm import Layout, LayoutGeometry, Area, Window
class MyLayout(Layout):
@property
def name(self) -> str:
return "my-layout"
def calculate(self, windows: list[Window], area: Area) -> dict[Window, LayoutGeometry]:
result = {}
# ... implement layout logic ...
return result
This implementation uses the following River protocols:
river-window-management-v1: Core window managementriver-xkb-bindings-v1: Keyboard bindingsriver-layer-shell-v1: Layer shell integrationThe project uses Nix flakes for reproducible builds. The flake provides:
packages.pwm: The pwm window manager binarypackages.river: River compositor 0.4.x (from upstream)packages.river-pwm: Smart launcher script (auto-detects nested/bare-metal mode)Note: The flake includes River 0.4.x for convenience, but River is developed separately by the River project.
ISC License (same as River).
pwm is created by pinpox as a window manager for the River Wayland compositor.
River itself is developed by Isaac Freund and the River contributors.
53 commits
Python
96.3%
Nix
3.2%