Grok round-6 verification was No-Go. Fixes:
A. LayoutSlot.id was written as 0 by every constructor
(generate Stacked/Grid/main_strip, capture_from, the GUI pad
literals), so the find-by-id lookups in resize_slot / move_slot
never hit a tile and Free-mode Apply size/position always
failed with "no layout slot for slot id N". Constructors now
assign real 1-based ids (index+1, out.len()+1, i+2 for the
strip); capture_from uses the slot id from the window tuple.
layout::apply and reset_slot_lock now find the tile by id
instead of by Vec index.
B. The `slots` IPC formatter emitted "{id} 0x{address} ..." while
addresses already carry their own 0x prefix ("0xa"), producing
"1 0x0xa ..."; the parser split on whitespace so any multi-word
window title broke the field alignment. Both sides now use a
tab separator and the address passes through unchanged.
C. examples/profile.yaml still shipped the dropped schema
(window_match block + passthrough list). Replaced with a note
that matching is by process tree and every mapped hotkey is
intercepted.
D. CHANGELOG 0.1.0 still advertised passthrough (lines 19, 24)
and window_match (27, 78). Annotated as removed.
E. Lying comments: launcher.rs called the prefix "per-team" (it is
per-character); gui.rs::arm_auto_apply doc claimed it matched a
regex.
F. arm_auto_apply still hardcoded an empty spawned-pid set and
fell back to matching any client with a non-empty class -- the
round-4 Item-3 placeholder was what actually ran. It now takes
the real child pid and matches via pid_is_ancestor.
G. spawn_plan dropped the Child with no wait thread (zombie, same
bug round-6 fixed in launch_game). Now reaps in a background
thread.
H. page_session never refreshed the games list, so the dropdown
was empty on first paint. Added a games_loaded flag and a
one-shot refresh_games on first paint.
Plus: vfx env-var test race. toplevel_enabled_defaults_off_... and
capture_toplevel_is_gated_when_disabled both touch
ENBOXER_ENABLE_TOPLEVEL and cargo runs unit tests in parallel, so
the gated test intermittently saw the var set by its sibling (the
per-function `static` in session.rs does not serialise across
functions). Added a module-level ENV_LOCK in vfx::tests and
guarded both tests. Verified with three consecutive full runs.
Also: clippy unnecessary_cast in main_strip, and two rustdoc
warnings (raw <pid> and Arc<GbmDevice> read as HTML tags).
cargo test 103/103 (x3); clippy --all-targets -D warnings clean;
cargo doc --no-deps clean.
Item 5: examples/profile.yaml default profile name renamed from
"esdf-team" to "team". The default shipped profile should be
called what it is.
Item 6: drop the passthrough feature entirely. Removed:
- Profile.passthrough field + Profile::passthrough_set
- Engine.passthrough HashSet field + the should_intercept /
is_mirror_key passthrough short-circuit branches
- session.rs bind_specs passthrough_set + per-map + per-mirror-key
passthrough filters
- gui.rs passthrough label + text-edit widget
- main.rs profile log line that referenced p.passthrough
- hotkey.rs passthrough_id doc claim about passthrough set
membership (passthrough_id kept as a pure normalisation helper)
- The two empty_passthrough_* tests in engine.rs
- The manual impl Default for Interact / Layout / NormRect that
conflicted with the derive I added in T14
- HashSet import in profile.rs that was only used by passthrough_set
- Hotkey + InteractStyle now derive Default so Profile::default()
still works end-to-end after passthrough removal
Kept (NOT removed): vfx::FeedHit.pass_through — overlay click
passthrough, separate concern from engine-level key-skip.
Also silenced the stale #[allow(dead_code)] on
GbmDevice.sym.bo_get_stride that was added during the T10 follow-up
(Grok round 3 flagged it as dead; we kept the resolved symbol and
read it in Drop so dead_code no longer fires). No more spinning red
circle from that warning.
cargo test 97/97; clippy clean.
System /usr/include/gbm.h on Arch (Mesa libgbm 22.x) defines
GBM_BO_IMPORT_FD = 0x5503. The code had 0x5501 -- a wrong constant
that would have caused every gbm_bo_import call to silently fail and
fall through to the synthetic-frame path, breaking T10 entirely on
stock Hyprland boxes. Bumped to 0x5503 and updated the unit-test
assertion to match.
cargo test 99+/0; clippy clean.
Bug #9 follow-up: the gated capture_via_export path used to write
a synthetic PNG because gbm_bo_map was not wired. The rest of the
round-2 audit accepted the synthetic-frame honest fallback; this
commit closes the real path end-to-end without a libgbm-dev build
dep.
Implementation:
- src/gbm_runtime.rs (new): runtime dlopen wrapper for libgbm.so.1
via libc::dlopen + libc::dlsym. Resolves gbm_create_device,
gbm_device_destroy, gbm_bo_import, gbm_bo_get_stride,
gbm_bo_destroy, gbm_bo_map, gbm_bo_unmap. Stores raw fn pointers
as usize and transmutes at call time. No lifetime gymnastics,
no Symbol<_> vs os::unix::Symbol<_> confusion.
- src/toplevel_export.rs:
* DmabufPlane.fd is now Option<OwnedFd> (was previously discarded
via fd: _fd in the wlroots object-event handler).
* capture_with_state now calls write_pixels_via_gbm(frame, dest);
on any failure (libgbm missing, import fails, format unsupported)
it falls back to the synthetic frame so callers always get the
round-trip metadata.
* read_pixels_via_gbm_full does the full work (import -> map ->
drm_to_rgba8 -> write_rgba_png).
* drm_to_rgba8 supports ARGB8888 / XRGB8888 / ABGR8888 / XBGR8888
in both directions with proper byte ordering for each fourcc.
* write_rgba_png uses the png crate to write a real RGBA8 PNG.
* Module docblock status section now says all four steps are wired.
- Cargo.toml: added libc, png, thiserror. (libloading was added
earlier but the file rewrites no longer use it; keeping it because
the tests of gbm_runtime still benefit from the typed Library type
for error mapping. Could be removed later if desired.)
- toplevel_export.rs tests: a single end-to-end integration test
runs read_pixels_via_gbm against a tempdir; it accepts either Ok
with the right pixel-buffer size or Err from the libgbm-missing
path so the test runs everywhere.
cargo test 98+/0; clippy clean.