8.7 KiB
STEP20C valid-grab / hidden-owner fixture (EXPERIMENTAL)
This fixture preserves the bounded headless comparison reported in the STEP20C probe. It is not part of the Mosaic build or package. Its private SceneFX symbols and Mosaic edits are feasibility evidence, not production interfaces. The result is PARTIALLY_FEASIBLE at the measured pixels and pointer locations only.
Provenance and exact inputs
| Input | Base / origin | SHA-256 |
|---|---|---|
mosaic-popup-plus-base.patch |
Complete private delta against Mosaic cd550382b311efdbfe3ed892f4e1d281d852e754 |
d416f6413ea097a48a44d231e50ffba363914f46c8687f0ea2e4dcacd5f31fe9 |
scenefx-popup-plus-base.patch |
Complete private delta against SceneFX tag 0.5, 37ccd723bef49e6891156ffafce8f549f01446cc |
c74c515b98da8f5f637e260e6a3755c7a75bd78d1c39e54a67850f1c383e30e7 |
hidden-guard.patch |
Incremental private delta after the Mosaic patch | 35785a8f3e863b3c1fd87932d8ff0c2949b03cb04382cc34e1126170968f802b |
grab-client.c |
Original valid-serial XDG client from the probe lab | 202afdc5dae0ee4aba570eef4a563f8b298474eb84e33af9510c4c81c05d16e4 |
pointer-daemon.c |
Original persistent virtual pointer from the probe lab | a00fcedc38ccb7ca4c25c982d9f38e8bde3168a3833f0c9cf2056e841d720938 |
run.py |
Original headless runner from the probe lab | b2aaa90188ea387cb8a69aa69935b56e63f5ce70eb98e74783b0fb3c9236a41f |
wlr-virtual-pointer-unstable-v1.xml |
wlr-protocols, b010a03648b88d143236de193bddbfea0c08bc84, unstable/ |
3ff6d540be0bc5228195bf072bde42117ea17945a5c2061add5d3cf97d6bb524 |
The six lab files above are byte-identical to the originals in
/tmp/swayfx-mosaic-valid-grab-7SA2yO/; none was adapted. The protocol XML
regenerates that lab's virtual-pointer-client.h and
virtual-pointer-protocol.c byte-for-byte. xdg-shell.xml comes from the
installed wayland-protocols package. The pinned pristine SwayFX base is
fd71a6bdc061bd633b488ae7b83e8a6981d22f86; do not apply the Mosaic
private patch to that base. The Mosaic commit above already includes the
project's prior Mosaic changes.
The original environment used SwayFX 0.6 (swayfx 0.6-1), SceneFX 0.5
(scenefx 0.5-1), wlroots 0.20.2 (wlroots0.20 0.20.2-1),
wayland-client 1.26.0, and the installed wayland-protocols XML. Meson,
Ninja, wayland-scanner, a C17 compiler, pkg-config, Python, kitty,
swaymsg, grim, wev, and /usr/bin/sway are required. Package releases
and scanner versions may change; record them when reproducing.
Rebuild in a new temporary laboratory
Run from this repository root. The commands copy only source fixtures into a
new mktemp directory; all compiled files, sockets, logs and captures stay
there. Keep R for the commands below, then remove it during cleanup.
set -eu
R=$(mktemp -d /tmp/swayfx-mosaic-valid-grab-replay-XXXXXXXX)
F="$PWD/tooling/probes/step20c-valid-grab"
cp "$F/grab-client.c" "$F/pointer-daemon.c" "$F/run.py" "$F"/*.patch \
"$F/wlr-virtual-pointer-unstable-v1.xml" "$R/"
mkdir "$R/mosaic" "$R/scenefx"
git archive cd550382b311efdbfe3ed892f4e1d281d852e754 | tar -xf - -C "$R/mosaic"
git clone --quiet https://github.com/wlrfx/scenefx.git "$R/scenefx-git"
git -C "$R/scenefx-git" checkout --quiet --detach 37ccd723bef49e6891156ffafce8f549f01446cc
git -C "$R/scenefx-git" archive HEAD | tar -xf - -C "$R/scenefx"
(cd "$R/scenefx" && git apply --check "$R/scenefx-popup-plus-base.patch" && git apply "$R/scenefx-popup-plus-base.patch")
(cd "$R/mosaic" && git apply --check "$R/mosaic-popup-plus-base.patch" && git apply "$R/mosaic-popup-plus-base.patch")
# This is the unguarded baseline. Save it only in the temporary lab.
cp "$R/mosaic/sway/desktop/transaction.c" "$R/transaction-before-hidden.c"
(cd "$R/mosaic" && git apply --check "$R/hidden-guard.patch" && git apply "$R/hidden-guard.patch")
meson setup "$R/scenefx-build" "$R/scenefx" -Dexamples=false -Dwerror=false
meson compile -C "$R/scenefx-build" -j 8
PKG_CONFIG_PATH="$R/scenefx-build/meson-uninstalled" meson setup "$R/mosaic-build" "$R/mosaic" \
-Dmosaic-package=true -Ddefault-wallpaper=false -Dswaybar=false -Dswaynag=false \
-Dman-pages=disabled -Dsd-bus-provider=libsystemd -Dwerror=false
PKG_CONFIG_PATH="$R/scenefx-build/meson-uninstalled" meson compile -C "$R/mosaic-build" -j 8
wayland-scanner client-header /usr/share/wayland-protocols/stable/xdg-shell/xdg-shell.xml "$R/xdg-shell-client.h"
wayland-scanner private-code /usr/share/wayland-protocols/stable/xdg-shell/xdg-shell.xml "$R/xdg-shell-protocol.c"
wayland-scanner client-header "$R/wlr-virtual-pointer-unstable-v1.xml" "$R/virtual-pointer-client.h"
wayland-scanner private-code "$R/wlr-virtual-pointer-unstable-v1.xml" "$R/virtual-pointer-protocol.c"
cc -std=c17 -Wall -Wextra -Wno-unused-parameter -I"$R" "$R/grab-client.c" "$R/xdg-shell-protocol.c" -o "$R/grab-client" $(pkg-config --cflags --libs wayland-client)
cc -std=c17 -Wall -Wextra -Wno-unused-parameter -I"$R" "$R/pointer-daemon.c" "$R/virtual-pointer-protocol.c" -o "$R/pointer-daemon" $(pkg-config --cflags --libs wayland-client)
For the unguarded comparison, reconstruct a second disposable Mosaic source/build directory from the same Mosaic commit and apply only the first Mosaic patch. Keep the guarded binary intact for restoration:
mkdir "$R/mosaic-unguarded"
git archive cd550382b311efdbfe3ed892f4e1d281d852e754 | tar -xf - -C "$R/mosaic-unguarded"
(cd "$R/mosaic-unguarded" && git apply --check "$R/mosaic-popup-plus-base.patch" && git apply "$R/mosaic-popup-plus-base.patch")
cmp "$R/mosaic-unguarded/sway/desktop/transaction.c" "$R/transaction-before-hidden.c"
PKG_CONFIG_PATH="$R/scenefx-build/meson-uninstalled" meson setup "$R/mosaic-unguarded-build" "$R/mosaic-unguarded" \
-Dmosaic-package=true -Ddefault-wallpaper=false -Dswaybar=false -Dswaynag=false \
-Dman-pages=disabled -Dsd-bus-provider=libsystemd -Dwerror=false
PKG_CONFIG_PATH="$R/scenefx-build/meson-uninstalled" meson compile -C "$R/mosaic-unguarded-build" -j 8
The original runner always selects R/mosaic-build/sway/swayfx-mosaic. To run
the unguarded case, first save that temporary guarded binary and replace it
with the unguarded build; restore it afterward. Never modify a system binary
or library.
Run the original reference cases
run.py resolves its laboratory from its own copied path. It removes inherited
WAYLAND_DISPLAY and SWAYSOCK, creates a mode-0700 run directory for each
case, starts a two-output headless compositor, discovers its new sockets, and
passes that socket explicitly to every swaymsg -s call. The private SceneFX
library path is process-local to the private compositor. It never targets the
active desktop socket. Run only these previously reported cases:
python "$R/run.py" control boundary_left
python "$R/run.py" private_standard boundary_right
python "$R/run.py" private_mosaic boundary_left
python "$R/run.py" private_mosaic # guarded, no hidden click; tests mapped return
python "$R/run.py" private_mosaic_hit # guarded hidden-click case
cp "$R/mosaic-build/sway/swayfx-mosaic" "$R/guarded-swayfx-mosaic"
cp "$R/mosaic-unguarded-build/sway/swayfx-mosaic" "$R/mosaic-build/sway/swayfx-mosaic"
mv "$R/run-private_mosaic_hit" "$R/run-private_mosaic_hit-guarded"
python "$R/run.py" private_mosaic_hit # unguarded baseline
cp "$R/guarded-swayfx-mosaic" "$R/mosaic-build/sway/swayfx-mosaic"
The runner reuses run-private_mosaic_hit/ for both variants; rename that
directory within R after the unguarded run to retain both result sets.
Check client.log for the same received/used nonzero serial and XDG configure;
inspect pointer.log, wev.log, IPC JSON and the left/right PNGs. Expected
sampled observations: standard control and private standard deliver popup
input at (900,150); Mosaic clips that point; unguarded hidden owner leaks a
yellow pixel and popup enter/button at (100,150); guarded hidden owner shows
ordinary background and no popup enter/button there; the no-click guarded
case shows the same mapped popup after camera return. A hidden outside click
may trigger popup_done under the valid grab without delivering a popup
button, as it did in the original report. Treat any disagreement as a new
observation, not as a reason to rewrite the recorded result.
The probe does not establish universal leak freedom, full transaction/damage correctness, effects/saved-buffer behavior, ABI durability, general multi-output safety, or an offscreen-popup UX policy. Valid-grab nested popups and other output geometries remain NOT TESTED.
Cleanup
After all processes started by run.py have exited, remove only the new lab:
rm -rf -- "$R"
Do not clean the original probe laboratory as part of this procedure.