Xwayland pointer constraints get confused by multiple outputs
Sometimes, Xwayland (1.20.9) doesn't destroy the pointer confine region after focusing a different Xwayland window, if that window was on a different output than the one the constraint was created on. Reproduction steps are a bit icky, but should hopefully make clear what goes wrong.
I'm using sway/wlroots master, but from the logs I believe this would happen on other compositors too.
To reproduce, 3 workspaces are necessary.
Workspace 1 contains an instance of Xterm, and for convenience an instance of another terminal tailing the Sway log file (
-d turned on for debug output; I tail and
| grep --line-buffered -E '(pointer|cursor)'). The Xterm window should be the one focused here.
Workspace 2 should be on another output and contain a single Xwayland application that captures the mouse. I use https://github.com/gnif/LookingGlass for this (it's a VM utility, but the bug manifests even if there is no VM running, so it seems like a convenient reproduction).
Start LookingGlass with
Workspace 3 should be on the same output as workspace 2, and contain two applications: one Wayland-native, and one Xwayland. I used Kitty and Xterm again. Focus the Wayland-native app, not Xterm.
Now, to reproduce:
- Focus LookingGlass in workspace 2. Verify that the pointer is captured.
02:08:58.563 [DEBUG] [types/wlr_pointer_constraints_v1.c:244] new locked_pointer 0x557285200a40 (res 0x5572850577b0) 02:08:58.563 [DEBUG] [types/wlr_pointer_constraints_v1.c:343] constrained 0x557285200a40
- Use keybinding to switch to workspace 1. Do not move the mouse. Observe that Xterm is focused, but that the cursor has not appeared.
02:09:05.027 [DEBUG] [types/wlr_pointer_constraints_v1.c:353] unconstrained 0x557285200a40
- Use keybinding to switch to workspace 3. The cursor will have warped to the middle of the Wayland-native application. Move it over Xterm, and notice that the cursor disappears again.
- Click on Xterm. The cursor re-appears, and the pointer confine is finally destroyed.
02:12:10.674 [DEBUG] [types/seat/wlr_seat_pointer.c:384] button_count=1 grab_serial=40811 serial=40838 02:12:10.674 [DEBUG] [types/wlr_pointer_constraints_v1.c:47] destroying constraint 0x5572852236f0
This is in contrast to "normal" behavior, where Xwayland destroys the confine during the first motion event on another Xwayland surface. Indeed, during step 2), if the mouse is moved then the confine is indeed destroyed and the bugs in 3) no longer happen. However, moving the mouse over an Xterm in 3) no longer triggers the confine destruction.
I haven't taken a look at the Xwayland code, but it sounds like it may be ignoring the initial movement that's part of
wl_pointer.enter event when considering whether to destroy confines. wlroots, at least, does not send a
wl_pointer.motion event until there is actual movement post-enter.