srdusr
aboutsummaryrefslogtreecommitdiffstats
path: root/docs
diff options
context:
space:
mode:
authorsrdusr <[email protected]>2024-04-02 00:58:00 +0200
committersrdusr <[email protected]>2024-04-02 00:58:00 +0200
commit8110bb2773b6c841029a51eca7971f42a36f480c (patch)
treeb3b364a6c0231fe408229e94dc9e25ce4562ad02 /docs
parentd1f856edc516047575cf46f12fad2b59006363c8 (diff)
downloadsrdwm-8110bb2773b6c841029a51eca7971f42a36f480c.tar.gz
srdwm-8110bb2773b6c841029a51eca7971f42a36f480c.zip
Rewrite srdwm in Rust: working X11 and Wayland backends, Lua config
The C++ prototype (moved to legacy-cpp/) was mostly a design skeleton: X11 and Windows backends were partially real, Wayland created the wlroots object graph but never wired a single event listener, macOS was stub except monitor enumeration, and the Lua engine's srd.bind() stored a key-combo string but never the actual closure. See docs/PRIOR_ART.md for the full audit. This replaces it with a Cargo workspace: - srdwm-core: platform-independent window/workspace/monitor state, a real master-stack tiling layout, and SmartPlacement grid/cascade/ snap-to-edge placement - fixing several bugs in the C++ version (hardcoded 2-column grid, cascade that never cascaded, snap-to-edge that always returned a fixed rect). 35 unit tests. - srdwm-config: the srd Lua API via mlua, implementing the surface docs/DEFAULTS.md always documented but the C++ engine never actually built (srd.window.close()/focus(direction), srd.workspace.next(), real keybinding closures, require("srd") support). 10 unit tests. - srdwm-x11: a real reparenting WM with a drawn title bar (buttons, drag, resize), verified live under Xephyr - frame placement and client offset match srdwm-core's computed geometry exactly, and the decoration renders correctly on screen. - srdwm-wayland: a from-scratch smithay compositor (the C++ version had nothing working to port from) - runs via the winit backend, tracks xdg-shell toplevels through the same WindowManager and hit-testing code X11 uses, verified to start/render/run without crashing. Decorations are solid-color (no text yet); see docs/IMPLEMENTATION_STATUS.md for exact scope. - srdwm-windows / srdwm-macos: structured, cfg-gated designs informed by komorebi/glazewm and yabai/AeroSpace respectively (see docs/PRIOR_ART.md), honestly marked as unbuilt/unverified since this sandbox has no Windows or macOS target.
Diffstat (limited to 'docs')
-rw-r--r--docs/ARCHITECTURE.md118
-rw-r--r--docs/GUI_SETTINGS.md382
-rw-r--r--docs/IMPLEMENTATION_STATUS.md465
-rw-r--r--docs/PLATFORM_IMPLEMENTATION.md636
-rw-r--r--docs/PRIOR_ART.md79
5 files changed, 326 insertions, 1354 deletions
diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md
new file mode 100644
index 0000000..61d036c
--- /dev/null
+++ b/docs/ARCHITECTURE.md
@@ -0,0 +1,118 @@
+# Architecture
+
+## Crate layout
+
+```
+crates/
+ core/ srdwm-core window/workspace/monitor state, layout engine,
+ smart placement, hit-testing - pure logic,
+ no I/O, no platform dependency
+ config/ srdwm-config Lua (`srd`) scripting engine, wraps mlua
+ platform/ srdwm-platform the `Platform` trait + PlatformKind detection
+ x11/ srdwm-x11 X11 backend (x11rb)
+ wayland/ srdwm-wayland Wayland backend (smithay)
+ windows/ srdwm-windows Windows backend (windows-rs, cfg-gated)
+ macos/ srdwm-macos macOS backend (core-graphics/accessibility-sys, cfg-gated)
+ srdwm/ srdwm (bin) wires config + core + platform together
+```
+
+Dependency direction is strictly one-way: `core` depends on nothing else in
+the workspace; `platform` depends only on `core`; each backend depends on
+`core` + `platform`; `config` depends only on `core` (it never talks to a
+platform directly - see below); the `srdwm` binary is the only crate that
+depends on everything.
+
+## Why config never touches a platform directly
+
+`srdwm-config`'s `srd.window.close()` (etc.) mutates a
+`Rc<RefCell<WindowManager>>` shared with the running backend - it does not
+call into `srdwm-x11` or `srdwm-wayland` itself. The backend is the thing
+that notices the `WindowManager`'s state changed (on its next `poll_events`
+tick, via `main.rs`'s `sync()` helper) and pushes the resulting geometry to
+the real X11/Wayland surface.
+
+This indirection is deliberate: it's what let the exact same `srd` API
+implementation, with the exact same test suite, work correctly against a
+`WindowManager` in isolation (10 config tests never touch a display server)
+and then, unmodified, drive a real X11 session and a real Wayland
+compositor. If `srd.window.close()` called `platform.close()` directly, the
+config crate would need a generic `Platform` handle and every test would
+need a fake one.
+
+## The `Platform` trait
+
+```rust
+trait Platform {
+ fn kind(&self) -> PlatformKind;
+ fn poll_events(&mut self) -> Result<Vec<srdwm_core::Event>>;
+ fn monitors(&mut self) -> Result<Vec<Monitor>>;
+ fn apply_geometry(&mut self, window: WindowId, geometry: Rect) -> Result<()>;
+ fn set_title(&mut self, ...) / focus / minimize / restore / close (...);
+ fn set_decorated / set_border_color / set_border_width / redraw_decoration (...);
+ fn grab_keyboard(&mut self) / ungrab_keyboard(&mut self);
+}
+```
+
+`poll_events` is the one place each backend bridges its native event model
+(X11's blocking `XNextEvent`, Wayland's callback-driven `wl_display`
+dispatch) into the common `srdwm_core::Event` queue; everything downstream
+of that - layout, placement, focus, drag/resize - is platform-independent.
+This mirrors the legacy C++ `Platform` interface's shape (see
+`docs/PRIOR_ART.md`), which was one of the few architectural decisions in
+that codebase that held up.
+
+Both `X11Platform` and `WaylandPlatform` additionally hold their own
+`Rc<RefCell<WindowManager>>` clone (shared with `srdwm-config`), so that
+when a backend detects a new window (X11 `MapRequest`, Wayland
+`new_toplevel`), it can call `wm.alloc_window_id()` + `wm.add_window(...)`
+directly rather than needing a separate "please allocate an ID for me"
+round-trip through `main.rs`.
+
+## Decoration strategy per platform
+
+Windows can't be decorated the same way on every platform, so each backend
+takes the approach that's actually available to it (informed by the prior
+art in `docs/PRIOR_ART.md`):
+
+- **X11**: classic reparenting WM. srdwm creates a frame window, reparents
+ the client into it below a drawn titlebar band, and owns all decoration
+ pixels directly (Xlib/xcb core drawing). Full control, which is why "full
+ title bar support" (buttons, drag, resize, matching Windows/macOS) is most
+ complete here.
+- **Wayland**: srdwm *is* the compositor, so it negotiates
+ `zxdg_decoration_manager_v1` server-side mode and renders a decoration
+ band itself via `smithay`'s `SolidColorRenderElement`, composited above
+ each client surface. Same `ResizeEdge::hit_test` as X11; see
+ `docs/IMPLEMENTATION_STATUS.md` for what's not finished (text, precise
+ global-keybinding routing).
+- **Windows**: DWM will not give you a custom-width or custom-drawn frame
+ without disabling the native one entirely, so the design (not yet built --
+ see status doc) keeps DWM's frame and controls it (`DWMWA_BORDER_COLOR`),
+ matching how komorebi/glazewm operate rather than fighting DWM.
+- **macOS**: there is no public API to draw on another process's window at
+ all. The design (also not yet built) is a separate, click-through overlay
+ window that tracks the target window's position via the Accessibility
+ API, matching AeroSpace's AX-only approach rather than yabai's
+ SIP-disabling private APIs.
+
+## Why `srdwm_core::window::ResizeEdge::hit_test` is shared, not duplicated
+
+Titlebar hit-testing (which pixel band is "drag", which is the close
+button, which edge is a resize grab) is pure geometry - it doesn't need to
+know anything about X11 or Wayland. Putting it in `srdwm-core` means the
+X11 and Wayland backends *cannot* drift into behaving differently for the
+same click, which was worth the small indirection cost (both backends pass
+`(frame_rect, x, y)` in and get back a `TitlebarHit` enum to act on).
+
+## Config loading
+
+`Engine::new(wm, config_dir)` seeds every key documented in
+`docs/DEFAULTS.md` before any user script runs (so `srd.get(...)` never
+returns `nil` for a documented key), then `Engine::load_init()` executes
+`config_dir/init.lua`, which in the shipped example
+(`config/srd/init.lua`) calls `srd.load("keybindings")` etc. to pull in the
+rest - `srd.load(name)` reads and executes `config_dir/{name}.lua` in the
+same Lua state, so later files can see earlier `srd.bind()`/`srd.set()`
+calls. Config directory resolution order: `$SRDWM_CONFIG_PATH`, then
+`$XDG_CONFIG_HOME/srdwm/srd`, then `~/.config/srdwm/srd` (matching
+`docs/DEFAULTS.md`'s documented location).
diff --git a/docs/GUI_SETTINGS.md b/docs/GUI_SETTINGS.md
deleted file mode 100644
index bc892b5..0000000
--- a/docs/GUI_SETTINGS.md
+++ /dev/null
@@ -1,382 +0,0 @@
-# SRDWM GUI Settings Program
-
-## Overview
-The SRDWM GUI Settings program provides a user-friendly interface for configuring the window manager without editing Lua files directly. It integrates seamlessly with existing system settings structures on Windows, macOS, and Linux.
-
-## Architecture
-
-### Cross-Platform GUI Framework
-- **Linux**: GTK4 with native desktop integration
-- **Windows**: WinUI 3 with Windows Settings integration
-- **macOS**: SwiftUI with System Preferences integration
-
-### System Integration
-- **Windows**: Appears in Windows Settings > System > Window Manager
-- **macOS**: Appears in System Preferences > Desktop & Screen Saver > Window Manager
-- **Linux**: Appears in GNOME Settings, KDE System Settings, etc.
-
-## Main Interface
-
-### 1. General Settings Tab
-```
-┌─────────────────────────────────────────────────────────┐
-│ General Settings │
-├─────────────────────────────────────────────────────────┤
-│ Default Layout: [Dynamic ▼] │
-│ Smart Window Placement: ☑ │
-│ Window Gap: [8] pixels │
-│ Border Width: [2] pixels │
-│ Enable Animations: ☑ │
-│ Animation Duration: [200] ms │
-│ │
-│ Focus Follows Mouse: ☐ │
-│ Mouse Follows Focus: ☑ │
-│ Auto Raise Windows: ☐ │
-│ Auto Focus Windows: ☑ │
-└─────────────────────────────────────────────────────────┘
-```
-
-### 2. Key Bindings Tab
-```
-┌─────────────────────────────────────────────────────────┐
-│ Key Bindings │
-├─────────────────────────────────────────────────────────┤
-│ Layout Switching │
-│ ├─ Tiling Layout: [Mod4+1] [Change] [Remove] │
-│ ├─ Dynamic Layout: [Mod4+2] [Change] [Remove] │
-│ └─ Floating Layout: [Mod4+3] [Change] [Remove] │
-│ │
-│ Window Management │
-│ ├─ Close Window: [Mod4+q] [Change] [Remove] │
-│ ├─ Minimize Window: [Mod4+m] [Change] [Remove] │
-│ └─ Maximize Window: [Mod4+f] [Change] [Remove] │
-│ │
-│ [Add New Binding] │
-└─────────────────────────────────────────────────────────┘
-```
-
-### 3. Layouts Tab
-```
-┌─────────────────────────────────────────────────────────┐
-│ Layouts │
-├─────────────────────────────────────────────────────────┤
-│ Tiling Layout │
-│ ├─ Split Ratio: [50]% [Reset] │
-│ ├─ Master Ratio: [60]% [Reset] │
-│ ├─ Auto Swap: ☑ │
-│ └─ Gaps: Inner [8] Outer [16] [Reset] │
-│ │
-│ Dynamic Layout │
-│ ├─ Snap Threshold: [50]px [Reset] │
-│ ├─ Grid Size: [6] [Reset] │
-│ ├─ Cascade Offset: [30]px [Reset] │
-│ └─ Smart Placement: ☑ │
-│ │
-│ [Add Custom Layout] │
-└─────────────────────────────────────────────────────────┘
-```
-
-### 4. Themes Tab
-```
-┌─────────────────────────────────────────────────────────┐
-│ Themes │
-├─────────────────────────────────────────────────────────┤
-│ Current Theme: [Nord ▼] [Preview] │
-│ │
-│ Colors │
-│ ├─ Background: [■] #2e3440 [Change] │
-│ ├─ Foreground: [■] #eceff4 [Change] │
-│ ├─ Primary: [■] #88c0d0 [Change] │
-│ └─ Secondary: [■] #81a1c1 [Change] │
-│ │
-│ Window Decorations │
-│ ├─ Border Width: [2]px [Reset] │
-│ ├─ Title Bar Height: [24]px [Reset] │
-│ └─ Font: [JetBrains Mono 10] [Change] │
-│ │
-│ [Import Theme] [Export Theme] [Create New] │
-└─────────────────────────────────────────────────────────┘
-```
-
-### 5. Window Rules Tab
-```
-┌─────────────────────────────────────────────────────────┐
-│ Window Rules │
-├─────────────────────────────────────────────────────────┤
-│ Rule 1: Firefox → Dynamic Layout │
-│ ├─ Match: Class = "firefox" │
-│ ├─ Action: Layout = "dynamic" │
-│ └─ [Edit] [Delete] │
-│ │
-│ Rule 2: Terminal → Tiling Layout │
-│ ├─ Match: Class = "terminal" │
-│ ├─ Action: Layout = "tiling" │
-│ └─ [Edit] [Delete] │
-│ │
-│ [Add New Rule] │
-└─────────────────────────────────────────────────────────┘
-```
-
-### 6. Performance Tab
-```
-┌─────────────────────────────────────────────────────────┐
-│ Performance │
-├─────────────────────────────────────────────────────────┤
-│ Graphics │
-│ ├─ Enable V-Sync: ☑ │
-│ ├─ Max FPS: [60] [Reset] │
-│ └─ Enable Caching: ☑ │
-│ │
-│ Memory │
-│ ├─ Window Cache Size: [100] [Reset] │
-│ ├─ Event Queue Size: [1000] [Reset] │
-│ └─ Layout Timeout: [16]ms [Reset] │
-│ │
-│ [Optimize for Performance] [Reset to Defaults] │
-└─────────────────────────────────────────────────────────┘
-```
-
-## Key Binding Editor
-
-### Add/Edit Key Binding Dialog
-```
-┌─────────────────────────────────────────────────────────┐
-│ Edit Key Binding │
-├─────────────────────────────────────────────────────────┤
-│ Key Combination: [Press keys here...] │
-│ Current: Mod4+Shift+1 │
-│ │
-│ Action Type: [Window Management ▼] │
-│ Action: [Close Window ▼] │
-│ │
-│ Custom Command: [________________] │
-│ │
-│ [Test Binding] [OK] [Cancel] │
-└─────────────────────────────────────────────────────────┘
-```
-
-### Key Combination Parser
-- **Mod4**: Super/Windows key
-- **Mod1**: Alt key
-- **Mod2**: Num Lock
-- **Mod3**: Scroll Lock
-- **Shift**: Shift key
-- **Ctrl**: Control key
-
-## Theme Editor
-
-### Color Picker Integration
-```
-┌─────────────────────────────────────────────────────────┐
-│ Color Picker │
-├─────────────────────────────────────────────────────────┤
-│ Color: [■] #88c0d0 │
-│ │
-│ RGB: R [136] G [192] B [208] │
-│ HSV: H [199] S [35] V [82] │
-│ │
-│ Preset Colors: │
-│ [■][■][■][■][■][■][■][■] │
-│ │
-│ [Pick from Screen] [OK] [Cancel] │
-└─────────────────────────────────────────────────────────┘
-```
-
-### Font Selector
-```
-┌─────────────────────────────────────────────────────────┐
-│ Font Selection │
-├─────────────────────────────────────────────────────────┤
-│ Font Family: [JetBrains Mono ▼] │
-│ Font Size: [10] [Reset] │
-│ Font Weight: [Normal ▼] │
-│ Font Style: [Normal ▼] │
-│ │
-│ Preview: The quick brown fox jumps over the lazy dog │
-│ │
-│ [OK] [Cancel] │
-└─────────────────────────────────────────────────────────┘
-```
-
-## System Integration
-
-### Windows Integration
-```cpp
-// Windows Settings integration
-class WindowsSettingsIntegration {
-public:
- void register_with_settings();
- void create_settings_page();
- void handle_settings_changes();
-
-private:
- void add_to_windows_settings();
- void create_registry_entries();
- void register_protocol_handler();
-};
-```
-
-### macOS Integration
-```swift
-// macOS System Preferences integration
-class MacOSSettingsIntegration: NSObject {
- func registerWithSystemPreferences()
- func createPreferencesPane()
- func handlePreferencesChanges()
-
- private func addToSystemPreferences()
- func createPreferencePaneBundle()
- func registerURLScheme()
-}
-```
-
-### Linux Integration
-```cpp
-// Linux desktop integration
-class LinuxDesktopIntegration {
-public:
- void register_with_desktop();
- void create_settings_app();
- void handle_settings_changes();
-
-private:
- void add_to_gnome_settings();
- void add_to_kde_settings();
- void create_desktop_file();
- void register_mime_types();
-};
-```
-
-## Configuration Management
-
-### Auto-Save and Validation
-```cpp
-class ConfigurationManager {
-public:
- void auto_save_changes();
- bool validate_configuration();
- void backup_configuration();
- void restore_configuration();
-
-private:
- void save_to_lua_files();
- void validate_lua_syntax();
- void create_backup();
- void notify_user_of_changes();
-};
-```
-
-### Import/Export
-```cpp
-class ConfigurationIO {
-public:
- bool import_configuration(const std::string& path);
- bool export_configuration(const std::string& path);
- bool import_from_other_wm(const std::string& wm_name);
-
-private:
- void parse_import_format();
- void convert_to_srdwm_format();
- void validate_imported_config();
-};
-```
-
-## Advanced Features
-
-### Live Preview
-- **Real-time updates**: Changes apply immediately
-- **Window preview**: See how windows will look
-- **Layout preview**: Visualize layout changes
-- **Theme preview**: Live theme switching
-
-### Configuration Sync
-- **Cloud sync**: Sync settings across devices
-- **Version control**: Track configuration changes
-- **Backup/restore**: Automatic configuration backups
-- **Migration tools**: Import from other window managers
-
-### Accessibility
-- **High contrast**: High contrast mode support
-- **Screen reader**: Full screen reader compatibility
-- **Keyboard navigation**: Complete keyboard navigation
-- **Large text**: Scalable interface elements
-
-## Installation and Distribution
-
-### Package Integration
-```bash
-# Linux (Debian/Ubuntu)
-sudo apt install srdwm-settings
-
-# Linux (Arch)
-sudo pacman -S srdwm-settings
-
-# Windows (Chocolatey)
-choco install srdwm-settings
-
-# macOS (Homebrew)
-brew install srdwm-settings
-```
-
-### System Integration
-```bash
-# Linux desktop files
-~/.local/share/applications/srdwm-settings.desktop
-
-# Windows registry
-HKEY_CURRENT_USER\Software\SRDWM\Settings
-
-# macOS preferences
-~/Library/Preferences/com.srdwm.settings.plist
-```
-
-## Development
-
-### Building the GUI
-```bash
-# Linux (GTK4)
-meson build -Dgui=true
-ninja -C build
-
-# Windows (WinUI 3)
-dotnet build src/gui/SRDWM.Settings.Windows
-
-# macOS (SwiftUI)
-xcodebuild -project src/gui/SRDWM.Settings.macOS.xcodeproj
-```
-
-### Testing
-```bash
-# Unit tests
-ninja -C build test
-
-# Integration tests
-ninja -C build integration-test
-
-# GUI tests
-ninja -C build gui-test
-```
-
-## User Experience
-
-### First Run Experience
-1. **Welcome dialog**: Introduction to SRDWM
-2. **Quick setup**: Essential settings configuration
-3. **Tutorial**: Interactive configuration guide
-4. **Import options**: Import from existing setups
-
-### Contextual Help
-- **Tooltips**: Hover for help text
-- **Help button**: Context-sensitive help
-- **Documentation**: Integrated user manual
-- **Examples**: Sample configurations
-
-### Error Handling
-- **Validation**: Real-time configuration validation
-- **Error messages**: Clear, actionable error messages
-- **Recovery**: Automatic error recovery
-- **Logging**: Detailed error logging
-
-This GUI settings program provides a professional, user-friendly interface that integrates seamlessly with existing system structures while maintaining the power and flexibility of the Lua configuration system.
-
-
diff --git a/docs/IMPLEMENTATION_STATUS.md b/docs/IMPLEMENTATION_STATUS.md
index 23d4e9d..5481c4c 100644
--- a/docs/IMPLEMENTATION_STATUS.md
+++ b/docs/IMPLEMENTATION_STATUS.md
@@ -1,336 +1,129 @@
-# SRDWM Implementation Status
-
-## Overview
-This document provides a comprehensive overview of the current implementation status of SRDWM, including completed features, in-progress work, and next steps.
-
-## ✅ **Completed Features**
-
-### 1. **Lua Configuration System**
-- **Status**: ✅ **FULLY IMPLEMENTED**
-- **Files**:
- - `src/config/lua_manager.h/cc` - Complete Lua integration
- - `config/srd/*.lua` - Example configuration files
- - `docs/DEFAULTS.md` - Complete default configuration reference
-- **Features**:
- - Full Lua 5.4+ integration with C++
- - Complete `srd` module API
- - Configuration loading from `srd/*.lua` files
- - Key binding system
- - Layout configuration
- - Theme management
- - Window rules
- - Configuration validation and reset
- - Error handling and logging
-
-### 2. **Platform Architecture Design**
-- **Status**: ✅ **FULLY DESIGNED**
-- **Files**:
- - `docs/PLATFORM_IMPLEMENTATION.md` - Complete platform guide
- - `src/platform/platform.h` - Platform abstraction interface
- - `src/platform/platform_factory.h/cc` - Platform factory implementation
-- **Features**:
- - Proper separation of X11 vs Wayland (no mixing!)
- - Platform detection and selection
- - Cross-platform abstraction layer
- - Automatic platform detection
-
-### 3. **Build System**
-- **Status**: ✅ **FULLY IMPLEMENTED**
-- **Files**:
- - `CMakeLists.txt` - Complete build configuration
-- **Features**:
- - Platform-specific dependency management
- - Lua integration
- - Conditional compilation for different platforms
- - Proper include and library paths
-
-### 4. **Documentation**
-- **Status**: ✅ **COMPREHENSIVE**
-- **Files**:
- - `docs/DEFAULTS.md` - Complete configuration reference
- - `docs/GUI_SETTINGS.md` - GUI settings program design
- - `docs/PLATFORM_IMPLEMENTATION.md` - Platform implementation guide
- - `docs/IMPLEMENTATION_STATUS.md` - This status document
-
-## 🔄 **In Progress**
-
-### 1. **Platform-Specific Implementations**
-- **Status**: 🔄 **HEADERS CREATED, IMPLEMENTATION IN PROGRESS**
-- **Files**:
- - `src/platform/x11_platform.h` - X11 platform header ✅
- - `src/platform/wayland_platform.h` - Wayland platform header ✅
- - `src/platform/windows_platform.h` - Windows platform header ✅
- - `src/platform/macos_platform.h` - macOS platform header ✅
-- **Progress**: Headers and interfaces defined, implementation needed
-
-### 2. **Core Window Management**
-- **Status**: 🔄 **INTERFACES DEFINED, IMPLEMENTATION NEEDED**
-- **Files**:
- - `src/core/window.h/cc` - Window class interface ✅
- - `src/core/window_manager.h/cc` - Window manager interface ✅
- - `src/layouts/layout_engine.h/cc` - Layout engine interface ✅
-- **Progress**: Basic structure defined, platform integration needed
-
-## ❌ **Not Yet Started**
-
-### 1. **Platform Implementation Files**
-- `src/platform/x11_platform.cc` - X11 implementation
-- `src/platform/wayland_platform.cc` - Wayland implementation
-- `src/platform/windows_platform.cc` - Windows implementation
-- `src/platform/macos_platform.cc` - macOS implementation
-
-### 2. **Smart Placement Algorithms**
-- `src/layouts/smart_placement.cc` - Smart window placement implementation
-
-### 3. **GUI Settings Program**
-- Cross-platform settings interface
-- System integration (Windows Settings, macOS Preferences, Linux Settings)
-
-### 4. **Advanced Features**
-- Window rules engine
-- Advanced theming system
-- Performance optimization
-- Accessibility features
-
-## 🚀 **Next Implementation Steps**
-
-### **Phase 1: Platform Implementation (Priority: HIGH)**
-
-#### **1.1 X11 Platform Implementation**
-```bash
-# Create X11 implementation
-touch src/platform/x11_platform.cc
-# Implement X11 event handling, window management, input handling
-```
-
-**Key Requirements**:
-- X11 event loop and event conversion
-- Window management (create, destroy, move, resize)
-- Input handling (keyboard, mouse)
-- Monitor detection and management
-- EWMH/NETWM compliance
-
-#### **1.2 Wayland Platform Implementation**
-```bash
-# Create Wayland implementation
-touch src/platform/wayland_platform.cc
-# Implement Wayland compositor using wlroots
-```
-
-**Key Requirements**:
-- wlroots backend setup
-- Wayland protocol handling (XDG Shell, Layer Shell)
-- XWayland support
-- Surface management
-- Input device handling
-
-#### **1.3 Windows Platform Implementation**
-```bash
-# Create Windows implementation
-touch src/platform/windows_platform.cc
-# Implement Win32 API integration
-```
-
-**Key Requirements**:
-- Win32 window management
-- Global hooks for input
-- DWM integration
-- Window subclassing
-
-#### **1.4 macOS Platform Implementation**
-```bash
-# Create macOS implementation
-touch src/platform/macos_platform.cc
-# Implement Core Graphics/AppKit integration
-```
-
-**Key Requirements**:
-- Core Graphics window management
-- Accessibility APIs
-- Event taps
-- AppKit integration
-
-### **Phase 2: Core Window Management (Priority: HIGH)**
-
-#### **2.1 Window Class Implementation**
-```cpp
-// Implement platform-specific window operations
-class Window {
- // Platform-specific window handles
- #ifdef LINUX_PLATFORM
- Window x11_handle_;
- struct wlr_surface* wayland_surface_;
- #elif defined(WIN32_PLATFORM)
- HWND win32_handle_;
- #elif defined(MACOS_PLATFORM)
- CGWindowID macos_window_id_;
- #endif
-};
-```
-
-#### **2.2 Window Manager Implementation**
-```cpp
-// Implement core window management logic
-class WindowManager {
- // Platform integration
- std::unique_ptr<Platform> platform_;
-
- // Window management
- void handle_window_created(Window* window);
- void handle_window_destroyed(Window* window);
- void handle_window_focused(Window* window);
-};
-```
-
-### **Phase 3: Layout System (Priority: MEDIUM)**
-
-#### **3.1 Smart Placement Implementation**
-```cpp
-// Implement Windows 11-style smart placement
-class SmartPlacement {
- PlacementResult place_window(const Window* window, const Monitor& monitor);
- PlacementResult place_in_grid(const Window* window, const Monitor& monitor);
- PlacementResult snap_to_edge(const Window* window, const Monitor& monitor);
-};
-```
-
-#### **3.2 Layout Engine Implementation**
-```cpp
-// Implement layout management
-class LayoutEngine {
- void arrange_windows_on_monitor(const Monitor& monitor);
- void switch_layout(const std::string& layout_name);
- void configure_layout(const std::string& layout_name, const LayoutConfig& config);
-};
-```
-
-### **Phase 4: Advanced Features (Priority: LOW)**
-
-#### **4.1 Window Rules Engine**
-```cpp
-// Implement automatic window management
-class WindowRulesEngine {
- void apply_rules_to_window(Window* window);
- bool matches_rule(const Window* window, const WindowRule& rule);
- void execute_rule_action(const Window* window, const WindowRule& rule);
-};
-```
-
-#### **4.2 GUI Settings Program**
-```cpp
-// Cross-platform settings interface
-class SettingsProgram {
- #ifdef LINUX_PLATFORM
- void create_gtk_interface();
- #elif defined(WIN32_PLATFORM)
- void create_winui_interface();
- #elif defined(MACOS_PLATFORM)
- void create_swiftui_interface();
- #endif
-};
-```
-
-## 🧪 **Testing Strategy**
-
-### **Unit Testing**
-```bash
-# Test each platform independently
-mkdir tests/
-touch tests/test_x11_platform.cc
-touch tests/test_wayland_platform.cc
-touch tests/test_windows_platform.cc
-touch tests/test_macos_platform.cc
-```
-
-### **Integration Testing**
-```bash
-# Test platform integration
-touch tests/test_platform_factory.cc
-touch tests/test_lua_integration.cc
-```
-
-### **Platform-Specific Testing**
-```bash
-# Test on actual platforms
-# Linux: X11 and Wayland environments
-# Windows: Windows 10/11
-# macOS: macOS 12+
-```
-
-## 📊 **Current Progress Metrics**
-
-| Component | Status | Progress | Priority |
-|-----------|--------|----------|----------|
-| Lua Configuration | ✅ Complete | 100% | HIGH |
-| Platform Architecture | ✅ Complete | 100% | HIGH |
-| Build System | ✅ Complete | 100% | HIGH |
-| Documentation | ✅ Complete | 100% | HIGH |
-| Platform Headers | 🔄 In Progress | 80% | HIGH |
-| Platform Implementation | ❌ Not Started | 0% | HIGH |
-| Core Window Management | 🔄 In Progress | 40% | HIGH |
-| Layout System | ❌ Not Started | 0% | MEDIUM |
-| Smart Placement | ❌ Not Started | 0% | MEDIUM |
-| GUI Settings | ❌ Not Started | 0% | LOW |
-
-**Overall Progress: 35%**
-
-## 🎯 **Immediate Next Steps**
-
-### **Week 1-2: Platform Implementation**
-1. **Implement X11 platform** (`src/platform/x11_platform.cc`)
-2. **Implement Wayland platform** (`src/platform/wayland_platform.cc`)
-3. **Test platform detection and initialization**
-
-### **Week 3-4: Core Integration**
-1. **Integrate platforms with window manager**
-2. **Implement basic window operations**
-3. **Test window creation and management**
-
-### **Week 5-6: Layout System**
-1. **Implement smart placement algorithms**
-2. **Create layout engine**
-3. **Test layout switching and configuration**
-
-## 🚨 **Critical Notes**
-
-### **1. Wayland vs X11 Separation**
-- **NEVER mix X11 and Wayland APIs**
-- Use wlroots for Wayland implementation
-- Handle XWayland as special case within Wayland
-- Maintain strict separation in platform implementations
-
-### **2. Platform Abstraction**
-- Keep platform-specific code isolated
-- Use common interfaces for cross-platform functionality
-- Implement platform detection automatically
-- Respect each platform's event model
-
-### **3. Testing Requirements**
-- Test each platform independently
-- Validate platform-specific features
-- Use CI/CD with multiple platform targets
-- Test on actual hardware when possible
-
-## 🔮 **Future Enhancements**
-
-### **Phase 5: Performance Optimization**
-- GPU acceleration
-- Efficient rendering
-- Memory management
-- Event batching
-
-### **Phase 6: Advanced Features**
-- Plugin system
-- Scripting engine
-- Network transparency
-- Virtual desktop support
-
-### **Phase 7: Ecosystem Integration**
-- Package managers
-- Theme repositories
-- Configuration sharing
-- Community tools
-
-This implementation approach ensures that SRDWM works correctly on each platform while respecting the fundamental differences between X11, Wayland, Windows, and macOS. The current focus should be on completing the platform implementations to establish a solid foundation for the window management system.
-
-
+# Implementation status
+
+This mirrors the style of the legacy C++ project's own status doc (now at
+`legacy-cpp/docs/IMPLEMENTATION_STATUS.md`), but for the Rust rewrite.
+"Verified" means: built with `cargo test --workspace` (0 warnings under
+`cargo clippy --workspace`) and, where applicable, actually run and observed
+doing the thing described - not just "the code compiles and looks right."
+
+## ✅ Complete and verified
+
+### Core window/workspace/layout engine (`crates/core`)
+- `WindowManager`: window/workspace/monitor state, focus cycling, directional
+ focus (`Direction::{Left,Right,Up,Down}`), drag/resize state machine,
+ hit-testing shared by every backend.
+- `MasterStackLayout`: real dwm-style master/stack tiling with configurable
+ ratio and gaps (the legacy C++ tiling layout only ever split windows into
+ equal-width columns, ignoring its own documented `master_ratio` config key).
+- `SmartPlacement`: grid placement with real per-cell occupancy tracking,
+ diagonal cascade fallback, and Windows-Snap-style edge magnetism
+ (half/quarter/maximize zones). The legacy C++ version's grid placement
+ used a `static` round-robin counter that hardcoded a 2-column layout
+ regardless of window count; its cascade never actually cascaded; its
+ snap-to-edge always returned a fixed centered rectangle.
+- 35 unit tests, deterministic (window arrangement no longer depends on
+ `HashMap` iteration order - an early version of `arrange_workspace` did,
+ and it was caught by a flaky test during this rewrite; see the fix in
+ `crates/core/src/manager.rs`).
+
+### Lua config engine (`crates/config`)
+- Full `srd` API matching `docs/DEFAULTS.md`'s documented (not the legacy
+ C++'s actually-implemented) surface: `srd.set/get/reset/reset_all/reset_category`,
+ `srd.window.{focused,close,minimize,maximize,focus,set_decorations,
+ set_border_color,set_border_width,set_floating,toggle_floating,is_floating}`,
+ `srd.layout.{set,configure}`, `srd.workspace.{next,prev,switch,move_window}`,
+ `srd.theme.{set_colors,set_decorations}`, `srd.bind`, `srd.load`,
+ `srd.spawn`, `srd.notify`, `srd.quit`.
+- `srd.bind()` stores the actual Lua closure via `mlua`'s registry and
+ invokes it on dispatch (the legacy engine stored only the key-combo
+ string - keybindings could never fire).
+- `local srd = require("srd")` works (registered via `package.preload`, not
+ just as a global) - every shipped example config opens with this line,
+ and it would have failed against a naive "global-only" registration; this
+ was caught and fixed during the smoke test.
+- 10 unit tests, including one that reproduces the exact legacy bug
+ (`window:close()` on a table with no methods) and shows it now works.
+
+### X11 backend (`crates/x11`)
+- Real reparenting WM: frame windows sized to actual client geometry (not
+ the legacy's hardcoded 800px titlebar), drawn title bar with
+ close/maximize/minimize buttons, drag-to-move, edge/corner resize --
+ all driven by the same `ResizeEdge::hit_test` the Wayland backend uses.
+- Correct other-WM detection via a *checked* `SUBSTRUCTURE_REDIRECT`
+ request (the legacy version's error handler discarded errors and always
+ reported success).
+- RandR monitor enumeration using CRTC pixel mode, not output physical
+ millimeters (the legacy version conflated the two).
+- `WM_DELETE_WINDOW`-aware close, click-to-focus via a passive button grab
+ + replay (the standard dwm/openbox pattern), global keybinding grabs
+ translated from Lua combo strings via a hand-maintained keysym table
+ (`crates/x11/src/keysyms.rs`, letters/digits/navigation/F-keys/media keys;
+ not a full xkbcommon keymap).
+- **Verified live**: run under Xephyr with the shipped example config, an
+ `xterm` client was correctly reparented (frame at the exact
+ `SmartPlacement`-computed position, client offset by exactly
+ `TITLEBAR_HEIGHT`), and the drawn title bar (background, title text,
+ minimize/maximize/close glyphs) was confirmed via screenshot.
+
+### Windows and macOS backends (`crates/windows`, `crates/macos`)
+- Structured as honest stubs: real-looking `windows-rs`/Core Graphics calls
+ behind `cfg(windows)` / `cfg(target_os = "macos")`, but **never built or
+ run** - this sandbox only has the `x86_64-unknown-linux-gnu` target
+ installed. On any other target the same methods return
+ `PlatformError::Unsupported` rather than pretending to work.
+- Design intent (informed by komorebi/glazewm for Windows, yabai/AeroSpace
+ for macOS - see `docs/PRIOR_ART.md`) is documented in each crate's module
+ doc comment: keep DWM's native frame on Windows rather than fight it;
+ use the public Accessibility API plus an overlay window for decorations
+ on macOS, not private APIs.
+
+## 🔄 Wayland backend (`crates/wayland`) - real, more limited scope than X11
+
+This is the one piece with essentially no working prior art to port (see
+`docs/PRIOR_ART.md`): the legacy C++ never wired a single event listener.
+What's here is a genuine from-scratch `smithay`-based compositor, not a stub:
+
+- ✅ Runs via smithay's winit backend (nested window), initializes EGL/GLES,
+ advertises a real Wayland socket, and was verified to start, initialize
+ rendering, and run its event loop without crashing (log-verified; a
+ full visual confirmation the way X11 got one was skipped deliberately --
+ see below).
+- ✅ xdg-shell toplevels are tracked through the *same*
+ `srdwm_core::WindowManager` the X11 backend uses - new windows get a
+ real `WindowId`, go through `SmartPlacement`/`MasterStackLayout` exactly
+ like X11 windows do.
+- ✅ xdg-decoration is negotiated to server-side mode.
+- ✅ Pointer click/drag/resize on the decoration band uses the identical
+ `hit_test` code path as X11.
+- ⚠️ Decorations are a solid-color titlebar band with **no text** - font
+ rasterization (glyph atlas, text shaping) is a substantial independent
+ piece of work, not something to fake with a placeholder.
+- ⚠️ Global keybindings use a coarse heuristic: any keypress with Super/Mod4
+ held is treated as WM-exclusive and not forwarded to the client; anything
+ else is forwarded. A precise design would thread the config's actual
+ bound-key set into the platform layer (X11 does this correctly via
+ per-combo `XGrabKey`); Wayland's compositor-sees-everything-first model
+ makes the equivalent design more involved and was left as a TODO rather
+ than rushed.
+- ❌ No DRM/udev backend (i.e. cannot run as the actual system compositor on
+ a bare TTY, only nested under an existing session) - winit backend only.
+- ❌ No XWayland integration.
+
+**Why the visual verification stopped short of a screenshot**: the winit
+window opens on the *host* compositor, and the only available display in
+this sandbox was the user's live desktop session (not an isolated nested
+server the way Xephyr was for X11). A screenshot of that would have
+captured the user's actual desktop/other work, which isn't appropriate to
+casually paste into a build log. The X11 backend's Xephyr-based
+verification is the same class of test, done on an isolated, disposable
+display instead.
+
+## Not implemented anywhere yet
+
+- Window rules (match-by-title/class -> action). `config/srd/rules.lua` is
+ a documented placeholder.
+- `srd.debug.*` namespace, `srd.validate_config()` beyond a trivial always-true.
+- Animations (`general.animations`/`animation_duration` config keys exist
+ and are read into defaults, but nothing consumes them yet).
+- A native GUI settings app (the legacy project's `GUI_SETTINGS.md` was
+ pure design doc even in C++; not revisited here).
diff --git a/docs/PLATFORM_IMPLEMENTATION.md b/docs/PLATFORM_IMPLEMENTATION.md
deleted file mode 100644
index 4e70767..0000000
--- a/docs/PLATFORM_IMPLEMENTATION.md
+++ /dev/null
@@ -1,636 +0,0 @@
-# SRDWM Platform Implementation Guide
-
-## Overview
-This document outlines the proper implementation approach for each platform, recognizing that **Wayland/XWayland is fundamentally different from X11** and requires completely different technologies and approaches.
-
-## Platform Architecture Differences
-
-### Linux: X11 vs Wayland
-- **X11**: Traditional X11 window management with Xlib/XCB
-- **Wayland**: Modern display protocol requiring wlroots or similar compositor framework
-- **XWayland**: X11 applications running on Wayland (requires special handling)
-
-### Windows vs macOS vs Linux
-- **Windows**: Win32 API with global hooks and window subclassing
-- **macOS**: Core Graphics/AppKit with accessibility APIs and event taps
-- **Linux**: X11 or Wayland with different event systems
-
-## Linux Implementation
-
-### X11 Backend
-```cpp
-// X11-specific implementation using Xlib/XCB
-class X11Platform : public Platform {
-private:
- Display* display_;
- Window root_;
- std::map<Window, Window*> window_map_;
-
-public:
- bool initialize() override {
- display_ = XOpenDisplay(nullptr);
- if (!display_) return false;
-
- root_ = DefaultRootWindow(display_);
- setup_event_handling();
- return true;
- }
-
- void setup_event_handling() {
- // X11 event masks and handlers
- XSelectInput(display_, root_,
- SubstructureRedirectMask | SubstructureNotifyMask |
- KeyPressMask | KeyReleaseMask |
- ButtonPressMask | ButtonReleaseMask |
- PointerMotionMask);
- }
-
- bool poll_events(std::vector<Event>& events) override {
- XEvent xevent;
- while (XPending(display_)) {
- XNextEvent(display_, &xevent);
- convert_x11_event(xevent, events);
- }
- return true;
- }
-
- void convert_x11_event(const XEvent& xevent, std::vector<Event>& events) {
- switch (xevent.type) {
- case MapRequest:
- handle_map_request(xevent.xmaprequest);
- break;
- case ConfigureRequest:
- handle_configure_request(xevent.xconfigurerequest);
- break;
- case KeyPress:
- handle_key_press(xevent.xkey);
- break;
- // ... other event types
- }
- }
-};
-```
-
-### Wayland Backend (using wlroots)
-```cpp
-// Wayland implementation using wlroots
-class WaylandPlatform : public Platform {
-private:
- struct wl_display* display_;
- struct wlroots_backend* backend_;
- struct wlroots_compositor* compositor_;
- struct wlroots_output* output_;
- struct wlroots_input_device* input_device_;
-
-public:
- bool initialize() override {
- // Initialize wlroots backend
- backend_ = wlroots_backend_create();
- if (!backend_) return false;
-
- // Create compositor
- compositor_ = wlroots_compositor_create(backend_);
- if (!compositor_) return false;
-
- // Setup output and input
- setup_output();
- setup_input();
-
- return true;
- }
-
- void setup_output() {
- // Create and configure output
- output_ = wlroots_output_create(compositor_);
- wlroots_output_set_mode(output_, 1920, 1080, 60);
- wlroots_output_commit(output_);
- }
-
- void setup_input() {
- // Setup input devices
- input_device_ = wlroots_input_device_create(compositor_);
- wlroots_input_device_set_capabilities(input_device_,
- WLROOTS_INPUT_DEVICE_CAP_KEYBOARD |
- WLROOTS_INPUT_DEVICE_CAP_POINTER);
- }
-
- bool poll_events(std::vector<Event>& events) override {
- // wlroots event loop
- wlroots_backend_dispatch(backend_);
-
- // Process wlroots events
- struct wlroots_event* event;
- while ((event = wlroots_backend_get_event(backend_))) {
- convert_wlroots_event(event, events);
- wlroots_event_destroy(event);
- }
-
- return true;
- }
-
- void convert_wlroots_event(struct wlroots_event* event, std::vector<Event>& events) {
- switch (wlroots_event_get_type(event)) {
- case WLROOTS_EVENT_NEW_SURFACE:
- handle_new_surface(event);
- break;
- case WLROOTS_EVENT_SURFACE_COMMIT:
- handle_surface_commit(event);
- break;
- case WLROOTS_EVENT_KEYBOARD_KEY:
- handle_keyboard_key(event);
- break;
- // ... other event types
- }
- }
-};
-```
-
-### XWayland Support
-```cpp
-// XWayland support for running X11 apps on Wayland
-class XWaylandManager {
-private:
- struct wlroots_xwayland* xwayland_;
- struct wlroots_xwayland_server* xwayland_server_;
-
-public:
- bool initialize(struct wlroots_compositor* compositor) {
- // Create XWayland server
- xwayland_server_ = wlroots_xwayland_server_create(compositor);
- if (!xwayland_server_) return false;
-
- // Setup XWayland
- xwayland_ = wlroots_xwayland_create(xwayland_server_);
- if (!xwayland_) return false;
-
- return true;
- }
-
- void handle_xwayland_surface(struct wlroots_surface* surface) {
- // Handle X11 windows running on Wayland
- // These need special treatment for proper integration
- }
-};
-```
-
-## Windows Implementation
-
-### Win32 API Integration
-```cpp
-// Windows implementation using Win32 API
-class WindowsPlatform : public Platform {
-private:
- HINSTANCE h_instance_;
- std::map<HWND, Window*> window_map_;
- HHOOK keyboard_hook_;
- HHOOK mouse_hook_;
-
-public:
- bool initialize() override {
- h_instance_ = GetModuleHandle(nullptr);
-
- // Register window class
- if (!register_window_class()) return false;
-
- // Setup global hooks
- setup_global_hooks();
-
- return true;
- }
-
- bool register_window_class() {
- WNDCLASSEX wc = {};
- wc.cbSize = sizeof(WNDCLASSEX);
- wc.lpfnWndProc = window_proc;
- wc.hInstance = h_instance_;
- wc.lpszClassName = L"SRDWM_Window";
- wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
-
- return RegisterClassEx(&wc) != 0;
- }
-
- void setup_global_hooks() {
- // Global keyboard hook
- keyboard_hook_ = SetWindowsHookEx(WH_KEYBOARD_LL,
- keyboard_proc, h_instance_, 0);
-
- // Global mouse hook
- mouse_hook_ = SetWindowsHookEx(WH_MOUSE_LL,
- mouse_proc, h_instance_, 0);
- }
-
- static LRESULT CALLBACK window_proc(HWND hwnd, UINT msg,
- WPARAM wparam, LPARAM lparam) {
- switch (msg) {
- case WM_CREATE:
- // Handle window creation
- break;
- case WM_DESTROY:
- // Handle window destruction
- break;
- case WM_SIZE:
- // Handle window resizing
- break;
- // ... other messages
- }
- return DefWindowProc(hwnd, msg, wparam, lparam);
- }
-
- static LRESULT CALLBACK keyboard_proc(int nCode, WPARAM wparam, LPARAM lparam) {
- if (nCode >= 0) {
- KBDLLHOOKSTRUCT* kbhs = (KBDLLHOOKSTRUCT*)lparam;
- // Handle global keyboard events
- handle_global_keyboard(wparam, kbhs);
- }
- return CallNextHookEx(nullptr, nCode, wparam, lparam);
- }
-
- static LRESULT CALLBACK mouse_proc(int nCode, WPARAM wparam, LPARAM lparam) {
- if (nCode >= 0) {
- MSLLHOOKSTRUCT* mhs = (MSLLHOOKSTRUCT*)lparam;
- // Handle global mouse events
- handle_global_mouse(wparam, mhs);
- }
- return CallNextHookEx(nullptr, nCode, wparam, lparam);
- }
-};
-```
-
-## macOS Implementation
-
-### Core Graphics/AppKit Integration
-```cpp
-// macOS implementation using Core Graphics and AppKit
-class MacOSPlatform : public Platform {
-private:
- CGEventTap event_tap_;
- std::map<CGWindowID, Window*> window_map_;
-
-public:
- bool initialize() override {
- // Request accessibility permissions
- if (!request_accessibility_permissions()) return false;
-
- // Setup event tap
- setup_event_tap();
-
- // Setup window monitoring
- setup_window_monitoring();
-
- return true;
- }
-
- bool request_accessibility_permissions() {
- // Check if accessibility is enabled
- const void* keys[] = { kAXTrustedCheckOptionPrompt };
- const void* values[] = { kCFBooleanTrue };
-
- CFDictionaryRef options = CFDictionaryCreate(
- kCFAllocatorDefault, keys, values, 1, nullptr, nullptr);
-
- bool trusted = AXIsProcessTrustedWithOptions(options);
- CFRelease(options);
-
- return trusted;
- }
-
- void setup_event_tap() {
- // Create event tap for global events
- event_tap_ = CGEventTapCreate(
- kCGSessionEventTap,
- kCGHeadInsertEventTap,
- kCGEventTapOptionDefault,
- CGEventMaskBit(kCGEventKeyDown) |
- CGEventMaskBit(kCGEventKeyUp) |
- CGEventMaskBit(kCGEventLeftMouseDown) |
- CGEventMaskBit(kCGEventLeftMouseUp) |
- CGEventMaskBit(kCGEventMouseMoved),
- event_tap_callback,
- this);
-
- if (event_tap_) {
- CFRunLoopSourceRef run_loop_source =
- CFMachPortCreateRunLoopSource(kCFAllocatorDefault, event_tap_, 0);
- CFRunLoopAddSource(CFRunLoopGetCurrent(), run_loop_source, kCFRunLoopCommonModes);
- CGEventTapEnable(event_tap_, true);
- }
- }
-
- static CGEventRef event_tap_callback(CGEventTapProxy proxy, CGEventType type,
- CGEventRef event, void* user_info) {
- MacOSPlatform* platform = static_cast<MacOSPlatform*>(user_info);
- return platform->handle_event_tap(proxy, type, event);
- }
-
- CGEventRef handle_event_tap(CGEventTapProxy proxy, CGEventType type, CGEventRef event) {
- switch (type) {
- case kCGEventKeyDown:
- handle_key_event(event, true);
- break;
- case kCGEventKeyUp:
- handle_key_event(event, false);
- break;
- case kCGEventLeftMouseDown:
- handle_mouse_event(event, true);
- break;
- case kCGEventLeftMouseUp:
- handle_mouse_event(event, false);
- break;
- case kCGEventMouseMoved:
- handle_mouse_motion(event);
- break;
- }
- return event;
- }
-
- void setup_window_monitoring() {
- // Monitor window creation/destruction
- CGWindowListCopyWindowInfo(kCGWindowListOptionOnScreenOnly |
- kCGWindowListExcludeDesktopElements,
- kCGNullWindowID);
- }
-};
-```
-
-## Platform Detection and Selection
-
-### Automatic Platform Detection
-```cpp
-// Platform factory with automatic detection
-class PlatformFactory {
-public:
- static std::unique_ptr<Platform> create_platform() {
- #ifdef _WIN32
- return std::make_unique<WindowsPlatform>();
- #elif defined(__APPLE__)
- return std::make_unique<MacOSPlatform>();
- #else
- // Linux: detect X11 vs Wayland
- return detect_linux_platform();
- #endif
- }
-
-private:
- static std::unique_ptr<Platform> detect_linux_platform() {
- // Check environment variables
- const char* wayland_display = std::getenv("WAYLAND_DISPLAY");
- const char* xdg_session_type = std::getenv("XDG_SESSION_TYPE");
-
- if (wayland_display || (xdg_session_type && strcmp(xdg_session_type, "wayland") == 0)) {
- // Try Wayland first
- auto wayland_platform = std::make_unique<WaylandPlatform>();
- if (wayland_platform->initialize()) {
- std::cout << "Using Wayland backend" << std::endl;
- return wayland_platform;
- }
- std::cout << "Wayland initialization failed, falling back to X11" << std::endl;
- }
-
- // Fall back to X11
- auto x11_platform = std::make_unique<X11Platform>();
- if (x11_platform->initialize()) {
- std::cout << "Using X11 backend" << std::endl;
- return x11_platform;
- }
-
- std::cerr << "Failed to initialize any platform backend" << std::endl;
- return nullptr;
- }
-};
-```
-
-## Dependencies and Build System
-
-### CMake Configuration
-```cmake
-# Platform-specific dependencies
-if(WIN32)
- # Windows dependencies
- find_package(PkgConfig REQUIRED)
- set(PLATFORM_LIBS user32 gdi32)
-
-elseif(APPLE)
- # macOS dependencies
- find_library(COCOA_LIBRARY Cocoa)
- find_library(CARBON_LIBRARY Carbon)
- find_library(IOKIT_LIBRARY IOKit)
- set(PLATFORM_LIBS ${COCOA_LIBRARY} ${CARBON_LIBRARY} ${IOKIT_LIBRARY})
-
-else()
- # Linux dependencies
- find_package(PkgConfig REQUIRED)
-
- # X11 dependencies
- pkg_check_modules(X11 REQUIRED x11 xcb xcb-keysyms)
-
- # Wayland dependencies (optional)
- pkg_check_modules(WAYLAND wayland-client wayland-cursor)
- pkg_check_modules(WLROOTS wlroots)
-
- if(WAYLAND_FOUND AND WLROOTS_FOUND)
- add_definitions(-DWAYLAND_ENABLED)
- set(PLATFORM_LIBS ${PLATFORM_LIBS} ${WAYLAND_LIBRARIES} ${WLROOTS_LIBRARIES})
- endif()
-
- set(PLATFORM_LIBS ${PLATFORM_LIBS} ${X11_LIBRARIES})
-endif()
-```
-
-### Package Dependencies
-```bash
-# Ubuntu/Debian
-sudo apt install libx11-dev libxcb1-dev libxcb-keysyms1-dev
-sudo apt install libwayland-dev libwlroots-dev
-
-# Arch Linux
-sudo pacman -S xorg-server-devel wayland wlroots
-
-# Fedora
-sudo dnf install libX11-devel libxcb-devel wayland-devel wlroots-devel
-```
-
-## Event Handling Differences
-
-### X11 Event System
-```cpp
-// X11 events are synchronous and direct
-void X11Platform::handle_map_request(const XMapRequestEvent& event) {
- Window* window = create_window(event.window);
- if (window) {
- window_map_[event.window] = window;
- // X11 window is now managed
- }
-}
-```
-
-### Wayland Event System
-```cpp
-// Wayland events are asynchronous and callback-based
-void WaylandPlatform::handle_new_surface(struct wlroots_event* event) {
- struct wlroots_surface* surface = wlroots_event_get_surface(event);
-
- // Create window for new surface
- Window* window = create_window_from_surface(surface);
- if (window) {
- surface_window_map_[surface] = window;
- }
-}
-```
-
-### Windows Event System
-```cpp
-// Windows uses message-based event system
-LRESULT WindowsPlatform::window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
- switch (msg) {
- case WM_CREATE:
- // Window creation
- break;
- case WM_DESTROY:
- // Window destruction
- break;
- }
- return DefWindowProc(hwnd, msg, wparam, lparam);
-}
-```
-
-### macOS Event System
-```cpp
-// macOS uses event taps and accessibility APIs
-CGEventRef MacOSPlatform::handle_event_tap(CGEventTapProxy proxy, CGEventType type, CGEventRef event) {
- switch (type) {
- case kCGEventKeyDown:
- // Handle key press
- break;
- case kCGEventMouseMoved:
- // Handle mouse movement
- break;
- }
- return event;
-}
-```
-
-## Window Management Differences
-
-### X11 Window Management
-```cpp
-// X11: Direct window manipulation
-void X11Platform::set_window_position(Window* window, int x, int y) {
- XMoveWindow(display_, window->get_x11_handle(), x, y);
-}
-
-void X11Platform::set_window_size(Window* window, int width, int height) {
- XResizeWindow(display_, window->get_x11_handle(), width, height);
-}
-```
-
-### Wayland Window Management
-```cpp
-// Wayland: Surface-based management
-void WaylandPlatform::set_window_position(Window* window, int x, int y) {
- struct wlroots_surface* surface = window->get_wayland_surface();
- wlroots_surface_set_position(surface, x, y);
-}
-
-void WaylandPlatform::set_window_size(Window* window, int width, int height) {
- struct wlroots_surface* surface = window->get_wayland_surface();
- wlroots_surface_set_size(surface, width, height);
-}
-```
-
-### Windows Window Management
-```cpp
-// Windows: Win32 API calls
-void WindowsPlatform::set_window_position(Window* window, int x, int y) {
- HWND hwnd = window->get_win32_handle();
- SetWindowPos(hwnd, nullptr, x, y, 0, 0,
- SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
-}
-
-void WindowsPlatform::set_window_size(Window* window, int width, int height) {
- HWND hwnd = window->get_win32_handle();
- SetWindowPos(hwnd, nullptr, 0, 0, width, height,
- SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
-}
-```
-
-### macOS Window Management
-```cpp
-// macOS: Core Graphics API calls
-void MacOSPlatform::set_window_position(Window* window, int x, int y) {
- CGWindowID window_id = window->get_macos_window_id();
- CGPoint position = CGPointMake(x, y);
-
- // Use accessibility APIs to move window
- AXUIElementRef element = AXUIElementCreateApplication(
- window->get_macos_pid());
-
- if (element) {
- AXUIElementSetAttributeValue(element, kAXPositionAttribute, &position);
- CFRelease(element);
- }
-}
-```
-
-## Testing and Validation
-
-### Platform-Specific Testing
-```cpp
-// Test each platform independently
-class PlatformTest {
-public:
- static void test_x11_platform() {
- auto platform = std::make_unique<X11Platform>();
- assert(platform->initialize());
- // Test X11-specific functionality
- }
-
- static void test_wayland_platform() {
- auto platform = std::make_unique<WaylandPlatform>();
- assert(platform->initialize());
- // Test Wayland-specific functionality
- }
-
- static void test_windows_platform() {
- auto platform = std::make_unique<WindowsPlatform>();
- assert(platform->initialize());
- // Test Windows-specific functionality
- }
-
- static void test_macos_platform() {
- auto platform = std::make_unique<MacOSPlatform>();
- assert(platform->initialize());
- // Test macOS-specific functionality
- }
-};
-```
-
-## Best Practices
-
-### 1. **Platform Abstraction**
-- Keep platform-specific code isolated
-- Use common interfaces for cross-platform functionality
-- Implement platform detection automatically
-
-### 2. **Wayland vs X11**
-- **Never mix X11 and Wayland APIs**
-- Use wlroots for Wayland (don't implement from scratch)
-- Handle XWayland as a special case within Wayland
-
-### 3. **Event Handling**
-- Respect each platform's event model
-- Don't force synchronous behavior on asynchronous platforms
-- Handle platform-specific quirks gracefully
-
-### 4. **Window Management**
-- Use platform-native APIs for best performance
-- Don't try to emulate one platform's behavior on another
-- Handle platform-specific window states properly
-
-### 5. **Testing**
-- Test each platform independently
-- Use CI/CD with multiple platform targets
-- Validate platform-specific features thoroughly
-
-This implementation approach ensures that SRDWM works correctly on each platform while respecting the fundamental differences between X11, Wayland, Windows, and macOS.
-
-
diff --git a/docs/PRIOR_ART.md b/docs/PRIOR_ART.md
new file mode 100644
index 0000000..722e865
--- /dev/null
+++ b/docs/PRIOR_ART.md
@@ -0,0 +1,79 @@
+# Prior art
+
+Two kinds of "prior art" shaped this rewrite: the legacy C++ codebase this
+project itself started as, and the wider field of window managers/compositors
+that solve pieces of the same problem.
+
+## The legacy C++ codebase
+
+`legacy-cpp/` (formerly the repo root) is preserved for reference. An
+`Explore`-agent audit of it before the rewrite found it was mostly a design
+skeleton rather than working software:
+
+| Backend | Status | What was real |
+|---|---|---|
+| X11 (`x11_platform.cc`) | Partially functional | Reparenting decoration model, EWMH atom list, basic Xlib window ops. No drag/resize, hardcoded 800px titlebar width, RandR monitor bug (used physical mm instead of pixel mode), fake "another WM" detection. |
+| Windows (`windows_platform.cc`) | Partially functional | DWM border-color tinting, global low-level hooks, real `EnumDisplayMonitors`. No virtual desktop support, no subclassing. |
+| Wayland (`wayland_platform.cc`) | Architecture only | Created the wlroots backend/renderer/compositor/seat/xdg-shell objects in the right order, but never called `wl_signal_add` on a single one - no window was ever actually managed. |
+| macOS (`macos_platform.cc`) | Mostly stub | Real Accessibility-permission request and `CGDisplay`-based monitor enumeration. Window move/resize were empty TODOs; the "overlay window" decoration idea was never implemented. |
+| Lua config (`lua_manager.cc`) | Partially functional | Scalar config get/set worked. `srd.bind()` stored the key-combo string but not the actual Lua closure - keybindings could never fire. `srd.window.focused()` returned a hardcoded placeholder table with no methods, so the shipped example config's `window:close()` would have errored at runtime. |
+
+The Rust rewrite fixes these rather than porting them: see
+`docs/IMPLEMENTATION_STATUS.md` for what's real now, and the module-level doc
+comments in `crates/x11/src/lib.rs` and `crates/wayland/src/lib.rs` for the
+specific bugs each backend's replacement corrects.
+
+## Comparable window managers/compositors
+
+None of these were copied from - srdwm's Lua-config, single-binary,
+cross-platform-trait design doesn't match any of them exactly - but each
+informed a specific decision:
+
+- **[niri](https://github.com/YaLTeR/niri)** (Rust, Wayland, smithay) - the
+ closest architectural sibling to `crates/wayland`. Confirms smithay is a
+ viable foundation for a real tiling compositor, not just toy examples.
+- **[river](https://codeberg.org/river/river)** (Zig, Wayland, wlroots) --
+ configured via an external CLI/IPC protocol rather than an embedded
+ scripting language. srdwm deliberately goes the other way (embedded Lua,
+ matching the project's own history and this rewrite's brief), but river is
+ a useful reminder that "protocol, not library" is a legitimate alternative
+ to what this project does.
+- **[leftwm](https://github.com/leftwm/leftwm)** and
+ **[penrose](https://github.com/sminez/penrose)** (Rust, X11) - both
+ reimplement dwm/xmonad-style tiling in Rust; penrose in particular is a
+ "bring your own `main.rs`" library rather than a turnkey binary. Reference
+ points for idiomatic X11-in-Rust event loop structure (`crates/x11` uses
+ `x11rb`, as both of these do).
+- **[komorebi](https://github.com/LGUG2Z/komorebi)** and
+ **[glazewm](https://github.com/glzr-io/glazewm)** (Rust, Windows) - both
+ keep the *native* DWM frame and manage layout/focus around it rather than
+ replacing decorations, communicating with a companion CLI over IPC. This
+ directly informed `crates/windows`' documented plan: Windows doesn't get a
+ custom titlebar by disabling the native frame and hand-drawing one (as X11
+ does) but by controlling the existing frame (`DWMWA_BORDER_COLOR` etc.),
+ since that's what's actually achievable without fighting DWM.
+- **[yabai](https://github.com/koekeishiya/yabai)** and
+ **[AeroSpace](https://github.com/nikitabobko/AeroSpace)** (macOS) - yabai
+ uses private, partially-undocumented APIs and a signed "scripting addition"
+ that requires disabling System Integrity Protection for full functionality;
+ AeroSpace deliberately restricts itself to the public Accessibility API,
+ trading some capability for not requiring SIP changes. `crates/macos`'
+ documented design follows AeroSpace's approach (AX-only), consistent with
+ the legacy C++ code's own choice to request Accessibility permission
+ rather than pursue private APIs.
+
+## What's genuinely novel here (not borrowed from anywhere)
+
+- `srdwm_core::window::ResizeEdge::hit_test` - one hit-testing/decoration
+ function shared verbatim by both the X11 and Wayland backends, so "drag
+ the titlebar" and "grab the corner to resize" behave identically
+ regardless of display server. Neither the legacy C++ nor any of the
+ projects above shares decoration logic across backends this way (each
+ reimplements per-backend, since none of them target both X11 reparenting
+ *and* Wayland SSD from the same core).
+- The `srd` Lua API's shape (`srd.window.close()` acting on the currently
+ focused window, `srd.window.focus("left")` for directional navigation,
+ `srd.workspace.next()`) matches what `docs/DEFAULTS.md` always
+ *documented* - but the legacy engine never actually implemented that
+ surface (see table above). This rewrite implements the documented API for
+ real rather than inventing a new one.