From 98931d99b0f4e0014022782bfd180744495766d4 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Fri, 13 Mar 2026 08:47:45 +0530 Subject: [PATCH] Wayland: Fix momentum scrolling not working on compositors that send a stop frame with no axis information Fixes #9653 --- docs/changelog.rst | 2 ++ glfw/wl_init.c | 10 +++++++++- glfw/wl_platform.h | 1 + 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index 191aa50e3..f90bfb2de 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -180,6 +180,8 @@ Detailed list of changes - X11: Fix a regression that caused some high res scroll devices to be treated as line based scroll devices (:iss:`9649`) +- Wayland: Fix momentum scrolling not working on compositors that send a stop frame with no axis information (:iss:`9653`) + 0.46.0 [2026-03-11] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/glfw/wl_init.c b/glfw/wl_init.c index e38f651ae..be840b40f 100644 --- a/glfw/wl_init.c +++ b/glfw/wl_init.c @@ -206,27 +206,35 @@ pointer_handle_frame(void *data UNUSED, struct wl_pointer *pointer UNUSED) { _GLFWwindow* window = _glfw.wl.pointerFocus; if (!window) return; GLFWScrollEvent ev = {.keyboard_modifiers=_glfw.wl.xkb.states.modifiers}; + bool found = false; if (info.discrete.y_axis_type != AXIS_EVENT_UNKNOWN) { ev.unscaled.y = info.discrete.y; if (info.discrete.y_axis_type == AXIS_EVENT_VALUE120) ev.offset_type = GLFW_SCROLL_OFFEST_V120; + found = true; } else if (info.continuous.y_axis_type != AXIS_EVENT_UNKNOWN) { ev.offset_type = GLFW_SCROLL_OFFEST_HIGHRES; ev.unscaled.y = info.continuous.y; + found = true; } if (info.discrete.x_axis_type != AXIS_EVENT_UNKNOWN) { ev.unscaled.x = info.discrete.x; if (info.discrete.x_axis_type == AXIS_EVENT_VALUE120) ev.offset_type = GLFW_SCROLL_OFFEST_V120; + found = true; } else if (info.continuous.x_axis_type != AXIS_EVENT_UNKNOWN) { ev.offset_type = GLFW_SCROLL_OFFEST_HIGHRES; ev.unscaled.x = info.continuous.x; + found = true; } + bool stopped = info.y_stop_received || info.x_stop_received; + if (!found && stopped) ev.offset_type = window->wl.prev_frame_offset_type; ev.unscaled.x *= -1; const double scale = ev.offset_type == GLFW_SCROLL_OFFEST_HIGHRES ? _glfwWaylandWindowScale(window) : 1; ev.x_offset = scale * ev.unscaled.x; ev.y_offset = scale * ev.unscaled.y; glfw_handle_scroll_event_for_momentum( - window, &ev, info.y_stop_received || info.x_stop_received, info.source_type == WL_POINTER_AXIS_SOURCE_FINGER); + window, &ev, stopped, info.source_type == WL_POINTER_AXIS_SOURCE_FINGER); + window->wl.prev_frame_offset_type = ev.offset_type; /* clear pointer_curr_axis_info for next frame */ memset(&info, 0, sizeof(info)); } diff --git a/glfw/wl_platform.h b/glfw/wl_platform.h index e9ae1533e..8e8f72ba7 100644 --- a/glfw/wl_platform.h +++ b/glfw/wl_platform.h @@ -212,6 +212,7 @@ typedef struct _GLFWwindowWayland uint32_t source_type; monotonic_t x_start_time, x_stop_time, y_stop_time, y_start_time; } pointer_curr_axis_info; + GLFWOffsetType prev_frame_offset_type; _GLFWcursor* currentCursor; double cursorPosX, cursorPosY, allCursorPosX, allCursorPosY;