Skip to content

Incorrect axis_discrete events when scrolling not a multiple of 120 #2068

Description

@MithicSpirit

Abstract

When scroll events are sent without being a multiple of 120, the axis_discrete event (sent for wl_seat protocol version < 8) can behave poorly. In particular, it waits to accumulate to 120 before firing an axis_discrete event, so if an event is too small then no axis_discrete event is fired (similarly, if it is too big, then multiple axis_discrete events are fired). A particular case in which this is problematic is for Wine with the wayland backend (winewayland.drv, which uses wl_seat protocol version 5): this is often used for games, which may bind something to the scroll wheel, in which case the control may misbehave.

Reproduction

  1. Use niri.
  2. Set the mouse input scroll-factor to a value other than 1.
  3. Run a program that uses an old version of wl_seat (tested on wev by explicitly setting the protocol version to 5); enabling WAYLAND_DEBUG=1 is also helpful here.
  4. Try scrolling one mouse wheel notch at a time, and note when axis_discrete events fire.

Possible solution

I can see the merit in some applications or input methods to have it work like it currently does, so a broad approach that always fires axis_discrete events would be too heavy-handed. Therefore, I think that Smithay should always fire at least one axis_discrete event when the source is discrete (Wheel or WheelTilt) and otherwise continue as now. For what it's worth, I believe this is how KDE works currently.

Another interesting option is to allow the library consumer (e.g., niri) to control this behavior. The simplest interface I can imagine for this is adding a function AxisFrame::discrete(mut self, axis: Axis, value: Option<i32>). If this function is not called at all then the default Smithay behavior is used (either the current behavior or the one described above); if it is called with a Some value, then that is forwarded to WlPointer::axis_discrete; if it called with a None value, then no WlPointer::axis_discrete call is made at all. I'm not entirely fond of this (how should multiple calls to AxisFrame::discrete be combined?), but it shows the idea of what kind of control I think would be necessary.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions