The NanoWM Architecture
Context
In an era of increasing software bloat, modern desktop environments often exceed 500MB of idle RAM and rely on thousands of dependencies. Even 'minimalist' tiling window managers have transitioned toward complex configuration parsers and heavy abstractions that obscure the underlying X11 protocol logic.
Decision
Develop NanoWM in pure C using Xlib and Xinerama, employing a 'Header-less' Unity Build architectural pattern where the entire system state, keybindings, and event logic are defined via compile-time X-Macros.
Alternatives Considered
Rust-based Window Manager (Smithay/Wayland)
- Memory safety guarantees by default
- Modern dependency management via Cargo
- Significantly larger binary footprint
- Wayland ecosystem is too verbose for a <100 line target
Extension of DWM (Suckless)
- Battle-tested codebase and massive patch library
- Existing community support
- Inherits 'Master/Stack' tiling logic which creates cognitive overhead
- Harder to implement custom Xinerama pointer-warping logic without deep refactoring
Reasoning
C was chosen for its 'mechanical sympathy'—the ability to interact directly with X11 atoms and events without an abstraction layer. By using C macros for configuration, we eliminate the need for a runtime parser, reducing the binary to under 50KB. This approach ensures that the window manager remains under 100 lines of code while maintaining professional-grade multi-monitor support.
The Bloat Problem
Modern systems development often prioritizes developer convenience over machine efficiency. This leads to:
- Binary Bloat: Simple utilities often exceed several megabytes due to static linking of unused library code.
- Slow Feedback: Complex build systems can take seconds or minutes to resolve dependencies before a single line is compiled.
- Fragmentation: Memory management becomes inconsistent when mixing multiple third-party allocation strategies.
Architectural Pillars
We codified three pillars to maintain a professional, scalable codebase without the traditional baggage:
1. The TBL (Table) Macro Pattern
We replaced complex config parsers and global registry arrays with X-Macros. This allows a single definition of a system component—like a keybinding—to be expanded multiple times for different purposes (e.g., generating the XGrabKey calls and the KeyPress dispatch logic).
2. Unity Builds (Single Translation Unit)
Instead of compiling multiple .c files and linking them, we include all logic into a single unit.
- Near-Instant Builds: Compiling takes less than 50ms.
- Global Optimization: The compiler performs constant folding across the entire project without needing a separate Link-Time Optimization (LTO) pass.
3. Xinerama-Aware Geometry
By calculating the exact offsets of every connected monitor, we force windows into a strict ‘Monocle’ layout. This ensures that every window is exactly the size of the active screen, removing the need for complex layout engines.
Results & Impact
- Compilation Speed: Build times dropped from ~2 seconds (Make/GCC) to < 50ms (TCC), enabling a ‘save-to-test’ loop that feels instantaneous.
- Binary Footprint: NanoWM was reduced to under 30KB, fitting entirely within the CPU’s L1 cache for maximum execution speed.
- Portability: Binaries are statically linked against a minimal libc, allowing them to run on any Linux kernel version without requiring specific shared libraries.
- Maintainability: The entire architecture is contained within a few hundred lines of code, making it possible for a single developer to hold the entire system state in their head.
The Road Ahead
The primary challenge remains standardization. While this architecture is perfect for solo power-users and high-performance system tools, it requires a shift in mindset for collaborative environments. My next goal is to document a “Minimalist C Standard Library” to provide a common ground for developers adopting this pattern.