mirror of
https://github.com/ghostty-org/ghostty.git
synced 2026-04-19 14:00:29 +00:00
fix(macOS): filter phantom mouse events that defeat mouse-hide-while-typing (#11066)
## Summary Ports the phantom mouse-motion position-equality check from the GTK runtime to the embedded runtime (used by macOS). On macOS, TUI apps like Zellij that frequently update the window title cause phantom `mouseMoved` events at the same coordinates. These flow through `embedded.zig` → `Surface.zig` `cursorPosCallback` → `showMouse()`, which explicitly calls `NSCursor.setHiddenUntilMouseMoves(false)` and unhides the cursor, defeating `mouse-hide-while-typing`. The GTK runtime already filters these in PR #4973 (for #3345): ```zig const is_cursor_still = @abs(priv.cursor_pos.x - pos.x) < 1 and @abs(priv.cursor_pos.y - pos.y) < 1; if (is_cursor_still) return; ``` This PR adds the same check to `embedded.zig`'s `cursorPosCallback`, using the already-stored `self.cursor_pos` field. ## Test plan - [x] Enable `mouse-hide-while-typing = true` in Ghostty config - [ ] Run a TUI app that updates the window title frequently (e.g. Zellij) - [ ] Type — cursor should hide and stay hidden despite title updates - [ ] Move the mouse — cursor should reappear normally - [ ] Verify no regressions with normal mouse movement, focus-follows-mouse, or link hovering
This commit is contained in:
@@ -848,7 +848,7 @@ pub const Surface = struct {
|
||||
mods: input.Mods,
|
||||
) void {
|
||||
// Convert our unscaled x/y to scaled.
|
||||
self.cursor_pos = self.cursorPosToPixels(.{
|
||||
const pos = self.cursorPosToPixels(.{
|
||||
.x = @floatCast(x),
|
||||
.y = @floatCast(y),
|
||||
}) catch |err| {
|
||||
@@ -859,6 +859,19 @@ pub const Surface = struct {
|
||||
return;
|
||||
};
|
||||
|
||||
// There are cases where the platform reports a mouse motion event
|
||||
// without the cursor actually moving. For example, on macOS, updating
|
||||
// the window title can trigger a phantom mouse-move event at the same
|
||||
// coordinates. This can cause the mouse to incorrectly unhide when
|
||||
// mouse-hide-while-typing is enabled (commonly seen with TUI apps
|
||||
// like Zellij that frequently update the title). To prevent incorrect
|
||||
// behavior, we only continue with callback logic if the cursor has
|
||||
// actually moved.
|
||||
if (@abs(self.cursor_pos.x - pos.x) < 1 and
|
||||
@abs(self.cursor_pos.y - pos.y) < 1) return;
|
||||
|
||||
self.cursor_pos = pos;
|
||||
|
||||
self.core_surface.cursorPosCallback(self.cursor_pos, mods) catch |err| {
|
||||
log.err("error in cursor pos callback err={}", .{err});
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user