swayfx-mosaic/tooling/probes/step20c-valid-grab/README.md

143 lines
8.7 KiB
Markdown

# STEP20C valid-grab / hidden-owner fixture (EXPERIMENTAL)
This fixture preserves the bounded headless comparison reported in
[the STEP20C probe](../../../docs/design/STEP20C_VALID_GRAB_HIDDEN_OWNER_PROBE.md).
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](https://github.com/wlrfx/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](https://github.com/swaywm/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.
```sh
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:
```sh
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:
```sh
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:
```sh
rm -rf -- "$R"
```
Do not clean the original probe laboratory as part of this procedure.