From e20f7cb1abd28cd4954ec23ce56491fad7107bb3 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Sun, 9 Aug 2026 08:10:04 -0300 Subject: [PATCH] gtk4-prep: restore right-click node popup and alt+scroll channel tab switching --- src/bauhaus/bauhaus.c | 21 +++++++++++++++++++++ src/bauhaus/bauhaus.h | 6 +++++- src/iop/atrous.c | 9 ++++++++- src/iop/colorequal.c | 15 +++++++++++++-- src/iop/colorzones.c | 9 ++++++++- src/iop/denoiseprofile.c | 16 ++++++++++++++++ src/iop/rawdenoise.c | 13 +++++++++++++ 7 files changed, 84 insertions(+), 5 deletions(-) diff --git a/src/bauhaus/bauhaus.c b/src/bauhaus/bauhaus.c index 004354a53b5..4bf0788ff3d 100644 --- a/src/bauhaus/bauhaus.c +++ b/src/bauhaus/bauhaus.c @@ -3333,6 +3333,27 @@ static void _popup_show(GtkWidget *widget) gtk_widget_grab_focus(pop->area); } +/** open the value-entry popup of a bauhaus widget, as if it were right-clicked. + * GTK4: gtk_get_current_event() is gone; when porting, read the time from + * the gesture's last event instead (gtk_gesture_get_last_event()). */ +void dt_bauhaus_widget_show_popup(GtkWidget *widget) +{ + dt_bauhaus_widget_t *w = DT_BAUHAUS_WIDGET(widget); + dt_bauhaus_t *bh = darktable.bauhaus; + + if(w->type == DT_BAUHAUS_TOGGLE) return; + + GdkEvent *event = gtk_get_current_event(); + if(event) + { + bh->opentime = gdk_event_get_time(event); + gdk_event_free(event); + } + bh->mouse_x = 0; + bh->mouse_y = 0; + _popup_show(widget); +} + static void _slider_add_step(GtkWidget *widget, float delta, const guint state, diff --git a/src/bauhaus/bauhaus.h b/src/bauhaus/bauhaus.h index ca8366768be..fcec2cec6cc 100644 --- a/src/bauhaus/bauhaus.h +++ b/src/bauhaus/bauhaus.h @@ -1,6 +1,6 @@ /* This file is part of darktable, - Copyright (C) 2012-2025 darktable developers. + Copyright (C) 2012-2026 darktable developers. darktable is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -195,6 +195,10 @@ const char* dt_bauhaus_widget_get_label(GtkWidget *widget); void dt_bauhaus_widget_hide_label(GtkWidget *widget); void dt_bauhaus_widget_set_show_extended_label(GtkWidget *widget, gboolean show); +// open the value-entry popup of a bauhaus widget, as if it were right-clicked. +// Used by callers that want the popup without sending the widget a synthetic +// button press (which a gesture-based widget cannot handle cleanly) +void dt_bauhaus_widget_show_popup(GtkWidget *widget); void dt_bauhaus_widget_set_module(GtkWidget *widget, dt_action_t *module); gpointer dt_bauhaus_widget_get_module(GtkWidget *widget); diff --git a/src/iop/atrous.c b/src/iop/atrous.c index 0da6c999b9d..2d357894544 100644 --- a/src/iop/atrous.c +++ b/src/iop/atrous.c @@ -1531,7 +1531,14 @@ static void area_scrolled(GtkEventControllerScroll *controller, if(dt_modifier_eq(controller, GDK_MOD1_MASK)) { - // FIXME: GTK4 - need to forward scroll event to notebook + // alt+scroll switches the channel tab (as before the controller conversion) + // GTK4: no gtk_widget_event() -- reimplement as a controller on the notebook + GdkEvent *event = gtk_get_current_event(); + if(event) + { + gtk_widget_event(GTK_WIDGET(g->channel_tabs), event); + gdk_event_free(event); + } return; } diff --git a/src/iop/colorequal.c b/src/iop/colorequal.c index fb2441eab13..670aa6c9de2 100644 --- a/src/iop/colorequal.c +++ b/src/iop/colorequal.c @@ -2761,7 +2761,17 @@ static void _area_button_press_callback(GtkGestureSingle *gesture, else g->dragging = TRUE; } - // other buttons: forward not supported with event controllers, ignored + else + { + // other buttons (e.g. right-click): open the value-entry popup of the + // selected node's slider. The old button-press-event handler forwarded + // the event to the slider widget; a gesture-based bauhaus widget cannot + // be fed a synthetic press (the unmatched release would leave its + // gesture with a stale sequence), so open the popup directly. Claim the + // event so it does not bubble up to the module menu. + dt_bauhaus_widget_show_popup(_get_slider(g, g->selected)); + dt_gui_claim(gesture); + } } static void _area_button_release_callback(GtkGestureSingle *gesture, @@ -2771,8 +2781,9 @@ static void _area_button_release_callback(GtkGestureSingle *gesture, dt_iop_module_t *self) { dt_iop_colorequal_gui_data_t *g = self->gui_data; + const guint button = gtk_gesture_single_get_current_button(gesture); - if(gtk_gesture_single_get_current_button(gesture) == GDK_BUTTON_PRIMARY) + if(button == GDK_BUTTON_PRIMARY) g->dragging = FALSE; } diff --git a/src/iop/colorzones.c b/src/iop/colorzones.c index 86f373e9446..8a9652c160a 100644 --- a/src/iop/colorzones.c +++ b/src/iop/colorzones.c @@ -1867,7 +1867,14 @@ static void _area_scrolled_callback(GtkEventControllerScroll *controller, if(dt_modifier_is(dt_key_modifier_state(), GDK_MOD1_MASK)) { - // FIXME: event forwarding to g->channel_tabs removed + // alt+scroll switches the channel tab (as before the controller conversion) + // GTK4: no gtk_widget_event() -- reimplement as a controller on the notebook + GdkEvent *event = gtk_get_current_event(); + if(event) + { + gtk_widget_event(GTK_WIDGET(g->channel_tabs), event); + gdk_event_free(event); + } return; } diff --git a/src/iop/denoiseprofile.c b/src/iop/denoiseprofile.c index 102aebd082e..41927feebee 100644 --- a/src/iop/denoiseprofile.c +++ b/src/iop/denoiseprofile.c @@ -3543,6 +3543,22 @@ static void denoiseprofile_scrolled(GtkEventControllerScroll *controller, { dt_iop_denoiseprofile_gui_data_t *g = self->gui_data; + if(dt_modifier_eq(controller, GDK_MOD1_MASK)) + { + // alt+scroll switches the channel tab (as before the controller conversion) + // GTK4: no gtk_widget_event() -- reimplement as a controller on the notebook + GdkEvent *event = gtk_get_current_event(); + if(event) + { + gtk_widget_event(GTK_WIDGET(g->channel > DT_DENOISE_PROFILE_B + ? g->channel_tabs_Y0U0V0 + : g->channel_tabs), + event); + gdk_event_free(event); + } + return; + } + if(dy != 0.0) { g->mouse_radius = CLAMP(g->mouse_radius * (1.f - 0.1f * dy), diff --git a/src/iop/rawdenoise.c b/src/iop/rawdenoise.c index 23ce2759b03..4c34c9bfb85 100644 --- a/src/iop/rawdenoise.c +++ b/src/iop/rawdenoise.c @@ -850,6 +850,19 @@ static void rawdenoise_scrolled(GtkEventControllerScroll *controller, gdouble dx { dt_iop_rawdenoise_gui_data_t *g = self->gui_data; + if(dt_modifier_eq(controller, GDK_MOD1_MASK)) + { + // alt+scroll switches the channel tab (as before the controller conversion) + // GTK4: no gtk_widget_event() -- reimplement as a controller on the notebook + GdkEvent *event = gtk_get_current_event(); + if(event) + { + gtk_widget_event(GTK_WIDGET(g->channel_tabs), event); + gdk_event_free(event); + } + return; + } + if(dy != 0.0) { g->mouse_radius = CLAMP(g->mouse_radius * (1.0 - 0.1 * dy), 0.2 / DT_IOP_RAWDENOISE_BANDS, 1.0);