diff options
| author | srdusr <[email protected]> | 2024-04-02 01:07:00 +0200 |
|---|---|---|
| committer | srdusr <[email protected]> | 2024-04-02 01:07:00 +0200 |
| commit | 43175c78a5b450eb108738187b72e80d36a7bf5d (patch) | |
| tree | dbbadbcc18162f766f5af653d81882aaaa6f5e41 /docs | |
| parent | 8110bb2773b6c841029a51eca7971f42a36f480c (diff) | |
| download | srdwm-43175c78a5b450eb108738187b72e80d36a7bf5d.tar.gz srdwm-43175c78a5b450eb108738187b72e80d36a7bf5d.zip | |
Add window rules, real config validation, and a Wayland DRM/udev backend
- srd.rule(): match windows by title/class, apply floating/maximized/
workspace/geometry/decoration actions on creation (crates/core/src/rules.rs)
- srd.validate_config()/srd.debug.*: real range/format checks and
status/profiling helpers, replacing the always-true stub
- Wayland titlebar text rendering via fontdue, unit-tested without a
display (crates/wayland/src/decoration.rs)
- Wayland precise keybinding matching, replacing the "any Super-held key"
heuristic, sharing the keysym table with X11 (moved to
crates/core/src/keysyms.rs)
- Wayland DRM/udev backend (crates/wayland/src/udev.rs): runs as the real
compositor on a bare TTY via libseat/libinput/KMS, software rendering
via Pixman + dumb buffers (no GBM/EGL required)
- srdwm_platform::detect() fix, found via VM testing: a bare TTY with no
DISPLAY/WAYLAND_DISPLAY now correctly resolves to Wayland instead of an
X11 backend that can never work there
- XWayland integration groundwork (crates/wayland/src/xwayland.rs): spawn,
X11Wm, and full XwmHandler event routing into the same WindowManager/
Space pipeline as native clients. Windows don't render yet - a real
glamor-vs-software-renderer conflict in XWayland's own fallback path,
root-caused via WAYLAND_DEBUG tracing and documented in
docs/IMPLEMENTATION_STATUS.md rather than worked around blind.
All verified live in an isolated QEMU VM: X11 backend shows two
decorated, correctly-tiled xterms with real title text; the DRM/udev
Wayland backend opens the GPU, initializes input, and scans out a
rendered frame via KMS page-flip.
Diffstat (limited to 'docs')
| -rw-r--r-- | docs/DEFAULTS.md | 46 | ||||
| -rw-r--r-- | docs/IMPLEMENTATION_STATUS.md | 161 |
2 files changed, 181 insertions, 26 deletions
diff --git a/docs/DEFAULTS.md b/docs/DEFAULTS.md index 9b36f5a..74dfba6 100644 --- a/docs/DEFAULTS.md +++ b/docs/DEFAULTS.md @@ -191,6 +191,33 @@ srd.bind("Mod4+d", function() srd.spawn("rofi -show drun") end) - Default: Mod4+ srd.bind("Mod4+Return", function() srd.spawn("alacritty") end) -- Default: Mod4+Return ``` +## Window Rules + +Match windows by title/class and apply actions once, when they're first +created: + +```lua +srd.rule(matcher, actions) +``` + +`matcher` fields (at least one required; an empty matcher matches nothing): +- `title` - case-insensitive substring match against the window title. +- `class` (alias `app_id`) - case-insensitive exact match against the + window's `WM_CLASS` (X11) / `app_id` (Wayland). + +`actions` fields (all optional): +- `floating` (bool), `maximized` (bool) +- `workspace` (number) - workspace id to place the window on +- `x`, `y`, `width`, `height` (number) - explicit geometry; all four must be + given together to take effect +- `decorated` (bool) +- `border_color` (`{r, g, b}`), `border_width` (number) + +```lua +srd.rule({ class = "pavucontrol" }, { floating = true }) +srd.rule({ title = "Picture-in-Picture" }, { floating = true, width = 480, height = 270 }) +``` + ## Platform-Specific Defaults ### Linux (X11/Wayland) @@ -319,18 +346,21 @@ srd.reset_category("general") ### Debug Commands ```lua -- Check configuration status -srd.debug.config_status() +- Check configuration status: returns { keys, bound_keys, log_entries, config_dir } +local status = srd.debug.config_status() -- Validate current configuration -srd.debug.validate_config() +- Validate current configuration against docs/DEFAULTS.md's ranges/formats: +- returns ok (bool), errors (array of human-readable strings, empty when ok) +local ok, errors = srd.debug.validate_config() +- equivalently, at the top level: +local ok, errors = srd.validate_config() -- Show current settings -srd.debug.show_settings() +- Show current settings: logs every key = value and returns them as a table +local settings = srd.debug.show_settings() -- Performance profiling +- Performance profiling: profile_stop() returns elapsed seconds (number) srd.debug.profile_start() -srd.debug.profile_stop() +local elapsed = srd.debug.profile_stop() ``` This documentation provides a comprehensive reference for all default values and configuration options in SRDWM. diff --git a/docs/IMPLEMENTATION_STATUS.md b/docs/IMPLEMENTATION_STATUS.md index 5481c4c..576b3dc 100644 --- a/docs/IMPLEMENTATION_STATUS.md +++ b/docs/IMPLEMENTATION_STATUS.md @@ -33,15 +33,27 @@ doing the thing described - not just "the code compiles and looks right." 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.spawn`, `srd.notify`, `srd.quit`, `srd.rule`, `srd.validate_config`, + `srd.debug.{config_status,validate_config,show_settings,profile_start,profile_stop}`. - `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). +- `srd.rule(matcher, actions)` matches windows by title (substring) or + class/app_id (exact) and applies floating/maximized/workspace/geometry/ + decoration/border actions once, when a matching window is first created + (`crates/core/src/rules.rs`, applied from `WindowManager::add_window`). + `config/srd/rules.lua` documents the API instead of being a no-op + placeholder. +- `srd.validate_config()` (and `srd.debug.validate_config()`) actually + check the numeric ranges, layout-name references, and hex-color formats + documented in `docs/DEFAULTS.md`'s "Validation Rules" section, returning + `(ok, errors)` - not a trivial always-true. `srd.debug.config_status()`/ + `show_settings()`/`profile_start()`/`profile_stop()` are real too. - `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 +- 15 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`) @@ -64,6 +76,10 @@ doing the thing described - not just "the code compiles and looks right." `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. +- **Re-verified in an isolated QEMU VM** (see "QEMU VM verification" below): + two `xterm` clients reparented and placed by `SmartPlacement`, each with + a drawn titlebar showing real title text and close/maximize/minimize + glyphs, screenshotted via QEMU's `screendump`. ### Windows and macOS backends (`crates/windows`, `crates/macos`) - Structured as honest stubs: real-looking `windows-rs`/Core Graphics calls @@ -95,19 +111,71 @@ What's here is a genuine from-scratch `smithay`-based compositor, not a stub: - ✅ 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. +- ✅ Decorations render actual title text (`crates/wayland/src/decoration.rs`): + glyphs rasterized via `fontdue` against whatever monospace font is found + under `/usr/share/fonts` etc. (falls back to solid-color-only, same as + before, if none is found), uploaded per-frame through smithay's + `MemoryRenderBuffer`. Pure `(width, height, text) -> Vec<u8>` function, + unit-tested without any GL/display context. +- ✅ Global keybindings are matched precisely: `WaylandPlatform::connect` + takes the config's actual bound-key combo strings (same format/shared + `srdwm_core::keysyms` table the X11 backend's `XGrabKey` calls use) and + only a matching keypress is withheld from the focused client - no more + "any Super-held key is ours" heuristic. +- ✅ DRM/udev backend (`crates/wayland/src/udev.rs`): runs as the real + compositor on a bare TTY, no host session to nest under. Single primary + GPU, first connected connector, its first-listed mode, real `libseat` + session/seat handling (VT-switch pause/resume, no raw root-only + `/dev/dri` open), real `libinput` input sharing the exact same + keybinding/hit-test code the winit backend uses. Rendering is + **software** (smithay's `PixmanRenderer` into plain KMS dumb buffers via + the legacy, non-atomic `set_crtc`/`page_flip` API) rather than + GBM/EGL/`DrmCompositor`-based hardware acceleration: that path needs a + GPU with working KMS+3D driver support that a low-spec machine's VM isn't + guaranteed to have, while dumb buffers work on essentially any DRM + driver. `WaylandPlatform::connect` (winit) picks this backend + automatically when no `WAYLAND_DISPLAY`/`DISPLAY` is set, falling back to + nested winit if udev init fails for any reason. + **Verified live in an isolated QEMU VM** (see below): started on a bare + virtual TTY with no `DISPLAY`/`WAYLAND_DISPLAY`, opened `/dev/dri/card1` + via a real libseat session, initialized libinput, advertised a Wayland + socket, and rendered a frame that scanned out correctly via KMS + page-flip - confirmed by screendumping the guest's virtual framebuffer + and matching the exact clear color (`[0.05, 0.05, 0.08]`) the compositor + renders. No client-side visual check yet (the VM has no Wayland-native + client installed to test against, only X11 ones - see below). No + hotplug (connectors or GPUs) after startup. +- 🔄 XWayland integration (`crates/wayland/src/xwayland.rs`), udev/DRM + backend only (the winit backend would need its own `calloop::EventLoop` + added first - see the module's doc comment): spawns XWayland, starts + `X11Wm`, and implements `XwmHandler`/`XWaylandShellHandler` to bridge + X11-only clients into the same `WindowManager`/`Space` pipeline + xdg-shell windows use (`CreateNotify`/`MapRequest` create a real + `srdwm_core::Window`, matched by rules via `class()`; unmap/destroy + clean up the same way). **Verified working up through window creation + and event routing, then found a real architectural blocker**: XWayland + tries `glamor` (GBM-based rendering) first; since this compositor is + deliberately software-only (no GBM/DMA-BUF support - the whole point of + the dumb-buffer approach above), glamor fails, and XWayland's + post-failure fallback path skips the `xwayland_shell_v1` protocol + entirely, so `X11Surface::wl_surface()` never resolves and windows never + render. Confirmed by tracing the actual Wayland protocol exchange + (`WAYLAND_DEBUG=1` on the spawned XWayland process): it binds + `xwayland_shell_v1` at startup, then a second, window-creation-time + registry pass sees the global but never binds it, and + `get_xwayland_surface`/`set_serial` never appear at all. `Xwayland + -help` confirms a `-shm` flag exists that forces shared-memory buffers + from the start (matching this compositor's `wl_shm`/`ImportMem`-only + renderer) instead of trying and falling back from glamor - but + `smithay::xwayland::XWayland::spawn` builds its `Xwayland` command line + internally with a fixed argument list and has no way to add `-shm`. + Fixing this for real means either bypassing `XWayland::spawn` with a + custom implementation (reimplementing its X11 lock-file/socket-pair/ + readiness-detection logic, which is intentionally private to smithay -- + `mod x11_sockets;`, not `pub mod`) or giving the compositor real + GBM/DMA-BUF import support, undoing the earlier deliberate low-spec/ + no-GPU-required design. Left as a documented gap rather than rushing a + low-level reimplementation with no cheap way to iterate on it. **Why the visual verification stopped short of a screenshot**: the winit window opens on the *host* compositor, and the only available display in @@ -118,11 +186,68 @@ 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. +## QEMU VM verification + +Both the X11 backend and the Wayland/DRM-udev backend were re-verified from +scratch in an isolated QEMU VM (not the sandbox they were originally built +in), to check they work somewhere other than the exact environment that +built them: + +- **VM**: minimal Arch Linux rootfs (base, linux, xorg-server, xterm, mesa, + seatd, libinput, libxkbcommon, xf86-input-libinput - built by copying the + host's own already-installed files for these packages plus their full + dependency closure, rather than a fresh `pacstrap`, since this sandbox's + network throughput made a real package download impractical). Booted via + direct kernel+initramfs (no bootloader), `virtio-gpu`/`virtio-keyboard`/ + `virtio-mouse`/`virtio-net`, autologin on both the serial console and + `tty1`, `-display none` with QMP `screendump` for visual verification + (no interactive GUI needed on the host side). +- **X11 backend**: `run-x11.sh` starts Xorg on `vt1` then execs `srdwm` as + an X11 client (the standard way it becomes the WM). Two `xterm`s spawned + via the config's `startup.lua` were reparented, tiled/placed by + `SmartPlacement`, and both show a drawn titlebar with real "xterm" title + text and close/maximize/minimize glyphs - screenshotted and visually + confirmed. +- **Wayland/DRM-udev backend**: run directly on the bare console (no `-x` + script needed - no `DISPLAY`/`WAYLAND_DISPLAY` set at all). Opened + `/dev/dri/card1` via `libseat`, initialized `libinput`, advertised a real + Wayland socket, and rendered/page-flipped a frame - confirmed by + screendumping the guest's virtual display and matching the exact clear + color the compositor renders. This required a real bug fix, found by + this exact test: `srdwm_platform::detect()` previously defaulted to X11 + whenever neither `WAYLAND_DISPLAY` nor `XDG_SESSION_TYPE=wayland` was + set, *regardless of whether `DISPLAY` was set either* - meaning on a + genuinely bare TTY it picked X11, a backend that can never work there + (`srdwm_x11::X11Platform` only ever connects to an already-running X + server; it doesn't start one). `detect()` now only picks X11 when + `DISPLAY` is set without Wayland evidence; every other case, including a + bare TTY, resolves to Wayland, which is the only backend able to run + standalone there. +- **Not (yet) verified**: nested Wayland (the `backend_winit` path) running + as an X11 client under this VM's Xorg - `smithay`'s `winit` backend + failed with `Failed to initialize an event loop`, which is an error + surfaced from inside the `winit` crate's own X11 initialization, not + `srdwm`'s code; most likely this minimal VM's software-only Xorg is + missing a GLX/DRI3 piece `winit`'s EGL context creation wants. The nested + path was already verified once before (Xephyr-equivalent, log-verified + per the section above); this is a gap in re-verifying it in this + specific minimal VM, not a known-broken code path. +- No Wayland-native client was available in this minimal VM to visually + confirm client-side rendering under either Wayland backend (only + `xterm`, which is X11-only) - the compositor/socket/render-pipeline + side is confirmed, but no real Wayland app has been shown on-screen yet. +- **XWayland**: `xterm` launched with `DISPLAY` pointed at the udev + backend's spawned XWayland connected successfully and stayed alive + (`CreateNotify`/`MapRequest` both reached `XwmHandler`, logged and + handled with no crash), but never rendered - this is the + glamor/`-shm` blocker documented above, root-caused via + `WAYLAND_DEBUG=1` protocol tracing on the XWayland process rather than + guessed at. + ## 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. +- XWayland actually rendering a window (blocked on the glamor/`-shm` + issue above; the spawn/protocol/window-tracking plumbing is real). - 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 |