mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-17 09:16:11 +03:00
apprt/macos,gtk: unfocused splits now highlight hovered links
Fixes #1547 The core change to make this work is to make the cursor position callback support taking updated modifiers. On both macOS and GTK, cursor position events also provide the pressed modifiers so we can pass those in.
This commit is contained in:
@ -556,7 +556,10 @@ bool ghostty_surface_mouse_button(ghostty_surface_t,
|
|||||||
ghostty_input_mouse_state_e,
|
ghostty_input_mouse_state_e,
|
||||||
ghostty_input_mouse_button_e,
|
ghostty_input_mouse_button_e,
|
||||||
ghostty_input_mods_e);
|
ghostty_input_mods_e);
|
||||||
void ghostty_surface_mouse_pos(ghostty_surface_t, double, double);
|
void ghostty_surface_mouse_pos(ghostty_surface_t,
|
||||||
|
double,
|
||||||
|
double,
|
||||||
|
ghostty_input_mods_e);
|
||||||
void ghostty_surface_mouse_scroll(ghostty_surface_t,
|
void ghostty_surface_mouse_scroll(ghostty_surface_t,
|
||||||
double,
|
double,
|
||||||
double,
|
double,
|
||||||
|
@ -505,7 +505,8 @@ extension Ghostty {
|
|||||||
|
|
||||||
// Convert window position to view position. Note (0, 0) is bottom left.
|
// Convert window position to view position. Note (0, 0) is bottom left.
|
||||||
let pos = self.convert(event.locationInWindow, from: nil)
|
let pos = self.convert(event.locationInWindow, from: nil)
|
||||||
ghostty_surface_mouse_pos(surface, pos.x, frame.height - pos.y)
|
let mods = Ghostty.ghosttyMods(event.modifierFlags)
|
||||||
|
ghostty_surface_mouse_pos(surface, pos.x, frame.height - pos.y, mods)
|
||||||
|
|
||||||
// If focus follows mouse is enabled then move focus to this surface.
|
// If focus follows mouse is enabled then move focus to this surface.
|
||||||
if let window = self.window as? TerminalWindow,
|
if let window = self.window as? TerminalWindow,
|
||||||
|
@ -1459,7 +1459,7 @@ pub fn keyCallback(
|
|||||||
// mod changes can affect link highlighting.
|
// mod changes can affect link highlighting.
|
||||||
self.mouse.link_point = null;
|
self.mouse.link_point = null;
|
||||||
const pos = self.rt_surface.getCursorPos() catch break :mouse_mods;
|
const pos = self.rt_surface.getCursorPos() catch break :mouse_mods;
|
||||||
self.cursorPosCallback(pos) catch {};
|
self.cursorPosCallback(pos, null) catch {};
|
||||||
if (rehide) self.mouse.hidden = true;
|
if (rehide) self.mouse.hidden = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2421,7 +2421,7 @@ pub fn mouseButtonCallback(
|
|||||||
// expensive because it could block all our threads.
|
// expensive because it could block all our threads.
|
||||||
if (self.hasSelection()) {
|
if (self.hasSelection()) {
|
||||||
const pos = try self.rt_surface.getCursorPos();
|
const pos = try self.rt_surface.getCursorPos();
|
||||||
try self.cursorPosCallback(pos);
|
try self.cursorPosCallback(pos, null);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2887,9 +2887,18 @@ pub fn mousePressureCallback(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Cursor position callback.
|
||||||
|
///
|
||||||
|
/// The mods parameter is optional because some apprts do not provide
|
||||||
|
/// modifier information on cursor position events. If mods is null then
|
||||||
|
/// we'll use the last known mods. This is usually accurate since mod events
|
||||||
|
/// will trigger key press events but on some platforms we don't get them.
|
||||||
|
/// For example, on macOS, unfocused surfaces don't receive key events but
|
||||||
|
/// do receive mouse events so we have to rely on updated mods.
|
||||||
pub fn cursorPosCallback(
|
pub fn cursorPosCallback(
|
||||||
self: *Surface,
|
self: *Surface,
|
||||||
pos: apprt.CursorPos,
|
pos: apprt.CursorPos,
|
||||||
|
mods: ?input.Mods,
|
||||||
) !void {
|
) !void {
|
||||||
// Crash metadata in case we crash in here
|
// Crash metadata in case we crash in here
|
||||||
crash.sentry.thread_state = self.crashThreadState();
|
crash.sentry.thread_state = self.crashThreadState();
|
||||||
@ -2898,6 +2907,9 @@ pub fn cursorPosCallback(
|
|||||||
// Always show the mouse again if it is hidden
|
// Always show the mouse again if it is hidden
|
||||||
if (self.mouse.hidden) self.showMouse();
|
if (self.mouse.hidden) self.showMouse();
|
||||||
|
|
||||||
|
// Update our modifiers if they changed
|
||||||
|
if (mods) |v| self.modsChanged(v);
|
||||||
|
|
||||||
// The mouse position in the viewport
|
// The mouse position in the viewport
|
||||||
const pos_vp = self.posToViewport(pos.x, pos.y);
|
const pos_vp = self.posToViewport(pos.x, pos.y);
|
||||||
|
|
||||||
|
@ -763,7 +763,12 @@ pub const Surface = struct {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cursorPosCallback(self: *Surface, x: f64, y: f64) void {
|
pub fn cursorPosCallback(
|
||||||
|
self: *Surface,
|
||||||
|
x: f64,
|
||||||
|
y: f64,
|
||||||
|
mods: input.Mods,
|
||||||
|
) void {
|
||||||
// Convert our unscaled x/y to scaled.
|
// Convert our unscaled x/y to scaled.
|
||||||
self.cursor_pos = self.cursorPosToPixels(.{
|
self.cursor_pos = self.cursorPosToPixels(.{
|
||||||
.x = @floatCast(x),
|
.x = @floatCast(x),
|
||||||
@ -776,7 +781,7 @@ pub const Surface = struct {
|
|||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
self.core_surface.cursorPosCallback(self.cursor_pos) catch |err| {
|
self.core_surface.cursorPosCallback(self.cursor_pos, mods) catch |err| {
|
||||||
log.err("error in cursor pos callback err={}", .{err});
|
log.err("error in cursor pos callback err={}", .{err});
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
@ -1716,8 +1721,20 @@ pub const CAPI = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Update the mouse position within the view.
|
/// Update the mouse position within the view.
|
||||||
export fn ghostty_surface_mouse_pos(surface: *Surface, x: f64, y: f64) void {
|
export fn ghostty_surface_mouse_pos(
|
||||||
surface.cursorPosCallback(x, y);
|
surface: *Surface,
|
||||||
|
x: f64,
|
||||||
|
y: f64,
|
||||||
|
mods: c_int,
|
||||||
|
) void {
|
||||||
|
surface.cursorPosCallback(
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
@bitCast(@as(
|
||||||
|
input.Mods.Backing,
|
||||||
|
@truncate(@as(c_uint, @bitCast(mods))),
|
||||||
|
)),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export fn ghostty_surface_mouse_scroll(
|
export fn ghostty_surface_mouse_scroll(
|
||||||
|
@ -1040,7 +1040,7 @@ pub const Surface = struct {
|
|||||||
core_win.cursorPosCallback(.{
|
core_win.cursorPosCallback(.{
|
||||||
.x = @floatCast(pos.xpos),
|
.x = @floatCast(pos.xpos),
|
||||||
.y = @floatCast(pos.ypos),
|
.y = @floatCast(pos.ypos),
|
||||||
}) catch |err| {
|
}, null) catch |err| {
|
||||||
log.err("error in cursor pos callback err={}", .{err});
|
log.err("error in cursor pos callback err={}", .{err});
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
@ -1386,7 +1386,7 @@ fn gtkMouseUp(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn gtkMouseMotion(
|
fn gtkMouseMotion(
|
||||||
_: *c.GtkEventControllerMotion,
|
ec: *c.GtkEventControllerMotion,
|
||||||
x: c.gdouble,
|
x: c.gdouble,
|
||||||
y: c.gdouble,
|
y: c.gdouble,
|
||||||
ud: ?*anyopaque,
|
ud: ?*anyopaque,
|
||||||
@ -1415,7 +1415,12 @@ fn gtkMouseMotion(
|
|||||||
self.grabFocus();
|
self.grabFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
self.core_surface.cursorPosCallback(self.cursor_pos) catch |err| {
|
// Get our modifiers
|
||||||
|
const event = c.gtk_event_controller_get_current_event(@ptrCast(ec));
|
||||||
|
const gtk_mods = c.gdk_event_get_modifier_state(event);
|
||||||
|
const mods = translateMods(gtk_mods);
|
||||||
|
|
||||||
|
self.core_surface.cursorPosCallback(self.cursor_pos, mods) catch |err| {
|
||||||
log.err("error in cursor pos callback err={}", .{err});
|
log.err("error in cursor pos callback err={}", .{err});
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
Reference in New Issue
Block a user