A Wayland tiling compositor — Rust + Smithay, tag-based, with first-party lock screen, monitor profiles, screenshot helper and IPC.
margo is a Wayland compositor in the dwl/mango tradition — a Rust + Smithay port of mango with tags instead of workspaces, a deep tiling layout catalogue, and a complete first-party stack for everyday use: a GTK4 desktop shell (mshell) with bar / menus / notifications / OSD / settings UI, a control CLI (mctl), a screen locker (mlock), a TUI login manager (mlogind), monitor profiles (mlayout), and a screenshot helper (mscreenshot). The whole stack ships from one workspace and one release. The compositor speaks dwl-ipc-v2 so third-party shells like noctalia also work — but you don't need one.
Everything below is part of the default install — the whole shell recolours itself from your wallpaper with Material You.
These are eight of mshell's 30-plus widgets. More on the documentation site.
| Binary | Role |
|---|---|
margo |
Wayland compositor — DRM/KMS backend, tag workflow, layout engine |
start-margo |
Watchdog supervisor — restart-on-crash with a rolling budget, sd_notify integration, signal forwarding, PR_SET_PDEATHSIG parent-child invariant |
mctl |
Compositor IPC + control — status / clients / outputs / focused / dispatch / tags / layout / reload / theme / twilight {status,preview,test,set,reset,toggle,preset} / migrate / actions / check-config / config-errors / rules |
mshell |
First-party desktop shell — GTK4 + relm4 + gtk4-layer-shell, bar with configurable pill set, dashboard / clock / quick-settings / notifications menus, OSD, in-app Settings UI |
mshellctl |
Shell IPC — menu / bar / audio / brightness / lock / settings / wallpaper / set-wallpaper / inspect / quit (open/close menus, cycle wallpapers, toggle audio mute, drive the settings window, GTK inspector) |
mlock |
Screen locker — ext-session-lock-v1, cairo + pango, PAM auth, wallpaper backdrop, avatar, F1/F2/F3 power keys |
mlayout |
Named monitor profiles — mlayout suggest writes presets for the detected setup, mlayout set <name> flips between them |
mscreenshot |
Screen / region / window capture — wraps grim + slurp + wl-copy + optional editor (swappy / satty); --delay N countdown, --output NAME monitor pin, notification action buttons |
mlogind |
TUI login / display manager (fork of lemurs) — bare-TTY greeter on a VT, PAM auth + X/Wayland session launch, themed from the margo matugen palette; mlogind sync-theme tracks the wallpaper |
mwizard |
First-launch setup wizard — opens the in-shell layer-shell wizard menu (theme / keyboard / touchpad / Wi-Fi / wallpaper / bar), thin shim over mshellctl wizard |
mvisual |
Visual debugger for the renderer |
Every directory in the workspace maps 1:1 to a binary it produces. Library-only crates (margo-config, margo-layouts, mshellshare, and the mshell-crates/* family) keep their descriptive prefix.
- Tags, not workspaces. Nine multi-select tags; press the same tag twice to bounce back, several together to view a union, pin tags to a home monitor, regex-match windows into tags at map time.
- Layouts that remember. Tile, scroller, grid, monocle, deck, dwindle, center / right / vertical mirrors and an overview. Each tag holds its own layout choice.
- Spring + bezier animations. Niri-style spring physics with mid-flight retarget for window movement; bezier curves for open / close / tag / focus / layer transitions. SDF drop shadows, rounded corners, focus-fade opacity.
- Modern protocol stack.
ext-session-lock-v1,ext-idle-notify-v1, DMA-BUF screencopy,pointer_constraints+relative_pointer,xdg_activationwith anti-focus-steal, runtimewlr_output_management, VBlank-accuratepresentation-time,wp_color_management_v1. - Window rules with PCRE2. Float password prompts, pin apps to tags, screencast-blackout password managers, swallow terminal children, force CSD per-app — all by
app_id/titleregex. Acceptswidth:50%/height:50%monitor-relative fractions alongside absolute pixels (mango 0.13+ syntax). - Mango 0.13+ feature parity. Drag-tile-to-tile (drag one tiled window onto another to swap them, optional 300×300 thumbnail during drag), split mouse / trackpad acceleration profiles, trackpad-specific scroll factor.
- Twilight blue-light filter. Static / Geo (sunrise-aware) / Manual / Schedule modes. Schedule mode reads sunsetr-compatible TOML presets from
~/.config/margo/twilight/and interpolates in mired space between consecutive presets across the day; first run seeds a six-preset starter set the user can edit by hand or viamctl twilight preset {list,set,remove,schedule}. - In-compositor screencast portal. Five Mutter D-Bus shims + a PipeWire pipeline so
xdg-desktop-portal-gnomeserves Window / Entire-Screen tabs without gnome-shell. - Embedded scripting. Drop
~/.config/margo/init.rhai; call any compositor action from a sandboxed Rhai interpreter, hookon_focus_change/on_tag_switch/on_window_open. - Hot reload.
mctl reload(orSuper+Ctrl+R) re-applies window rules, key binds, monitor topology, animation curves, gestures — no logout. - DRM hotplug. Dock / undock, plug a second monitor mid-session; outputs come and go cleanly.
dwl-ipc-v2compatibility. Drop-in for noctalia, waybar-dwl, fnott, and any other dwl/mango widget — that's how the bar / launcher / OSD / notifications surface on screen.
A small Rust watchdog launcher. Start your session through it instead of calling margo directly:
# DM session line (e.g. /usr/share/wayland-sessions/margo.desktop)
Exec=start-margo
# Or under uwsm, replacing the compositor leaf:
uwsm app -a start-margo -- start-margoThree improvements over Hyprland's start-hyprland:
- Crash budget.
--max-restarts 3 --restart-window-secs 60by default — after that many crashes in the window the supervisor exits non-zero, returning the user to the DM instead of pinning a CPU on a respawn loop with a broken config.start-hyprlandwill respawn indefinitely. - systemd
sd_notify. EmitsREADY=1after spawn andSTOPPING=1on shutdown, so aType=notifyunit (uwsm'swayland-wm@.servicetemplate) sees the session as active without polling. - Signal forwarding preserves the signal. SIGTERM / SIGINT / SIGHUP are forwarded as-is, so margo's own teardown (Wayland surface destruction, ext-session-lock cleanup,
session.jsonsnapshot) runs end-to-end.start-hyprlandalways sends SIGTERM regardless of what it received.
Shared with start-hyprland: PR_SET_PDEATHSIG(SIGKILL) so a kill -9 start-margo cannot leave an orphaned compositor; --path for dev/staging margo builds; -- to forward everything after it to margo.
Ready-to-copy session glue (a Wayland-session .desktop, a uwsm wrapper, the margo-session launcher, and a systemd drop-in) lives in contrib/sessions/ — see its README for the quick install.
mlockusesext-session-lock-v1, so the compositor cooperates: locked sessions stay locked across mlock crashes, and onlymargo'sforce_unlockkeybind can break out. Renders a blurred wallpaper, large clock, time-of-day greeting, avatar (~/.faceor AccountsService), frosted password card with shake-on-fail and an attempt counter. Authenticates the session owner via PAM. Battery indicator andF1/F2/F3power keys with a two-press confirmation banner.
mlogindis a first-party TUI login / display manager, forked from lemurs (MIT/Apache-2.0) and brought under the workspace. It runs as a systemd service on a bare VT — no compositor needed to log in — drawing aratatuigreeter (user field + session switcher + password), authenticating through PAM, and launching the chosen X11 / Wayland session (margo included). Themed from the margo matugen palette via$-variables in/etc/mlogind/variables.toml;sudo mlogind sync-themerepaints it from the active wallpaper so the greeter matches the desktop. Power controls (F1Shutdown /F2Reboot /F3Suspend) and opt-in fingerprint login (pam_fprintd). The package ships its config + PAM + systemd unit to/etc(inert until yousystemctl enable mlogind); it never auto-replaces your current display manager.
A first-party GTK4 + relm4 + gtk4-layer-shell desktop shell that consumes dwl-ipc-v2 directly. No need to wire up an external shell unless you want one — mshell ships with everything below preconfigured, and Settings UI lives inside the same panel as the menus (no separate window).
- Bar with configurable pill set. Workspace pills (per-tag accent + window-count dots), active-window pill, clock, media player, network speed, battery, audio, tray, notifications. Plus the opt-in A-series (Privacy mic+cam indicator, CPU/RAM/Temp sysstat, Caps/Num/Scroll lock keys, Dark-mode toggle, KeepAwake idle-inhibit, rounded screen corners) and B-series (System-update count badge with right-click refresh, Display→Layout panel driving mlayout).
- Composite menus. Dashboard (hero + 2-col + power footer) folds clock, weather and quick-settings into a single panel; clock menu carries a noctalia-style calendar grid; session menu (
super+delete) drives Lock / Logout / Suspend / Reboot / Shutdown with 3-second countdown confirmation; notifications menu with urgency bar, count badge, action buttons and date-grouped history. - OSD. Brightness / volume / network-change pills with consistent 320 px noctalia-style geometry.
- Wallpaper. Per-tag wallpaper assignment, optional rotation timer,
mshellctl wallpaper next/prev/randomfor scriptable cycling. - Idle.
ext-idle-notify-v1consumer; trayKeepAwakepill toggles the inhibit at runtime. - Settings UI. Alphabetic sidebar with Bar at top level and Widgets as a group exposing every pill and menu as its own page. Live preview, debounced reload — slider drags don't thrash the compositor.
- Sound. Optional matugen-style palette (
mshell-matugen) generates wallpaper-derived themes that drive both the shell and the compositor border / focus colours.
The repository ships a single installer, install.sh, that
detects your distribution and does the right thing — build, install, and
uninstall. Clone the repo and run it:
git clone https://github.com/kenanpelit/margo
cd margo
./install.sh # build + install (detects distro)
./install.sh uninstall # remove margo
./install.sh --helpIt installs all twelve binaries (compositor + shell + helpers), the
margo-portal screencast/screenshot backend, the Wayland session entry,
example configs and layouts, and shell completions.
From the AUR (recommended) — margo-git
builds the full stack from GitHub HEAD; any AUR helper resolves the
dependencies and builds it:
paru -S margo-git # or: yay -S margo-gitIt's a VCS (-git) package — re-running the same command rebuilds against
the latest main. Uninstall with pacman -Rns margo-git.
From the repo — ./install.sh runs the bundled PKGBUILD through
makepkg + pacman (handy when working on the tree locally):
./install.sh # makepkg build + pacman install
./install.sh uninstall # pacman -R margo-gitRequires GTK ≥ 4.20. margo's GTK4 bindings need GTK 4.19+, so Ubuntu 24.04 LTS (GTK 4.14) is not supported — and
apt upgradewon't help, because an LTS keeps the same GTK for its lifetime. Use Ubuntu 25.10+ / 26.04 LTS (or any distro with GTK 4.20+). The installer verifies the GTK version up front and stops early with a clear message on older releases.
The Ubuntu path installs the build dependencies via apt, bootstraps a
current Rust toolchain with rustup if the system one is too old (margo
is Rust edition 2024), builds gtk4-layer-shell from source when it
isn't packaged, then compiles and installs to /usr. Every installed
path is recorded in /usr/local/share/margo/install-manifest.txt, so
uninstall removes exactly what was added.
./install.sh deps # install build dependencies only (optional)
./install.sh # deps + Rust + build + install
./install.sh uninstall # remove (reads the install manifest)cargo build --release --workspace
for bin in margo start-margo mctl mshell mshellctl mlock mlayout mscreenshot mvisual mlogind mwizard mpicker; do
sudo install -Dm755 target/release/$bin /usr/bin/$bin
done
sudo install -Dm644 margo.desktop /usr/share/wayland-sessions/margo.desktopSystem dependencies: wayland, libinput, libxkbcommon, seatd, mesa, libdrm, pixman, pcre2, cairo, pango, pam, gtk4 (≥ 4.20), gtk4-layer-shell, xorg-xwayland (optional). Runtime: grim, slurp, wl-clipboard for screenshots; wlr-randr for live monitor re-layout; notify-send (libnotify) for mscreenshot's notification action buttons.
nix run github:kenanpelit/margoThe flake exposes packages.default, a devShells.default with rust-analyzer + clippy, plus nixosModules.margo and hmModules.margo.
All user config lives in ~/.config/margo/:
~/.config/margo/
├── config.conf # margo — compositor
├── layout_*.conf # mlayout — monitor profiles
├── twilight/ # mshell / mctl — blue-light filter
│ ├── schedule.conf # HH:MM → preset name lines
│ └── presets/ # <name>.toml (static_temp + static_gamma)
└── mshell/ # mshell — shell config, themes, wallpapers
A complete annotated config.conf ships at margo/src/config.example.conf. Hot-reloadable — mctl reload (or Super+Ctrl+R) re-applies window rules, key binds, monitor topology, animation curves.
# config.conf — small excerpt
borderpx = 3
border_radius = 12
focused_opacity = 1.0
unfocused_opacity = 0.9
tagrule = id:1, layout_name:scroller, monitor_name:DP-3
tagrule = id:7, layout_name:scroller, monitor_name:eDP-1
windowrule = tags:1, appid:^Kenp$
windowrule = isfloating:1, width:640, height:260, title:^(Authentication Required|Unlock Keyring)$
animation_clock_move = spring
animation_clock_tag = bezier
animation_curve_open = 0.16,1.0,0.30,1.0
bind = super, Return, spawn, kitty
bind = super, q, killclient
bind = super+ctrl, s, sticky_window
bind = super+ctrl, r, reload_config
bind = alt, l, spawn, mlock
bind = NONE, Print, screenshot-region-uiValidate before reloading:
mctl check-config# Compositor inspection
mctl status # per-output: focused / tags / layout
mctl clients --tag 2 # every window on tag 2 (table)
mctl outputs --json | jq '.[].name'
mctl focused # `app_id · title`, scriptable
# Compositor control
mctl dispatch togglefullscreen
mctl dispatch view 4 # tag bitmask 4 = tag 3
mctl reload
# Twilight (built-in blue-light filter)
mctl twilight status # current temp / phase / source
mctl twilight set mode=schedule # switch to preset schedule
mctl twilight preset list # all presets + the active schedule
mctl twilight preset set evening 2300 92
mctl twilight preset schedule set 19:00 evening
# Layout profiles
mlayout suggest # propose & activate a preset
mlayout set vertical-ext-top # apply a saved profile
# Screenshots
mscreenshot rec # region → editor → file + clipboard
mscreenshot rec --delay 3 # 3-second countdown for menus / tooltips
mscreenshot screen --output eDP-1 # pin to a specific monitor
mscreenshot window # focused window
# Shell
mshellctl menu show dashboard # bring up the composite dashboard
mshellctl menu session lock # one-shot lock from the session menu
mshellctl wallpaper next # cycle wallpaperDrop ~/.config/margo/init.rhai; margo evaluates it at startup.
// Auto-tag Spotify into tag 8
on_window_open(|| {
if focused_appid() == "spotify" {
dispatch("tagview", [tag(8)]);
}
});
// Bump tag 9 wallpaper via the external shell
on_tag_switch(|| {
if current_tag() == 9 {
spawn("osc-shell ipc call wallpaper next");
}
});
Engine: Rhai (pure Rust, sandboxed by default). Reference: docs/scripting-design.md.
- Documentation site — install, configuration, scripting, design notes (mkdocs-material).
CHANGELOG.md— release-by-release history (Keep-a-Changelog).road_map.md— what's shipped, what's queued, design trade-offs.docs/— design notes for in-flight features and the post-install validation checklist.mctl --help,mctl actions --verbose,mlock --help,mlayout --help,mscreenshot --help— generated from source, always current.
Built on Smithay. The compositor is a Rust rewrite of mango (which forked dwl, itself a dwm-on-wlroots descendant) — the tag model, pertag, layout algorithms and dwl-ipc protocol trace back through that line. The shell (mshell) is a fork of OkShell. Wayland protocol code is ported from niri (foreign-toplevel write-side, ext-workspace, virtual-pointer), and mshell widgets reimplement patterns from noctalia. margo additionally borrows architectural patterns (not code) from niri (focus oracle, hotplug, screencast portal, transactional resize), anvil (Smithay's reference compositor) and Hyprland (color-management protocol shape). mlock follows the architecture of nlock and waylock.
Derived portions are preserved under their respective licenses — see licenses/: mango, dwl, OkShell, niri (GPL-3.0-or-later), dwm and noctalia (MIT). margo is GPL-3.0-or-later. (margo is a pure-Smithay Rust compositor; it carries no wlroots, tinywl or sway code, so those upstream licenses are not included.)
GPL-3.0-or-later. See LICENSE.








