Subject: bug#35389: 27.0.50; [PATCH] Emacs on macOS sets mouse-wheel variables directly

From: Eli Zaretskii <[email-masked]>
Date: Sun, 12 May 2019 17:36:50 +0300

> Date: Sun, 12 May 2019 12:05:04 +0100
> From: Alan Third <[email-masked]>
> Cc: [email-masked], [email-masked], [email-masked]
> 
> I’ll try and explain how the scrolling works on macOS, that will
> probably answer some of your questions.

Thanks, it does help.

> Unfortunately we can’t just treat each of these NSEvents as a request
> to scroll a single line as we can receive many small requests very
> quickly. This is what Emacs used to do and it was basically useless.
> The slightest two finger drag on the trackpad could result in Emacs
> scrolling several pages.
> 
> What the current code does is add those pixel values up until they
> reach a certain value, then send Emacs an event telling it to scroll.
> Unfortunately those pixel values include a built‐in acceleration
> factor, so the more the user drags their fingers across the trackpad,
> the higher the pixel values will be, proportionally. We can’t disable
> that, and as far as I can tell the user can’t even disable it for the
> whole system.

Is the algorithm used by the system to "accelerate" known?  If so,
could we "un-accelerate" those values, by scaling them back to the
original amount of dragging received from the user, as if acceleration
was disabled?  Then we could apply our own acceleration as on other
platforms.  Would that work?

If something like that does work, we could offer it, at least as an
option, for those who'd like Emacs to behave the same a on other
platforms.

> > Why Shift should _accelerate_ on macOS was never discussed, in any of
> > the linked discussions or the links inside them (stack-overflow etc.)
> 
> Indeed. I’d have no issue with changing that. My only concern is that
> changing back to the defaults (i.e. scrolling 5 lines by default) may
> be too fast due to the system acceleration.

Maybe we could scale the amount and/or undo the acceleration, to
countermand these effects?

> > There's also the issue with trackball that differs from a real mouse
> > wheel.  I don't think I understand why it's an Emacs problem; do other
> > apps somehow distinguish between the trackball and the mouse and
> > produce a different behavior?  If so, why cannot Emacs distinguish
> > between them?
> 
> Emacs could easily differentiate between scrollwheel scrolls and
> trackpad scrolls, but the infrastructure isn’t there. We could add a
> new event type, for example. This may be useful for other ports when
> we reach the point of being able to support gestures, if anyone ever
> creates a native GTK port, say. But for now it would only be supported
> on macOS, and I fear it might then become a political issue and have
> to be disabled anyway.

If Emacs handles this event internally, and just translates it to the
appropriate combination of wheel scroll events available on other
platforms, I see no political issues with that.  Later, if and when
such events are supported on other platforms, we could expose them on
macOS as well.

>           /* FIXME: At the top or bottom of the buffer we should
>            * ignore momentum-phase events.  */
>           if (! ns_use_mwheel_momentum
>               && [theEvent momentumPhase] != NSEventPhaseNone)
>             return;
> 
> Emacs doesn’t scroll right to the bottom of the buffer, it always
> displays two lines (perhaps more? I’m unsure if this is a setting
> users can change). If the window is displaying the bottom two lines
> and the user attempts to scroll down it displays a warning. I’d like
> to be able to detect that Emacs can’t scroll any more, but that seems
> a little more complex than checking that point is at the end of the
> buffer.
> 
> This only affects ‘momentum’ phase scrolls. The simple solution is
> ignore it or turn it off — we don’t need it — but it would be nice to
> make it work properly.
> 
> I suppose if I could detect that the first or last line is being
> displayed in the window then I could just ignore momentum. That’s
> probably quite straight forward.

I think vertical-motion is the primitive you are looking for, assuming
I understood the situation.  You can also call
Fline_beginning_position and Fline_end_position from C.

If these don't help, please tell why, maybe I don't have a clear idea
of the context in which you need to make these calls.