i3-compatible tiling WM written in Zig. ~7,500 LOC (src + bar), 3 binaries (zephwm, zephwm-msg, zephwm-bar). Target: HackberryPi Zero (RPi Zero 2W, 512MB RAM). All tests pass (~700+ tests across 7 suites), zero memory leaks.
- Frame windows: full X11 reparenting with save-set for crash recovery, ICCCM-compliant unreparent on shutdown/restart
- Font detection: 4-font fallback (fixed → misc-fixed-semicondensed → misc-fixed-normal → cursor) with xcb_query_font metrics
- Per-output bar: one bar window per monitor, output-scoped _NET_WM_STRUT_PARTIAL, per-bar workspace filtering
- i3bar click protocol: bidirectional stdin/stdout, per-block tracking (StatusBlock), protocol header detection (click_events:true)
- Synthetic ConfigureNotify: sent to all clients after relayout (ICCCM requirement for reparenting WMs)
- Border layout fix: frame content shrunk by 2*border so borders fit within layout rect (visible on all 4 sides)
border normal: i3-compatible title bar on individual windows — per-window title bar with ellipsis text truncation, deferred flush-then-draw, layout space reservation, Expose/PropertyNotify redrawborder normal <width>: width argument parsing for bothborder normal Nandborder pixel N- Ellipsis: long window titles truncated with "..." in tabbed, stacked, and border normal title bars
- Frame background fix: XCB_CW_BACK_PIXMAP=None prevents X server white repaint on resize
- i3 default colors: unfocused title bar bg #222222 + text #888888 (was #333333/#ffffff)
- Default border normal: new windows default to border normal 2 (matching i3)
- Config:
default_border normal/pixel/none [N]fully supported - Docker i3 comparison: compare_i3.sh for pixel-level visual comparison against real i3
- Config-driven colors:
client.focused/client.unfocusedbg/text reflected in title bars, reload-aware client.focused_inactive: parsed with border/bg/text colorshide_edge_borders: none/vertical/horizontal/both/smart, hides border on sole tiling window- Scratchpad fix: move scratchpad now correctly unmaps the window
- Perf: eliminated redundant xcb_flush in render, O(n²)→O(n) tabbed visibility, merged iterations
- Extended tests: xterm/urxvt/xclock/xeyes, 20-window stress, memory check (4MB RSS)
- Core tiling: hsplit/vsplit/tabbed/stacked, focus/move/resize, marks, scratchpad
- Multi-monitor: XRandR 1.5, focus_output, hot-plug, workspace-output config, move workspace to output
- IPC: all 11 message types, event subscription (workspace/window/mode/binding/output)
- Commands: border none/pixel/normal/toggle, sticky enable/disable/toggle, splith/splitv
- Urgent workspace: WM_HINTS urgency propagation, clear on focus
- Performance: O(1) window HashMap, batched xcb flush, single-pass render with deferred floating/fullscreen
- Config: keybinds, variables, modes, colors, gaps, for_window, assign, exec/exec_always
- drawTitleBars runs AFTER frame configure (with flush), not before — prevents X11 clear-on-resize
- Client window uses separate mask (no CONFIG_WINDOW_BORDER_WIDTH) — was causing random client borders
- Stacked GC_BACKGROUND set for correct text background on unfocused headers
- Last tab extends to frame edge (integer division remainder fix)
- Zero-size windows clamped to 1px minimum
- config_border_px passed through applyTree for correct per-window default
zig build test # ~110 unit tests
bash test_xephyr.sh # 73 basic integration
bash test_xephyr_newfeatures.sh # 43 new feature tests
bash test_xephyr_extended.sh # 59 advanced tests
bash test_xephyr_multimon.sh # 35 multi-monitor tests
bash test_xephyr_resolutions.sh # 180 multi-resolution (10 resolutions)
bash test_xephyr_visual.sh # 170 pixel verification (10 resolutions)
bash test_docker_realapps.sh # 65 Docker tests (xterm + alacritty + kitty, screenshot pixel checks)
bash test_realapps_extended.sh # 27 extended tests (urxvt, xclock, xeyes, stress, scratchpad) via Dockerfile.realapps
Docker tests use Xvfb inside container (2GB mem limit), no host impact.
- HackberryPi real hardware test — build and run on actual RPi Zero 2W (720x720 HyperPixel4)
- Cross-compile:
zig build -Doptimize=ReleaseSmallon device or with aarch64 sysroot - Test with actual i3 config, i3blocks, rofi
- Cross-compile:
- kitty/alacritty pixel content checks skipped in Docker (GPU rendering doesn't work with Xvfb)
border toggledoes not resetborder_width_overridewhen cycling stylesbindcodenot implemented (keysym works for all keys)focused_inactivecolor not yet used in rendering (parsed but not applied)- Pango/FreeType fonts not supported (X11 core fonts only, no CJK/emoji)
- Single-threaded epoll loop (main.zig)
- Container tree: root → output → workspace → split_con → window
- Frame windows: every managed window reparented into WM-owned frame
- Window lookup: HashMap(u32, *Container) for O(1), both client_id and frame_id
- UnmapNotify: pending_unmap counter + mapped state + ev.event==ev.window guard + frame_id guard
- Render: single-pass, title bars after frame configure + flush, deferred floating/fullscreen
- Save-set: clients added to X server save-set before reparent (crash recovery)
- Synthetic ConfigureNotify: sent to all managed windows after relayoutAndRender
- Repo: git@github.com:midasdf/zephwm.git
- Branch: master
- Latest: d46cab5