Skip to content

Scale down MacOS scrolling from event controllers#20710

Open
dtorop wants to merge 3 commits intodarktable-org:masterfrom
dtorop:scroll-controller-fixes-macos
Open

Scale down MacOS scrolling from event controllers#20710
dtorop wants to merge 3 commits intodarktable-org:masterfrom
dtorop:scroll-controller-fixes-macos

Conversation

@dtorop
Copy link
Copy Markdown
Contributor

@dtorop dtorop commented Mar 31, 2026

Attenuate discrete scrolling deltas via a proxy handler set up in dt_gui_connect_scroll_discrete().

Usage:

  GtkEventController *scroll_controller =
    dt_gui_connect_scroll_discrete(widget, flags, handler_func, user_data);

The handler_func will receive discrete (integral) scroll deltas. The proxy will transparently accumulate smooth scroll (trackpad/touchpad) fractional scrolling as needed to provide integral steps. It will attenuate smooth scroll events, with slight attenuation on non-MacOS systems and substantial attenuation when compiled for MacOS..

To make a cross-plaform smooth scroll handler, we need to scale down the MacOS scroll deltas. For traditional GTK 3 code, dt_gui_get_scroll_unit_deltas() took care of this. This PR allows for using the GTK4-ready scroll signal generated by a GtkEventControllerScroll.

Notes:

  • MacOS trackpad scroll deltas are greater magnitude than those on other systems. They appear to be integral, normally 1 or 2, but can be as high as 10. This may be because they are distance-based and "kinetic". On Linux, similar scroll actions produce $0 \lt delta \leq 1$. GDK/GTK passes on the scroll events from the OS and does not unify their scales.
  • This PR changes the delta attenuation formula:
    • previously: $out = scale \cdot in$. On MacOS, $scale = \frac{1}{50} = 0.02$. On all other systems, $scale = 1$.
    • this PR: $out = scale \cdot in^{compression}$. This progressively attenuates large deltas, and slightly amplifies small deltas. On MacOS, $scale = 0.06, compression = 0.7$. On all other systems, $scale = 0.95, compression = 0.9$.
  • The new dt_gui_connect_scroll_discrete() should eventually replace all uses of dt_gui_get_scroll_unit_deltas() and dt_gui_get_scroll_unit_delta(). This will be follow-up work to make GTK4-ready code. There are about 18 of places to change this. Until this work is done, the feel of trackpad scrolling will be slightly different depending on whether it is handled by the old or new code.
  • This PR only attenuates/provides discrete scroll events. It will take follow-up work to add a proxy to provide GTK4 ready attenuation of non-discrete scroll events. There are only a couple uses of these in the codebase.
  • When calling dt_gui_connect_scroll_discrete(), the flags do not need to include GTK_EVENT_CONTROLLER_SCROLL_DISCRETE but should include one of GTK_EVENT_CONTROLLER_SCROLL_VERTICAL, GTK_EVENT_CONTROLLER_SCROLL_HORIZONTAL or GTK_EVENT_CONTROLLER_SCROLL_DISCRETE.

Also: In bauhaus _widget_scroll(), warn in the unlikely case called with a non-scroll or null event, rather than ignoring this via a NOP conditional. Don't free a null event.

Also: Update/remove a couple comments. In GTK4 it seems preferable to target events directly to widgets (as gtk_propagate_event and gtk_event_controller_handle_event are gone) so don't apologize in comments for using gtk_widget_event().

Fixes: #20698

See #20701 for some other discussion.

MacOS trackpad scroll events appear to be of much greater magnitude
than those on other systems. To make them usable, we need to scale
down the scroll deltas. For traditional GTK 3 code,
dt_gui_get_scroll_unit_deltas() took care of this. Unfortunately, this
code depends on the "scroll-event" signal. To make the code GTK 4
ready, we need to handle the "scroll" signal generated by a
GtkEventControllerScroll.

