all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
From: Alan Third <alan@idiocy.org>
To: Tak Kunihiro <homeros.misasa@gmail.com>
Cc: Emacs-Devel devel <emacs-devel@gnu.org>
Subject: Re: Smoother macOS touchpad scrolling
Date: Mon, 11 Sep 2017 19:09:20 +0100	[thread overview]
Message-ID: <20170911180920.GA92807@breton.holly.idiocy.org> (raw)
In-Reply-To: <20170910083758.GA30315@breton.holly.idiocy.org>

[-- Attachment #1: Type: text/plain, Size: 757 bytes --]

On Sun, Sep 10, 2017 at 09:37:58AM +0100, Alan Third wrote:
> How about instead of using the default font height, I provide a
> variable that the user can use to set a ‘line height’ of their own
> choosing? i.e. ‘(setq ns-touchpad-scroll-line-height 1)’ for one
> pixel.

Updated patch attached.

I’ve modified mousewheel scrolling so it also makes use of macOS’s
built‐in mousewheel acceleration. My thinking was that if we turn off
Emacs progressive scrolling for touchpad, then mousewheels can feel
awfully slow. ns-use-system-mwheel-acceleration allows you to turn it
off if you don’t like the new behaviour, but it has no effect on
touchpad scrolling.

If anyone gives the patch a try, please let me know what you think.
-- 
Alan Third

[-- Attachment #2: 0001-Provide-smoother-touchpad-scrolling-on-macOS.patch --]
[-- Type: text/plain, Size: 9583 bytes --]

From 6cca3c21434d63f9be3ee4a45a34eebd6226cada Mon Sep 17 00:00:00 2001
From: Alan Third <alan@idiocy.org>
Date: Fri, 8 Sep 2017 19:26:47 +0100
Subject: [PATCH] Provide smoother touchpad scrolling on macOS

* etc/NEWS: Describe changes.
* lisp/term/ns-win.el (mouse-wheel-scroll-amount,
mouse-wheel-progressive-speed): Set to smarter values for macOS touchpads.
* src/nsterm.m (emacsView::mouseDown): Use precise scrolling deltas to
calculate scrolling for touchpads and mouse wheels.
(syms_of_nsterm): Add variables 'ns-use-system-mwheel-acceleration',
'ns-touchpad-scroll-line-height' and 'ns-touchpad-use-momentum'.
---
 etc/NEWS            |   6 ++
 lisp/term/ns-win.el |   7 +++
 src/nsterm.m        | 165 +++++++++++++++++++++++++++++++++++++++++++++++-----
 3 files changed, 163 insertions(+), 15 deletions(-)

diff --git a/etc/NEWS b/etc/NEWS
index 3f1df23ec3..0f4a3d7884 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -1817,6 +1817,12 @@ of frame decorations on macOS 10.9+.
 ---
 ** 'process-attributes' on Darwin systems now returns more information.
 
+---
+** Mousewheel and trackpad scrolling on macOS 10.7+ now behaves more
+like the macOS default.  The new variables
+'ns-use-system-mwheel-acceleration', 'ns-touchpad-scroll-line-height'
+and 'ns-touchpad-use-momentum' can be used to customise the behavior.
+
 \f
 ----------------------------------------------------------------------
 This file is part of GNU Emacs.
diff --git a/lisp/term/ns-win.el b/lisp/term/ns-win.el
index cfce83f892..dfdcdfe23e 100644
--- a/lisp/term/ns-win.el
+++ b/lisp/term/ns-win.el
@@ -736,6 +736,13 @@ ns-paste-secondary
 (global-unset-key [horizontal-scroll-bar drag-mouse-1])
 
 
+;;;; macOS-like defaults for trackpad and mouse wheel scrolling.
+
+(when (featurep 'cocoa)
+  (setq mouse-wheel-scroll-amount '(1 ((shift) . 5) ((control))))
+  (setq mouse-wheel-progressive-speed nil))
+
+
 ;;;; Color support.
 
 ;; Functions for color panel + drag
diff --git a/src/nsterm.m b/src/nsterm.m
index 001e4576e8..1c3847e6ff 100644
--- a/src/nsterm.m
+++ b/src/nsterm.m
@@ -6498,24 +6498,142 @@ - (void)mouseDown: (NSEvent *)theEvent
 
   if ([theEvent type] == NSEventTypeScrollWheel)
     {
-      CGFloat delta = [theEvent deltaY];
-      /* Mac notebooks send wheel events w/delta =0 when trackpad scrolling */
-      if (delta == 0)
+#if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
+#if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
+      if ([theEvent respondsToSelector:@(hasPreciseScrollingDeltas)])
         {
-          delta = [theEvent deltaX];
-          if (delta == 0)
+#endif
+          /* If the input device is a touchpad or similar, use precise
+           * scrolling deltas.  These are measured in pixels, so we
+           * have to add them up until they exceed one line height,
+           * then we can send one, or more, scroll wheel events.
+           *
+           * If the device only has coarse scrolling deltas, like a
+           * real mousewheel, the deltas represent a ratio of whole
+           * lines, so round up the number of scroll events sent per
+           * click.  This means we always send at least one scroll
+           * event per click, but can still scroll more than one line
+           * if the OS tells us to.
+           */
+          bool horizontal;
+          int lines = 0;
+          int scrollUp = NO;
+
+          /* FIXME: At the top or bottom of the buffer we should
+           * ignore momentum-phase events.  */
+          if (! ns_touchpad_use_momentum
+              && [theEvent momentumPhase] != NSEventPhaseNone)
+            return;
+
+          if ([theEvent hasPreciseScrollingDeltas])
             {
-              NSTRACE_MSG ("deltaIsZero");
-              return;
+              static int totalDeltaX, totalDeltaY;
+              int lineHeight;
+
+              if (NUMBERP (ns_touchpad_scroll_line_height))
+                lineHeight = XINT (ns_touchpad_scroll_line_height);
+              else
+                {
+                  /* FIXME: Use actual line height instead of the default.  */
+                  lineHeight = default_line_pixel_height
+                    (XWINDOW (FRAME_SELECTED_WINDOW (emacsframe)));
+                }
+
+              if ([theEvent phase] == NSEventPhaseBegan)
+                {
+                  totalDeltaX = 0;
+                  totalDeltaY = 0;
+                }
+
+              totalDeltaX += [theEvent scrollingDeltaX];
+              totalDeltaY += [theEvent scrollingDeltaY];
+
+              /* Calculate the number of lines, if any, to scroll, and
+               * reset the total delta for the direction we're NOT
+               * scrolling so that small movements don't add up.  */
+              if (abs (totalDeltaX) > abs (totalDeltaY)
+                  && abs (totalDeltaX) > lineHeight)
+                {
+                  horizontal = YES;
+                  scrollUp = totalDeltaX > 0;
+
+                  lines = abs (totalDeltaX / lineHeight);
+                  totalDeltaX = totalDeltaX % lineHeight;
+                  totalDeltaY = 0;
+                }
+              else if (abs (totalDeltaY) >= abs (totalDeltaX)
+                       && abs (totalDeltaY) > lineHeight)
+                {
+                  horizontal = NO;
+                  scrollUp = totalDeltaY > 0;
+
+                  lines = abs (totalDeltaY / lineHeight);
+                  totalDeltaY = totalDeltaY % lineHeight;
+                  totalDeltaX = 0;
+                }
             }
-          emacs_event->kind = HORIZ_WHEEL_EVENT;
+          else
+            {
+              CGFloat delta;
+
+              if ([theEvent scrollingDeltaY] == 0)
+                {
+                  horizontal = YES;
+                  delta = [theEvent scrollingDeltaX];
+                }
+              else
+                {
+                  horizontal = NO;
+                  delta = [theEvent scrollingDeltaY];
+                }
+
+              lines = (ns_use_system_mwheel_acceleration)
+                ? ceil (fabs (delta)) : 1;
+
+              scrollUp = delta > 0;
+            }
+
+          for (int i = 0 ; i < lines ; i++)
+            {
+              emacs_event->kind = horizontal ? HORIZ_WHEEL_EVENT : WHEEL_EVENT;
+
+              emacs_event->code = 0;
+              emacs_event->modifiers = EV_MODIFIERS (theEvent) |
+                (scrollUp ? up_modifier : down_modifier);
+              XSETINT (emacs_event->x, lrint (p.x));
+              XSETINT (emacs_event->y, lrint (p.y));
+              EV_TRAILER (theEvent);
+            }
+#if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
         }
       else
-        emacs_event->kind = WHEEL_EVENT;
+#endif
+#endif /* defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */
+#if defined (NS_IMPL_GNUSTEP) || MAC_OS_X_VERSION_MIN_REQUIRED < 1070
+        {
+          CGFloat delta = [theEvent deltaY];
+          /* Mac notebooks send wheel events w/delta =0 when trackpad scrolling */
+          if (delta == 0)
+            {
+              delta = [theEvent deltaX];
+              if (delta == 0)
+                {
+                  NSTRACE_MSG ("deltaIsZero");
+                  return;
+                }
+              emacs_event->kind = HORIZ_WHEEL_EVENT;
+            }
+          else
+            emacs_event->kind = WHEEL_EVENT;
 
-      emacs_event->code = 0;
-      emacs_event->modifiers = EV_MODIFIERS (theEvent) |
-        ((delta > 0) ? up_modifier : down_modifier);
+          emacs_event->code = 0;
+          emacs_event->modifiers = EV_MODIFIERS (theEvent) |
+            ((delta > 0) ? up_modifier : down_modifier);
+          XSETINT (emacs_event->x, lrint (p.x));
+          XSETINT (emacs_event->y, lrint (p.y));
+          EV_TRAILER (theEvent);
+        }
+#endif
     }
   else
     {
@@ -6523,10 +6641,10 @@ - (void)mouseDown: (NSEvent *)theEvent
       emacs_event->code = EV_BUTTON (theEvent);
       emacs_event->modifiers = EV_MODIFIERS (theEvent)
                              | EV_UDMODIFIERS (theEvent);
+      XSETINT (emacs_event->x, lrint (p.x));
+      XSETINT (emacs_event->y, lrint (p.y));
+      EV_TRAILER (theEvent);
     }
-  XSETINT (emacs_event->x, lrint (p.x));
-  XSETINT (emacs_event->y, lrint (p.y));
-  EV_TRAILER (theEvent);
 }
 
 
@@ -9166,6 +9284,23 @@ Nil means use fullscreen the old (< 10.7) way.  The old way works better with
 This variable is ignored on Mac OS X < 10.7 and GNUstep.  */);
   ns_use_srgb_colorspace = YES;
 
+  DEFVAR_BOOL ("ns-use-system-mwheel-acceleration",
+               ns_use_system_mwheel_acceleration,
+     doc: /*Non-nil means use macOS's standard mouse wheel acceleration.
+This variable is ignored on macOS < 10.7 and GNUstep.  Default is t.  */);
+  ns_use_system_mwheel_acceleration = YES;
+
+  DEFVAR_LISP ("ns-touchpad-scroll-line-height", ns_touchpad_scroll_line_height,
+               doc: /*The number of pixels touchpad scrolling considers a line.
+Nil or a non-number means use the default frame line height.
+This variable is ignored on macOS < 10.7 and GNUstep.  Default is nil.  */);
+  ns_touchpad_scroll_line_height = Qnil;
+
+  DEFVAR_BOOL ("ns-touchpad-use-momentum", ns_touchpad_use_momentum,
+               doc: /*Non-nil means touchpad scrolling uses momentum.
+This variable is ignored on macOS < 10.7 and GNUstep.  Default is t.  */);
+  ns_touchpad_use_momentum = YES;
+
   /* TODO: move to common code */
   DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars,
 	       doc: /* Which toolkit scroll bars Emacs uses, if any.
-- 
2.12.0


  reply	other threads:[~2017-09-11 18:09 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-09-08 18:46 Smoother macOS touchpad scrolling Alan Third
2017-09-08 22:21 ` Tak Kunihiro
2017-09-09  8:18   ` Alan Third
2017-09-10  1:20     ` Tak Kunihiro
2017-09-10  8:37       ` Alan Third
2017-09-11 18:09         ` Alan Third [this message]
2017-09-12  1:54           ` James Nguyen
2017-09-12 17:03             ` Alan Third
2017-09-12 23:13           ` Tak Kunihiro
2017-09-13 16:26             ` Better macOS scrolling (was: Smoother macOS touchpad scrolling) Alan Third
2017-09-13 22:52               ` Better macOS scrolling Tak Kunihiro
2017-09-16 22:33         ` Smoother macOS touchpad scrolling Alan Third
2017-09-18 18:10           ` Charles A. Roelli
2017-09-18 18:57             ` Charles A. Roelli
2017-09-18 19:03             ` Alan Third
2017-09-18 20:19               ` Charles A. Roelli
2017-09-19 19:12                 ` Alan Third

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20170911180920.GA92807@breton.holly.idiocy.org \
    --to=alan@idiocy.org \
    --cc=emacs-devel@gnu.org \
    --cc=homeros.misasa@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this external index

	https://git.savannah.gnu.org/cgit/emacs.git
	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.