Zero linked C, down to the kernel.

carrot is a tiling Wayland compositor, pure Rust from the top of the window stack to the bottom of the syscall table. No libwayland, no libdrm, no libinput. No libc, even. Everything beneath it is hand-grown.

Join the Discord Read the docs

v0.1.0 beta · GPL-3.0 · x86_64 Linux

Fresh from the garden

Under the whimsy there's a real, daily-drivable tiling compositor. The first beta already ships:

  • Dwindle + scrolling tiling

    A split tree or an endless column strip, switched live per workspace, with springs and bezier curves animating all of it.

  • Built for gaming

    VRR, tearing via wp-tearing-control, pointer constraints and relative motion, adaptive acceleration with real per-device DPI.

  • XWayland, in-house

    A complete X11 window manager, hand-rolled down to the wire protocol. Not a single line of libxcb.

  • Multi-monitor that behaves

    Hotplug, per-output modes, DPMS sleep and wake-on-input, VT switching that cleans up after itself.

  • Config in KDL or Lua

    A runtime switch, not a rebuild. A unit test proves both languages parse to the identical config.

  • burrow, the companion CLI

    JSON IPC over one socket, a live event stream for status bars, dispatchers for scripts, launch-to-workspace.

What’s grown · what’s still growing

First beta, honest ledger. Everything under Grown runs today. Still growing is planted: some of it parsed and waiting on the renderer, some of it still a seedling.

Grown

  • Complete input stack, from raw evdev to keymaps compiled in pure Rust
  • Atomic KMS with a hardware cursor plane
  • Vulkan renderer over a runtime-loaded Mesa driver
  • DMA-BUF import with explicit sync
  • Clipboard, drag & drop, primary selection
  • Screenshot and screen-record protocol support
  • PipeWire screencast portal for screen sharing
  • Layer-shell panels, docks, and lock screens
  • Session lock (ext-session-lock) that survives a crashed locker
  • Idle management and per-window idle inhibit
  • Taskbar and dock support (foreign-toplevel)
  • Window rules with per-window opacity and key remaps
  • Input injection server (libei protocol) for widgets and launchers
  • logind session integration without libseat or root
  • Device and monitor hotplug over raw netlink
  • Animations: springs, easings, and named bezier curves, tuned per kind
  • Scrolling layout: an endless column strip with width presets and an animated view
  • Presentation timing (wp_presentation) from real DRM flip timestamps
  • Rounded corners, ring borders, and drop shadows, drawn as SDF effects
  • Kawase blur with a cached backdrop, per window and per layer
  • Dim-inactive, resize crossfade, and tiled drag-and-swap
  • Direct scanout: a fullscreen game's buffer flips straight to the plane, zero-copy
  • Predictive late-latch scheduling, with every-vblank frame callbacks

The full changelog runs about ninety entries.

Still growing

  • Workspace groups + scratchpads: workspaces are flat numbers today; groups of ten and named special workspaces are still seedlings
  • Window groups, tabs: no grouping or groupbar yet; focus cycling covers the gap for now
  • Pin, PiP, free float placement: floats drag and resize under grabs, but nothing pins across workspaces, snaps to a corner, or centers on demand yet
  • Bordered fullscreen: fullscreen ships borderless only; the bordered variant waits its turn
  • no-capture granularity: the blackout treats every capture path alike today; telling your own deliberate screenshot apart from a live cast or recording is still a seedling
  • Fractional scale + viewporter: the n/120 coordinate model is already built; the two protocols are next
  • Multi-GPU: the renderer trait is in place; a second card has never actually loaded
  • Touch, gestures, tablets: keyboard, pointer, and wheel ship today; the rest is staged behind them
  • X11 loose ends: INCR clipboard transfers and the X11 drag-and-drop bridge

Watching it grow? Come watch from up close.

Zero linked C. Not low‑C. Zero.

Every Wayland compositor you’ve used borrows the same dozen C libraries. carrot grew its own, every layer of it, from the protocol wire format down to the dynamic linker. This is the root system:

  • libwaylanda declarative wire macro

    the whole protocol layer is generated by one Rust macro; every opcode is pinned by golden byte-fixture tests

  • libdrm + libgbmraw kernel modesetting

    atomic commits built by hand from ioctl opcodes; scanout buffers allocated straight out of Vulkan, no gbm anywhere

  • libinputevdev, decoded by hand

    24-byte kernel structs read off an io_uring ring, with adaptive accel and per-device DPI parsed from udev's own data files

  • libxkbcommonkbvm + a sealed memfd

    keymaps compile in pure Rust and ship to clients in a write-sealed memfd; a full US keymap is baked into the binary so carrot boots with zero XKB data on disk

  • libseata logind client from scratch

    session takeover, VT switching, and device pause/resume over hand-marshalled D-Bus, with teardown ordered before the ack, the way logind demands

  • libdbusits own wire codec

    client and server roles, the SASL auth burst, and the out-of-band fd queue, all written from the spec

  • libxcb / xlibxparsnip

    an X11 wire library generated from declarative tables, plus the window manager that speaks it, sequence fencing and selections included

  • libpipewirea native client node

    the SPA-POD wire format and the graph-driver activation dance (shared-memory atomics and eventfd kicks), reproduced from raw offsets

  • libeian EIS server

    input injection for launchers and remote desktops, routed through the same seat code as real keyboards

  • libvulkandlopen-rs, a Rust dynamic linker

    no Khronos loader: carrot finds the Mesa driver's .so, loads it with a pure-Rust linker, and negotiates the loader interface itself

  • glibc + ld.sotaproot

    carrot's own libc, forked from c-ward, under a static-PIE that applies its own relocations: there is no interpreter to ask

0*C libraries linked
~57,000lines of Rust
~230commits to first beta
1language, all the way down

The deepest trick: the binary keeps its dynamic symbol table alive so that when Mesa's GPU driver is loaded at runtime, the driver's calls to malloc resolve back into carrot's own Rust libc. The C driver believes it is talking to glibc. It is actually talking to the compositor.

Help it grow.

carrot is one developer, a first beta, and a very deep hole. Testers, contributors, protocol pedants, and people who just want to watch. The burrow has room.

Join the Discord Star it on GitHub

v0.1.0 beta is the first release: tiling, a complete input stack, XWayland, VRR, tearing, and some ninety sibling features. Read the changelog.