Closed Bug 1213601 Opened 9 years ago Closed 5 years ago

Kinetic scrolling does not work on Linux

Categories

(Core :: Widget: Gtk, defect, P2)

41 Branch
defect

Tracking

()

RESOLVED FIXED
mozilla69
Tracking Status
firefox69 --- fixed

People

(Reporter: nagisa, Assigned: val, Mentored)

References

(Depends on 1 open bug, Blocks 5 open bugs, Regressed 1 open bug)

Details

(Whiteboard: tpi:+)

User Story

How to enable/disable kinetic scrolling?

Go to `about:config` and toggle pref `apz.gtk.kinetic_scroll.enabled`

Attachments

(3 files)

Attached video Demonstration (deleted) —
GTK 3 kinetic scrolling does not work, but does work in native applications.

Note: my system has no kinetic scrolling emulation at driver level enabled (common with synaptics drivers).

See an attached video for the demonstration.
Depends on: gtk3
Blocks: gtk3
No longer depends on: gtk3
Does this just apply to touch screens?
This is reproducible on regular touchpad with xf86-input-libinput driver.
Ah, I also forgot to mention this is gtk 3.18.
That's strange; the GTK documentation mentions that "Kinetic scrolling only applies to devices with source GDK_SOURCE_TOUCHSCREEN."
Hmm, that might be just a documentation bug, especially given it is noted in release notes https://help.gnome.org/misc/release-notes/3.18/more.html.en#scrolling.
If you're referring to support for floating point scroll deltas (smooth scrolling), you'll need to set the environment variable MOZ_USE_XINPUT2. See bug 1207700 for more details.
No, this is about scrolling "inertia" - the content keeps moving after the fingers have been lifted after a flick.

Though, the implementation in GTK3 might need XInput2 regardless.
I already have “smooth” scrolling in a sense that firefox seems to scroll in as precisely as 1 pixel increments, implying XInput2 being enabled (starting with the environment variable changes nothing, for the record).

I’m referring here to kinetic scrolling (as specified in issue title) where removing fingers from the touchpad while scrolling will not immediately stop scrolling but decrease in speed over a period of time (seems to be 1.5 seconds or thereabouts). I think it is clearly visible in the video.

