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;