mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-08-02 14:57:31 +03:00
core: do high precision scrolling Y calculations
This commit is contained in:
@ -298,8 +298,8 @@ extension Ghostty {
|
||||
var y = event.scrollingDeltaY
|
||||
if event.hasPreciseScrollingDeltas {
|
||||
mods = 1
|
||||
x *= 0.1
|
||||
y *= 0.1
|
||||
|
||||
// TODO(mitchellh): do we have to scale the x/y here?
|
||||
}
|
||||
|
||||
// Determine our momentum value
|
||||
|
@ -127,6 +127,10 @@ const Mouse = struct {
|
||||
|
||||
/// The last x/y sent for mouse reports.
|
||||
event_point: terminal.point.Viewport = .{},
|
||||
|
||||
/// Pending scroll amounts for high-precision scrolls
|
||||
pending_scroll_x: f64 = 0,
|
||||
pending_scroll_y: f64 = 0,
|
||||
};
|
||||
|
||||
/// The configuration that a surface has, this is copied from the main
|
||||
@ -1274,8 +1278,6 @@ pub fn scrollCallback(
|
||||
yoff: f64,
|
||||
scroll_mods: input.ScrollMods,
|
||||
) !void {
|
||||
_ = scroll_mods;
|
||||
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
@ -1292,16 +1294,59 @@ pub fn scrollCallback(
|
||||
|
||||
// log.info("SCROLL: xoff={} yoff={} mods={}", .{ xoff, yoff, scroll_mods });
|
||||
|
||||
// Positive is up
|
||||
const ScrollAmount = struct {
|
||||
// Positive is up, right
|
||||
sign: isize = 1,
|
||||
delta_unsigned: usize = 0,
|
||||
delta: isize = 0,
|
||||
};
|
||||
|
||||
const y: ScrollAmount = if (yoff == 0) .{} else y: {
|
||||
// Non-precision scrolling is easy to calculate.
|
||||
if (!scroll_mods.precision) {
|
||||
const y_sign: isize = if (yoff > 0) -1 else 1;
|
||||
const y_delta_unsigned: usize = if (yoff == 0) 0 else @max(@divFloor(self.grid_size.rows, 15), 1);
|
||||
const y_delta_unsigned: usize = @max(@divFloor(self.grid_size.rows, 15), 1);
|
||||
const y_delta: isize = y_sign * @intCast(isize, y_delta_unsigned);
|
||||
break :y .{ .sign = y_sign, .delta_unsigned = y_delta_unsigned, .delta = y_delta };
|
||||
}
|
||||
|
||||
// Precision scrolling is more complicated. We need to maintain state
|
||||
// to build up a pending scroll amount if we're only scrolling by a
|
||||
// tiny amount so that we can scroll by a full row when we have enough.
|
||||
|
||||
// Add our previously saved pending amount to the offset to get the
|
||||
// new offset value.
|
||||
//
|
||||
// NOTE: we currently mutiply by -1 because macOS sends the opposite
|
||||
// of what we expect. This is jank we should audit our sign usage and
|
||||
// carefully document what we expect so this can work cross platform.
|
||||
// Right now this isn't important because macOS is the only high-precision
|
||||
// scroller.
|
||||
const poff = self.mouse.pending_scroll_y + (yoff * -1);
|
||||
|
||||
// If the new offset is less than a single unit of scroll, we save
|
||||
// the new pending value and do not scroll yet.
|
||||
const cell_size = self.cell_size.height;
|
||||
if (@fabs(poff) < cell_size) {
|
||||
self.mouse.pending_scroll_y = poff;
|
||||
break :y .{};
|
||||
}
|
||||
|
||||
// We scroll by the number of rows in the offset and save the remainder
|
||||
const amount = poff / cell_size;
|
||||
self.mouse.pending_scroll_y = poff - (amount * cell_size);
|
||||
|
||||
break :y .{
|
||||
.delta_unsigned = @intFromFloat(usize, @fabs(amount)),
|
||||
.delta = @intFromFloat(isize, amount),
|
||||
};
|
||||
};
|
||||
|
||||
// Positive is right
|
||||
const x_sign: isize = if (xoff < 0) -1 else 1;
|
||||
const x_delta_unsigned: usize = if (xoff == 0) 0 else 1;
|
||||
const x_delta: isize = x_sign * @intCast(isize, x_delta_unsigned);
|
||||
log.info("scroll: delta_y={} delta_x={}", .{ y_delta, x_delta });
|
||||
log.info("scroll: delta_y={} delta_x={}", .{ y.delta, x_delta });
|
||||
|
||||
{
|
||||
self.renderer_state.mutex.lock();
|
||||
@ -1322,9 +1367,9 @@ pub fn scrollCallback(
|
||||
self.io.terminal.modes.mouse_event == .none and
|
||||
self.io.terminal.modes.mouse_alternate_scroll)
|
||||
{
|
||||
if (y_delta_unsigned > 0) {
|
||||
const seq = if (y_delta < 0) "\x1bOA" else "\x1bOB";
|
||||
for (0..y_delta_unsigned) |_| {
|
||||
if (y.delta_unsigned > 0) {
|
||||
const seq = if (y.delta < 0) "\x1bOA" else "\x1bOB";
|
||||
for (0..y.delta_unsigned) |_| {
|
||||
_ = self.io_thread.mailbox.push(.{
|
||||
.write_stable = seq,
|
||||
}, .{ .forever = {} });
|
||||
@ -1350,7 +1395,7 @@ pub fn scrollCallback(
|
||||
// the normal logic.
|
||||
|
||||
// Modify our viewport, this requires a lock since it affects rendering
|
||||
try self.io.terminal.scrollViewport(.{ .delta = y_delta });
|
||||
try self.io.terminal.scrollViewport(.{ .delta = y.delta });
|
||||
|
||||
// If we're scrolling up or down, then send a mouse event. This requires
|
||||
// a lock since we read terminal state.
|
||||
|
Reference in New Issue
Block a user