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.
This commit is contained in:
Christian Hergert
2022-02-24 18:55:42 -08:00
parent 617deb8bb6
commit f278f3610b
2 changed files with 51 additions and 21 deletions

View File

@@ -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);
}

View File

@@ -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)
{