srdusr
aboutsummaryrefslogtreecommitdiffstats
path: root/docs/IMPLEMENTATION_STATUS.md
AgeCommit message (Collapse)AuthorFilesLines
2025-09-14Docs: master TODO/DEFAULTS/status updates, feature-gap survey, lockfilesrdusr1-2/+14
docs/TODO.md is this shift's single consolidated pending-work list (see its own header for why it exists alongside PANEL_SUPPORT_TODO.md/ SESSION_HANDOFF.md rather than replacing them) - every commit in this batch has its own dated entry there with the full root-cause/ verification narrative. docs/DEFAULTS.md corrected against the real config engine and extended for every new general.* key this shift added (aspect_ratio rule action, phone_mode). docs/FEATURE_GAP.md is a new survey against niri/Hyprland/sway, requested directly. docs/ IMPLEMENTATION_STATUS.md and docs/PRIOR_ART.md updated to match. Cargo.lock reflects the new resvg/usvg/tiny-skia dependencies (real icon-theme SVG rendering).
2025-08-08Render real window content on the GPU render pathsrdusr1-3/+6
Past clear-color + cursor: a GPU-driven head now renders every visible window's real content too, via surface_content_elements (the same generic-over-renderer helper the Pixman path uses, unmodified against gpu.renderer instead of udev.renderer). Content pushed after the cursor (so the cursor stays on top), in the same front-to-back `ids` order the Pixman path's own custom_elements already relies on for correct occlusion between windows - plain painter's-algorithm draw order, no separate clip needed since content is window-shaped. Deliberately the *unrounded* path: no corner masking (that's built against PixmanRenderer specifically on this backend) and no decorations (border, titlebar) - a GPU-driven head now shows real window content, square corners, no chrome. Decorations are the remaining real gap before this path has parity with the software one. Per-window geometry/position math (geom from window_anims or w.geometry, band for a decorated window's titlebar reservation, content_offset clamped non-negative) mirrors the Pixman path's own content push exactly, including an earlier double- subtraction and negative-margin fixes - so a CSD client with a real shadow margin positions the same way on either render path. Untested on real GPU-enabled hardware as of this writing: builds, passes clippy, full test suite green, and matches the existing Pixman path's geometry logic by inspection, but SRDWM_GPU/general.gpu were both unset on the machine this was built on - noted honestly in gpu.rs's own module doc comment, DEFAULTS.md, and IMPLEMENTATION_STATUS.md.
2025-05-29Correct docs/DEFAULTS.md against the real config engine, audit-stylesrdusr1-1/+11
Grepped the whole compositor for a second reader of every documented general.*/theme.*/layout.*/performance.*/debug.*/platform.* config key beyond its own seed call in crates/config/src/engine/support.rs. Several sections turned out to be entirely or mostly decorative -- accepted, stored, sometimes range/type-validated, but never actually applied to window/render behavior - which this file presented no differently from the real, working settings around them: - theme.colors.* (background/foreground/primary/secondary/accent/ error/warning/success): none read past the seed call. The real, working theme surface is theme.decorations.* below it. - performance.* and debug.* (vsync/max_fps/window_cache_size/ event_queue_size/layout_timeout/enable_caching, logging/log_level/ profile/trace_events/show_layout_bounds/show_window_geometry): every key in both namespaces is dead. Real frame pacing comes from the display's own hardware vsync; RUST_LOG is the real logging control. - layout.tiling/dynamic/floating.*: only master_ratio is real (WindowManager::tiling.master_ratio). split_ratio, every behavior.* table, per-layout gaps.inner/outer, snap_threshold, grid_size, cascade_offset, smart_placement, default_position, remember_position, always_on_top are all dead - the real gap setting for every layout is general.window_gap. - theme.decorations.border.focused_style/unfocused_style and title_bar.show/font: dead - solid is the only border style this compositor draws, and the titlebar always uses whatever system font find_system_font picks. - platform.x11.*/platform.wayland.*/platform.windows.*/platform.macos.* use_*/global_hooks/accessibility_enabled: all dead - EWMH/NetWM/ xdg-shell/layer-shell/DWM/Win32/Cocoa/Core Graphics support is simply always compiled in, never behind a toggle. platform.backend/ platform.os are the two real, but read-only, keys in this section. Also: the Environment Variables section listed SRDWM_THEME/ SRDWM_DEBUG_LEVEL/SRDWM_PLATFORM/SRDWM_MAX_FPS/SRDWM_VSYNC, none of which exist anywhere in the codebase - replaced with the real set (SRDWM_CONFIG_PATH, SRDWM_STATE_PATH, SRDWM_GPU, RUST_LOG), found by grepping every std::env::var call in the compositor's own source. Validation Rules' numeric list was missing corner-radius entirely (theme.decorations.border.radius, 0-100, real in the validator despite the doc gap) and resize_margin/inactive_dim, and didn't note that srd set (unlike the Lua config path) doesn't run these checks at all. Added general.gpu's own documentation section (new here - see the matching commit adding the config option itself). Also updates IMPLEMENTATION_STATUS.md's udev-backend paragraph, which described the real GBM+EGL+DrmCompositor GPU path as not existing at all ("that path needs a GPU...") - it now exists, opt-in, with its current real scope (every head, cursor, no window content yet) noted in place of the stale absence.
2024-05-30Fix decoration drift during animated transitions; checkpoint ↵srdusr1-4/+1480
IPC/global-menu/output-management work Border/titlebar decoration was built from Window.geometry (the animation's final target) in both wayland backends' render loops, while sync_geometry already draws a window's actual content at window_anims' interpolated rect during any maximize/fullscreen/open-slide tween. Border and content read two different rectangles for the whole transition, so the border visibly detached from the window it was outlining - reported as "borders aren't flush." Both udev.rs and winit.rs now read the same animated rect for titlebar placement, border-strip placement, and the occlusion test against later windows in stacking order. Verified: cargo build --workspace, cargo clippy (0 new warnings), cargo test -p srdwm-core (111/111). Also checkpoints substantial protocol/IPC work from prior sessions that had accumulated uncommitted: gtk-shell1 support (gtk_shell.rs, the vendored gtk-shell.xml, xwayland.rs's X11-side mirror) backing the global app menu; zwlr_foreign_toplevel_manager_v1 (foreign_toplevel.rs) broadcasting distinct maximized/minimized/fullscreen/activated state per window; output_management (ext-output-management + layer-shell exclusive-zone reservation tracking); workspace.rs and context_menu.rs; a Unix-socket IPC crate (platform/src/ ipc.rs) and a `srd` control-CLI crate (crates/ctl); xkb_config.rs; and a theme module (core/src/theme.rs). A peer session working the AGS shell concurrently verified several of these live against a running srdwm: the global menu rendering a real app's File/Edit menu over gtk-shell1, and foreign-toplevel correctly reporting maximized and fullscreen as independent, non-simultaneous states with the geometry each implies (maximize stops at a reserved top bar and past a dock; fullscreen reaches the true monitor edge).
2024-05-29Config at ~/.config/srd; cursor shapes, key repeat, pin, mouse defaultssrdusr1-27/+53
Config path drops a level: ~/.config/srd, not ~/.config/srdwm/srd, which said the same thing twice. No other user-facing path had the same problem -- srdwm reads the config dir and writes nothing else. Cursor shapes. A client's own cursor surface is now rendered with the hotspot it declared, so an I-beam over text or a hand over a link shows the app's image instead of srdwm's arrow. The built-in arrow stays as the fallback when no client has set one, over decorations and the desktop. Named shapes still fall back to the arrow; most toolkits set a surface. Decorations and cursors now share one OverlayElement type, since render_output takes a single custom-element slice. Key repeat (srd.bind_repeat, Hyprland's binde). Held volume, brightness and switcher keys repeat at the seat's own rate rather than firing once. Driven from the poll loop, not a timer source: the winit backend has no calloop loop of its own, and poll_events already runs continuously in both backends. Repeat stops when *that* key is released, not when any key is. Always-on-top / pin, for the picture-in-picture and HUD rules that used it. Window::always_on_top was another declared-but-never-read field. Enforced in WindowManager's stacking order rather than at render time, so every consumer of stacking_order gets it and none can forget to honour it. Mouse-only window management, checked end to end: drag the titlebar to move, drag any edge or corner to resize, titlebar buttons to close/maximise/ minimise, click to focus, drag to a screen edge to snap, and now double-click the titlebar to maximise. The resize grab band went from 6px to 10px - a hairline is genuinely hard to hit with a mouse, which is why Hyprland ships extend_border_grab_area. Also removed the emoji status markers from docs/IMPLEMENTATION_STATUS.md.
2024-05-14Draw a cursor, handle the lid, and everything a real config needssrdusr1-0/+23
Groundwork for actually daily-driving this: porting the user's Hyprland config exposed what srdwm couldn't yet express, and testing on a bare TTY exposed something worse. A visible mouse cursor. Nothing drew a pointer at all - on a bare TTY the mouse was simply invisible. It hid because the nested backend runs inside another compositor, which draws a cursor over srdwm's window; only the DRM backend, i.e. the actual session path, was affected. A built-in arrow is now composited above everything on the output the pointer is on. It's a reviewable ASCII bitmap rather than an XCursor theme: a cursor that is always present beats a prettier one that sometimes isn't, the same reasoning as decoration.rs's font fallback. Client-set cursor surfaces and named shapes are still not rendered, so an app asking for an I-beam gets the arrow. Lid switch. libinput switch events are handled and surfaced to config as srd.on("lid_closed"/"lid_open", fn), so closing the lid can lock and suspend instead of doing nothing. Config-driven additions, each needed by a binding in the ported config and none of which existed: fullscreen (Window.fullscreen was a dead field -- declared, never read or written), directional window move that swaps with the neighbour and reorders the stack so tiling follows, focus cycling, modifier+drag to move/resize anywhere in a window rather than only by the titlebar, modifier+scroll to change workspace, and 8 XF86 media/power keysyms taken from the system's own XF86keysym.h. The keysym tables are hand-maintained in both directions and a key missing from either fails silently, so a round-trip test now covers every one the configs bind. Verified in the QEMU VM: a bare-TTY screendump shows a recognisable arrow at the pointer position (113 white fill + 58 black outline pixels at screen centre, where the pointer starts).
2024-04-12udev: connector hotplug, and rescue windows on an unplugged monitorsrdusr1-6/+49
Monitors were probed once at startup, so plugging or unplugging one while srdwm was running went unnoticed. A UdevBackend event source now watches for the kernel's `change` uevent and reconciles the head list against a fresh connector probe - forcing a re-probe rather than trusting cached status, since on a hotplug the cache is exactly what has gone stale. Removing a head tears down everything it owned: the wl_output global, its place in the Space, its DRM framebuffers and dumb buffers (dropping the Rust structs alone leaks the kernel-side objects, which matters when a cable is plugged repeatedly), and any lock surface for it - otherwise confirm_lock_if_presented would wait forever on a monitor that no longer exists. New connectors go through the same bring_up_head path as startup, so a monitor plugged in later is set up identically to one present at boot. Heads are then repositioned left-to-right, since removing one shifts the rest, and layer maps re-arranged so bars follow their moved output. set_monitors rehomes windows stranded by the change, and main.rs re-queries the whole monitor list on MonitorAdded/MonitorRemoved rather than applying the single monitor in the event, because the others' positions move too. The rehoming had a bug that unit tests missed and live testing caught. It originally keyed off Window::monitor, but that field records the monitor a window was *assigned* at creation, not where it is: add_window always sets it from the primary monitor, so a window placed on the second monitor by a rule - or dragged there - still reads monitor == 0. The field-only check saw a valid id, skipped the window, and left it at coordinates that no longer existed: invisible and unreachable. Found by unplugging a monitor out from under a real xterm and watching it vanish from both heads. It now keys off geometry, with a regression test that fails against the old logic. Verified in the QEMU VM, booting with one connector and toggling the second at runtime: plug in -> head added and rendering at its own resolution; unplug -> head removed cleanly; and an xterm at global x=1500 survived its monitor being unplugged, reappearing at x=680 (= min(1500, 1280-600)) with its size intact. Writing to /sys/class/drm/<connector>/status changes the connector but emits no uevent on this kernel, so the signal the kernel would send is synthesized with `udevadm trigger`; the whole reaction path is genuinely exercised.
2024-04-08Wayland: clipboard, session lock, screencopy, multi-monitor; modularizesrdusr1-18/+205
Implements the protocols that were blocking srdwm-wayland from being a real session, plus multi-monitor, and splits the backend into modules. Everything here was verified by running it against real clients, not just compiled. Protocols - wlr-layer-shell + xdg-output: bars/launchers/notifications. xdg-output is not optional in practice - without it wofi segfaults rather than degrading, since it calls get_xdg_output without null-checking. - Clipboard: wl_data_device_manager, primary selection, and wlr-data-control. Data-control is what `wl-paste --watch cliphist store` needs, as it reads the selection without holding focus. Selection focus now follows keyboard focus, without which a focused window can neither copy nor paste. - ext-session-lock: `locked` gates rendering and input. No key is treated as a WM binding while locked - the config binds Mod4+Return to spawn a terminal, so honouring bindings at a locked screen would defeat the lock. The lock is confirmed only after a client-content-free frame has actually been presented, never at request time. - wlr-screencopy (hand-written; smithay ships no helper) for grim/slurp. Multi-monitor Every connected connector becomes a head with its own buffers, damage tracker and page-flip state, matched by CRTC so differing refresh rates don't gate each other. Outputs are reached through primary_output/output_at/ output_for_wl rather than a single field, which kept the change to ~11 call sites. Session lock creates one lock surface per output and waits for all of them, so a second monitor can't still show the desktop when the locker is told the session is safe. Modes are picked by the PREFERRED flag, not list order, and CRTCs are never double-assigned. Bugs found by testing, not review - Nothing gave a newly-created window Wayland focus: a freshly-opened app received no keystrokes and could not paste until clicked. - Opening a window at a locked screen stole keyboard focus. Caught by counting wl_keyboard.enter delivered to a client launched while locked: 1 before the guard, 0 after. A killed locker correctly leaves it locked. - Reading back the winit EGL window surface destroyed the GL context on the first screencopy capture, taking the compositor down. Root-caused by A/B-ing the same build with only the readback removed; capture now renders an offscreen pass. - Output mode was resent every frame at 60Hz, flooding any client bound to wl_output with duplicate mode/done events. - general.default_layout was defaulted and validated but never read, so setting it did nothing. srdwm is dynamic-first (Windows/macOS style, with drag-to-edge snapping); tiling is one opt-in layout, and that stays true. - .gitignore's unanchored `srdwm` matched any path component of that name, silently excluding the whole crates/srdwm source crate - the binary crate the workspace lists as a member, so a fresh clone could not build. Modularization lib.rs went from ~1260 lines to 78: state, protocols, input, lock, screencopy, winit and udev now each own one responsibility. lock is grouped by feature rather than kind on purpose, since its security invariant spans state, protocol handling and rendering at once. Multi-monitor was verified in the QEMU VM with a two-output virtio-gpu: both heads screendumped at their own resolution showing srdwm's clear colour, and a window forced to global x=1500 landed on head 1 at head-local x=220 while head 0 stayed empty. Known limitation, now documented: the nested winit backend stalls while its window is occluded, because the host stops scheduling frames and eglSwapBuffers blocks.
2024-04-05Track the daily-driver blockers for srdwm-wayland as TODOssrdusr1-0/+18
layer-shell, clipboard (wl_data_device_manager), session-lock, and udev-backend multi-monitor support are the gaps identified when deciding srdwm isn't ready to add to a session picker yet - recorded in docs/IMPLEMENTATION_STATUS.md's "Not implemented anywhere yet" section and as inline TODOs at the relevant code (CompState's delegate_*! list, udev.rs's find_connected_output).
2024-04-04Fix XWayland: it now actually renders and receives keyboard inputsrdusr1-33/+59
Three real bugs found and fixed via WAYLAND_DEBUG=1 protocol tracing in the QEMU VM, plus a fourth found along the way: - XWayland tried glamor (GBM rendering) first, which fails against this deliberately software-only compositor; its post-failure fallback path never used the xwayland_shell_v1 protocol at all, so X11Surface:: wl_surface() never resolved. Fixed by shadowing `Xwayland` on PATH with a wrapper script that always re-execs it with -shm (smithay's XWayland::spawn hardcodes its own argv and can't be bypassed either, since XWaylandClientData's fields are private). - Even with -shm, set_mapped(true) was only called after wl_surface() already resolved, deadlocking XWayland (it never advances a window past surface creation until the map is granted). Fixed by calling set_mapped(true) unconditionally in map_window_request. - The window then rendered as a ~1px sliver: initial geometry was seeded from X11Surface::geometry(), which can still be a tiny default at MapRequest time. Fixed by using the same 800x600 default the xdg-shell path already uses. - Typing didn't reach the window until a broader, XWayland-independent bug was fixed: nothing in the Wayland backend ever called KeyboardHandle::set_focus, so no window (native or X11) could ever receive keyboard input. Fixed in handle_pointer_button, along with TitlebarHit::Close being X11-surface-blind. Verified live: xterm launched via XWayland renders correctly sized and decorated, and a synthetic keypress sequence (ls + Enter) executed in its shell, screendump-confirmed.
2024-04-02Add window rules, real config validation, and a Wayland DRM/udev backendsrdusr1-18/+143
- 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.
2024-04-02Rewrite srdwm in Rust: working X11 and Wayland backends, Lua configsrdusr1-336/+129
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.
2024-03-25Initial Commitsrdusr1-0/+336