From 436d42da6ef61a5ea20d5102c4baed7bf0993606 Mon Sep 17 00:00:00 2001 From: srdusr <99972264+srdusr@users.noreply.github.com> Date: Mon, 20 Apr 2026 00:48:00 +0200 Subject: Confirm Nemo's popup works; fix the two bugs that hid it, and shadow bleed across a monitor seam Nemo's right-click context menu was the last open punch-list item, parked twice as untestable. It works: verified end to end in a throwaway nested compositor, menu and submenu both, at the correct position and stacking. The popup path itself needed no fix, so the POPUP-GEOM-DIAG/POPUP-GRAB-DIAG diagnostics are removed. Two real bugs turned up in the way of testing it. zwlr_virtual_pointer was a silent no-op on the winit backend. Every Motion/MotionAbsolute handler read UdevState::bounds() behind an early return when state.udev was None, and that field is Some only for the DRM backend. The protocol advertised its global, accepted create_virtual_pointer and accepted every request, then discarded all motion with no error and no log. That is the backend a nested instance runs on, so the only safe way to drive a throwaway compositor - a Wayland client of that compositor, which cannot reach any other session, unlike ydotool's /dev/uinput writes - did not work at all. Bounds now come from WindowManager::monitors() when udev is absent; both backends fill that list from Platform::monitors(). The winit backend's screencopy pass rendered no popups and no shadows. It re-renders the scene offscreen, and that second scene was missing tiers, so grim on a nested instance reported the opposite of the truth: a menu drawing perfectly on screen photographed as absent. The DRM backend never had this, since it serves screencopy from the on-screen frame it just drew. Border strips are still missing from that pass, called out in the code rather than left silent. Also fixed, from the "windows show a bit in the other monitor" report: shadow_rect expanded by SHADOW_SIZE on every side with no monitor-boundary awareness, so a window flush against a seam put its 24px shadow strip on the neighbouring screen. shadow_rect_clipped clips to the bounding box of the monitors the window's geometry actually touches - not just its assigned one, since a window straddling a seam really does occupy both and clipping there would cut its shadow off mid-body. The bitmap's own extent stays unclipped, because the src rectangle indexes into it; only the fragment list is clipped. Six tests on the incident's own numbers. Not confirmed on screen: the nested backend cannot produce a second monitor. New tool: tools/virtual-pointer-click, a scriptable virtual-pointer driver that acknowledges each command after its round-trip, so a test script can put a screenshot between a move and the click that follows it. 489 tests pass, clippy clean. --- tools/virtual-pointer-click/src/main.rs | 161 ++++++++++++++++++++++++++++++++ 1 file changed, 161 insertions(+) create mode 100644 tools/virtual-pointer-click/src/main.rs (limited to 'tools/virtual-pointer-click/src') diff --git a/tools/virtual-pointer-click/src/main.rs b/tools/virtual-pointer-click/src/main.rs new file mode 100644 index 0000000..993de45 --- /dev/null +++ b/tools/virtual-pointer-click/src/main.rs @@ -0,0 +1,161 @@ +// A scriptable zwlr_virtual_pointer_unstable_v1 driver: reads one command +// per line from stdin and turns it into a virtual-pointer request against +// whatever compositor WAYLAND_DISPLAY names. +// +// WHY THIS EXISTS RATHER THAN ydotool +// +// ydotool writes to /dev/uinput. That is a kernel-level device shared by +// every session on the machine, so a synthetic click from it lands wherever +// the real seat's focus happens to be - which, when the target is a nested +// throwaway compositor, is very often the user's real desktop instead. This +// tool is an ordinary Wayland client of one specific compositor, so its +// input physically cannot reach any other one. That makes it the safe way +// to drive a nested test instance, which is the only reason it exists. +// +// ../virtual-pointer-pin-test is not this: it is a fixed left-button drag +// used to verify pinned delivery, and it blocks on stdin exactly once. This +// one stays alive and takes a stream of commands, so a shell script can +// interleave a `grim` screenshot between a move and the click that follows +// it - which is what "never click at a position you have not verified +// first" actually requires. +// +// Usage: +// vpclick (commands on stdin, one per line) +// +// move absolute, as a fraction of EXTENT (5000 5000 = centre) +// press