For discrete scrolls, we can handle this transparently via the
dt_gui_connect_scroll_discrete() setup function. This new function is
similar to dt_gui_connect_scroll(). There is no need to call it with
the GTK_EVENT_CONTROLLER_SCROLL_DISCRETE flag, as it adds this
automatically. If darktable is compiled for MacOS, a proxy function
will scale down the scroll events.

Note that this commit doesn't do anything to help scale down scroll
events from a non-discrete GtkEventControllerScroll.

Also: In bauhaus _widget_scroll, actually warn if called an a
non-scroll event or no event rather than having a useless NOP
conditional. Don't free the event in unlikely case we can't retrieve
it.

Also: Update/remove a couple comments. In GTK4 it seems preferable to
target events directly to widgets (as gtk_propagate_event and
gtk_event_controller_handle_event are gone) so don't apologize in
comments for using gtk_widget_event().

Fixes: darktable-org#20698
@MStraeten
Copy link
Copy Markdown
Collaborator

no decrease of sensitivity on sliders and also scope (color harmony rotation) with this fix

@dtorop
Copy link
Copy Markdown
Contributor Author

dtorop commented Mar 31, 2026

@MStraeten: Drat! So it doesn't fix anything?

Would you have time to add a bit of diagnostic code in and send the output when scrolling a slider? Something like:

modified   src/gui/gtk.c
@@ -4699,6 +4699,7 @@ static void _scroll_discrete_proxy(GtkEventControllerScroll* self,
                                     gdouble dy,
                                     _scroll_handler_proxy_t *h)
 {
+  dt_print_ext("proxy dx %f dy %f cur_dx %f cur_dy %f", dx, dy, h->cur_dx, h->cur_dy);
   // Even though the event controller has already accumulated smooth
   // scroll events to discrete dx/dy, MacOS smooth scrolling events
   // are too fast so scale them down via another accumulating stage.
@@ -4722,6 +4723,7 @@ static void _scroll_discrete_proxy(GtkEventControllerScroll* self,
       h->cur_dy -= steps;
       dy = steps;
     }
+    dt_print_ext("smooth dx %f dy %f cur_dx %f cur_dy %f", dx, dy, h->cur_dx, h->cur_dy);
   }
   if(dx != 0.0 || dy != 0.0)
     h->scroll_callback_real(self, dx, dy, h->scroll_data_real);

I also realize there might be a slightly nicer way to implement this (only accumulate scrolling at the darktable level, not at the GTK level), but not material unless this actually works.

@MStraeten
Copy link
Copy Markdown
Collaborator