In firefox, removing fingers from the touchpad will stop scrolling immediately. The scrolling in the video might look a little bit janky, though, because I had to record it at 15 fps.
(In reply to Jan Steffens from comment #7)
> No, this is about scrolling "inertia" - the content keeps moving after the
> fingers have been lifted after a flick.
> 
> Though, the implementation in GTK3 might need XInput2 regardless.

My mistake; looks like kinetic scrolling is indeed implemented at the widget level (see gtkscrolledwindow.c) and not in simulated XI2 events (as some touchpad driver implementations provided). It looks like the scrolling follows a deceleration path after the GdkEventScroll event reports scroll deltas of zero.

I'm not sure how kinetic/fling scrolling is implemented on other platforms in Gecko, I suspect we'll be able to reuse some code for this rather than have to re-implement this in the widget code.
The FAQ of libinput says:

> libinput does not implement kinetic scrolling for touchpads. Instead it provides the libinput_event_pointer_get_axis_source() function that enables callers to implement kinetic scrolling on a per-widget basis, see Scroll sources.

Meaning that it's up to the client to implement it. https://wayland.freedesktop.org/libinput/doc/latest/faq.html
Priority: -- → P2
Whiteboard: tpi:+
I just compiled firefox nightly with --enable-default-toolkit=cairo-gtk3-wayland. It seems that I do have pixel perfect scrolling (as discovered in this bug earlier) but I don't have kinetic scrolling, the inertia after releasing both fingers from scrolling on the touchpad. This is on gnome-shell on wayland and therefore using libinput. 

It seems that we would need to add gtk_scrolled_window_set_kinetic_scrolling somewhere. It's been several years since this bug was last discussed so perhaps the environment has changed now that GTK3 is default and many distros are including wayland or using it by default, and I think it would be a great usability improvement. To see how it works, you can install Gnome Web (Epiphany) and see how it does have working kinetic scrolling. I don't know exactly where to insert that line, but I think it should be a simple insertion (somewhere) and kinetic scrolling should work. I'm on Ubuntu 18.04.
I think that enabling kinetic scrolling would probably involve adding "gtk_scrolled_window_set_kinetic_scrolling" to widget/gtk/mozgtk/mozgtk.c and then calling "gtk_scrolled_window_set_kinetic_scrolling" with kinetic_scrolling TRUE in widget/gtk/nsWindow.cpp. Unfortunately I don't know how to code C++ but I did find a cool example program at 

https://github.com/linuxmint/gtk/blob/master/tests/testkineticscrolling.c 

that you can compile like this: 

gcc testkineticscrolling.c -o testkineticscrolling `pkg-config --cflags --libs gtk+-3.0` 

And that includes that function to enable kinetic scrolling, so you can see how the function is used in practice.
Firefox doesn't use GtkScrolledWindow for the main content. From a quick grep in the source, I can see it's only used for crashreporter_linux. The actual browser only uses a GtkScrollbar. The main content is all custom gecko stuff.

I think I found something — Firefox describes scroll events as WidgetWheelEvent, which has a property 'mIsMomentum' that's set by the Mac code, but not GTK..
You're completely right about crashreporter_linux actually - I was testing webrender and crashed firefox, and kinetic scrolling worked on the window shown after pressing "details" on the crash reporter, how interesting... 

Since there's no GtkScrolledWindow in the main firefox window, I think that as you said, mIsMomentum is the way to go.

Now that many distributions are shipping wayland (and thus libinput - including Ubuntu, even on Xorg) and since the other two big platforms (macOS and Windows) already support kinetic scrolling, I think it would be a big usability improvement to add kinetic scrolling to Linux. It is now the only platform without it.

Gnome Web (Epiphany) supports kinetic scrolling and it works very well, it would be great to have it on Firefox too.
I looked at this a bit more, just setting some random fields like that doesn't work. Looks like this place needs to emit proper APZ events (PanGestureInput).

> Gnome Web (Epiphany)

Yeah, here's WebKitGTK's patch for this: https://bugs.webkit.org/show_bug.cgi?id=155750

Kinetic scrolling works with my touchscreen

  • FF nightly with GDK_BACKEND=wayland under Sway
  • ELAN Touchscreen

Not with my trackpad.

Is this issue valid, given the docs say kinetic scrolling is only for touchscreens?
https://developer.gnome.org/gtk3/stable/GtkScrolledWindow.html#id-1.3.16.3.11.9

I think it is very much valid. Lots of GTK apps support kinetic scrolling, like Epiphany and Gnome Files and Evolution and Evince. Kinetic scrolling does work on touchscreens on firefox (I tested on a Lenovo Yoga 2) but it should work for trackpads as well. Not only that, but macOS and Windows both have it for trackpads and have had it for years. Firefox on Linux is the only one that doesn't have kinetic implemented.

(In reply to ericdrex from comment #16)

Is this issue valid, given the docs say kinetic scrolling is only for touchscreens?
https://developer.gnome.org/gtk3/stable/GtkScrolledWindow.html#id-1.3.16.3.11.9

They don't say it's only for touchscreens. It just says "When a touchscreen is used" as an example. Of course that should be worded better, it definitely works with touchpads in native GTK widgets.

Anyway: it already works with touchscreens in Firefox because for touchscreens, Firefox gets raw touch events, and they get shoved directly into the shared (non-platform-specific) touchscreen handling code. Of course that's going to work!

For touchpads, everything is different. You get scroll events and you have to accumulate deltas and calculate the velocity when the scroll ends, like GTK does for its widgets: https://gitlab.gnome.org/GNOME/gtk/blob/a0129f556b1fd655215165739d0277d7f7a2c1a8/gtk/gtkeventcontrollerscroll.c#L336-348

I've been occasionally looking at the Firefox code, but haven't figured out how to wire this up to the APZ stuff…

The WebKit patch just replicates Gtk's kinetic scrolling model in WebKit. This is a valid approach for Gecko. Botond can probably provide more details on how to hook it up.

Flags: needinfo?(botond)
Summary: Kinetic scrolling does not work → Kinetic scrolling does not work on Linux

Yes, this is one of several improvements to Linux scrolling that we would like to make, tracked overall in bug 1459717. Unfortunately, it hasn't been a high enough priority to make our roadmap so far.

Greg, it seems like you've spent some time investigating this and developed some familiarity with the relevant code. Would you be interested in working on this if I mentored you through it?

Blocks: 1459717
Mentor: botond
Flags: needinfo?(botond) → needinfo?(greg)

(In reply to Botond Ballo [:botond] from comment #21)

seems like you've spent some time investigating this and developed some familiarity with the relevant code. Would you be interested in working on this if I mentored you through it?

I could try :)

Surely there must be a way to tell APZ to do the kinetic thing based on just position deltas and time? That's sort of what it does for touchscreens, right? (Because raw finger events is all you get for those.)

https://hg.mozilla.org/mozilla-central/file/tip/widget/gtk/nsWindow.cpp#l2841 is where this is handled now. What events can be used instead of wheel events?

Flags: needinfo?(greg)

(In reply to greg from comment #22)

Surely there must be a way to tell APZ to do the kinetic thing based on just position deltas and time? That's sort of what it does for touchscreens, right? (Because raw finger events is all you get for those.)

There are two ways kinetic scrolling could potentially work:

  • The OS / widget toolkit continues sending events even after the fingers leave the touchpad, representing the kinetic scroll. In this case, we just listen for those events and scroll in response to them, just as we'd scroll in response to the events we get while the fingers are in contact with the touchpad. This is how we do it for macOS trackpads.

  • The OS / widget toolkit does not send events after the fingers leave the touchpad, but we are able to detect when the fingers leave the touchpad, and then kick off an "animation" which runs (without additional user input) over a period of time and does additional scrolling. This is how we do it for touchscreens (on all platforms).

The first thing to determine is which of these strategies is applicable for Linux touchpads.

(I'm not sure what we do for Windows touchpads. The fact that we have kinetic scrolling on Windows touchpads at all was news to me, but I tested it and that does seem to be the case.)

If it's the latter, then we need the following information to be able to do kinetic scrolling:

  • A way to tell when a touchpad gesture starts (fingers go down), so we know to start collecting velocity information.
  • A precise pixel delta (not just "one wheel tick") from each scroll event, so we can maintain an accurate velocity.
  • A way to tell when a touchpad gesture ends (fingers are lifted), so we know to kick off the kinetic scroll.

The current API we use to receive scroll events is GdkScrollEvent. Does that expose the above information?

Sorry for butting in, I've been watching this for a little while and have a bit of info I've found from looking into it.

On the first point: some balance should likely be struck between just taking the last event's delta and averaging deltas over the movement. If the average over all the events is taken, the velocity at release (finger up) could be significantly different from the calculated average velocity. An example would be if a scroll gesture starts slowly, then picks up speed. The average would place the starting velocity for the fling below the ending velocity of the scroll, making the motion jerky. Just taking the last event's delta seems to be a fairly natural feeling approach in my experience, and should probably be assessed for viability. An advantage to this approach would be that the only event that would be needed to be used would be the "finger up" event's deltas to calculate starting velocity for a fling.

On the second point: https://developer.gnome.org/gdk3/stable/gdk3-Events.html#gdk-event-get-scroll-deltas seems to be able to give smooth (single pixel) scroll deltas, but I am not personally familiar enough with GDK to know appropriate usage.

On the third: https://developer.gnome.org/gdk3/stable/gdk3-Events.html#gdk_event_is_scroll_stop_event appears suitable for this purpose, and explicitly describes the use case of "on finger lift" for gestures, with a corresponding boolean (from what I can tell) in https://developer.gnome.org/gdk3/stable/gdk3-Event-Structures.html#GdkEventScroll

Whether the deltas for the last scroll event are accurate, I do not know, but I would imagine they should be fairly close to reality.

From this, it is my opinion that GdkScrollEvent should indeed work for these purposes.

(In reply to Sawyer Bergeron from comment #27)

On the first point: some balance should likely be struck between just taking the last event's delta and averaging deltas over the movement.

Since Firefox already does this for touchscreens, I guess we don't need to reinvent that part…

But Gtk calculates over the whole scroll, dividing the sum of all deltas by the difference between the time of the last and first events:
https://gitlab.gnome.org/GNOME/gtk/blob/81c8efc863fed7f3d348b9050db5f031fa3fceba/gtk/gtkeventcontrollerscroll.c#L158-193

On the second point: https://developer.gnome.org/gdk3/stable/gdk3-Events.html#gdk-event-get-scroll-deltas […]
On the third: https://developer.gnome.org/gdk3/stable/gdk3-Events.html#gdk_event_is_scroll_stop_event appears suitable […]

Yep, gdk_event_is_scroll_stop_event is just an accessor (event->scroll.is_stop). Similarly gdk_event_get_scroll_deltas is a glorified accessor for event->scroll.delta_(x|y) (it just first checks that the event is a GDK_SCROLL_SMOOTH one).

And of course the values are correct. That's the only API GDK offers, it's not like there's a choice :)

There was no question about the Gtk side, all I need to know is how to plug this data into APZ using what's available from nsWindow.

So, in terms of plugging this into APZ, I can think of two possible approaches.

Let's assume, in either case, that we can classify a GdkEventScroll into one of four types:

  1. Scroll event not from a touchpad (e.g. from a mouse wheel)
  2. Scroll event representing the fingers going down on a touchpad
  3. Scroll event representing the fingers moving across a touchpad
  4. Scroll event representing the fingers being lifted from a touchpad

Approach 1: Continue creating wheel events (WidgetWheelEvent) for type 1, but create touch events (WidgetTouchEvent) for types 2-4 instead. Type 2 would become eTouchStart, type 3 would become eTouchMove, and type 4 would become eTouchEnd. This way, the exact same codepaths will be triggered as if the user performed a touchscreen gesture.

Approach 2: Continue creating wheel events for all four types, but annotate the wheel event with the type (adding a new field to store it if necessary). When the wheel event is handled downstream in AsyncPanZoomController, perform special handling for types 2-4. Types 2 and 3 would trigger code for tracking the velocity, similar to what eTouchStart and eTouchMove trigger. Type 4 would trigger code for kicking off the kinetic scroll (called a "fling animation" in this code), similar to what eTouchEnd triggers. (I can give more details if we decide to go with this approach.)

The first approach seems like it would be easier, so all else being equal it would be perferrable. I don't know if we're going to run into any complications from trying to pretend that touchpad events are touch events -- this is one of those things where you just have to try it to see. If it doesn't work out for some reason, the second approach can be our fallback.

Kats pointed out that approach 1 would have the side effect that the events dispatched to web content would change from being wheel events, to being touch events. That's probably a side effect we don't want.

Kats also suggested a variant of approach 2 that would be slightly easier: generate events of type PanGestureInput, similarly to what we do for Mac touchpads. The advantage of this is that velocity tracking is already hooked up for these, so the only new piece we'd need to add to AsyncPanZoomController is the code to kick off a fling animation after a PANGESTURE_END event.

There is one slight complication that comes with using PanGestureInput, which is that we still need a wheel event to dispatch to web content. That means we can't use DisaptchInputEvent, we instead have to do something like this:

// create PanGestureInput
// dispatch to APZ via mAPZC->InputBridge()->ReceiveInputEvent()
// convert to WidgetWheelEvent using PanGestureInput::ToWidgetWheelEvent()
// dispatch to web content via `ProcessUntransformedAPZEvent()`

(The code would look very similar to nsBaseWidget::DispatchTouchInput(), except it would use a PanGestureInput. We can even introduce a new helper nsBaseWidget::DispatchPanGestureInput() for this purpose.)

(In reply to Botond Ballo [:botond] from comment #30)

generate events of type PanGestureInput, similarly to what we do for Mac touchpads. The advantage of this is that velocity tracking is already hooked up for these, so the only new piece we'd need to add to AsyncPanZoomController is the code to kick off a fling animation after a PANGESTURE_END event.

Yeah, that's kind of what I was thinking about when I was looking at Mac code. I was too scared to look deep into APZ though :D Now looking at the AsyncPanZoomController

So we need to basically do what HandleEndOfPan() does but inside OnPanEnd() when a flag is set indicating that the system won't supply fling events on its own (i.e. we're on Gtk, not Mac)? That makes sense, I'll try implementing this.

(In reply to greg from comment #31)

So we need to basically do what HandleEndOfPan() does but inside OnPanEnd() when a flag is set indicating that the system won't supply fling events on its own (i.e. we're on Gtk, not Mac)?

That's the idea, yes.

That makes sense, I'll try implementing this.

Thanks! Let me know if you run into any issues.

(In reply to Botond Ballo [:botond] from comment #32)

Thanks! Let me know if you run into any issues.

For some reason, I'm getting flings in the opposite direction. I have a spring-loaded Firefox now :D

I see that macOS code has negative deltas preciseDelta = ScreenPoint(-pixelDeltaX * scale, -pixelDeltaY * scale)

but if I do that, the scroll direction gets inverted, not the fling direction.

(In reply to greg from comment #33)

(In reply to Botond Ballo [:botond] from comment #32)

Thanks! Let me know if you run into any issues.

For some reason, I'm getting flings in the opposite direction. I have a spring-loaded Firefox now :D

I see that macOS code has negative deltas preciseDelta = ScreenPoint(-pixelDeltaX * scale, -pixelDeltaY * scale)

but if I do that, the scroll direction gets inverted, not the fling direction.

Might this be related to what OS added and called "natural scrolling" lately?

(In reply to Clément Lefèvre from comment #34)

Might this be related to what OS added and called "natural scrolling" lately?

I don't think so. Natural scrolling just reverses top and bottom globally, on all incoming events (wl_pointer.axis). It's completely transparent to applications, you might as well be holding the trackpad upside down. Just panning works fine anyway. It's something in APZ related to flings specifically.

Getting the direction right can be tricky. Let's step through it for a particular case, say moving the fingers upwards:

  • What is the sign of the displacement you populate into the PanGestureInput in nsWindow.cpp?
  • Does that match the value read here?
  • What is the sign of logicalPlanDisplacement here? That is the input to the velocity calculation.
  • What are startPoint and endPoint here? The delta between them is supposed to be the negation of logicalPanDisplacement, for reasons explained in the comment just above. This is what determines the direction of the actual scroll.
  • Finally, what is the sign of the velocity computed here (or in the code you copied from there)?

logicalPanDisplacement.y is always positive, flingVelocity comes out negative.

GDK x 2085.000000 y 927.000000 dx 0.000000 dy 2.755469
PhysPanDisp x 0.000000 y 2.755469
logPanDisp.x 0.000000
logPanDisp.y 2.755493
startPoint x 2085.000000 y 681.000000 endPoint x 2085.000000 y 678.244507
GDK x 2085.000000 y 927.000000 dx 0.000000 dy 3.815234
PhysPanDisp x 0.000000 y 3.815234
logPanDisp.x 0.000000
logPanDisp.y 3.815247
startPoint x 2085.000000 y 681.000000 endPoint x 2085.000000 y 677.184753
GDK x 2085.000000 y 927.000000 dx 0.000000 dy 5.113672
PhysPanDisp x 0.000000 y 5.113672
logPanDisp.x 0.000000
logPanDisp.y 5.113647
startPoint x 2085.000000 y 681.000000 endPoint x 2085.000000 y 675.886353
… (everything positive) …
GDK x 2085.000000 y 927.000000 dx 0.000000 dy 0.000000
PhysPanDisp x 0.000000 y 0.000000
logPanDisp.x 0.000000
logPanDisp.y 0.000000
startPoint x 2085.000000 y 681.000000 endPoint x 2085.000000 y 681.000000
flingVelocity x 0.000000 y -0.824520

Could it be time related? I currently have

PanGestureInput panEvent(eventType, aEvent->time, GetEventTimeStamp(aEvent->time), …);

because things like delta between last and current event were breaking fling, and it seems like other events are constructed using just raw aEvent->time

Oh, there's also this ScrollSnap thing I'm not really doing

Discussed the sign issue with Markus, and we agree the current code is wrong: the logical pan displacement should be subtracted here, not added.

The fact that we're adding it appears to be a regression introduced in bug 1457586.

WORK IN PROGRESS

Not yet done:

  • not screwing with systems where OS/UI framework sends the kinetic events (macOS)
  • dispatching scroll events to web content

// convert to WidgetWheelEvent using PanGestureInput::ToWidgetWheelEvent()
// dispatch to web content via ProcessUntransformedAPZEvent()

No clue if this was already on your radar, but it seems that when running as xwayland with xinput2 enabled, this patch doesn't enable kinetic scrolling. It seems the source device for me ends up being something other than GDK_SOURCE_TOUCHPAD (0, rather than 6) when checked.

If I run firefox in wayland mode (env GDK_BACKEND=wayland) then this patch does indeed work to enable kinetic scrolling.

I'm seeing the same behavior across kwin, mutter, and wlroots.

(In reply to Sawyer Bergeron from comment #42)

No clue if this was already on your radar, but it seems that when running as xwayland with xinput2 enabled, this patch doesn't enable kinetic scrolling. It seems the source device for me ends up being something other than GDK_SOURCE_TOUCHPAD (0, rather than 6) when checked.

Kinetic scrolling doesn't work under Xwayland in native GTK widgets either (I just tried Gedit).

(In reply to greg from comment #43)

Kinetic scrolling doesn't work under Xwayland in native GTK widgets either
(I just tried Gedit).
With Fedora 30 (freshly installed, without any changes) kinetic scrolling works well in gnome core applications.

(In reply to Helge Wiethoff from comment #44)

(In reply to greg from comment #43)
With Fedora 30 (freshly installed, without any changes) kinetic scrolling works well in gnome core applications.

They don't use Xwayland if you don't tell them to, they obviously default to running Wayland-native ;)

Try GDK_BACKEND=x11 gedit.

And vice versa, put Firefox into native mode MOZ_ENABLE_WAYLAND=1 firefox and kinetic scrolling will work with my patch.

Eventually Firefox will default to native, it just defaults to Xwayland for now because of outstanding bugs. See bug 1543600.

Is kinetic scrolling going to work if you don't use Wayland at all?

(In reply to Botond Ballo [:botond] from comment #46)

Is kinetic scrolling going to work if you don't use Wayland at all?

It does appear to work on an X only Gnome session for me.

(In reply to Sawyer Bergeron from comment #47)

(In reply to Botond Ballo [:botond] from comment #46)

Is kinetic scrolling going to work if you don't use Wayland at all?

It does appear to work on an X only Gnome session for me.

Yeah, makes sense, in "real" X (xorg-server), it should work if you use xf86-input-libinput as the input driver.

Might also require setting the MOZ_USE_XINPUT2=1 environment variable. Or not.

If anyone is still on xf86-input-synaptics for some reason (it's been deprecated), they won't be getting the precise scrolling events required for this, they're only getting wheel events, with fling simulated by the driver (decelerating mouse wheel… ugh)

(In reply to greg from comment #45)

And vice versa, put Firefox into native mode MOZ_ENABLE_WAYLAND=1 firefox and kinetic scrolling will work with my patch.
Nice. So i hope this will (In reply to greg from comment #45)

(In reply to Helge Wiethoff from comment #44)

(In reply to greg from comment #43)
With Fedora 30 (freshly installed, without any changes) kinetic scrolling works well in gnome core applications.

They don't use Xwayland if you don't tell them to, they obviously default to running Wayland-native ;)

Try GDK_BACKEND=x11 gedit.
Ah okay... Now i understand your previous post... Yes i can confirm this ;)

And vice versa, put Firefox into native mode MOZ_ENABLE_WAYLAND=1 firefox and kinetic scrolling will work with my patch.
I haven't compiled firefox by myself... I was hoping to see it someday in the published version :)

Thanks for your support. And for your patch of course!

I tested this patch in my machine the other day (ubuntu 19.04/gnome/xorg). It definitely works under xorg, but you do need to use MOZ_USE_XINPUT2=1

btw, it's so awesome to see this being worked on greg!

Pushed by bballo@mozilla.com:
https://hg.mozilla.org/integration/mozilla-inbound/rev/f9699ae30f4d
Implement kinetic/inertial scrolling (fling) for Gtk touchpads. r=botond,karlt
Status: NEW → RESOLVED
Closed: 5 years ago
Resolution: --- → FIXED
Target Milestone: --- → mozilla69
Assignee: nobody → greg

Greg, thanks a lot for your contribution here and your patience in seeing the review process through to its end!

Absolutely agree, Greg. Running the latest nightly with your contribution, and this one patch really makes Firefox feel like it belongs on Linux. Really nice!

Regressions: 1554365
Regressions: 1554456

I think we should probably back this change out until we get a handle on the two regressions. Does anyone have any objections?

Status: RESOLVED → REOPENED
Resolution: FIXED → ---

I know that the change is currently backed out, but when it was enabled it also caused bug 1554408 on a Wayland session.

I know that the change is currently backed out, but when it was enabled it also caused bug 1554408 on a Wayland session.

Added to regression list, so that we can verify when the patch is re-landed with proper fix.

Regressions: 1554408

The next step here is to go through the regressing bugs, and update the patch to address them. It seems like we have a theory for what caused each of them:

Once we have an updated patch, we'll want to verify that it fixes each of the regressing bugs prior to re-landing. If there are some you can't reproduce yourself, we can ask the bug's reporter to test a Try build.

Let me know if there's anything I can help with!

I could not reproduce bug 1554365 under Xwayland with or without XINPUT2, hopefully the mLastScrollEventTime was the reason indeed. I don't have a modern Mac either, so let's ask the reporter for that too.

Updated D27983 to Diff 111888 with the fixes. Big facepalm on the bitfields — I completely forgot that the constructor is a thing that's used here (and I wrote its invocation in the gtk code) and it does initialize fields — I was thinking of adding mSimulateMomentum = false to the Mac code when it hit me..

As the reporter of Bug 1554365, I can confirm the problem is fixed when using the build target in the above Try push.

As the reporter of Bug 1554456, I can confirm the problem is fixed when using the build target in the above Try push.

See also my last comment on the original ticket.

For me, bug 1554408 is still not fixed, unfortunately. I used the 'Linux x64 shippable opt', build id 20190529214050.

I'm not able to re-create any issue here with ubnuntu 18.04.2 on a dell xps 13 (using the built in touchpad). I launched firefox with GDK_BACKEND=wayland in a gnome wayland session and I have pixel perfect scrolling

does the kinetic scrolling work for you? (e.g. if you do a fling gesture)

Yes the kinetic scroll works. Also using the keyboard or a standard mouse scrollwheel result in smooth scrolling . Using the external trackpad, however, results in 'rough' scrolling. On the 'normal' nightly builds scrolling is smooth even when using the external trackpad.

Not sure why the results are different when using a built-in touchpad. Unfortunately I don't have access to a Linux-based laptop at the moment so can't test that myself.

I seem to be able to reproduce bug 1554408 on my machine on the integrated touchpad. This is a Dell XPS 15 9560 running arch. Kinetic scrolling works behind it all, but it seems like a double scrolling bug, as though legacy mouse wheel clicks are being sent and consumed on top of the smooth touch events. This varies in reproduceability between web pages, with pages like about:config not being affected but pages like the Wikipedia home page and articles being affected. This occurs on gnome (xorg and Wayland), sway, and kde on x (with this patch not being applicable to kde on Wayland at the moment). It seems to depend on a variety of factors just how severe it is, including page zoom and how fast I input a gesture.

Using firefox with wayland in Sway in a old Lenovo with synaptics, kinetic scrolling with inertia using 2 finger touchpad scroll works fine up to 25 May 2019 nightly build. Since 26 May included, there is not inertia more.

The only difference I'm seeing with the kinetic scrolling patch is that the 'smooth scrolling' preference doesn't have any effect (and I'm not sure you'd want it to with pixel perfect/kinetic scrolling enabled)

Do you guys have 'smooth scrolling' enabled under preferences?

If so, if you try a build without the kinetic scrolling patch, un-check smooth scrolling, but keep xinput 2 scrolling enabled, is that the same behavior you're talking about?

(In reply to Brandon Watkins from comment #69)

The only difference I'm seeing with the kinetic scrolling patch is that the 'smooth scrolling' preference doesn't have any effect (and I'm not sure you'd want it to with pixel perfect/kinetic scrolling enabled)

Do you guys have 'smooth scrolling' enabled under preferences?

If so, if you try a build without the kinetic scrolling patch, un-check smooth scrolling, but keep xinput 2 scrolling enabled, is that the same behavior you're talking about?

I think you might be on to something here. When using the 'try build' (id 20190529214050) the 'smooth scrolling' preference indeed has no effect on the 2-finger scroll gesture, it's never smooth. The preference does affect mouse wheel and keyboard scrolling which are not longer smooth when 'smooth scrolling' is disabled.

When disabling smooth scrolling in the latest nightly build, the behaviour of a 2-finger scroll gesture is very similar to that of the 'try build', just without the kinetic effect. In addition, no matter which method you choose (2-finger gesture, mouse wheel or keyboard) they all result in a 'rough' scroll.

To summarize, it seems that the 'smooth scrolling' preference indeed has no effect on the 2-finger gesture in the 'try build'.

I tested that in a GNOME shell Wayland session, running Firefox with Wayland enabled (GDK_BACKEND=wayland).

(In reply to zeubea from comment #68)

Using firefox with wayland in Sway in a old Lenovo with synaptics, kinetic scrolling with inertia using 2 finger touchpad scroll works fine up to 25 May 2019 nightly build. Since 26 May included, there is not inertia more.

Yes, the patch has been backed out due to regressions :( Look above in this thread, I've posted an updated patch, hopefully will be merged again soon.

(In reply to Yariv from comment #70)

When disabling smooth scrolling in the latest nightly build, the behaviour of a 2-finger scroll gesture is very similar to that of the 'try build', just without the kinetic effect. In addition, no matter which method you choose (2-finger gesture, mouse wheel or keyboard) they all result in a 'rough' scroll.

To summarize, it seems that the 'smooth scrolling' preference indeed has no effect on the 2-finger gesture in the 'try build'.

Yes, "smooth scrolling" is exclusively about wheels/keyboards — a more accurate name for it would be "simulate smoothness by interpolating pixel-precise events from line scrolling events" or something. Touchpads that deliver pixel-precise events are by definition always smooth.

However, you say that your external touchpad is rough AND does get the kinetic scrolling?! That sounds very odd..

Please post the output of sudo libinput list-devices and sudo libinput list-devices (for the latter, after running the command, do some two-finger scrolls and abort with Ctrl-C).

err, sudo libinput debug-events of course

(In reply to greg v [:myfreeweb] from comment #72)

err, sudo libinput debug-events of course

libinput list-devices:

Device:           Microsoft Microsoft IntelliMouse® Optical
Kernel:           /dev/input/event4
Group:            5
Seat:             seat0, default
Capabilities:     pointer 
Tap-to-click:     n/a
Tap-and-drag:     n/a
Tap drag lock:    n/a
Left-handed:      disabled
Nat.scrolling:    disabled
Middle emulation: disabled
Calibration:      n/a
Scroll methods:   button
Click methods:    none
Disable-w-typing: n/a
Accel profiles:   flat *adaptive
Rotation:         n/a

Device:           john’s Trackpad
Kernel:           /dev/input/event20
Group:            7
Seat:             seat0, default
Size:             132x112mm
Capabilities:     pointer gesture
Tap-to-click:     disabled
Tap-and-drag:     enabled
Tap drag lock:    disabled
Left-handed:      disabled
Nat.scrolling:    disabled
Middle emulation: disabled
Calibration:      n/a
Scroll methods:   *two-finger edge 
Click methods:    button-areas *clickfinger 
Disable-w-typing: n/a
Accel profiles:   none
Rotation:         n/a

"john’s Trackpad" is my external Apple Trackpad. Yep that's how I named it, long story.
I omitted irrelevant devices.

libinput debug-events:

-event4   DEVICE_ADDED     Microsoft Microsoft IntelliMouse® Optical seat0 default group5  cap:p left scroll-nat scroll-button
-event5   DEVICE_ADDED     Apple Inc. Apple Keyboard         seat0 default group6  cap:k
-event6   DEVICE_ADDED     Apple Inc. Apple Keyboard         seat0 default group6  cap:k
-event20  DEVICE_ADDED     john’s Trackpad                 seat0 default group7  cap:pg  size 132x112mm tap(dl off) left scroll-nat scroll-2fg-edge click-buttonareas-clickfinger

again, omitted irrelevant devices.

About the trackpad, in the gnome-control-center it's configured to enable natural scrolling, tap-to-click and two-finger scrolling. 'Edge Scrolling' is disabled.

I also tried to do a short vertical 2-finger scroll gesture, got the following:

 event20  POINTER_AXIS      +3.44s	vert 0.81* horiz -0.32* (finger)
 event20  POINTER_AXIS      +3.45s	vert 0.81* horiz -0.16* (finger)
 event20  POINTER_AXIS      +3.46s	vert 0.81* horiz -0.32* (finger)
 event20  POINTER_AXIS      +3.47s	vert 0.81* horiz -0.16* (finger)
 event20  POINTER_AXIS      +3.48s	vert 0.32* horiz -0.16* (finger)
 event20  POINTER_AXIS      +3.49s	vert 0.65* horiz -0.32* (finger)
 event20  POINTER_AXIS      +3.50s	vert 0.32* horiz -0.16* (finger)
 event20  POINTER_AXIS      +3.51s	vert 0.32* horiz -0.16* (finger)
 event20  POINTER_AXIS      +3.52s	vert 0.32* horiz -0.16* (finger)
 event20  POINTER_AXIS      +3.54s	vert 0.32* horiz -0.16* (finger)
 event20  POINTER_AXIS      +3.55s	vert 0.00 horiz -0.16* (finger)

this is of course just a snippet.

(In reply to greg v [:myfreeweb] from comment #71)

Yes, "smooth scrolling" is exclusively about wheels/keyboards — a more accurate name for it would be "simulate smoothness by interpolating pixel-precise events from line scrolling events" or something. Touchpads that deliver pixel-precise events are by definition always smooth.

Except the scrolling in the current nightly feels much better with smooth scrolling enabled than with it disabled.
So "smooth scrolling" still applies some filtering to precise-scrolling touchpads that's missing from the kinetic-scroll path.

(In reply to Jan Alexander Steffens [:heftig] from comment #74)

Except the scrolling in the current nightly feels much better with smooth scrolling enabled than with it disabled.
So "smooth scrolling" still applies some filtering to precise-scrolling touchpads that's missing from the kinetic-scroll path.

If smooth scrolling makes a difference, you are NOT getting precise events in Firefox, period.

Either you're running on X11 without MOZ_USE_XINPUT2 set, or on X11 with a legacy driver (e.g. xf86-input-synaptics) that emits wheel events, or something else is screwed up somehow.

(In reply to Yariv from comment #73)

I also tried to do a short vertical 2-finger scroll gesture, got the following:

That looks fine. I'm not sure how you're getting "rough" scrolling in a GNOME Wayland session with that.

(In reply to greg v [:myfreeweb] from comment #75)

(In reply to Jan Alexander Steffens [:heftig] from comment #74)

Except the scrolling in the current nightly feels much better with smooth scrolling enabled than with it disabled.
So "smooth scrolling" still applies some filtering to precise-scrolling touchpads that's missing from the kinetic-scroll path.

If smooth scrolling makes a difference, you are NOT getting precise events in Firefox, period.

Either you're running on X11 without MOZ_USE_XINPUT2 set, or on X11 with a legacy driver (e.g. xf86-input-synaptics) that emits wheel events, or something else is screwed up somehow.

(In reply to Yariv from comment #73)

I also tried to do a short vertical 2-finger scroll gesture, got the following:

That looks fine. I'm not sure how you're getting "rough" scrolling in a GNOME Wayland session with that.

Hi Greg, on my machine I end up also having a difference between smooth scroll being turned on or left off even with precise events with Xinput 2 turned on. Scrolling is controllable down to the pixel, but with smooth scrolling turned on it is just made more sluggish (still maintaining smooth events)

I can also reproduce the "jagged scrolling" bug on my machine with the provided patch applied, not sure if they're related.

(In reply to Sawyer Bergeron from comment #76)

Hi Greg, on my machine I end up also having a difference between smooth scroll being turned on or left off even with precise events with Xinput 2 turned on. Scrolling is controllable down to the pixel, but with smooth scrolling turned on it is just made more sluggish (still maintaining smooth events)

hm, wait — without the patch, they are turned into wheel events internally, so they might still be affected. But with the patch, you absolutely should not see a difference.

(In reply to greg v [:myfreeweb] from comment #77)

(In reply to Sawyer Bergeron from comment #76)

Hi Greg, on my machine I end up also having a difference between smooth scroll being turned on or left off even with precise events with Xinput 2 turned on. Scrolling is controllable down to the pixel, but with smooth scrolling turned on it is just made more sluggish (still maintaining smooth events)

hm, wait — without the patch, they are turned into wheel events internally, so they might still be affected. But with the patch, you absolutely should not see a difference.

Come to think of it I didn't yet test turning on and off smooth scrolling with this patch, I'll verify later but that would make sense that it should no longer happen.

I have a suspicion that there's not really a 'bug' here, rather some users are used to the smooth scrolling effect being applied on top of xinput2 scrolling... with the patch, the smooth scrolling pref's effect is no longer there (when using xinput2), so the scrolling (ignoring the kinetic scrolling effect) feels different to those users.

There is potentially (some) merit to having some kind of additional smoothing on top of precise scrolling. With xinput2 the scrolling is pixel precise, so it is smooth if your finger's motion across the touchpad is smooth... but if your finger's motion across the touchpad is not smooth (e.g. if your touchpad doesn't have a particularly smooth surface and your fingers skip as you move them across it) those imperfections are noticed in the scroll.

The smooth scroll pref did have the effect of smoothing out those imperfections with your scroll motion, but personally I always kept it disabled when using xinput2 scrolling because I didn't think it was worth the increase in input latency (and the xinput2 scrolling was 'smooth enough for me; certainly far smoother than scrolling in steps like with xinput2 disabled)

In any case, IMO having kinetic scrolling is vastly more important than having some faux smooth scrolling being applied on top of already pixel precise scrolling...

(In reply to Brandon Watkins from comment #79)

I have a suspicion that there's not really a 'bug' here, rather some users are used to the smooth scrolling effect being applied on top of xinput2 scrolling... with the patch, the smooth scrolling pref's effect is no longer there (when using xinput2), so the scrolling (ignoring the kinetic scrolling effect) feels different to those users.

There is potentially (some) merit to having some kind of additional smoothing on top of precise scrolling. With xinput2 the scrolling is pixel precise, so it is smooth if your finger's motion across the touchpad is smooth... but if your finger's motion across the touchpad is not smooth (e.g. if your touchpad doesn't have a particularly smooth surface and your fingers skip as you move them across it) those imperfections are noticed in the scroll.

The smooth scroll pref did have the effect of smoothing out those imperfections with your scroll motion, but personally I always kept it disabled when using xinput2 scrolling because I didn't think it was worth the increase in input latency (and the xinput2 scrolling was 'smooth enough for me; certainly far smoother than scrolling in steps like with xinput2 disabled)

In any case, IMO having kinetic scrolling is vastly more important than having some faux smooth scrolling being applied on top of already pixel precise scrolling...

Due to some reason I'm not getting pixel-perfect accuracy on my setup. I have to barely move the fingers in order to get small scrolling movement, and even then it usually moves the content by what seems to be at least multiplies of 2 pixels, maybe more. Sometimes it just doesn't register the move at first, then 'jumps' by what seems to be about 10 pixels when it does.

Moreover, regardless of the speed I move my fingers, any scroll feels very jaggy compared to a nightly version without the kinetic scroll patch. Is there some internal multiplier? Or maybe it's an 'Apple External Trackpad' specific behaviour... I'm running Firefox in Wayland mode on a bog-standard Ubuntu 18.04 GNOME Shell Wayland session, so the only thing that comes to mind is some 'special' treatment of the trackpad.

In any case I see no problem with enabling both kinetic scrolling and a smoothing filter, so we can get the better of both worlds.

Forgot to mention that I have WebRender enabled on my machine. Without WebRender it's harder to see the difference in scrolling smoothness since even the nightly without the kinetic patch is not that smooth. See bug 1545927 for more details.

(In reply to Yariv from comment #80)

Due to some reason I'm not getting pixel-perfect accuracy on my setup. I have to barely move the fingers in order to get small scrolling movement, and even then it usually moves the content by what seems to be at least multiplies of 2 pixels, maybe more.

Well, 2 pixels is almost precise.

Sometimes it just doesn't register the move at first, then 'jumps' by what seems to be about 10 pixels when it does.

Looks like you have a performance problem that is not related to scrolling specifically.

Moreover, regardless of the speed I move my fingers, any scroll feels very jaggy compared to a nightly version without the kinetic scroll patch. Is there some internal multiplier? Or maybe it's an 'Apple External Trackpad' specific behaviour... I'm running Firefox in Wayland mode on a bog-standard Ubuntu 18.04 GNOME Shell Wayland session, so the only thing that comes to mind is some 'special' treatment of the trackpad.

I have an Apple Magic Trackpad as well (however on FreeBSD with a userspace driver I modified), on Wayfire (wlroots based compositor). The patch has been developed with that trackpad :)

In any case I see no problem with enabling both kinetic scrolling and a smoothing filter, so we can get the better of both worlds.

The "filter" is applied (somewhere deep in Firefox) to WheelEvent, not PanGestureEvent. It's specifically designed for wheels/keys that scroll by lines. It does not apply to 2-finger pan gestures, by design. It is not applied to them on macOS and it won't be applied here.

(In reply to greg v [:myfreeweb] from comment #75)

If smooth scrolling makes a difference, you are NOT getting precise events in Firefox, period.

Wrong; I can scroll pixel by pixel moving my fingers very slowly. This is independent of the smooth scrolling setting.

Either you're running on X11 without MOZ_USE_XINPUT2 set, or on X11 with a legacy driver (e.g. xf86-input-synaptics) that emits wheel events, or something else is screwed up somehow.

Actually, I'm on Wayland. Behavior is the same as on X11 with MOZ_USE_XINPUT2.

(In reply to greg v [:myfreeweb] from comment #71)

Yes, "smooth scrolling" is exclusively about wheels/keyboards — a more accurate name for it would be "simulate smoothness by interpolating pixel-precise events from line scrolling events" or something.

It's not really interpolating anything. It's just taking the destination of the scroll (e.g. "1 line below current position"), and instead of jumping to it immediately, an animation is launched which follows a predefined curve to take you to the destination over several frames. If another event is received while the animation is in progress, the animation's destination is updated and the current position along the curve is recomputed.

For this reason...

(In reply to Yariv from comment #80)

In any case I see no problem with enabling both kinetic scrolling and a smoothing filter, so we can get the better of both worlds.

... it's not just a matter of "enabling a filter". Pan gesture events (which is what Greg's patch switches to using, instead of wheel events, and which is what enables kinetic scrolling) have never been hooked up to trigger animations the way wheel events do with smooth scrolling (mostly because trackpads generally send events frequently enough that there's no point). We could conceivably try to hook that up, but it would involve additional work beyond what Greg's patch currently does, and it would be an unknown in terms of the impact it would have given the variety of trackpads out there.

I wonder if the issue is that some trackpads or trackpad + driver combinations do not generate events often enough, or generate events that are not precise enough, to feel smooth with instant scrolling (no animations). If so, the next question would be whether we can identify such trackpads programatically, and make our behaviour conditional on them.

(In reply to Botond Ballo [:botond] from comment #84)

(In reply to Yariv from comment #80)
I wonder if the issue is that some trackpads or trackpad + driver combinations do not generate events often enough, or generate events that are not precise enough, to feel smooth with instant scrolling (no animations). If so, the next question would be whether we can identify such trackpads programatically, and make our behaviour conditional on them.

Well on my setup scrolling definitely doesn't feel smooth with the kinetic patch applied. I attached a short snippet of events captured using libinput debug-events in comment #73, so that can serve as one data point. If necessary I can generate more captures.

If so, the next question would be whether we can identify such trackpads programatically, and make our behaviour conditional on them.

I'm wondering if it'd be better to have a pref option so that it turns on by default, but user can choose to turn off if they encounter problems or don't want this feature for some reason.

(In reply to violet.bugreport from comment #86)

If so, the next question would be whether we can identify such trackpads programatically, and make our behaviour conditional on them.

I'm wondering if it'd be better to have a pref option so that it turns on by default, but user can choose to turn off if they encounter problems or don't want this feature for some reason.

An about:config option would certainly be easy to put in place. However, it's not very discoverable: a user who runs into this issue would probably only learn about it if they file a bug (as you did). Another user who is not inclined to file a bug may just suffer in silence or switch to a different browser.

An about:preferences option would be more discoverable, but it requires UX approval, and the bar for approving new options for about:preferences is fairly high (in terms of how often it's likely to be used) because the UX team does not want that page to be too crowded with uncommon options.

This is why just automatically figuring out what the better thing to do, would be ideal. However, if we can't figure out such a way, we could consider falling back to an about:config option.

GTK itself doesn't have an option to reinterpret pan events as legacy wheel events for the native GTK scrollables. WebKitGTK doesn't have that either. So I don't think Firefox should. There is no better thing to do.

(By the way, I don't think Yariv mentioned how scrolling behaves in gtk3-demo and epiphany.)

Comment 67 is interesting:

seems like a double scrolling bug, as though legacy mouse wheel clicks are being sent and consumed on top of the smooth touch events

though the fix for bug 1554365 was supposed to fix the old problem of legacy events again.

// By the way: smooth scrolling was already not supposed to be applied for touchpads. See the "This next step manually unsets smooth scrolling for touch devices" comment before setting SCROLL_ASYNCHRONOUSELY. Smooth was (is) applied unintentionally without my patch because APZ ignores SCROLL_ASYNCHRONOUSELY.

(In reply to greg v [:myfreeweb] from comment #88)

GTK itself doesn't have an option to reinterpret pan events as legacy wheel events for the native GTK scrollables. WebKitGTK doesn't have that either. So I don't think Firefox should. There is no better thing to do.

What resolution would you suggest for bug 1554408, then?

(In reply to greg v [:myfreeweb] from comment #88)

(By the way, I don't think Yariv mentioned how scrolling behaves in gtk3-demo and epiphany.)

Just tested both the gtk3-demo (the 'Text View' -> 'Multiple Views' is pretty good for that) as well as the epiphany web browser. Indeed scrolling is not smooth on these apps either. GEdit behaves the same so that's probably a GTK trait.

I wonder if it's some kind of an over-aggressive acceleration profile on the trackpad, an issue of lost movement messages (because bluetooth) or maybe this is the expected behaviour.

I think that 'smoothness' is pretty important. Considering that Google put a lot of effort into making the Android UI smooth, I'm probably not alone in this... Google used to call that 'Project Butter', debuted in Android 4.1 "Jelly Beans". You can read about that here: https://www.androidpolice.com/2012/07/12/getting-to-know-android-4-1-part-3-project-butter-how-it-works-and-what-it-added/

Anyway I'll open a bug on the GTK bug tracker.

(In reply to Yariv from comment #90)

Just tested both the gtk3-demo (the 'Text View' -> 'Multiple Views' is pretty good for that) as well as the epiphany web browser. Indeed scrolling is not smooth on these apps either. GEdit behaves the same so that's probably a GTK trait.
I wonder if it's some kind of an over-aggressive acceleration profile on the trackpad, an issue of lost movement messages (because bluetooth) or maybe this is the expected behaviour.

Maybe a driver issue or a compositor (gnome shell) issue. Or an issue with your expectations :)

The Apple Magic Trackpad definitely has a very high scrolling speed out of the box. I have a scrolling speed multiplier in my compositor (Wayfire) and I keep it at around 0.5. But even testing with 2.0 (extreme speeeeed) it's not what I'd describe as "not smooth". Very tiny finger movements do cause a jump, but that feels okay. Continuous scrolling is buttery smooth even with high speed.

// I added logging to D27983 anyway, run with MOZ_LOG=Widget:4 to get info about events like this:

[Parent 25713: Main Thread]: D/Widget [6275831] from device 'Wayland Finger Scrolling' type 6..
[Parent 25713: Main Thread]: D/Widget [6275831] pan smooth evt dx=0.000000 dy=-0.105078 inprogress=0
[Parent 25713: Main Thread]: D/Widget [6275831] is start
…
[Parent 25713: Main Thread]: D/Widget [6276045] from device 'Wayland Finger Scrolling' type 6..
[Parent 25713: Main Thread]: D/Widget [6276045] pan smooth evt dx=0.000000 dy=0.000000 inprogress=1
[Parent 25713: Main Thread]: D/Widget [6276045] is stop

This is more to test the suggestion in Comment 67 about potential duplicate legacy events. I doubt that they are happening though.

(In reply to Yariv from comment #90)

Anyway I'll open a bug on the GTK bug tracker.

Can you post a link here once you do that? :)

(In reply to Asif Youssuff from comment #93)

Can you post a link here once you do that? :)

Sure, but it'll probably take me a couple of days.

Target Milestone: mozilla69 → ---

I don't have a good enough internet connection to download and build that try for myself but if treeherder is able to provide the binary created from that try I'm happy to test it and see what's going on on my machine at the least with the jumpy scrolling.

You can get a binary by clicking the B next to Linux x64 opt | click Job Details | click target.tar.bz2

Just ran the latest try,

I honestly have no clue what could be going on. It seems that adjusting scaling and resolution on gnome changes how drastic the jumpiness of the scrolling is, but everything is smooth as butter under sway. There's definitely something going wrong on plain gnome wayland session for me, but it's quite possible it isn't related to this particular patch.

Do you see the same issue in native GTK3 apps? (e.g. Epiphany, Gedit, Nautilus)

What about firefox without this patch (with smooth scrolling pref disabled)?

Might just be the general poor performance of gnome's compositor resulting in missed frames

Attached file touchpadScroll.log (deleted) —

(In reply to greg v [:myfreeweb] from comment #91)

The Apple Magic Trackpad definitely has a very high scrolling speed out of the box. I have a scrolling speed multiplier in my compositor (Wayfire) and I keep it at around 0.5. But even testing with 2.0 (extreme speeeeed) it's not what I'd describe as "not smooth". Very tiny finger movements do cause a jump, but that feels okay. Continuous scrolling is buttery smooth even with high speed.

// I added logging to D27983 anyway, run with MOZ_LOG=Widget:4 to get info about events like this:

[Parent 25713: Main Thread]: D/Widget [6275831] from device 'Wayland Finger Scrolling' type 6..
[Parent 25713: Main Thread]: D/Widget [6275831] pan smooth evt dx=0.000000 dy=-0.105078 inprogress=0
[Parent 25713: Main Thread]: D/Widget [6275831] is start
…
[Parent 25713: Main Thread]: D/Widget [6276045] from device 'Wayland Finger Scrolling' type 6..
[Parent 25713: Main Thread]: D/Widget [6276045] pan smooth evt dx=0.000000 dy=0.000000 inprogress=1
[Parent 25713: Main Thread]: D/Widget [6276045] is stop

This is more to test the suggestion in Comment 67 about potential duplicate legacy events. I doubt that they are happening though.

I ran the latest 'try build'. The relevant part of the log is attached in comment 99.
Scrolling is not smooth, so nothing changed here.

Btw I checked again the behaviour of GNOME apps (Epiphany, GEdit etc). Epiphany behaves in a way similar to the way Firefox with the kinetic scroll patch behaves. However Epiphany is suffering less from 'scroll jump' when scrolling slowly. GEdit has similar behaviour with the trackpad, however the developers have implemented smooth keyboard scrolling for GEdit, whereas for Epiphany they apparently haven't.

I found this: https://pavelfatin.com/scrolling-with-pleasure/
I think it's a must-read for anyone trying to implement sane scrolling behaviour.

The author goes into great detail regarding precision, smoothness, and why they are not directly tied. This is just a small part of the pretty technical article. It's a long read but definitely worth the time.

What's the status of the patch now?

IIUC the one remaining bug seems to be a system level problem on certain machines rather than a bug in this patch. Is it ok to land the patch now or at least land it behind a pref so that interested Nightly users can keep using/testing this feature?

(In reply to violet.bugreport from comment #102)

What's the status of the patch now?

I was hoping someone would suggest a way to automatically detect trackpads for which we should keep the old behaviour (as per comment 87), but perhaps there is no good way to do that.

IIUC the one remaining bug seems to be a system level problem on certain machines rather than a bug in this patch. Is it ok to land the patch now or at least land it behind a pref so that interested Nightly users can keep using/testing this feature?

Sure. Greg, would you like to update the patch to put the new functionality behind a pref? It would involve adding a new entry to StaticPrefList.h (we can call it something like apz.gtk_kinetic_scroll.enabled) and then adding a call to the corresponding function (StaticPrefs::APZGTKKineticScrollEnabled()) as a condition of our new codepath in nsWindow.cpp. We can then consider enabling it by default in a separate patch.

(In reply to greg v [:myfreeweb] from comment #88)

// By the way: smooth scrolling was already not supposed to be applied for touchpads. See the "This next step manually unsets smooth scrolling for touch devices" comment before setting SCROLL_ASYNCHRONOUSELY. Smooth was (is) applied unintentionally without my patch because APZ ignores SCROLL_ASYNCHRONOUSELY.

Hmm... maybe just leave this unintentional behaviour as-is. Apply the 'smoothing' to precise events and we get both smooth and kinetic scroll?

(In reply to Yariv from comment #104)

Hmm... maybe just leave this unintentional behaviour as-is. Apply the 'smoothing' to precise events and we get both smooth and kinetic scroll?

It's not possible to "just leave" it.

Again: smoothing was applied because touchpad pan events from GTK were converted to MOUSE WHEEL events in Firefox AND the scroll engine of Firefox was ignoring the instruction to NOT smooth that was set.

Kinetic scrolling is achieved by properly reading pan events as pan events, for which Firefox DOES NOT implement smoothing, for good reason: it just adds latency and does not improve anything unless something is really broken.

And...

(In reply to Sawyer Bergeron from comment #97)

It seems that adjusting scaling and resolution on gnome changes how drastic the jumpiness of the scrolling is, but everything is smooth as butter under sway.

...it honestly seems like gnome-shell/mutter is broken. Or just slow?

(In reply to greg v [:myfreeweb] from comment #105)

Again: smoothing was applied because touchpad pan events from GTK were converted to MOUSE WHEEL events in Firefox AND the scroll engine of Firefox was ignoring the instruction to NOT smooth that was set.

Yep, I got that the first time you said that. However something here doesn't make sense. When I use the latest 'stable' release, which is v67.0.2 right now, indeed using the touchpad for scrolling has a minimal scroll distance which is identical to the scroll distance of a single mousewheel slick.

However on the latest nightly this is not the case. Both the guy from comment 83 and myself are getting precise scroll, which is also smooth. Please correct me if I'm wrong, but If the events were indeed converted to mouse wheel events we wouldn't be able to achieve precise scroll in the latest nightly.

(In reply to Yariv from comment #106)

Please correct me if I'm wrong, but If the events were indeed converted to mouse wheel events we wouldn't be able to achieve precise scroll in the latest nightly.

Wheel type does not imply line unit! In Firefox, wheel events can be precise, that's how precise scrolling is happening without this patch.

(By the way, mice with high precision wheels exist already.. support is being worked on in various places e.g. https://github.com/swaywm/wlroots/issues/1627 )

I'm not sure about stable – is it running natively on Wayland? Is Wayland support enabled in stable already?

(In reply to greg v [:myfreeweb] from comment #107)

Wheel type does not imply line unit! In Firefox, wheel events can be precise, that's how precise scrolling is happening without this patch.

Ah ok, now it all makes sense, thanks.

I'm not sure about stable – is it running natively on Wayland? Is Wayland support enabled in stable already?

Sorry for the confusion - I ran the stable version under 'XWayland'. Under Wayland (or XWayland with XINPUT2 enabled) it behaves the same as the latest nightly.

Hi there,

This is an enormous thread. Could someone familiar with it summarize what support has landed where and what issues there are? I'd love to test this out but I am unable to track four years of conversation.

Thank you very much
-Gus

Nothing has landed yet, but support for kinetic scrolling should land behind a pref soon. Stay tuned! The bug's status will change to "RESOLVED FIXED" when the patch lands in Nightly.

Pushed by bballo@mozilla.com:
https://hg.mozilla.org/integration/mozilla-inbound/rev/d9f7c87aa3b4
implement kinetic/inertial scrolling (fling) for Gtk. r=botond
Status: REOPENED → RESOLVED
Closed: 5 years ago5 years ago
Resolution: --- → FIXED
Target Milestone: --- → mozilla69
Depends on: 1560536
User Story: (updated)

good to see this back, the kinetic scrolling is working great with the pref enabled here!

Depends on: 1562101
Depends on: 1562363
Blocks: 1564238

(In reply to Asif Youssuff from comment #93)

Can you post a link here once you do that? :)

Took me a while, but anyway: https://gitlab.gnome.org/GNOME/gtk/issues/2025

I'm very excited that this finally works, but I have one complaint: once a two-finger fling has begun, I expected that touching the trackpad again with two fingers would stop the fling immediately, like on macOS (I see from bug 1554456 that this briefly regressed, but that looks fixed now). Instead, it seems that I have to actually scroll a little bit to stop it. Are there strong arguments for doing it this way instead of the macOS way?

(Yes, GTK apps like gedit do seem to exhibit the same behavior. But they carry that principle even further by continuing the fling even after a click has been registered, which can result in fling-selected text. Why anyone would want that is beyond me, but that's a different conversation. Firefox much more sensibly stops the fling immediately on click. Can Firefox be even more sensible and also stop the fling on touch?)

(In reply to Ryan Hendrickson [rhendric on GitLab, GitHub] from comment #115)

I'm very excited that this finally works, but I have one complaint: once a two-finger fling has begun, I expected that touching the trackpad again with two fingers would stop the fling immediately, like on macOS (I see from bug 1554456 that this briefly regressed, but that looks fixed now). Instead, it seems that I have to actually scroll a little bit to stop it. Are there strong arguments for doing it this way instead of the macOS way?

(Yes, GTK apps like gedit do seem to exhibit the same behavior. But they carry that principle even further by continuing the fling even after a click has been registered, which can result in fling-selected text. Why anyone would want that is beyond me, but that's a different conversation. Firefox much more sensibly stops the fling immediately on click. Can Firefox be even more sensible and also stop the fling on touch?)

See Libinput bug 300 [https://gitlab.freedesktop.org/libinput/libinput/issues/300]

Libinput doesn't currently support sending any such "tentative start interaction" event so any fix for that behavior would be blocked on libinput adding support for it. So far feedback on adding it is positive (no significant objections to adding it) but it will require a few standards changes and waiting for the next release (current one is feature frozen during RC period)

(In reply to Yariv from comment #114)

Took me a while, but anyway: https://gitlab.gnome.org/GNOME/gtk/issues/2025

Thanks! Watching it now. :)

(In reply to Ryan Hendrickson [rhendric on GitLab, GitHub] from comment #115)

I'm very excited that this finally works, but I have one complaint: once a two-finger fling has begun, I expected that touching the trackpad again with two fingers would stop the fling immediately, like on macOS (I see from bug 1554456 that this briefly regressed, but that looks fixed now). Instead, it seems that I have to actually scroll a little bit to stop it. Are there strong arguments for doing it this way instead of the macOS way?

(Yes, GTK apps like gedit do seem to exhibit the same behavior. But they carry that principle even further by continuing the fling even after a click has been registered, which can result in fling-selected text. Why anyone would want that is beyond me, but that's a different conversation. Firefox much more sensibly stops the fling immediately on click. Can Firefox be even more sensible and also stop the fling on touch?)

I agree, touching the trackpad with two fingers should stop the fling. Could you please file a new bug about that?

(In reply to Sawyer Bergeron from comment #116)

Libinput doesn't currently support sending any such "tentative start interaction" event so any fix for that behavior would be blocked on libinput adding support for it.

For me, when I touch the trackpad with two fingers during a fling, the fling continues, but a context menu also appears. The context menu appearing suggests that Firefox does receive an event of some sort. If we receive an event, we should be able to react to it and do things like stop the fling.

(In reply to Botond Ballo [:botond] from comment #118)

(In reply to Sawyer Bergeron from comment #116)

Libinput doesn't currently support sending any such "tentative start interaction" event so any fix for that behavior would be blocked on libinput adding support for it.

For me, when I touch the trackpad with two fingers during a fling, the fling continues, but a context menu also appears. The context menu appearing suggests that Firefox does receive an event of some sort. If we receive an event, we should be able to react to it and do things like stop the fling.

Ah, the context menu appears when the fingers are lifted after touching down. So perhaps you're right, and we don't receive anything when the fingers touch down.

Still, it's worth filing a new bug about this. Even if we need to wait for a libinput enhancement, we'll want to test the behaviour with that and evaluate if any changes are required on the Firefox side.

Looks like someone suggested basically sending a scroll event with zero delta in that libinput bug report so if that happens everything should basically "just work" AFAIK. Libinput maintainer is considering whether that will work. A bug report for it here is probably a good idea though regardless of which path is taken.

(In reply to Yariv from comment #114)

Took me a while, but anyway: https://gitlab.gnome.org/GNOME/gtk/issues/2025

Just in case anyone was curious about the Apple trackpad issue, turns out that the culprit is the rate of input events. Apple external trackpads emit about 90 events per second. Since the screen refresh rate is usually 60Hz, that gives us on average 1.5 input events per frame. So for example we get 1 input event on the first frame, 2 on the second, 1 on the third, 2 on the fourth etc. If, say, all input events were of a 4 pixels scroll, that would translate to 4px on the first frame, 8px on the second, 4px on the third, 8px on the fourth etc. etc. That results in a visibly jittery scroll.

The same thing actually happens on internal touchpads as well. However internal touchpads commonly have event rate of about 125Hz so almost all display frames receive 2 input events, and the for the 5 frames that receive an extra input event each second, the difference from the other frames is less severe. So people hardly notice the problem with internal touchpads.

Note that this problem is endemic to the whole GNOME stack - it affects GNOME Shell, Mutter, GTK etc. In fact as far as I'm aware it affects all of the Linux desktop environments (KDE, Sway, etc). However, as stated above, it's mostly noticeable in certain setups.

As for Firefox, IIUC it doesn't make use of the high-level GTK widgets such as GtkScrolledWindow for the content window. Rather Firefox is using custom widgets which interact directly with GDK. Since any solution for the "input event to screen refresh rate mismatch" will take a while to get implemented and will probably be implemented in GTK rather than GDK, I tend to think that supporting some form of smooth scroll in Firefox might make sense.

Considering that Firefox already has a smooth scroll animation implementation, as well as a UI for enabling smooth scrolling in the about:preferences page, maybe it should just be wired so that when the smooth scroll setting is enabled, accurate touch events will go through that animation machinery? Obviously the original events will have to be used for calculating the kinetic scroll initial velocity, but that shouldn't be hard to do.

FWIW, on Ubuntu 19.04, GNOME Web (epiphany browser) uses Webkit's implementation of both smooth and kinetic scrolling, and it works pretty well for the external trackpad.

Blocks: 1573188
Blocks: 1568722

(In reply to greg v [:myfreeweb] from comment #43)

(In reply to Sawyer Bergeron from comment #42)

No clue if this was already on your radar, but it seems that when running as xwayland with xinput2 enabled, this patch doesn't enable kinetic scrolling. It seems the source device for me ends up being something other than GDK_SOURCE_TOUCHPAD (0, rather than 6) when checked.

Kinetic scrolling doesn't work under Xwayland in native GTK widgets either (I just tried Gedit).

I think that I found out why kinetic scroll doesn't work under xwayland. The 'scroll stop' event is simply not emitted. I filed a bug report here: https://gitlab.freedesktop.org/xorg/xserver/issues/926

With the hack mentioned in the bug report, kinetic scroll is working for GTK apps. However it still doesn't work for Firefox - maybe because the source device is not GDK_SOURCE_TOUCHPAD, as mentioned above (didn't check).

You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: