Revert to using a fixed timer interval

Sadly, we cant rely on the Wayland compositor to send us reliably timed
scroll events.
This commit is contained in:
Kovid Goyal
2026-01-09 13:10:16 +05:30
parent 858240e324
commit 3232551c39

View File

@@ -24,13 +24,13 @@ typedef struct MomentumScroller {
min_velocity, // Minimum velocity before stopping
max_velocity, // Maximum velocity to prevent runaway scrolling
velocity_scale; // Scale factor for initial velocity
monotonic_t timer_interval; // animation speed
GLFWid timer_id, window_id;
ScrollSamples samples;
ScrollerState state;
struct { double x, y; } velocity;
int keyboard_modifiers;
monotonic_t timer_interval;
struct {
monotonic_t start, duration;
struct { double x, y; } displacement;
@@ -42,11 +42,13 @@ static const MomentumScroller defaults = {
.min_velocity = 0.5,
.max_velocity = 100,
.velocity_scale = 0.9,
.timer_interval = 10,
};
static MomentumScroller s = defaults;
GLFWAPI void
glfwConfigureMomentumScroller(double friction, double min_velocity, double max_velocity, double velocity_scale) {
glfwConfigureMomentumScroller(double friction, double min_velocity, double max_velocity, double velocity_scale, unsigned timer_interval_ms) {
s.timer_interval = ms_to_monotonic_t(timer_interval_ms);
#define S(w) s.w = w >= 0 ? w : defaults.w
S(friction); S(min_velocity); S(max_velocity); S(velocity_scale);
#undef S
@@ -118,29 +120,17 @@ set_velocity_from_samples(monotonic_t now) {
monotonic_t first_time = deque_peek_front(&s.samples)->timestamp;
monotonic_t last_time = deque_peek_back(&s.samples)->timestamp;
double time_span = MAX(1, last_time - first_time);
double total_time_between_events = 0;
monotonic_t prev_timestamp = 0;
double ts_weight = 0;
for (size_t i = 0; i < deque_size(&s.samples); i++) {
const ScrollSample *ss = deque_at(&s.samples, i);
double weight = 1.0 + (ss->timestamp - first_time) / time_span;
total_dx += ss->dx * weight; total_dy += ss->dy * weight;
total_weight += weight;
if (prev_timestamp) {
monotonic_t t = ss->timestamp - prev_timestamp;
total_time_between_events += t * weight;
ts_weight += weight;
}
prev_timestamp = ss->timestamp;
}
deque_clear(&s.samples);
if (ts_weight <= 0) return;
s.timer_interval = (monotonic_t)(total_time_between_events / ts_weight);
if (total_weight <= 0) return;
double dy = total_dy / total_weight, dx = total_dx / total_weight;
add_velocity(dx * s.velocity_scale, dy * s.velocity_scale);
if (false) timed_debug_print(
"momentum scroll: event velocity: %.1f final velocity: %.1f interval: %d ms\n",
dy, s.velocity.y, monotonic_t_to_ms(s.timer_interval));
if (false) timed_debug_print("momentum scroll: event velocity: %.1f final velocity: %.1f\n", dy, s.velocity.y);
}
static void
@@ -205,9 +195,8 @@ glfw_handle_scroll_event_for_momentum(
s.physical_event.start = 0;
}
} else {
memset(&s.physical_event, 0, sizeof(s.physical_event));
s.physical_event.start = now;
s.physical_event.displacement.x = 0;
s.physical_event.displacement.y = 0;
}
if (s.window_id && s.window_id != w->id) cancel_existing_scroll(true);
if (s.state != PHYSICAL_EVENT_IN_PROGRESS) cancel_existing_scroll(false);