Menu

#1901 Trackpad two-finger "wheel" scrolling broken on GTK3 + Wayland

Bug
closed-fixed
5
2017-03-21
2017-01-17
No

Version:

SciTE
Version 3.7.2 compiled for GTK+ 3.22.5
    Jan 17 2017 13:57:52

When built for GTK3 and running on Wayland, Scintilla seems to drop or otherwise not obey scrollwheel scrolling (in my specific case, actually two-finger scrolling on a trackpad).

With WAYLAND_DEBUG=1, the scroll events seem to be reported, as a bunch of this is dumped when trying to scroll:

[4291199.179] wl_pointer@8.frame()
[4291286.013] wl_pointer@8.axis_source(1)
[4291286.031] wl_pointer@8.axis(109819824, 0, 0.273438)
[4291286.038] wl_pointer@8.frame()
[4291303.554] wl_pointer@8.axis_source(1)
[4291303.600] wl_pointer@8.axis(109819833, 0, 0.273438)
[4291303.623] wl_pointer@8.frame()
[4291335.431] wl_pointer@8.axis_source(1)
[4291335.450] wl_pointer@8.axis(109819860, 0, 0.273438)

But, the editor doesn't scroll in any way.

I noticed this first on Geany 1.29 built for GTK3, and didn't encounter the problem until I switched from running an X-based Gnome session to a Wayland one. In Geany, the problem only affected the Scintilla editor widget and not any other UI elements, so they suggested the problem likely fell upstream. To confirm, I built Scintilla and SciTE against GTK3 and confirmed the same behavior. Other GTK3/Wayland programs (like gedit) work fine with the trackpad scroll, and seem to report basically the same WAYLAND_DEBUG output when scrolling.

The interesting thing is that a "real" scroll wheel on an actual mouse works fine, in both Geany and SciTE.

The trackpad's entry from libinput-list-devices:

Device:           bcm5974
Kernel:           /dev/input/event14
Group:            7
Seat:             seat0, default
Size:             104.88x75.33mm
Capabilities:     pointer 
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: enabled
Accel profiles:   none
Rotation:         n/a

Discussion

