[gtk/wip/chergert/fix-macos-overshoot] macos: fix kinetic scrolling with overshoot




commit f278f3610bdce090f1515b633d5473cd1674e2bc
Author: Christian Hergert <christian hergert me>
Date:   Thu Feb 24 18:55:42 2022 -0800

    macos: fix kinetic scrolling with overshoot
    
    Previously we had issues on macos where the overshoot would keep showing.
    To fix this we need to actually use discrete events instead of the
    generated deltas from macOS in the scroll wheel case. Additionally, we need
    to drop the kinetic momentum events from macOS and rely on the gtk kinetic
    events which are already happening anyway. We also need to submit the
    is_stop event for the GDK_SCROLL_SMOOTH case when we detect it.
    
    To keep the discrete scroll events correct, we need to alter the hack in
    gtkscrolledwindow.c to use the same path as other platforms except for
    when a smooth scroll event is in place. In the future, I would imagine that
    this falls into the boundary of high-precision scrolling and would share
    the same code paths as other platforms.
    
    With all of these in place, kinetic scrolling with overshoot appears the
    same on macOS as other platforms.

 gdk/macos/gdkmacosdisplay-translate.c | 43 +++++++++++++++++++++++++++--------
 gtk/gtkscrolledwindow.c               | 29 ++++++++++++++---------
 2 files changed, 51 insertions(+), 21 deletions(-)
---
diff --git a/gdk/macos/gdkmacosdisplay-translate.c b/gdk/macos/gdkmacosdisplay-translate.c
index 8e3cd90b82..646ba0cd9e 100644
--- a/gdk/macos/gdkmacosdisplay-translate.c
+++ b/gdk/macos/gdkmacosdisplay-translate.c
@@ -612,6 +612,8 @@ fill_scroll_event (GdkMacosDisplay *self,
   GdkModifierType state;
   GdkDevice *pointer;
   GdkEvent *ret = NULL;
+  NSEventPhase phase;
+  NSEventPhase momentumPhase;
   GdkSeat *seat;
   double dx;
   double dy;
@@ -619,6 +621,15 @@ fill_scroll_event (GdkMacosDisplay *self,
   g_assert (GDK_IS_MACOS_SURFACE (surface));
   g_assert (nsevent != NULL);
 
+  phase = [nsevent phase];
+  momentumPhase = [nsevent momentumPhase];
+
+  /* Ignore kinetic scroll events from the display server as we already
+   * handle those internally.
+   */
+  if (phase == 0 && momentumPhase != 0)
+    return NULL;
+
   seat = gdk_display_get_default_seat (GDK_DISPLAY (self));
   pointer = gdk_seat_get_pointer (seat);
   state = _gdk_macos_display_get_current_mouse_modifiers (self) |
@@ -684,19 +695,31 @@ fill_scroll_event (GdkMacosDisplay *self,
         }
       else
         {
-          g_assert (ret == NULL);
-
-          ret = gdk_scroll_event_new (GDK_SURFACE (surface),
-                                      pointer,
-                                      NULL,
-                                      get_time_from_ns_event (nsevent),
-                                      state,
-                                      -dx * 32,
-                                      -dy * 32,
-                                      FALSE);
+          ret = gdk_scroll_event_new_discrete (GDK_SURFACE (surface),
+                                               pointer,
+                                               NULL,
+                                               get_time_from_ns_event (nsevent),
+                                               state,
+                                               direction,
+                                               FALSE);
         }
     }
 
+  if (phase == NSEventPhaseEnded || phase == NSEventPhaseCancelled)
+    {
+      /* The user must have released their fingers in a touchpad
+       * scroll, so try to send a scroll is_stop event.
+       */
+      if (ret != NULL)
+        _gdk_event_queue_append (GDK_DISPLAY (self), g_steal_pointer (&ret));
+      ret = gdk_scroll_event_new (GDK_SURFACE (surface),
+                                  pointer,
+                                  NULL,
+                                  get_time_from_ns_event (nsevent),
+                                  state,
+                                  0.0, 0.0, TRUE);
+    }
+
   return g_steal_pointer (&ret);
 }
 
