srdusr
aboutsummaryrefslogtreecommitdiffstats
path: root/docs
diff options
context:
space:
mode:
authorsrdusr <[email protected]>2024-04-02 01:07:00 +0200
committersrdusr <[email protected]>2024-04-02 01:07:00 +0200
commit43175c78a5b450eb108738187b72e80d36a7bf5d (patch)
treedbbadbcc18162f766f5af653d81882aaaa6f5e41 /docs
parent8110bb2773b6c841029a51eca7971f42a36f480c (diff)
downloadsrdwm-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.md46
-rw-r--r--docs/IMPLEMENTATION_STATUS.md161
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