#14752

apprt/gtk: fix stuck mouse buttons after gesture resets

OpenDavey-Hugheswants to merge intofrom

Relevant Links

Vouch Request

Related: #10713 #11342

Problem

On my main dev system (Arch Linux, Wayland, KDE, with ghostty + tmux), I was noticing some issues where left clicks were not responding properly but it was resolved after I closed that particular ghostty window and launched a new one. I'm not sure if the related issues above are the exact same issue but they still might be relevant.

Fix

This is a potential fix but there's still some gaps that I would appreciate some discussion on. The main thing I observed in the current main build is that the side mouse buttons through gtk will get stuck in ghostty, and this is observable easily in the inspector. Buttons {8} and {9} are clicked even though I have released them:

This seems to happen if you click and drag with these side mouse buttons, which can happen accidentally quite easily, and interferes with normal right and left click operations.

The fix in this PR currently is to add handler to listen to the gtk unpaired-release event , and only handle this for buttons > 5. From what I understand, the current gcMouseDown and gcMouseUp handlers have behaviors for mouse buttons 1-5, so I think this PRs fix has the least interference with existing code.

The fix in this PR adds a handler to listen to the gtk unpaired-release event. From what I understand, gtk resets its click gesture if you move the mouse while holding a button > 5 (since it only tracks buttons 1-5 with its modifier masks), and also if you press a second button while one is already held down. When that happens the release comes through unpaired-release instead of the normal released event, so ghostty never sees the button get released.

After @jcollie's review, the handler now only forwards the release if ghostty's core still thinks that button is pressed. So releases for presses that ghostty never saw, like the second button in a chord or a click that just focused a split, get dropped and shouldn't trigger any clicks.

The fix works for these mouse buttons, and can be tested by observing the click state in the inspector, or running printf '\e[?1003h\e[?1006h'; cat -v in a shell and observing whether the code <35 comes through, which indicates that no buttons were held while the mouse pointer moved. Specifically the actions to replicate a stuck button can be something like:

  • hold down button
  • move mouse
  • release button
  • move mouse again and see whether <35 is in the code printed

Since the MacOS build doesn't use gtk, the side mouse button issue isn't a bug there.

However when testing all this I discovered it's kinda easy to get other buttons stuck, and I don't know the desired behavior for this is, so I would appreciate advice from contributors/maintainers. Similar things happen in both MacOS and Linux, though the behavior is slightly different when using something like tmux that has its own right-click menu and doesn't open ghostty's right click menu. But for example, if you do these steps:

  • hold down the left mouse button
  • right click once
  • drag the mouse
  • release left click

You will observe in the inspector that L is stuck in the "click state" row, and then gets unstuck when you click the left mouse button again. This can happen with the above steps if you reverse the left and right mouse buttons too.

I'm not really sure if this is a big deal since it gets unstuck so easily, unlike the buttons > 5 that my PR addresses, but I figured that maybe this was a gap worth investigating before merging this PR if some kind of overall better fix is deemed necessary.

Update: originally I asked here about how easy it is to get other buttons stuck. It turns out this is caused by the same gtk gesture reset, so with the change from @jcollie's review this PR fixes it on Linux too, and you can check it the same way as above by moving the mouse again and seeing whether <35 comes through. This should also work if you reverse the left and right mouse buttons. The similar behavior on MacOS isn't affected by this PR since it doesn't touch the MacOS app.

AI Disclosure

EDIT: Sorry I forgot to include this in the description but it was in my vouch request: I used an LLM to write the code and the test because I'm not super familiar with zig nor this codebase. I hope the potential gaps I've identified help identify the extent I understand this change and also what needs a closer look from an experienced contributor.

Activity

7
jcollie12d ago

Probably should forward an unpaired release for any button only when the core still has that button down (core_surface.mouse.click_state[button] == .press).

Davey-Hughes12d ago

Probably should forward an unpaired release for any button only when the core still has that button down (core_surface.mouse.click_state[button] == .press).

Good idea, I'll try this out and update the PR if it works.

Davey-Hughes12d ago

Ok @jcollie this fix works much better overall by adding the mouseButtonPressed(Button) check instead of just checking whether button > 5.

jcollierequested changes12d ago
jcollie12d ago

One tiny little nit.

Davey-Hughesreviewed11d ago
jcollieapproved changes11d ago