From 5beb01373db64cd9458a4c6ac9488f4918383b13 Mon Sep 17 00:00:00 2001 From: Sunny Date: Mon, 23 Mar 2026 23:48:03 +0000 Subject: [PATCH] Add smooth scroll support in GthImageViewer Enabling smooth scroll support in image viewer allows touch pad (on laptops) to zoom-in/zoom-out and change image without a mouse with a wheel. The zoom and image change scenarios are handled differently. Since smooth/non-discrete change in zoom level is preferable, the scroll delta is directly used to change the zoom level. But in case of image change, directly applying even a tiny scroll delta change +/- can result in quick and large jump in image change. A small threshold is introduced to reject tiny scroll delta which may result in unintended image change. This still allows large jumps in image change using scroll above the threshold. --- pix/gth-browser.c | 26 ++++++++++++++++++++++++-- pix/gth-image-viewer.c | 16 ++++++++++++++++ 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/pix/gth-browser.c b/pix/gth-browser.c index 822f657e..5570126b 100644 --- a/pix/gth-browser.c +++ b/pix/gth-browser.c @@ -6009,13 +6009,35 @@ gth_browser_viewer_scroll_event_cb (GthBrowser *browser, if (event->state & GDK_CONTROL_MASK) return FALSE; - if ((event->direction != GDK_SCROLL_UP) && (event->direction != GDK_SCROLL_DOWN)) + if ((event->direction != GDK_SCROLL_UP) && (event->direction != GDK_SCROLL_DOWN) + && (event->direction != GDK_SCROLL_SMOOTH)) return FALSE; handled = FALSE; switch (browser->priv->scroll_action) { case GTH_SCROLL_ACTION_CHANGE_FILE: - if (event->direction == GDK_SCROLL_UP) + if (event->direction == GDK_SCROLL_SMOOTH) + { + gdouble y_delta; + if (gdk_event_get_scroll_deltas ((GdkEvent *)event, NULL, &y_delta)) + { + /* Introduce a small threshold that must be crossed to trigger + * the action. This helps cancel out short touch scroll movements + * which may be unintended. */ + if (fabs(y_delta) < 0.5) + { + handled = FALSE; + break; + } + if (y_delta > 0) + gth_browser_show_next_image (browser, FALSE, FALSE); + else + gth_browser_show_prev_image (browser, FALSE, FALSE); + handled = TRUE; + } + break; + } + else if (event->direction == GDK_SCROLL_UP) gth_browser_show_prev_image (browser, FALSE, FALSE); else gth_browser_show_next_image (browser, FALSE, FALSE); diff --git a/pix/gth-image-viewer.c b/pix/gth-image-viewer.c index 7bcafb08..be7bf984 100644 --- a/pix/gth-image-viewer.c +++ b/pix/gth-image-viewer.c @@ -427,6 +427,7 @@ gth_image_viewer_realize (GtkWidget *widget) | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_MOTION_MASK | GDK_SCROLL_MASK + | GDK_SMOOTH_SCROLL_MASK | GDK_STRUCTURE_MASK); attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_WMCLASS; window = gdk_window_new (gtk_widget_get_parent_window (widget), @@ -2188,6 +2189,21 @@ gth_image_viewer_zoom_from_scroll (GthImageViewer *self, gtk_widget_queue_resize (GTK_WIDGET (self)); handled = TRUE; break; + case GDK_SCROLL_SMOOTH: + gdouble y_delta; + if (gdk_event_get_scroll_deltas ((GdkEvent *)event, NULL, &y_delta)) + { + if (y_delta < 0) + new_zoom_level = get_prev_zoom (self->priv->zoom_level); + else if (y_delta > 0) + new_zoom_level = get_next_zoom (self->priv->zoom_level); + else + break; + set_zoom_centered_at (self, new_zoom_level, FALSE, (int) event->x, (int) event->y); + gtk_widget_queue_resize (GTK_WIDGET (self)); + handled = TRUE; + } + break; default: break;