For GTK runtime, don't call cursorPosCallback if cursor pos didn't actually change. (#4973)

Fixes #3345

Piggybacking on the logic introduced PR
https://github.com/ghostty-org/ghostty/pull/3997, this patch prevents
mouse motion events with the same cursor position triggered by the
window title updating from un-hiding the mouse even when
`mouse-hide-while-typing` config item is true.
This commit is contained in:
Mitchell Hashimoto
2025-01-12 07:21:39 -08:00
committed by GitHub

View File

@ -1496,31 +1496,37 @@ fn gtkMouseMotion(
.y = @floatCast(scaled.y), .y = @floatCast(scaled.y),
}; };
// When the GLArea is resized under the mouse, GTK issues a mouse motion // There seem to be at least two cases where GTK issues a mouse motion
// event. This has the unfortunate side effect of causing focus to potentially // event without the cursor actually moving:
// change when `focus-follows-mouse` is enabled. To prevent this, we check // 1. GLArea is resized under the mouse. This has the unfortunate
// if the cursor is still in the same place as the last event and only grab // side effect of causing focus to potentially change when
// focus if it has moved. // `focus-follows-mouse` is enabled.
// 2. The window title is updated. This can cause the mouse to unhide
// incorrectly when hide-mouse-when-typing is enabled.
// To prevent incorrect behavior, we'll only grab focus and
// continue with callback logic if the cursor has actually moved.
const is_cursor_still = @abs(self.cursor_pos.x - pos.x) < 1 and const is_cursor_still = @abs(self.cursor_pos.x - pos.x) < 1 and
@abs(self.cursor_pos.y - pos.y) < 1; @abs(self.cursor_pos.y - pos.y) < 1;
// If we don't have focus, and we want it, grab it. if (!is_cursor_still) {
const gl_widget = @as(*c.GtkWidget, @ptrCast(self.gl_area)); // If we don't have focus, and we want it, grab it.
if (!is_cursor_still and c.gtk_widget_has_focus(gl_widget) == 0 and self.app.config.@"focus-follows-mouse") { const gl_widget = @as(*c.GtkWidget, @ptrCast(self.gl_area));
self.grabFocus(); if (c.gtk_widget_has_focus(gl_widget) == 0 and self.app.config.@"focus-follows-mouse") {
self.grabFocus();
}
// Our pos changed, update
self.cursor_pos = pos;
// Get our modifiers
const gtk_mods = c.gdk_event_get_modifier_state(event);
const mods = gtk_key.translateMods(gtk_mods);
self.core_surface.cursorPosCallback(self.cursor_pos, mods) catch |err| {
log.err("error in cursor pos callback err={}", .{err});
return;
};
} }
// Our pos changed, update
self.cursor_pos = pos;
// Get our modifiers
const gtk_mods = c.gdk_event_get_modifier_state(event);
const mods = gtk_key.translateMods(gtk_mods);
self.core_surface.cursorPosCallback(self.cursor_pos, mods) catch |err| {
log.err("error in cursor pos callback err={}", .{err});
return;
};
} }
fn gtkMouseLeave( fn gtkMouseLeave(