diff options
Diffstat (limited to 'docs/TODO.md')
| -rw-r--r-- | docs/TODO.md | 22 |
1 files changed, 22 insertions, 0 deletions
diff --git a/docs/TODO.md b/docs/TODO.md index d7c62a8..98deb48 100644 --- a/docs/TODO.md +++ b/docs/TODO.md @@ -13,6 +13,28 @@ that has the full story. Keep this list current as items close or open; update the source doc's own entry too, don't let this drift into a second stale copy the way `PANEL_SUPPORT_TODO.md` did. +## Real bug, root-caused and fixed: every new window opened alone landed in the exact same spot, not at all like Windows (2026-08-27) + +Reported live. Root-caused by reading `SmartPlacement::place`, not guessed: it tried a grid cell first, falling back to cascade only once the grid was full. Grid's own cell count is `existing.len() + 1` - with nothing else open (the overwhelmingly common real workflow: open one app, use it, close it, open the next), that count is always `1`, so the grid is always exactly one cell, and a 1x1 grid returns the same single cell every time regardless of session history. Cascade had a second, compounding version of the same bug: its own step was `existing.len() % max_steps`, also always `0` with nothing else open, so even a from-scratch cascade calculation reset to the origin on every call. + +Fixed both. `WindowManager` gained `next_cascade_step` (a `Cell<u32>`, not a plain field - `add_window`'s own `target_monitor` stays borrowed from `self.monitors` for the whole call, so a plain `&mut self` write would conflict with that live borrow), incremented on every real placement and *never* reset by a window closing - real Windows keeps advancing its own cascade position the same way even as earlier windows close. `SmartPlacement::cascade` now takes this counter instead of `existing.len()`. `SmartPlacement::place` now skips `grid` entirely when `existing` is empty, going straight to cascade instead - grid's real job is dividing screen space fairly among *concurrent* windows, and with nothing to divide against there is no way for a 1x1 grid to vary by history no matter how it's computed; cascading is the correct strategy for "nothing else is open right now." + +New/updated tests cover both the isolated `cascade` behavior and the full `place`/`add_window` integration (`a_window_opened_alone_cascades_rather_than_using_a_pointless_1x1_grid`, `opening_the_same_app_alone_twice_in_a_row_lands_in_different_spots`, `cascade_step_keeps_advancing_even_if_the_previous_window_closed`); two pre-existing tests that hardcoded the old grid-based first-window position were updated to match the new, deliberate behavior, not silently left contradicting it. + +Full workspace build/test/clippy clean (223 core / 141 wayland / 29 platform / 24 ctl / 28 config / 10 x11 tests). Not yet live-verified against a real interactive session (needs a restart) - the algorithm change itself is proven by the new tests, but "does it feel right opening real apps" is a live check still owed. + +## Fake (fully virtual, headless) monitors: a real, visible one, not a test stub (2026-08-27) + +Distinct from `srd.monitor.split` (divides one *real* output's own placement rectangle) and from the phone-monitor item's own aspect_ratio rule (a window-level primitive) - this is a genuinely independent, additional `wl_output` with no DRM connector/CRTC behind it at all. Researched prior art before building: niri ships a real `Headless` backend (`backend/headless.rs`, cloned at `~/reference-wms/niri`) but its own `render()` never actually composites anything - a no-render stub purely for that project's own test suite, not a usable feature. This is a real, visible one instead: it actually renders whatever is placed on it, on demand, whenever a `zwlr_screencopy_manager_v1` client (`grim`, `wf-recorder`, a custom viewer) asks for a frame. + +New `crates/wayland/src/udev/virtual_heads.rs` (its own module doc comment has the full design and stated scope limits: no layer-shell chrome, no native-lock participation, no `wlr-output-management-v1` listing - all additive later, none block basic use). `CompState::create_virtual_head`/`remove_virtual_head` create/destroy a real `Output` + `wl_output` global with no hardware behind it, placed left-to-right after every existing head. `service_virtual_head_captures` intercepts any pending screencopy capture targeting a fake monitor *before* `render_udev_frame` ever sees it (otherwise it would wait forever for a real page-flip that will never come - the exact hang class `docs/PANEL_SUPPORT_TODO.md`'s own P1 already named), and renders it on demand by reusing `udev/capture.rs::capture_workspace`'s exact off-screen-render technique, selecting windows by `Window::monitor` (a fake monitor's own real windows) rather than by workspace. + +Fully integrated with core placement: `platform.rs`'s `monitors()` reports each fake monitor as a genuine `srdwm_core::Monitor` (scale 1.0, no exclusive zone), so `add_window`/tiling/workspace-switching all treat it exactly like a real monitor with zero special-casing - and removing one rehomes its windows via `WindowManager::set_monitors`'s own existing safety net, the same one a real monitor unplug already relies on. + +New IPC (`create_fake_monitor`/`remove_fake_monitor`, `crates/platform/src/ipc.rs`) and CLI: `srd dispatch create fake-monitor <name> <width>x<height>` / `srd dispatch remove fake-monitor <name>`. Core-side request queue in `crates/core/src/manager/fake_monitor.rs`, same cross-boundary shape every other backend-owned request already uses. + +Full workspace build/test/clippy clean (221 core / 141 wayland / 29 platform / 24 ctl / 28 config / 10 x11 tests, 0 failed, 0 clippy warnings). Not yet live-verified against a real running session (needs a restart to pick up the installed binary, same standing rule as every other change this shift) - `srd dispatch create fake-monitor TEST-1 1920x1080` then `grim -o TEST-1 /tmp/test.png` is the concrete verification path once restarted. + ## Optional phone mode for AGS and srdwm: srdwm's own real half built (2026-08-27) Split the ask honestly rather than guessing at AGS's own side blind: the srdwm-side primitive a "phone mode" needs is a placement policy (new windows default to maximized, since a phone-shaped screen has no room for more than one at a time) plus a real signal a panel can read to adapt its own chrome - both now real; the AGS-side chrome adaptation itself is work in that project, not this one, the same boundary this session's other AGS-adjacent entries (combined monitor modes, the layout-restore race) already draw. |