Notes for the codebase review
Collected while building M5 to M7 and the follow-ups. Each item names where to look. Ordered roughly by how much it would pay back.
Structure
Stateis a god object. It has 70 public fields instate.rs. They cover backend handles, every smithay protocol state, layout, animation, capture, imports, Xwayland, lock, idle, activation and launch tracking. Every module isimpl State, so nothing has a boundary and any function can touch anything. The protocol states are mostly inert after construction. They could live in oneProtocolsstruct, with the live subsystems (lock, captures, imports, xwayland, toplevel handles) owning their own data and taking narrow arguments.- Three copies of “draw an output”.
drm::render_surface,nested::renderandcapture::output_elementseach assemble cursor plus lock-or-scene, and each destructuresStatefield by field to satisfy the borrow checker.capture::output_elementsis the general version. The backends should call one function and keep only presentation. scene::buildtakes ten arguments and carries#[expect(clippy::too_many_arguments)]. Most of them are one borrowed view of the world. ASceneInputstruct, or the split above, removes it.drm::render_surfacedoes too much. It handles VRR switching, timing and budget, scene assembly, lock confirmation, capture damage, frame callbacks and the slow-frame log. VRR and stats could be methods onSurface.handlers.rsis a grab bag. It holds compositor commit logic, xdg-shell, decorations, seat, selection, DnD, syncobj,hold_until_readable, workspace actions and fullscreen. The commit handler alone runs import, window commit, unmapped mapping, first-buffer, popups, layers and capture damage in sequence. A per-role dispatch would read better.layout/src/lib.rsis 1000 lines. Tags, outputs, parking, scratchpads, focus history and arrangement share oneimpl Layout. Scratchpads and output parking look separable.render-vk/src/renderer.rsis 1100 lines. It mixes the smithay trait impls, submission and stall handling, the shm cache, read-back and the newDmabufImporter.
Duplication
CLEARis defined identically indrm.rs,nested/mod.rsandcapture.rs.- Closing a window (xdg
send_closeor X11close) is written out in bothcommands.rsandtoplevels.rs. It belongs on a window helper next toroot()andidentity(). - Window lookup is a linear scan:
window_idby surface,x11_window_id, the toplevel key lookup intoplevels.rs, andListHandles::window. That’s fine at desktop window counts, but four spellings of the same search should be one index. - Smoke-test shell scripts were rewritten for every protocol (
/tmp/m4fix/smoke_*.sh). A smallxtaskor.nuharness that starts nested monolith with a client list and collects logs would make protocol checks repeatable, and could gate CI later.
Code quality
- Per-dispatch work that doesn’t need to run.
after_dispatchrunspublish_workspacesandpublish_toplevelsafter every batch of events. They rebuild full snapshots and lock every toplevel’s data for titles even when nothing changed. A dirty flag set by commits, layout changes and focus changes would make them nearly free. - Silent
let _ =on X11configureandset_*calls, onnotifier.successful, and on several protocol sends. Most are fine, but the X11 ones hide real failures. configure()instate.rshandles both xdg and X11 windows with two inline branches. Once more window kinds exist (none planned), it wants a small trait.Xwaylandlifecycle. A SIGKILLed monolith leaves its/tmp/.X*-lockand socket behind.claimhandles stale locks by pid, but a recycled pid makes it skip that display for good. Low priority.Focus::X11(Box<X11Surface>)exists only to satisfylarge_enum_variant. That’s fine, butX11Surfaceis 432 bytes, which is worth knowing.- Comment density is uneven. Some modules carry a doc line on most items, others none. Check against the comment rules in one sweep.
Tests
- The layout proptest pulls its weight. It caught the hidden root-leaf bug the moment the “hidden tiles have no area” invariant was added. More invariants in
check_geometry(focus always visible, tags always viewed somewhere) would be cheap and high-yield. - Nothing tests the protocol servers.
workspace.rsandtoplevel.rsdiff snapshots by hand, which is exactly the strange, racy logic the test policy wants covered. Candidates are a snapshot-diff test driving twoupdatecalls through a client, or a pure function that computes the diff and a test of that. render-vkhas golden and dmabuf tests. Nothing pins the submit-stall absorption logic, sinceStallPhase::sawis pure and tiny. It’s a candidate only if it ever changes.monolithitself has no tests, so behaviour such as lock confirmation, capture waiting and import blockers is only smoke-tested. Most of it needs a display. The pure parts (the frame budget,floats(), workspace filtering) could be pulled out and tested if they ever break.
Smaller observations
state.rsfree functionsroot,identity,configure,gapsandxkb_configare window, layout and config helpers living in the state module.- The
layers.rsdebug lines added to chase the quickshell report can be dropped or kept at trace. design/parked.mdand this file overlap a little. Parked is for behaviour and this is for structure.