diff --git a/gtk/gtkscrolledwindow.c b/gtk/gtkscrolledwindow.c
index 49be97080c..1842dcd528 100644
--- a/gtk/gtkscrolledwindow.c
+++ b/gtk/gtkscrolledwindow.c
@@ -1225,16 +1225,15 @@ check_update_scrollbar_proximity (GtkScrolledWindow *sw,
 }
 
 static double
-get_scroll_unit (GtkScrolledWindow *sw,
-                 GtkOrientation     orientation)
+get_scroll_unit (GtkScrolledWindow        *sw,
+                 GtkOrientation            orientation,
+                 GtkEventControllerScroll *scroll)
 {
-  double scroll_unit;
-
-#ifndef GDK_WINDOWING_MACOS
   GtkScrolledWindowPrivate *priv = gtk_scrolled_window_get_instance_private (sw);
   GtkScrollbar *scrollbar;
   GtkAdjustment *adj;
   double page_size;
+  double scroll_unit;
 
   if (orientation == GTK_ORIENTATION_HORIZONTAL)
     scrollbar = GTK_SCROLLBAR (priv->hscrollbar);
@@ -1247,8 +1246,16 @@ get_scroll_unit (GtkScrolledWindow *sw,
   adj = gtk_scrollbar_get_adjustment (scrollbar);
   page_size = gtk_adjustment_get_page_size (adj);
   scroll_unit = pow (page_size, 2.0 / 3.0);
-#else
-  scroll_unit = 1;
+
+#ifdef GDK_WINDOWING_MACOS
+  {
+    GdkEvent *event = gtk_event_controller_get_current_event (GTK_EVENT_CONTROLLER (scroll));
+
+    if (event != NULL &&
+        gdk_event_get_event_type (event) == GDK_SCROLL &&
+        gdk_scroll_event_get_direction (event) == GDK_SCROLL_SMOOTH)
+      scroll_unit = 1;
+  }
 #endif
 
   return scroll_unit;
@@ -1396,7 +1403,7 @@ scrolled_window_scroll (GtkScrolledWindow        *scrolled_window,
       double scroll_unit;
 
       adj = gtk_scrollbar_get_adjustment (GTK_SCROLLBAR (priv->hscrollbar));
-      scroll_unit = get_scroll_unit (scrolled_window, GTK_ORIENTATION_HORIZONTAL);
+      scroll_unit = get_scroll_unit (scrolled_window, GTK_ORIENTATION_HORIZONTAL, scroll);
 
       new_value = priv->unclamped_hadj_value + delta_x * scroll_unit;
       _gtk_scrolled_window_set_adjustment_value (scrolled_window, adj,
@@ -1411,7 +1418,7 @@ scrolled_window_scroll (GtkScrolledWindow        *scrolled_window,
       double scroll_unit;
 
       adj = gtk_scrollbar_get_adjustment (GTK_SCROLLBAR (priv->vscrollbar));
-      scroll_unit = get_scroll_unit (scrolled_window, GTK_ORIENTATION_VERTICAL);
+      scroll_unit = get_scroll_unit (scrolled_window, GTK_ORIENTATION_VERTICAL, scroll);
 
       new_value = priv->unclamped_vadj_value + delta_y * scroll_unit;
       _gtk_scrolled_window_set_adjustment_value (scrolled_window, adj,
@@ -1469,8 +1476,8 @@ scroll_controller_decelerate (GtkEventControllerScroll *scroll,
 
   shifted = (state & GDK_SHIFT_MASK) != 0;
 
-  unit_x = get_scroll_unit (scrolled_window, GTK_ORIENTATION_HORIZONTAL);
-  unit_y = get_scroll_unit (scrolled_window, GTK_ORIENTATION_VERTICAL);
+  unit_x = get_scroll_unit (scrolled_window, GTK_ORIENTATION_HORIZONTAL, scroll);
+  unit_y = get_scroll_unit (scrolled_window, GTK_ORIENTATION_VERTICAL, scroll);
 
   if (shifted)
     {


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]