1 2 > >> (Page 1 of 2)
  • Neil Hodgson

    Neil Hodgson - 2017-01-17

    I don't currently have a hardware setup that can test trackpad scrolling with GTK+/Wayland. You (or another contributor) could try adding some tracing to ScintillaGTK::ScrollEvent to see what is occurring.

     
  • John Flatness

    John Flatness - 2017-01-18

    It's been a while since I've touched C++ but here's what I've found with just some very simple print statements:

    Under normal operation with a touchpad, the ScrollEvent is not being fired at all: a simple print at the top of the method is never reached.

    Altering the event mask for wMain to use GDK_SMOOTH_SCROLL_MASK instead of GDK_SCROLL_MASK causes the event to be fired upon scroll (but of course it's all skipped as the method has code to explicitly skip any "smooth direction" events).

    My uninformed speculation is therefore that under Wayland (or possibly libinput generally) only smooth scroll events are being emitted for touchpad scrolls, so listening for them is required to support those devices. I could be wrong but that's the obvious explanation for me of what I'm seeing.

    If that were true though it would seem like this problem would appear on any GTK3 program that used only GDK_SCROLL_MASK, though I'm not familiar with any.

     
    • Neil Hodgson

      Neil Hodgson - 2017-01-19
       
      • John Flatness

        John Flatness - 2017-01-19

        I (for whatever reason) didn't check to see what it did when both GDK_SCROLL_MASK and GDK_SMOOTH_SCROLL_MASK are given. I'll report back on that.

        That's pretty unintuitive if true, not really how you'd expect a "mask" to work.

         
  • John Flatness

    John Flatness - 2017-01-20

    Alas, specifying both masks leads to no significant difference for this specific device (I suspect though that it restores "regular" mousewheel support which my initial SMOOTH_SCROLL only change would have dropped).

    With both SCROLL_MASK and SMOOTH_SCROLL_MASK, the touchpad seemingly generates only smooth scroll events: they all do enter the scroll handler, but they're all caught in the if for the smooth "direction."

    It really just looks like the Wayland backend doesn't generate emulated legacy scroll events for smooth scroll devices, or at least for this particular one, but it seems to me if that was the case it would have wide-reaching implications.

     
  • Neil Hodgson

    Neil Hodgson - 2017-01-21

    The code could be modified to interpret GDK_SCROLL_SMOOTH events. There would then be questions about whether both events are received on other systems. I won't be working on this myself in the near future.

    Scintilla doesn't support scrolling by pixel, only scrolling by text line. GDK_SCROLL_SMOOTH may be geared to pixel scrolling so may have to be divided down to work with Scintilla. Scintilla could also be modified to allow pixel scrolling but it would have to be thought through with additional APIs.

    It is possible that this is just a temporary bug until GTK+ supports non-smooth scroll events on Wayland.

     
  • John Flatness

    John Flatness - 2017-01-21

    My understanding is that the smooth events are indeed more geared to pixel-based or at any rate non-discrete scrolling.

    A brief hack that directly uses the delta values reported by the scroll event works, but obviously in an clunky/crummy way. Since I was just hacking away it uses the deltas directly as line numbers, so it scrolls not at all if you're scrolling slowly, and jumps many lines at once if you're scrolling very quickly. At a minimum it appeared to me that some persistent storage akin to what's currently used for wheel angle would be necessary, so that smaller scroll deltas could "build up" into full lines rather than needing to exceed the threshold in a single event as in the naive implementation.

    I suspect the multiple events would indeed be a problem for non-Wayland usage, and I didn't care at the time to try to confirm or figure what would be involved in ignoring the correct events if/when both show up... it's a problem mentioned by many GTK+ client programs. There is a call for detecting "emulated" events so perhaps that would be a relatively simple solution.

    It occurred to me as well that this could be interpreted as a bug in GTK+'s Wayland backend, but I'm not sure they want to perpetuate the "duplicate events" pattern. A quick glance seems to show that the X code doesn't synthesize "button/wheel" events for smooth scrolls either, rather that seems to have come from XInput.

     
  • John Flatness

    John Flatness - 2017-01-24

    A very simple implementation of listening to the smooth scroll events (just accumulate the values of the X and Y deltas from the smooth scroll events, then do the scroll and reset the accumulated value in that axis to zero when it exceeds 1) seems to work quite acceptably. I haven't done any multiplication or division of the deltas into different units; it seems to be more or less fine as-is (this means the horizontal scrolling is much slower than the vertical since vertical scrolls by lines while horizontal scrolls by pixels, but in my experience that's standard for Scintilla, at least with a touchpad).

    I suspect that there would be some problem with event duplication on X, though. I'm not exactly set up to test that at the moment so I haven't. A possible simple solution would be to guard the smooth scroll implementation with GDK_IS_WAYLAND_DISPLAY() so it just doesn't look at the smooth events at all under X.

     
  • John Flatness

    John Flatness - 2017-01-24

    Here's the dead-simple implementation if anybody is interested (without any attempt to constrain its operation to Wayland/libinput or to filter out duplicate events)

     
  • Neil Hodgson

    Neil Hodgson - 2017-01-25

    With the patch I see only GDK_SCROLL_SMOOTH events and no other scroll events on Fedora/Wayland and Ubuntu/X. Placing a trace shows delta_x==0 and delta_y==1 or -1 on Fedora/Wayland. On Ubuntu/X, delta_y is sometimes 0 - the initial scroll is always 0 but its also common when reversing direction and occasionally at other times.

    Does the trackpad produce non-integral delta_y? If it does, then the integer part should be used to scroll and the fractional part preserved.

    Scintilla commonly scrolls by 4 lines for each scroll wheel click (linesPerScroll) although this is modified by a system setting on Windows and has some other fiddles. With the patch, it only scrolls by one line for each click.

     
    • John Flatness

      John Flatness - 2017-01-25

      Yes, the pad produces noninteger deltas in both dimensions. The code currently just uses the integer part of the accumulated scroll once its absolute value exceeds 1, but I take it you're suggesting that instead of resetting to zero upon scroll it should instead keep the current fraction... that's probably right. There's no good reason I can think of for discarding the extra, other than that I just didn't think about it.

      The quirks with what's produced by "normal" devices are interesting. It's surprising to me that only the smooth events are appearing. On the touchpad (at least mine), multiplying by the linesPerScroll would likely make the scrolling very fast. The touchpad scroll values for slow to medium-speed scrolling hover around .5 to 1, but they're fired very often.

      It certainly seems from the numbers you're reporting that the "smooth" scroll events generated by a mousewheel aren't using the same units/scale as the touch smooth scroll events are, though I'm not 100% certain that's the case. Ideally I'd hoped to just keep mice using the standard up/down directional scroll events they're currently using so the smooth scroll would only apply for touch devices and the wheels would proceed unchanged using the linesPerScroll. I can pull the source device type out from the event if needed to distinguish touch and mouse events (I think).

       
      • Colomban Wendling

        Le 25/01/2017 à 08:22, John Flatness a écrit :

        Yes, the pad produces noninteger deltas in both dimensions. The code
        currently just uses the integer part of the accumulated scroll once
        its absolute value exceeds 1, but I take it you're suggesting that
        instead of resetting to zero upon scroll it should instead keep the
        current fraction... that's probably right. There's no good reason I
        can think of for discarding the extra, other than that I just didn't
        think about it.

        Yeah it seems that the "right" formula would be maintaining a floating
        point scroll value and add delta*scrollStep (where scrollStep is what is
        currently added for non-smooth scrolls). Then, use the integer part of
        it to actually scroll.

        The quirks with what's produced by "normal" devices are interesting.
        It's surprising to me that only the smooth events are appearing. On
        the touchpad (at least mine), multiplying by the linesPerScroll would
        likely make the scrolling very fast. The touchpad scroll values for
        slow to medium-speed scrolling hover around .5 to 1, but they're
        fired very often.

        It's odd indeed, as GTK itself doesn't seem to do anything special for
        handling smooth scroll for different input devices -- apart animating or
        not IIUC, in the case of GtkScrolledWindow.

        I can test on GTK 3.14 under X with a touchpad in the upcoming days to
        see what I get there.

         
  • John Flatness

    John Flatness - 2017-01-25

    GTK internally for its own smooth scrolling purposes uses a scroll "unit" that varies based on the size of the viewport: pixel scrolling amounts are calculated by multiplying the scroll event delta by the viewport's dimension in the direction of the scroll raised to the 2/3 power, meaning the same scroll events scroll larger distances on large windows than they do in smaller ones. This would be easy enough to implement here, I think, with the slight wrinkle that the unit would need to be divided by the height of a line, since we're scrolling line-by-line rather than pixel-by-pixel.

    Alternatively, simply multiplying by 4 and/or linesPerScroll is also very simple if that's what's desired instead. I checked back on the scroll numbers I'm seeing and multiplying by 4 would actually maybe not be as inappropriate as I originally thought. I'll try it out to see.

    At any rate, I'll post a version that more correctly handles the floating point leftovers than what the current one is doing.

     

    Last edit: John Flatness 2017-01-25
  • John Flatness

    John Flatness - 2017-01-25

    The actual speed of scrolling with the multiplied-by-4 deltas is pretty much fine, but there's a small problem where the scrolling gets pretty choppy/jumpy if you're doing fairly big or fast scrolls on the pad; the resulting calculated scroll in lines is quite large. With the slower scroll that's in place without the multiplication it's not really a problem. Just clamping the maximum amount of scroll to plus/minus something reasonable in a single event would probably avoid the problem, though.

    Interestingly, the GDK debugging output indicates that the "discrete" scroll events are still being generated somewhere if you use a wheel mouse:

    Gdk-Message: axis source wheel, seat 0x253a040
    Gdk-Message: discrete scroll, axis horizontal, value 1, seat 0x253a040
    Gdk-Message: scroll, axis horizontal, value 1.000000, seat 0x253a040
    Gdk-Message: frame, seat 0x253a040
    

    If GDK is printing that it would seem there should be a way to get at that discrete event, but I confirm the same thing, with the code I currently have, only the "smooth" scroll events are happening, even for wheel mouse scrolls.

    An updated patch is attached: instead of resetting to zero upon achieving an integral scroll amount, it just subtracts the trunc() of the accumulated delta, leaving the fractional remainder behind. It also multiplies the scroll delta units by 4 (currently just a redefinition of that multiplication factor rather than trying to reuse the existing one from the legacy scroll event), and fixes what I would imagine would be a build failure on GTK<3.4.

     

    Last edit: John Flatness 2017-01-25
  • Neil Hodgson

    Neil Hodgson - 2017-01-27

    The second patch works well on the Fedora/Wayland system for me.

    It has the same problem as before with some incremental scrolling movements having no effect on on Ubuntu/X. Turning smooth scrolling on/off with GDK_IS_WAYLAND_DISPLAY may be possible but it appears a little messy as it will require some detection of configuration
    https://developer.gnome.org/gdk3/stable/gdk3-Wayland-Interaction.html
    Possibly enable checking if pkg-config --exists gtk+-wayland-3.0

    Detection should occur early in the widget's life as the event mask is set early, before it is displayed.
    If it is possible for a system to have mixture of X and Wayland displays then the display may not be known at that point.

     
  • John Flatness

    John Flatness - 2017-01-27

    Does setting the env var GTK_CORE_DEVICE_EVENTS=1 cause any change to the behavior on X?

    It seems to me that what you're seeing could be the problem(s) described in these bugs, where there are scroll events from wheels that get dropped under the new XInput2 code:

    https://bugzilla.gnome.org/show_bug.cgi?id=750994
    https://bugzilla.gnome.org/show_bug.cgi?id=750870

    The prognosis doesn't sound good though: there was a patch in at one point but it got reverted. The attitude seems to be "wait it out for Wayland to take over and the problem will solve itself."

    So my understanding of where we are is this fun combination:

    • For devices that send both smooth and non-smooth events, GTK3 filters out the non-smooth ones if you have the GDK_SMOOTH_SCROLL_MASK mask set, so you can never see those events even though they're occurring. The code that does this looks like it only filters out emulated non-smooth events, but in practice, emulated means "wheel button events", even when they're coming from an actual wheel.
    • Wayland/libinput doesn't send the old button scrolls at all for touchpads, so you have to set GDK_SMOOTH_SCROLL_MASK to get any scroll events at all for those devices when on the Wayland backend
    • GTK3 under X since a while ago uses XInput2, which likes to send smooth-scroll events for all scrolls, even from wheel mice.
    • GTK's handling of XInput2 smooth scrolls is somewhat broken when those events come from wheel mice (see those bugs linked above), and some scrolls get dropped. Apparently this brokenness is an unavoidable consequence of deficiencies in XInput2, at least that's the impression I get.

    The only options I see that remain for adding touchpad support under Wayland are:

    • As you suggested, check to see if the display is Wayland before deciding to add the smooth scroll mask. I don't believe that there can be a mixture of Wayland and X devices within the same process/context. It would have to be ifdef'd for Wayland support being built at all and then also a runtime check to see if the Wayland backend is what's actually in use. This may be the best option available.
    • Live with the degraded scrolling on GTK3 under X. I don't know how major the problem is as I haven't seen it, but I can see how this one would be undesirable.
     

    Last edit: John Flatness 2017-01-27
  • John Flatness

    John Flatness - 2017-01-27

    Sorry, that env var should be GDK_CORE_DEVICE_EVENTS=1 rather than GTK as I initially wrote.

     
  • Neil Hodgson

    Neil Hodgson - 2017-01-28

    GDK_CORE_DEVICE_EVENTS=1 does restore X to previous behaviour.

    The patches remove the current code section that discards smooth scroll events. This fails on Ubuntu 12.4 by stopping scrolling up -- actually it flickers so the smooth scroll may be counteracting the non-smooth scroll.

    Attached is a patch that tries to discover whether Wayland is available and active and restores the discard of smooth events on older GTK+ 3.x.

    It contains some stderr tracing that will be removed.

    It does not correctly use pkg-config [--cflags|--libs] gtk+-wayland-3.0 as specified by the Wayland Interaction page. These give the same results as pkg-config [--cflags|--libs] gtk+-3.0. While Scintilla could do the correct thing here, the --libs option would be required by each application if it did make a difference.

    X is currently more popular than Wayland and it will have a very long tail. Degraded scrolling on X does not appear reasonable to me.

     
  • John Flatness

    John Flatness - 2017-01-28

    X is currently more popular than Wayland and it will have a very long tail. Degraded scrolling on X does not appear reasonable to me.

    That's a very reasonable outlook. (It's interesting to me that it doesn't seem to be the one GTK itself is going with, but that's neither here nor there.)

    On your patch, is HAVE_WAYLAND really needed? Shouldn't simply checking for GDK_WINDOWING_WAYLAND be sufficient and not require the Makefile change? Similarly, can the ifdefs for CHECK_SMOOTH just be checks against GDK_WINDOWING_WAYLAND as well, so you wouldn't have to define CHECK_SMOOTH? Both appear to be the case to me, but I could be missing something.

    Is the $(DWAY) in the CXXBASEFLAGS just a vestige of when you were "following the rules" from that Wayland Interaction page? (It doesn't seem like it's necessarily the most accurate page in the world.)

    On restoring the "ignore smooth scrolls" block I deleted, that makes sense, as does the idea that the scrolls are fighting each other (or doubling magnitude when scrolling down, I imagine) with the block gone.

     
  • Neil Hodgson

    Neil Hodgson - 2017-01-29

    On your patch, is HAVE_WAYLAND really needed? Shouldn't simply checking for GDK_WINDOWING_WAYLAND be sufficient and not require the Makefile change?

    I thought the Wayland Interaction page implied that <gdk/gdkwayland.h> was needed before GDK_WINDOWING_WAYLAND would be available but it looks like it is defined in gdkconfig.h.

    Is the $(DWAY) in the CXXBASEFLAGS just a vestige of when you were "following the rules" from that Wayland Interaction page?

    DWAY was from me struggling with 'make' quoting rules.

    Attached is a simpler patch.

     

    Last edit: Neil Hodgson 2017-01-29
  • John Flatness

    John Flatness - 2017-01-31

    I've finally gotten a chance to test your latest patch: it works great.

    I don't notice any degredation on Wayland vs. my earlier patches, and it's working fine with this same device under X, just using the legacy button events since they're actually delivered under X.

     
  • Neil Hodgson

    Neil Hodgson - 2017-02-01
    • labels: scintilla --> scintilla, gtk, wayland
    • status: open --> open-fixed
    • assigned_to: Neil Hodgson
     
  • Neil Hodgson

    Neil Hodgson - 2017-02-01

    Committed as [6f3c58].

     

    Related

    Commit: [6f3c58]

  • Neil Hodgson

    Neil Hodgson - 2017-02-20
    • status: open-fixed --> closed-fixed
     
  • Colomban Wendling

    This leads to double scorlling sometimes in Geany at least (which doesn't yet have 3.7.3, but I noticed when I was in the process of updating): at first it's fine, but after e.g. performing a search I get smooth scroll events under X11, which combine with non-smooth ones, leading to double scrolling.
    For now I didn't debug it too much so I'm not sure why it starts failing -- AFAIK Geany isn't doing anything weird here. But as before this patch smooth scroll mask wasn't set, but smooth scroll events were explicitly ignored, I guess it's not me (or Geany).

    Anyway, attached patch should really limit smooth scroll handling to Wayland, at least until we figure out what's going on here.

     
1 2 > >> (Page 1 of 2)

Log in to post a comment.