From aea16ba5d2896ef22bf0bea45e5e8142c0ff1c2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Sat, 15 Jun 2024 10:17:01 +0200 Subject: [PATCH] input: implement wl_pointer::axis_value120() This implements high resolution mouse wheel scroll events. A "normal" scroll step corresponds to the value 120. Anything less than that is a partial scroll step. This event replaces axis_discrete(), when we bind wl_seat v8 (which we now do, when available). We calculate the number of degrees that is required to scroll a single line, based off of the scrollback.multiplier value. Each high-res event accumulates, until we have at least the number of degress required to scroll one, or more lines. The remaining degrees are kept, and added to in the next scroll event. Closes #1738 --- CHANGELOG.md | 2 ++ input.c | 71 +++++++++++++++++++++++++++++++++++++++++++--------- wayland.c | 8 +++++- wayland.h | 1 + 4 files changed, 69 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9cb9b38c..85b8c59d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -60,8 +60,10 @@ * Support for `wp_single_pixel_buffer_v1`; certain overlay surfaces will now utilize the new single-pixel buffer protocol. This mainly reduces the memory usage, but should also be slightly faster. +* Support for high-res mouse wheel scroll events ([#1738][1738]). [1707]: https://codeberg.org/dnkl/foot/issues/1707 +[1738]: https://codeberg.org/dnkl/foot/issues/1738 ### Changed diff --git a/input.c b/input.c index 33b5446c..13999250 100644 --- a/input.c +++ b/input.c @@ -2768,7 +2768,7 @@ mouse_scroll(struct seat *seat, int amount, enum wl_pointer_axis axis) } } -static float +static double mouse_scroll_multiplier(const struct terminal *term, const struct seat *seat) { return (term->grid == &term->normal || @@ -2812,15 +2812,15 @@ wl_pointer_axis(void *data, struct wl_pointer *wl_pointer, static void wl_pointer_axis_discrete(void *data, struct wl_pointer *wl_pointer, - uint32_t axis, int32_t discrete) + enum wl_pointer_axis axis, int32_t discrete) { + LOG_DBG("axis_discrete: %d", discrete); struct seat *seat = data; if (touch_is_active(seat)) return; seat->mouse.have_discrete = true; - int amount = discrete; if (axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL) { @@ -2831,6 +2831,50 @@ wl_pointer_axis_discrete(void *data, struct wl_pointer *wl_pointer, mouse_scroll(seat, amount, axis); } +#if defined(WL_POINTER_AXIS_VALUE120_SINCE_VERSION) +static void +wl_pointer_axis_value120(void *data, struct wl_pointer *wl_pointer, + enum wl_pointer_axis axis, int32_t value120) +{ + LOG_DBG("axis_value120: %d -> %.2f", value120, (float)value120 / 120.); + + struct seat *seat = data; + + if (touch_is_active(seat)) + return; + + seat->mouse.have_discrete = true; + + /* + * 120 corresponds to a single "low-res" scroll step. + * + * When doing high-res scrolling, take the scrollback.multiplier, + * and calculate how many degrees there are per line. + * + * For example, with scrollback.multiplier = 3, we have 120 / 3 == 40. + * + * Then, accumulate high-res scroll events, until we have *at + * least* that much. Translate the accumulated value to number of + * lines, and scroll. + * + * Subtract the "used" degrees from the accumulated value, and + * keep what's left (this value will always be less than the + * per-line value). + */ + const double multiplier = mouse_scroll_multiplier(seat->mouse_focus, seat); + const double per_line = 120. / multiplier; + + seat->mouse.aggregated_120[axis] += (double)value120; + + if (fabs(seat->mouse.aggregated_120[axis]) < per_line) + return; + + int lines = (int)(seat->mouse.aggregated_120[axis] / per_line); + mouse_scroll(seat, lines, axis); + seat->mouse.aggregated_120[axis] -= (double)lines * per_line; +} +#endif + static void wl_pointer_frame(void *data, struct wl_pointer *wl_pointer) { @@ -2862,15 +2906,18 @@ wl_pointer_axis_stop(void *data, struct wl_pointer *wl_pointer, } const struct wl_pointer_listener pointer_listener = { - .enter = wl_pointer_enter, - .leave = wl_pointer_leave, - .motion = wl_pointer_motion, - .button = wl_pointer_button, - .axis = wl_pointer_axis, - .frame = wl_pointer_frame, - .axis_source = wl_pointer_axis_source, - .axis_stop = wl_pointer_axis_stop, - .axis_discrete = wl_pointer_axis_discrete, + .enter = &wl_pointer_enter, + .leave = &wl_pointer_leave, + .motion = &wl_pointer_motion, + .button = &wl_pointer_button, + .axis = &wl_pointer_axis, + .frame = &wl_pointer_frame, + .axis_source = &wl_pointer_axis_source, + .axis_stop = &wl_pointer_axis_stop, + .axis_discrete = &wl_pointer_axis_discrete, +#if defined(WL_POINTER_AXIS_VALUE120_SINCE_VERSION) + .axis_value120 = &wl_pointer_axis_value120, +#endif }; static bool diff --git a/wayland.c b/wayland.c index d65a404e..c357f382 100644 --- a/wayland.c +++ b/wayland.c @@ -1161,6 +1161,12 @@ handle_global(void *data, struct wl_registry *registry, if (!verify_iface_version(interface, version, required)) return; +#if defined(WL_POINTER_AXIS_VALUE120_SINCE_VERSION) + const uint32_t preferred = WL_POINTER_AXIS_VALUE120_SINCE_VERSION; +#else + const uint32_t preferred = required; +#endif + int repeat_fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK); if (repeat_fd == -1) { LOG_ERRNO("failed to create keyboard repeat timer FD"); @@ -1168,7 +1174,7 @@ handle_global(void *data, struct wl_registry *registry, } struct wl_seat *wl_seat = wl_registry_bind( - wayl->registry, name, &wl_seat_interface, required); + wayl->registry, name, &wl_seat_interface, min(version, preferred)); tll_push_back(wayl->seats, ((struct seat){ .wayl = wayl, diff --git a/wayland.h b/wayland.h index 7688fbdb..9577f08f 100644 --- a/wayland.h +++ b/wayland.h @@ -192,6 +192,7 @@ struct seat { /* We used a discrete axis event in the current pointer frame */ double aggregated[2]; + double aggregated_120[2]; bool have_discrete; } mouse;