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

From: Alan Third <[email-masked]>
Date: Sun, 12 May 2019 12:05:04 +0100

On Sun, May 12, 2019 at 07:58:50AM +0300, Eli Zaretskii wrote:
> > Date: Sat, 11 May 2019 23:50:21 +0100
> > From: Alan Third <[email-masked]>
> > Cc: Robert Pluim <[email-masked]>, [email-masked],
> > 	[email-masked]
> > 
> > > > (5 ((shift) . 1) ((control) . nil)))
> > > > 
> > > > to
> > > > 
> > > > (1 ((shift) . 5) ((control)))
> > > 
> > > What is the logic behind the value proposed for macOS 10.7, though?
> > > It sounds like Shift will _increase_ the scrolling amount instead of
> > > decreasing it in the default value?  What is the reason for such
> > > reversal?
> > 
> > I can’t recall... I think it was just something somebody provided as
> > an option and nobody disagreed.
> > 
> > Some of the previous discussion is available here:
> > 
> > http://emacs.1067599.n8.nabble.com/Smoother-macOS-touchpad-scrolling-td435666.html
> 
> I don't see the above discrepancy discussed anywhere, nor any
> justification for switching Shift from causing slower scrolling to
> causing faster scrolling.  Did I miss something?

No, I don’t think it was discussed at all. As I said I think it was
just thrown out there and nobody commented so it made it right
through. I don’t think it matters at all if we want to do something
different.

> What I see is 2 kinds of arguments:
> 
>   . Acceleration applied by Emacs makes scrolling too fast because
>     macOS itself accelerates by default
> 
>   . The default amount of scrolling -- 5 -- is too large for macOS
>     (not sure why -- is that also due to macOS defaults?)
>
> The first of these could be handled by turning acceleration off on
> macOS 10.7 by default.  Maybe the same with the latter.  Although I
> don't understand why the system's default scrolling should matter,
> because AFAIK Emacs scrolls by its own commands, it doesn't use the
> system for that.

I’ll try and explain how the scrolling works on macOS, that will
probably answer some of your questions.

The code in question is in nsterm.m in the method:

    - (void)mouseDown: (NSEvent *)theEvent

When a user scrolls with a scrollwheel on a mouse, one NSEvent is
created per ‘click’ of the wheel. The NSEvent provides a float that
describes how many lines the system believes that equates to, and as
you scroll more it increases the number of lines each click equates
to.

That is fine, we can ignore that and treat each click as one event in
Emacs.

When a user scrolls with a trackpad (dragging two fingers across the
surface) one or more NSEvents are generated, each of which contains a
number that equates to the number of pixels that the system thinks the
application should scroll. These numbers can be as little as one
pixel, or as high as 30 or 40 pixels or more.

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.

To try and ignore the system’s acceleration I chose an arbitrary
number, and if the pixel values added up to more than that then
treated it as a single Emacs scroll event. Unfortunately a large two
finger drag on the trackpad can produce as few as one Emacs scroll
event when the user (or at least me) expects a greater amount of
scrolling.
 
> 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.

> I understand now that this ship has sailed with Emacs 26, which I
> regret, because I think it was a serious mistake to make at least part
> of those changes.  Maybe we should try fixing that in future versions.
> 
> 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 you have another idea, please let me know.

> There was also a question in the 2017 discussion regarding how to know
> we are near the top or bottom of the buffer.  is that still an issue?
> Maybe I don't understand the problem, because the answer is trivial,
> we have 2 macros that provide the limits of the buffer's accessible
> portion, and another macro that provides the value of point.  If you
> need the position of the window-start, that is also readily available.

Yes, it’s still an issue. macOS adds ‘momentum’ when the user finishes
scrolling with the trackpad. It’s easy to turn off, but when it’s on
it can continue to try scrolling at the top and bottom of the Emacs
buffer which results in a barrage of Emacs warnings complaining it’s
already at the top or bottom of the buffer.

Ideally this should return when it’s not able to scroll any more:

          /* 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.

> Bottom line, I'd like to change Shift back to cause slow-down of the
> scrolling, as on other platforms.  Maybe also change the default
> itself back, and just make the acceleration off on macOS 10.7.

-- 
Alan Third