7*.* --> rotating color harmonies in scope
8*.* --> dragging slider

    71.1853 proxy dx 0.000000 dy -1.000000 cur_dx 0.000000 cur_dy 0.000000
    71.2043 proxy dx 0.000000 dy -5.000000 cur_dx 0.000000 cur_dy 0.000000
    71.2268 proxy dx 0.000000 dy -7.000000 cur_dx 0.000000 cur_dy 0.000000
    71.2352 proxy dx 0.000000 dy -3.000000 cur_dx 0.000000 cur_dy 0.000000
    71.2452 proxy dx 0.000000 dy -3.000000 cur_dx 0.000000 cur_dy 0.000000
    71.2553 proxy dx 0.000000 dy -3.000000 cur_dx 0.000000 cur_dy 0.000000
    71.2602 proxy dx 0.000000 dy -1.000000 cur_dx 0.000000 cur_dy 0.000000
    71.2692 proxy dx 0.000000 dy -4.000000 cur_dx 0.000000 cur_dy 0.000000
    71.2776 proxy dx 0.000000 dy -4.000000 cur_dx 0.000000 cur_dy 0.000000
    71.2856 proxy dx 0.000000 dy -1.000000 cur_dx 0.000000 cur_dy 0.000000
    71.2936 proxy dx 0.000000 dy -6.000000 cur_dx 0.000000 cur_dy 0.000000
    71.3011 proxy dx 0.000000 dy -6.000000 cur_dx 0.000000 cur_dy 0.000000
    71.3102 proxy dx 0.000000 dy -5.000000 cur_dx 0.000000 cur_dy 0.000000
    71.3187 proxy dx 0.000000 dy -2.000000 cur_dx 0.000000 cur_dy 0.000000
    71.3268 proxy dx 0.000000 dy -6.000000 cur_dx 0.000000 cur_dy 0.000000
    71.3351 proxy dx 0.000000 dy -5.000000 cur_dx 0.000000 cur_dy 0.000000
    71.3430 proxy dx 0.000000 dy -5.000000 cur_dx 0.000000 cur_dy 0.000000
    71.3519 proxy dx 0.000000 dy -3.000000 cur_dx 0.000000 cur_dy 0.000000
    71.3602 proxy dx 0.000000 dy -7.000000 cur_dx 0.000000 cur_dy 0.000000
    71.3685 proxy dx 0.000000 dy -5.000000 cur_dx 0.000000 cur_dy 0.000000
    71.3769 proxy dx 0.000000 dy -1.000000 cur_dx 0.000000 cur_dy 0.000000
    71.3852 proxy dx 0.000000 dy -7.000000 cur_dx 0.000000 cur_dy 0.000000
    71.4019 proxy dx 0.000000 dy -10.000000 cur_dx 0.000000 cur_dy 0.000000
    71.4103 proxy dx 0.000000 dy -5.000000 cur_dx 0.000000 cur_dy 0.000000
    71.4178 proxy dx 0.000000 dy -2.000000 cur_dx 0.000000 cur_dy 0.000000
    71.4268 proxy dx 0.000000 dy -5.000000 cur_dx 0.000000 cur_dy 0.000000
    71.4352 proxy dx 0.000000 dy -6.000000 cur_dx 0.000000 cur_dy 0.000000
    71.4424 proxy dx 0.000000 dy -4.000000 cur_dx 0.000000 cur_dy 0.000000
    71.4518 proxy dx 0.000000 dy -2.000000 cur_dx 0.000000 cur_dy 0.000000
    71.4602 proxy dx 0.000000 dy -4.000000 cur_dx 0.000000 cur_dy 0.000000
    71.4685 proxy dx 0.000000 dy -5.000000 cur_dx 0.000000 cur_dy 0.000000
    71.4768 proxy dx 0.000000 dy -4.000000 cur_dx 0.000000 cur_dy 0.000000
    71.4852 proxy dx 0.000000 dy -2.000000 cur_dx 0.000000 cur_dy 0.000000
    71.4935 proxy dx 0.000000 dy -4.000000 cur_dx 0.000000 cur_dy 0.000000
    71.5018 proxy dx 0.000000 dy -4.000000 cur_dx 0.000000 cur_dy 0.000000
    71.5102 proxy dx 0.000000 dy -1.000000 cur_dx 0.000000 cur_dy 0.000000
    71.5185 proxy dx 0.000000 dy -3.000000 cur_dx 0.000000 cur_dy 0.000000
    71.5268 proxy dx 0.000000 dy -3.000000 cur_dx 0.000000 cur_dy 0.000000
    71.5352 proxy dx 0.000000 dy -2.000000 cur_dx 0.000000 cur_dy 0.000000
    71.5435 proxy dx 0.000000 dy -1.000000 cur_dx 0.000000 cur_dy 0.000000
    71.5518 proxy dx 0.000000 dy -3.000000 cur_dx 0.000000 cur_dy 0.000000
    71.5601 proxy dx 0.000000 dy -2.000000 cur_dx 0.000000 cur_dy 0.000000
    71.5768 proxy dx 0.000000 dy -3.000000 cur_dx 0.000000 cur_dy 0.000000
    71.5852 proxy dx 0.000000 dy -2.000000 cur_dx 0.000000 cur_dy 0.000000
    71.5935 proxy dx 0.000000 dy -2.000000 cur_dx 0.000000 cur_dy 0.000000
    71.6018 proxy dx 0.000000 dy -1.000000 cur_dx 0.000000 cur_dy 0.000000
    71.6102 proxy dx 0.000000 dy -1.000000 cur_dx 0.000000 cur_dy 0.000000
    71.6185 proxy dx 0.000000 dy -2.000000 cur_dx 0.000000 cur_dy 0.000000
    74.0027 proxy dx 0.000000 dy 3.000000 cur_dx 0.000000 cur_dy 0.000000
    74.0214 proxy dx 0.000000 dy 7.000000 cur_dx 0.000000 cur_dy 0.000000
    74.0269 proxy dx 0.000000 dy 1.000000 cur_dx 0.000000 cur_dy 0.000000
    74.0409 proxy dx 0.000000 dy 7.000000 cur_dx 0.000000 cur_dy 0.000000
    74.0617 proxy dx 0.000000 dy 6.000000 cur_dx 0.000000 cur_dy 0.000000
    74.0773 proxy dx 0.000000 dy 3.000000 cur_dx 0.000000 cur_dy 0.000000
    74.0852 proxy dx 0.000000 dy 3.000000 cur_dx 0.000000 cur_dy 0.000000
    74.0935 proxy dx 0.000000 dy 3.000000 cur_dx 0.000000 cur_dy 0.000000
    74.1023 proxy dx 0.000000 dy 3.000000 cur_dx 0.000000 cur_dy 0.000000
    74.1108 proxy dx 0.000000 dy 1.000000 cur_dx 0.000000 cur_dy 0.000000
    74.1185 proxy dx 0.000000 dy 4.000000 cur_dx 0.000000 cur_dy 0.000000
    74.1269 proxy dx 0.000000 dy 3.000000 cur_dx 0.000000 cur_dy 0.000000
    74.1352 proxy dx 0.000000 dy 2.000000 cur_dx 0.000000 cur_dy 0.000000
    74.1436 proxy dx 0.000000 dy 3.000000 cur_dx 0.000000 cur_dy 0.000000
    74.1518 proxy dx 0.000000 dy 1.000000 cur_dx 0.000000 cur_dy 0.000000
    74.1602 proxy dx 0.000000 dy 3.000000 cur_dx 0.000000 cur_dy 0.000000
    74.1683 proxy dx 0.000000 dy 2.000000 cur_dx 0.000000 cur_dy 0.000000
    74.1763 proxy dx 0.000000 dy 1.000000 cur_dx 0.000000 cur_dy 0.000000
    74.1852 proxy dx 0.000000 dy 3.000000 cur_dx 0.000000 cur_dy 0.000000
    74.1935 proxy dx 0.000000 dy 3.000000 cur_dx 0.000000 cur_dy 0.000000
    74.2015 proxy dx 0.000000 dy 2.000000 cur_dx 0.000000 cur_dy 0.000000
    74.2094 proxy dx 0.000000 dy 1.000000 cur_dx 0.000000 cur_dy 0.000000
    74.2127 proxy dx 0.000000 dy 2.000000 cur_dx 0.000000 cur_dy 0.000000
    74.2185 proxy dx 0.000000 dy 1.000000 cur_dx 0.000000 cur_dy 0.000000
    74.2268 proxy dx 0.000000 dy 2.000000 cur_dx 0.000000 cur_dy 0.000000
    74.2348 proxy dx 0.000000 dy 3.000000 cur_dx 0.000000 cur_dy 0.000000
    74.2428 proxy dx 0.000000 dy 1.000000 cur_dx 0.000000 cur_dy 0.000000
    74.2460 proxy dx 0.000000 dy 2.000000 cur_dx 0.000000 cur_dy 0.000000
    74.2602 proxy dx 0.000000 dy 2.000000 cur_dx 0.000000 cur_dy 0.000000
    74.2680 proxy dx 0.000000 dy 1.000000 cur_dx 0.000000 cur_dy 0.000000
    74.2762 proxy dx 0.000000 dy 1.000000 cur_dx 0.000000 cur_dy 0.000000
    74.2852 proxy dx 0.000000 dy 3.000000 cur_dx 0.000000 cur_dy 0.000000
    74.2936 proxy dx 0.000000 dy 2.000000 cur_dx 0.000000 cur_dy 0.000000
    74.3011 proxy dx 0.000000 dy 1.000000 cur_dx 0.000000 cur_dy 0.000000
    74.3095 proxy dx 0.000000 dy 1.000000 cur_dx 0.000000 cur_dy 0.000000
    74.3185 proxy dx 0.000000 dy 3.000000 cur_dx 0.000000 cur_dy 0.000000
    74.3269 proxy dx 0.000000 dy 1.000000 cur_dx 0.000000 cur_dy 0.000000
    74.3435 proxy dx 0.000000 dy 2.000000 cur_dx 0.000000 cur_dy 0.000000
    74.3518 proxy dx 0.000000 dy 2.000000 cur_dx 0.000000 cur_dy 0.000000
    74.3602 proxy dx 0.000000 dy 1.000000 cur_dx 0.000000 cur_dy 0.000000
    74.3852 proxy dx 0.000000 dy 2.000000 cur_dx 0.000000 cur_dy 0.000000
    74.3935 proxy dx 0.000000 dy 1.000000 cur_dx 0.000000 cur_dy 0.000000
    74.4014 proxy dx 0.000000 dy 1.000000 cur_dx 0.000000 cur_dy 0.000000
    74.4268 proxy dx 0.000000 dy 1.000000 cur_dx 0.000000 cur_dy 0.000000
    74.4353 proxy dx 0.000000 dy 1.000000 cur_dx 0.000000 cur_dy 0.000000
    74.4733 proxy dx 0.000000 dy 1.000000 cur_dx 0.000000 cur_dy 0.000000
    74.4739 proxy dx 0.000000 dy 1.000000 cur_dx 0.000000 cur_dy 0.000000
    80.3740 proxy dx 0.000000 dy 1.000000 cur_dx 0.000000 cur_dy 0.000000
    80.3810 proxy dx 0.000000 dy 3.000000 cur_dx 0.000000 cur_dy 0.000000
    80.4159 proxy dx 0.000000 dy 3.000000 cur_dx 0.000000 cur_dy 0.000000
    80.4531 proxy dx 0.000000 dy 14.000000 cur_dx 0.000000 cur_dy 0.000000
    80.4829 proxy dx 0.000000 dy 5.000000 cur_dx 0.000000 cur_dy 0.000000
    80.5257 proxy dx 0.000000 dy 2.000000 cur_dx 0.000000 cur_dy 0.000000
    80.5476 proxy dx 0.000000 dy 7.000000 cur_dx 0.000000 cur_dy 0.000000
    80.5560 proxy dx 0.000000 dy 14.000000 cur_dx 0.000000 cur_dy 0.000000
    80.5698 proxy dx 0.000000 dy 4.000000 cur_dx 0.000000 cur_dy 0.000000
    80.5860 proxy dx 0.000000 dy 3.000000 cur_dx 0.000000 cur_dy 0.000000
    80.6015 proxy dx 0.000000 dy 4.000000 cur_dx 0.000000 cur_dy 0.000000
    80.6060 proxy dx 0.000000 dy 1.000000 cur_dx 0.000000 cur_dy 0.000000
    80.6199 proxy dx 0.000000 dy 2.000000 cur_dx 0.000000 cur_dy 0.000000
    80.6453 proxy dx 0.000000 dy 7.000000 cur_dx 0.000000 cur_dy 0.000000
    80.6840 proxy dx 0.000000 dy 10.000000 cur_dx 0.000000 cur_dy 0.000000
    80.6959 proxy dx 0.000000 dy 3.000000 cur_dx 0.000000 cur_dy 0.000000
    80.7064 proxy dx 0.000000 dy 2.000000 cur_dx 0.000000 cur_dy 0.000000
    80.7143 proxy dx 0.000000 dy 2.000000 cur_dx 0.000000 cur_dy 0.000000
    80.7227 proxy dx 0.000000 dy 1.000000 cur_dx 0.000000 cur_dy 0.000000
    80.7310 proxy dx 0.000000 dy 3.000000 cur_dx 0.000000 cur_dy 0.000000
    80.7478 proxy dx 0.000000 dy 1.000000 cur_dx 0.000000 cur_dy 0.000000
    80.7560 proxy dx 0.000000 dy 2.000000 cur_dx 0.000000 cur_dy 0.000000
    80.7905 proxy dx 0.000000 dy 2.000000 cur_dx 0.000000 cur_dy 0.000000
    80.7977 proxy dx 0.000000 dy 1.000000 cur_dx 0.000000 cur_dy 0.000000
    80.8313 proxy dx 0.000000 dy 1.000000 cur_dx 0.000000 cur_dy 0.000000
    80.8564 proxy dx 0.000000 dy 2.000000 cur_dx 0.000000 cur_dy 0.000000
    81.9194 proxy dx 0.000000 dy -3.000000 cur_dx 0.000000 cur_dy 0.000000
    81.9213 proxy dx 0.000000 dy -1.000000 cur_dx 0.000000 cur_dy 0.000000
    81.9387 proxy dx 0.000000 dy -4.000000 cur_dx 0.000000 cur_dy 0.000000
    81.9560 proxy dx 0.000000 dy -6.000000 cur_dx 0.000000 cur_dy 0.000000
    81.9879 proxy dx 0.000000 dy -5.000000 cur_dx 0.000000 cur_dy 0.000000
    82.0259 proxy dx 0.000000 dy -2.000000 cur_dx 0.000000 cur_dy 0.000000
    82.0393 proxy dx 0.000000 dy -10.000000 cur_dx 0.000000 cur_dy 0.000000
    82.0522 proxy dx 0.000000 dy -2.000000 cur_dx 0.000000 cur_dy 0.000000
    82.0654 proxy dx 0.000000 dy -2.000000 cur_dx 0.000000 cur_dy 0.000000
    82.0803 proxy dx 0.000000 dy -3.000000 cur_dx 0.000000 cur_dy 0.000000
    82.1111 proxy dx 0.000000 dy -4.000000 cur_dx 0.000000 cur_dy 0.000000
    82.1118 proxy dx 0.000000 dy -2.000000 cur_dx 0.000000 cur_dy 0.000000
    82.1259 proxy dx 0.000000 dy -3.000000 cur_dx 0.000000 cur_dy 0.000000
    82.1310 proxy dx 0.000000 dy -1.000000 cur_dx 0.000000 cur_dy 0.000000
    82.1674 proxy dx 0.000000 dy -2.000000 cur_dx 0.000000 cur_dy 0.000000
    82.1810 proxy dx 0.000000 dy -8.000000 cur_dx 0.000000 cur_dy 0.000000
    82.2068 proxy dx 0.000000 dy -3.000000 cur_dx 0.000000 cur_dy 0.000000
    82.2137 proxy dx 0.000000 dy -1.000000 cur_dx 0.000000 cur_dy 0.000000
    82.2227 proxy dx 0.000000 dy -1.000000 cur_dx 0.000000 cur_dy 0.000000
    82.2393 proxy dx 0.000000 dy -4.000000 cur_dx 0.000000 cur_dy 0.000000
    82.2608 proxy dx 0.000000 dy -3.000000 cur_dx 0.000000 cur_dy 0.000000
    82.2804 proxy dx 0.000000 dy -1.000000 cur_dx 0.000000 cur_dy 0.000000
    82.3171 proxy dx 0.000000 dy -4.000000 cur_dx 0.000000 cur_dy 0.000000
    82.3310 proxy dx 0.000000 dy -1.000000 cur_dx 0.000000 cur_dy 0.000000
    82.3445 proxy dx 0.000000 dy -8.000000 cur_dx 0.000000 cur_dy 0.000000
    82.3893 proxy dx 0.000000 dy -2.000000 cur_dx 0.000000 cur_dy 0.000000
    83.7899 proxy dx 0.000000 dy -1.000000 cur_dx 0.000000 cur_dy 0.000000
    83.8194 proxy dx 0.000000 dy -3.000000 cur_dx 0.000000 cur_dy 0.000000
    83.8204 proxy dx 0.000000 dy -1.000000 cur_dx 0.000000 cur_dy 0.000000
    83.8394 proxy dx 0.000000 dy -2.000000 cur_dx 0.000000 cur_dy 0.000000
    83.8480 proxy dx 0.000000 dy -2.000000 cur_dx 0.000000 cur_dy 0.000000
    83.8643 proxy dx 0.000000 dy -2.000000 cur_dx 0.000000 cur_dy 0.000000
    83.8781 proxy dx 0.000000 dy -3.000000 cur_dx 0.000000 cur_dy 0.000000```

@dtorop dtorop marked this pull request as draft April 1, 2026 01:59
@dtorop
Copy link
Copy Markdown
Contributor Author

dtorop commented Apr 1, 2026

@MStraeten: Thank you for debug output. It looks like the scroll-begin and scroll-end events aren't getting triggered on MacOS. If you have a chance to try this PR with the follow-up commit e8af2e6, I'd be interested to see whether this works better. There are now tunable "scale" and "compression" parameters, currently 0.25 and 0.7 respectively for MacOS. If the slider is still moving too fast, perhaps reducing one or both of these would help?

If there is no difference or otherwise trouble with this code, I'd be interested to see diagnostics via this diff:

modified   src/gui/gtk.c
@@ -4678,8 +4678,10 @@ static void _scroll_discrete_proxy(GtkEventControllerScroll* controller,
                                    gdouble dy,
                                    gpointer user_data)
 {
+  dt_print_ext("proxy dx %f dy %f cur_dx %f cur_dy %f", dx, dy, _scroll_discrete_dx, _scroll_discrete_dy);
   GdkEvent *event = gtk_get_current_event();
   if(!event) return;
+  dt_print_ext("event type %d dir %d emulated %d", gdk_event_get_event_type(event), event->scroll.direction, gdk_event_get_pointer_emulated(event));
   if(gdk_event_get_event_type(event) == GDK_SCROLL
      && event->scroll.direction == GDK_SCROLL_SMOOTH
      // avoid double counting real and emulated events when receiving smooth scrolls
@@ -4699,6 +4701,7 @@ static void _scroll_discrete_proxy(GtkEventControllerScroll* controller,
 #endif
     _scroll_discrete_dx += copysign(pow(fabs(dx), compression), dx * scale);
     _scroll_discrete_dy += copysign(pow(fabs(dy), compression), dy * scale);
+    dt_print_ext("scaled dx %f dy %f", copysign(pow(fabs(dx), compression), dx * scale), copysign(pow(fabs(dy), compression), dy * scale));
     dx = dy = 0.0;
     if(fabs(_scroll_discrete_dx) >= 1.0)
     {
@@ -4712,6 +4715,7 @@ static void _scroll_discrete_proxy(GtkEventControllerScroll* controller,
       _scroll_discrete_dy -= steps;
       dy = steps;
     }
+    dt_print_ext("smooth stop %d dx %f dy %f cur_dx %f cur_dy %f", event->scroll.is_stop, dx, dy, _scroll_discrete_dx, _scroll_discrete_dy);
   }
   if(dx != 0.0 || dy != 0.0)
   {

Attenuate smooth scroll delta by calculating delta ** compression,
which will reduce large deltas (apparently found in momentum-based
scrolling on MacOS). On MacOS, instead of scaling down smooth scroll
by DT_UI_SCROLL_SMOOTH_DELTA_SCALE, scale down by 0.25.

It appears that for MacOS, we do not receive "scroll-begin" and
"scroll-end" events for trackpad events, so instead exam the GdkEvent,
which brings this code closer to extant working
dt_gui_get_scroll_unit_deltas().

Don't use GTK_EVENT_CONTROLLER_SCROLL_DISCRETE flag, regardless of OS,
as _scroll_discrete_proxy() will accumulate smooth scroll
events. Don't bother to handle scroll stop events as we won't receive
them from GTK and it is OK to not clear accumulated scroll on stop.

Simplify storage for proxy discrete scroll handler. Don't use an
allocated struct. We can keep dx/dy globally, as we do not expect
multiple simultaneous scrolls of multiple widgets. Store real scroll
handler as GObject data.

Note that the exponential attenuation math is on recommendation from
ChatGPT, based on very little actual data from MacOS.
@dtorop dtorop force-pushed the scroll-controller-fixes-macos branch from f45d2be to e8af2e6 Compare April 1, 2026 04:40
@MStraeten
Copy link
Copy Markdown
Collaborator

MStraeten commented Apr 1, 2026

diagnostic log 20710.txt - need to play around with both parameters - starting point isn't significant better

btw: the scope is just sensitive to up/down movements, the slider for up/down and left/right movements.

Fix error in formula which didn't actually multiply by scale. Reduce
the scale for MacOS. Rationale:

From a sample of 431 MacOS smooth scroll events, median delta is 1.
Breakdown of deltas by probability:

1: 45%
2: 27%
3: 12%
4: 5%
5: 6%
6: 2%
7: 1%
8: 1%
9: 0.2%
10: 0.2%

Previously we used a scale of 0.02 and a compression of 1. Make
scale/compression which give equivalent attenuated results for an
average sample of 1.5.

Also:

- Handle horizontal scrolling for histogram
- Update bauhaus copyright date
@dtorop
Copy link
Copy Markdown
Contributor Author

dtorop commented Apr 2, 2026

I had the math wrong and was dropping the scale parameter. Should be fixed in the latest commit.

The whole idea of using pow() to attenuate scale may not be worth it. The alternative would be to set scale to 0.02 and compression to 1 for MacOS, which should match the GTK3 behavior.

And thank you for pointing out about horizontal scroll on scope. Had been on todo, should work now.

Maybe this version works better? If not, debugging code would be this:

modified   src/gui/gtk.c
@@ -4678,8 +4678,10 @@ static void _scroll_discrete_proxy(GtkEventControllerScroll* controller,
                                    gdouble dy,
                                    gpointer user_data)
 {
+  dt_print_ext("proxy dx %f dy %f cur_dx %f cur_dy %f", dx, dy, _scroll_discrete_dx, _scroll_discrete_dy);
   GdkEvent *event = gtk_get_current_event();
   if(!event) return;
+  dt_print_ext("event type %d dir %d emulated %d", gdk_event_get_event_type(event), event->scroll.direction, gdk_event_get_pointer_emulated(event));
   if(gdk_event_get_event_type(event) == GDK_SCROLL
      && event->scroll.direction == GDK_SCROLL_SMOOTH
      // avoid double counting real and emulated events when receiving smooth scrolls
@@ -4701,6 +4703,7 @@ static void _scroll_discrete_proxy(GtkEventControllerScroll* controller,
     dy = scale * copysign(pow(fabs(dy), compression), dy);
     _scroll_discrete_dx += dx;
     _scroll_discrete_dy += dy;
+    dt_print_ext("scaled dx %f dy %f cur_dx %f cur_dy %f", dx, dy, _scroll_discrete_dx, _scroll_discrete_dy);
     dx = dy = 0.0;
     if(fabs(_scroll_discrete_dx) >= 1.0)
     {
@@ -4714,6 +4717,7 @@ static void _scroll_discrete_proxy(GtkEventControllerScroll* controller,
       _scroll_discrete_dy -= steps;
       dy = steps;
     }
+    dt_print_ext("smooth stop %d dx %f dy %f cur_dx %f cur_dy %f", event->scroll.is_stop, dx, dy, _scroll_discrete_dx, _scroll_discrete_dy);
   }
   if(dx != 0.0 || dy != 0.0)
   {

@MStraeten
Copy link
Copy Markdown
Collaborator

that fix was successful. thanks for the effort

@dtorop dtorop marked this pull request as ready for review April 2, 2026 11:25
@dtorop
Copy link
Copy Markdown
Contributor Author

dtorop commented Apr 2, 2026

@MStraeten: Great! Thank you for so many rounds of tests. It's helpful to see the MacOS scroll delta #'s, to understand a bit more why it requires special case code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

macos: sensitivity of trackpad / magic mouse increased

2 participants