High-resolution scroll wheel support #3082
base: master
Are you sure you want to change the base?
Conversation
Thanks for working on this! In case this hasn't been noticed, @tokyovigilante made a PR for the same feature a few years (!) ago: #1628 |
Hi @emersion, thanks for pointing it out, I didn't noticed there was an existing PR. However, libinput's API has changed a bit. This PR includes every change made until now. |
Thanks for the @, I'm happy to hand this over to you @JoseExposito and review or test. As you note it had been both a moving target as well as a bit of a chicken and egg scenario waiting for libinput, wayland and GTK to all get their ducks in a row which is why I had parked this. |
2e2b320
to
4e30fb2
Compare
@tokyovigilante yes... This kind of features can be tricky, because of all the parts involved, hopefully this time we will get it merged 😄 @emersion GTK is ready: I updated the PR description with build instructions and removed the "Draft" tag. I'll drop a comment on the Wayland MR with all the links. |
libinput has been merged and 1.19 will be released in less than a month including high-resolution scroll support. @emersion at this point your feedback on the the Wayland protocol or in this PR would be very valuable, so I can perform the changes in time. |
Starting with Linux Kernel v5.0 two new axes are available for mice that support high-resolution wheel scrolling: REL_WHEEL_HI_RES and REL_HWHEEL_HI_RES. Both axes send data in fractions of 120 where each multiple of 120 amounts to one logical scroll event. Fractions of 120 indicate a wheel movement less than one detent. Three new events are now available on libinput: LIBINPUT_EVENT_POINTER_SCROLL_WHEEL, LIBINPUT_EVENT_POINTER_SCROLL_FINGER, and LIBINPUT_EVENT_POINTER_SCROLL_CONTINUOUS. These events replace the LIBINPUT_EVENT_POINTER_AXIS event, so new clients should simply ignore that event. Also, two new APIs are available to access the high-resolution data: libinput_event_pointer_get_scroll_value() and libinput_event_pointer_get_scroll_value_v120(). Create a new event, wlr_event_pointer_axis_v120, to represent high-resolution axis events and a signal to emit them: wlr_pointer->pointer.axis_value120.
Add a project argument (LIBINPUT_HAS_SCROLL_VALUE120) to allow building against old versions of libinput or, where high-resolution scroll is available, support it.
On newer versions of libinput, the event LIBINPUT_EVENT_POINTER_AXIS has been deprecated in favour of LIBINPUT_EVENT_POINTER_SCROLL_WHEEL, LIBINPUT_EVENT_POINTER_SCROLL_FINGER and LIBINPUT_EVENT_POINTER_SCROLL_CONTINUOUS. Where new events are provided by the backend, ignore LIBINPUT_EVENT_POINTER_AXIS.
Receive high-resolution scroll events from libinput and emit the appropiate wlr_pointer signal.
Receive high-resolution scroll events from the parent compositor using a Wayland listiner and emit the appropiate wlr_pointer signal.
Recevie the high-resolution scroll events from the libinput or Wayland backends, abstracted as pointer signals, and re-emit them from the cursor interface.
When the selected backend doesn't support high-resolution scroll, clients requesting high-resolution events must be handled properly. Upgrade the seat protocol to version 8 and change the defaul pointer axis handler to support new clients.
When the selected backend supports high-resolution scroll, wlroots will emit the axis_value120 signal. Add the required APIs so wlroots compositors can handle this new events and the default handler implemetion. For the moment, the default implementation does NOT handle clients that don't support high-scroll resolution.
When the selected backend supports high-resolution scroll but the client doesn't, we need to accumulate value120 deltas until we can notify a discrete event. In addition, add a expire time so accumulated deltas are reset after a period of inactivity.
Demostrate how to use the high-resolution scroll API.
4e30fb2
to
e523182
Compare
Updated to use |
This introduces a new event, |
@emersion yes, that should also work. I'm not as familiarized with the code as you are, so please me correct me if I'm wrong. If we remove the new event and add a filed in However, what would happen with compositors using their own |
Hm, is the old axis event trigger less often than the new one? Is it bad to not look at axis120 and just use axis/axis_discrete? |
Yes, when your hardware supports high-resolution scroll, the new event is sent more often. For example, a mouse with an extra mouse wheel "click" will send:
When both compositor and client support a version of the protocol >= 8, clients will ignore the old event in favour of the new one. That means that if the compositor's custom implementation of I think that, sadly, there's no way to not break the API? 🤔 |
An important note here: the mouse may send. There really is no correlation between the two events once they come out of the kernel. logitech devices in particular have some in-kernel wheel handling where some high-resolution events get filtered, so it's not always the same number of high-res events per low-res event. |
wlroots has migrated to gitlab.freedesktop.org. This pull request has been moved to: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/3082 |
Description:
Starting with Linux Kernel v5.0 two new axes are available for high-resolution wheel scrolling:
REL_WHEEL_HI_RES
andREL_HWHEEL_HI_RES
.Both axes send data in fractions of 120 where each multiple of 120 amounts to one logical scroll event. Fractions of 120 indicate a wheel movement less than one detent. A "detent" is the named used in the Kernel for a mouse wheel click:
https://www.kernel.org/doc/html/v5.11-rc7/input/event-codes.html#ev-rel
Three new events are now available on libinput:
LIBINPUT_EVENT_POINTER_SCROLL_WHEEL
,LIBINPUT_EVENT_POINTER_SCROLL_FINGER
, andLIBINPUT_EVENT_POINTER_SCROLL_CONTINUOUS
. These events replace theLIBINPUT_EVENT_POINTER_AXIS
event, so new clients should simply ignore that event.This
LIBINPUT_EVENT_POINTER_SCROLL_WHEEL
event adds a new APIlibinput_pointer_scroll_get_value_v120()
. Thelibinput_pointer_scroll_get_value_v120()
is a mirror from the kernel API (itself a copy of the Windows API). The new event is sent for all wheel events, even those that don't technically support high-resolution scrolling and even on older kernels that don't have this feature. So callers can simply ignore anyLIBINPUT_EVENT_POINTER_AXIS
event and use the new event types only.For
LIBINPUT_EVENT_POINTER_SCROLL_FINGER
andLIBINPUT_EVENT_POINTER_SCROLL_CONTINUOUS
, as well asLIBINPUT_EVENT_POINTER_SCROLL_WHEEL
, a new API is available:libinput_pointer_scroll_get_value()
. This API is similar tolibinput_pointer_axis_get_value()
.Status
How to test it:
Clone and install my libinput branch:
https://gitlab.freedesktop.org/libinput/libinput/-/merge_requests/652
Clone and install Peter's Wayland protocol:
https://gitlab.freedesktop.org/wayland/wayland/-/merge_requests/72/
Reboot.
tinywl
has been updated in this PR, so you can test that scroll is still working with backends that support and don't support high-resolution scroll.To test with a client that supports high-resolution scroll, clone my GTK branch: https://gitlab.gnome.org/GNOME/gtk/-/merge_requests/3839
And run it:
Of course, you'll need hardware to test it.
Logitech mice are supported, otherwise any mouse that shows a
ResolutionMultiplier
in the hid-recorder output (most Microsoft-branded mice of the last decade).Or, if you happen to have an Apple Magic Mouse, I added support in the Kernel. You'll need to compile the Kernel with my patches, let me know if you need help.
For code reviewers
It's easier to review this PR commit by commit.
I hesitated a lot about "seat: support lo-res clients using hi-res backends". Placing the accumulators in
wlr_seat_client
is technically incorrect, there should be an accumulator for each pointer inwlr_seat_client->pointers
.However, given that the accumulator expires after one second of inactivity and given than using 2 or more mice at the same time is a niche use case, I decided to leave the accumulator there for the sake of simplicity. Also, the side effects of using multiple mice at the same time are really difficult to notice.
Keeping the PR as draft until there is a client to test with.
cc @emersion @whot