all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
From: Alan Third <alan@idiocy.org>
To: Emacs-Devel devel <emacs-devel@gnu.org>
Subject: Smoother macOS touchpad scrolling
Date: Fri, 8 Sep 2017 19:46:34 +0100	[thread overview]
Message-ID: <20170908184634.GA20058@breton.holly.idiocy.org> (raw)

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

Attached is a patch to provide smoother scrolling with the touchpad on
macOS. It adds up the scrolling deltas and only sends a scroll event
when the total exceeds the frame’s default line‐height.

Scrolling quickly sometimes results in the screen stuttering a little.
I’m not sure if that’s just a result of scrolling quickly, or because
my code sends one scroll event for each line it wants to scroll and it
overloads Emacs redisplay or something.

Does anyone know if there’s a way, in C, to detect if we’re at the top
or bottom of the buffer? I’d rather not send momentum scroll events if
the buffer isn’t going to scroll.
-- 
Alan Third

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

From 1c9ca5b5d38274eb1a2eb2aa28ef43ac4670d3a6 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

* lisp/term/ns-win.el (mouse-wheel-scroll-amount,
mouse-wheel-progressive-speed): Set to smarter values for touchpads.
* src/nsterm.m (emacsView::mouseDown): Use precise scrolling deltas to
calculate scrolling for touchpads.
---
 lisp/term/ns-win.el |  9 ++++++
 src/nsterm.m        | 91 ++++++++++++++++++++++++++++++++++++++++++++++-------
 2 files changed, 88 insertions(+), 12 deletions(-)

diff --git a/lisp/term/ns-win.el b/lisp/term/ns-win.el
index cfce83f892..488ea9cf0b 100644
--- a/lisp/term/ns-win.el
+++ b/lisp/term/ns-win.el
@@ -736,6 +736,15 @@ ns-paste-secondary
 (global-unset-key [horizontal-scroll-bar drag-mouse-1])
 
 
+;;;; Sane defaults for trackpad scrolling.
+
+;; These aren't so good for mousewheel scrolling, but we can't
+;; differentiate between the two.
+
+(setq mouse-wheel-scroll-amount '(1 ((shift) . 5)))
+(setq mouse-wheel-progressive-speed nil)
+
+
 ;;;; Color support.
 
 ;; Functions for color panel + drag
diff --git a/src/nsterm.m b/src/nsterm.m
index be97e94dd5..432e4ada86 100644
--- a/src/nsterm.m
+++ b/src/nsterm.m
@@ -6498,24 +6498,91 @@ - (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 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, use the old method which sends one scroll event
+       * per mousewheel `click'.  We could use precise deltas here
+       * too, but they can result in as little as one pixel change per
+       * `click', which would make it appear to the user as though
+       * nothing was happening.
+       */
+
+      if ([theEvent hasPreciseScrollingDeltas])
         {
-          delta = [theEvent deltaX];
-          if (delta == 0)
+          static int totalDeltaX, totalDeltaY;
+          bool horizontal;
+          int lines = 0;
+          int 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;
+              lines = totalDeltaX / lineHeight;
+              totalDeltaX = totalDeltaX % lineHeight;
+              totalDeltaY = 0;
+            }
+          else if (abs (totalDeltaY) >= abs (totalDeltaX)
+                   && abs (totalDeltaY) > lineHeight)
+            {
+              horizontal = NO;
+              lines = totalDeltaY / lineHeight;
+              totalDeltaY = totalDeltaY % lineHeight;
+              totalDeltaX = 0;
+            }
+
+          for (int i = 0 ; i < abs (lines) ; i++)
             {
-              NSTRACE_MSG ("deltaIsZero");
-              return;
+              emacs_event->kind = horizontal ? HORIZ_WHEEL_EVENT : WHEEL_EVENT;
+
+              emacs_event->code = 0;
+              emacs_event->modifiers = EV_MODIFIERS (theEvent) |
+                ((lines > 0) ? up_modifier : down_modifier);
+              XSETINT (emacs_event->x, lrint (p.x));
+              XSETINT (emacs_event->y, lrint (p.y));
+              EV_TRAILER (theEvent);
             }
-          emacs_event->kind = HORIZ_WHEEL_EVENT;
+          return;
         }
       else
-        emacs_event->kind = WHEEL_EVENT;
+#endif /* defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 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);
+        }
     }
   else
     {
-- 
2.12.0


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

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-09-08 18:46 Alan Third [this message]
2017-09-08 22:21 ` Smoother macOS touchpad scrolling 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
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=20170908184634.GA20058@breton.holly.idiocy.org \
    --to=alan@idiocy.org \
    --cc=emacs-devel@gnu.org \
    /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.