From e3458e7070c77d54248c61d2425534940b43e2b0 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Sun, 26 Jul 2026 22:44:50 -0300 Subject: [PATCH 01/95] gtk4-prep: IOP module event controllers --- src/gui/gtk.c | 14 +++ src/gui/gtk.h | 7 ++ src/iop/atrous.c | 123 +++++++++++---------- src/iop/colorchecker.c | 59 +++++----- src/iop/colorequal.c | 73 +++++-------- src/iop/denoiseprofile.c | 100 ++++++++--------- src/iop/filmicrgb.c | 150 ++++++++++++-------------- src/iop/levels.c | 114 +++++++++----------- src/iop/lowlight.c | 71 ++++++------ src/iop/monochrome.c | 118 +++++++++----------- src/iop/rawdenoise.c | 70 ++++++------ src/iop/retouch.c | 73 +++++-------- src/iop/rgblevels.c | 145 +++++++++++-------------- src/iop/toneequal.c | 150 +++++++++++--------------- src/iop/zonesystem.c | 87 +++++++-------- src/libs/modulegroups.c | 226 +++++++++++++++++++++------------------ 16 files changed, 734 insertions(+), 846 deletions(-) diff --git a/src/gui/gtk.c b/src/gui/gtk.c index db66a175383..b0401cc676f 100644 --- a/src/gui/gtk.c +++ b/src/gui/gtk.c @@ -4946,6 +4946,20 @@ GtkEventController *(dt_gui_connect_scroll)(GtkWidget *widget, return controller; } +GtkEventController *(dt_gui_connect_key)(GtkWidget *widget, + GCallback pressed, + gpointer data) +{ + GtkEventController *controller = gtk_event_controller_key_new(widget); + gtk_event_controller_set_propagation_phase(controller, GTK_PHASE_TARGET); + g_object_weak_ref(G_OBJECT(widget), (GWeakNotify) g_object_unref, controller); + // GTK4 gtk_widget_add_controller(widget, GTK_EVENT_CONTROLLER(controller)); + + if(pressed) g_signal_connect(controller, "key-pressed", G_CALLBACK(pressed), data); + + return controller; +} + static int busy_nest_count = 0; diff --git a/src/gui/gtk.h b/src/gui/gtk.h index 30fa078f9c1..f4a1ee89885 100644 --- a/src/gui/gtk.h +++ b/src/gui/gtk.h @@ -588,6 +588,13 @@ GtkEventController *(dt_gui_connect_scroll)(GtkWidget *widget, ASSERT_FUNC_TYPE(scroll, void(*)(GtkEventControllerScroll *, double, double, __typeof__(data))), \ dt_gui_connect_scroll(GTK_WIDGET(widget), (flags), G_CALLBACK(scroll), (data))) +GtkEventController *(dt_gui_connect_key)(GtkWidget *widget, + GCallback pressed, + gpointer data); +#define dt_gui_connect_key(widget, pressed, data) ( \ + ASSERT_FUNC_TYPE(pressed, gboolean(*)(GtkEventControllerKey *, guint, guint, GdkModifierType, __typeof__(data))), \ + dt_gui_connect_key(GTK_WIDGET(widget), G_CALLBACK(pressed), (data))) + #define dt_gui_claim(gesture) \ gtk_gesture_set_state(GTK_GESTURE(gesture), GTK_EVENT_SEQUENCE_CLAIMED) #define dt_gui_deny(gesture) \ diff --git a/src/iop/atrous.c b/src/iop/atrous.c index be17168bd28..0cf35d9fefd 100644 --- a/src/iop/atrous.c +++ b/src/iop/atrous.c @@ -1025,17 +1025,26 @@ void gui_update(dt_iop_module_t *self) // gui stuff: -static gboolean area_enter_leave_notify(GtkWidget *widget, - GdkEventCrossing *event, - dt_iop_module_t *self) +static void area_enter_notify(GtkEventControllerMotion *controller, + gdouble x, + gdouble y, + dt_iop_module_t *self) { dt_iop_atrous_gui_data_t *g = self->gui_data; - g->in_curve = dt_gdk_event_get_type(event) == GDK_ENTER_NOTIFY; + g->in_curve = TRUE; if(!g->dragging) g->x_move = -1; + gtk_widget_queue_draw(gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller))); +} - gtk_widget_queue_draw(widget); - return FALSE; +static void area_leave_notify(GtkEventControllerMotion *controller, + dt_iop_module_t *self) +{ + dt_iop_atrous_gui_data_t *g = self->gui_data; + g->in_curve = FALSE; + if(!g->dragging) + g->x_move = -1; + gtk_widget_queue_draw(gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller))); } // fills in new parameters based on mouse position (in 0,1) @@ -1372,19 +1381,21 @@ static gboolean area_draw(GtkWidget *widget, return FALSE; } -static gboolean area_motion_notify(GtkWidget *widget, - GdkEventMotion *event, - dt_iop_module_t *self) +static void area_motion_notify(GtkEventControllerMotion *controller, + gdouble x, + gdouble y, + dt_iop_module_t *self) { dt_iop_atrous_gui_data_t *g = self->gui_data; dt_iop_atrous_params_t *p = self->params; + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); const int inset = INSET; GtkAllocation allocation; gtk_widget_get_allocation(widget, &allocation); const int height = allocation.height - 2 * inset - DT_RESIZE_HANDLE_SIZE; const int width = allocation.width - 2 * inset; - if(!g->dragging) g->mouse_x = CLAMP(dt_gdk_event_get_x(event) - inset, 0, width) / (float)width; - g->mouse_y = 1.0 - CLAMP(dt_gdk_event_get_y(event) - inset, 0, height) / (float)height; + if(!g->dragging) g->mouse_x = CLAMP(x - inset, 0, width) / (float)width; + g->mouse_y = 1.0 - CLAMP(y - inset, 0, height) / (float)height; darktable.control->element = 0; @@ -1398,7 +1409,7 @@ static gboolean area_motion_notify(GtkWidget *widget, *p = g->drag_params; if(g->x_move >= 0) { - const float mx = CLAMP(dt_gdk_event_get_x(event) - inset, 0, width) / (float)width; + const float mx = CLAMP(x - inset, 0, width) / (float)width; if(g->x_move > 0 && g->x_move < BANDS - 1) { const float minx = p->x[g->channel][g->x_move - 1] + 0.001f; @@ -1413,7 +1424,7 @@ static gboolean area_motion_notify(GtkWidget *widget, gtk_widget_queue_draw(widget); dt_dev_add_history_item_target(darktable.develop, self, TRUE, widget + g->channel); } - else if(dt_gdk_event_get_y(event) > height) + else if(y > height) { // move x-positions g->x_move = 0; @@ -1452,14 +1463,20 @@ static gboolean area_motion_notify(GtkWidget *widget, g->x_move = -1; gtk_widget_queue_draw(widget); } - return TRUE; } -static gboolean area_button_press(GtkWidget *widget, - GdkEventButton *event, - dt_iop_module_t *self) +static void area_button_press(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, + dt_iop_module_t *self) { - if(dt_gdk_event_get_button(event) == GDK_BUTTON_PRIMARY && dt_gdk_event_get_type(event) == GDK_2BUTTON_PRESS) + if(gtk_gesture_single_get_current_button(gesture) != GDK_BUTTON_PRIMARY) + return; + + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + + if(n_press >= 2) { // reset current curve dt_iop_atrous_params_t *p = self->params; @@ -1473,7 +1490,7 @@ static gboolean area_button_press(GtkWidget *widget, } dt_dev_add_history_item_target(darktable.develop, self, TRUE, widget + g->channel2); } - else if(dt_gdk_event_get_button(event) == GDK_BUTTON_PRIMARY) + else { // set active point dt_iop_atrous_gui_data_t *g = self->gui_data; @@ -1485,46 +1502,45 @@ static gboolean area_button_press(GtkWidget *widget, const int width = allocation.width - 2 * inset; g->mouse_pick = dt_draw_curve_calc_value(g->minmax_curve, - CLAMP(dt_gdk_event_get_x(event) - inset, 0, width) / (float)width); - g->mouse_pick -= 1.0 - CLAMP(dt_gdk_event_get_y(event) - inset, 0, height) / (float)height; + CLAMP(x - inset, 0, width) / (float)width); + g->mouse_pick -= 1.0 - CLAMP(y - inset, 0, height) / (float)height; g->dragging = 1; - return TRUE; } - return FALSE; } -static gboolean area_button_release(GtkWidget *widget, - GdkEventButton *event, - dt_iop_module_t *self) +static void area_button_release(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, + dt_iop_module_t *self) { - if(dt_gdk_event_get_button(event) == GDK_BUTTON_PRIMARY) - { - dt_iop_atrous_gui_data_t *g = self->gui_data; - g->dragging = 0; - reset_mix(self); - return TRUE; - } - return FALSE; + if(gtk_gesture_single_get_current_button(gesture) != GDK_BUTTON_PRIMARY) + return; + + dt_iop_atrous_gui_data_t *g = self->gui_data; + g->dragging = 0; + reset_mix(self); } -static gboolean area_scrolled(GtkWidget *widget, - GdkEventScroll *event, - dt_iop_module_t *self) +static void area_scrolled(GtkEventControllerScroll *controller, + gdouble dx, + gdouble dy, + dt_iop_module_t *self) { dt_iop_atrous_gui_data_t *g = self->gui_data; + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); - if(dt_gui_ignore_scroll(event)) return FALSE; - - if(dt_modifier_is(dt_gdk_event_get_state(event), GDK_MOD1_MASK)) - return gtk_widget_event(GTK_WIDGET(g->channel_tabs), (GdkEvent*)event); + if(dt_modifier_eq(controller, GDK_MOD1_MASK)) + { + // FIXME: GTK4 - need to forward scroll event to notebook + return; + } - int delta_y; - if(dt_gui_get_scroll_unit_delta(event, &delta_y)) + if(dy != 0.0) { - g->mouse_radius = CLAMP(g->mouse_radius * (1.0 - 0.1 * delta_y), 0.25 / BANDS, 1.0); + g->mouse_radius = CLAMP(g->mouse_radius * (1.0 - 0.1 * dy), 0.25 / BANDS, 1.0); gtk_widget_queue_draw(widget); } - return TRUE; } static void tab_switch(GtkNotebook *notebook, @@ -1770,18 +1786,11 @@ void gui_init(dt_iop_module_t *self) dt_action_define_iop(self, NULL, N_("graph"), GTK_WIDGET(g->area), &_action_def_equalizer); g_signal_connect(G_OBJECT(g->area), "draw", G_CALLBACK(area_draw), self); - g_signal_connect(G_OBJECT(g->area), "button-press-event", - G_CALLBACK(area_button_press), self); - g_signal_connect(G_OBJECT(g->area), "button-release-event", - G_CALLBACK(area_button_release), self); - g_signal_connect(G_OBJECT(g->area), "motion-notify-event", - G_CALLBACK(area_motion_notify), self); - g_signal_connect(G_OBJECT(g->area), "leave-notify-event", - G_CALLBACK(area_enter_leave_notify), self); - g_signal_connect(G_OBJECT(g->area), "enter-notify-event", - G_CALLBACK(area_enter_leave_notify), self); - g_signal_connect(G_OBJECT(g->area), "scroll-event", - G_CALLBACK(area_scrolled), self); + dt_gui_connect_click(g->area, area_button_press, area_button_release, self); + dt_gui_connect_motion(g->area, area_motion_notify, area_enter_notify, area_leave_notify, self); + dt_gui_connect_scroll(g->area, GTK_EVENT_CONTROLLER_SCROLL_BOTH_AXES + | GTK_EVENT_CONTROLLER_SCROLL_DISCRETE, + area_scrolled, self); self->widget = dt_gui_vbox(g->channel_tabs, g->area); diff --git a/src/iop/colorchecker.c b/src/iop/colorchecker.c index 548790259d6..730df9e250a 100644 --- a/src/iop/colorchecker.c +++ b/src/iop/colorchecker.c @@ -1380,22 +1380,24 @@ static gboolean checker_draw(GtkWidget *widget, return TRUE; } -static gboolean checker_motion_notify( - GtkWidget *widget, - GdkEventMotion *event, +static void checker_motion_notify( + GtkEventControllerMotion *controller, + gdouble x, + gdouble y, dt_iop_module_t *self) { // highlight? dt_iop_colorchecker_params_t *p = self->params; dt_iop_colorchecker_gui_data_t *g = self->gui_data; + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); GtkAllocation allocation; gtk_widget_get_allocation(widget, &allocation); const int width = allocation.width; const int height = allocation.height; - const float mouse_x = CLAMP(dt_gdk_event_get_x(event), 0, width); - const float mouse_y = CLAMP(dt_gdk_event_get_y(event), 0, height); + const float mouse_x = CLAMP(x, 0, width); + const float mouse_y = CLAMP(y, 0, height); int cells_x = 6, cells_y = 4; if(p->num_patches > 24) { @@ -1405,7 +1407,7 @@ static gboolean checker_motion_notify( const float mx = mouse_x * cells_x / (float)width; const float my = mouse_y * cells_y / (float)height; const int patch = (int)mx + cells_x * (int)my; - if(patch < 0 || patch >= p->num_patches) return FALSE; + if(patch < 0 || patch >= p->num_patches) return; char tooltip[1024]; snprintf(tooltip, sizeof(tooltip), _("(%2.2f %2.2f %2.2f)\n" @@ -1416,21 +1418,24 @@ static gboolean checker_motion_notify( "shift+click while color picking to replace patch"), p->source_L[patch], p->source_a[patch], p->source_b[patch]); gtk_widget_set_tooltip_text(g->area, tooltip); - return TRUE; } -static gboolean checker_button_press( - GtkWidget *widget, GdkEventButton *event, +static void checker_button_press( + GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, dt_iop_module_t *self) { dt_iop_colorchecker_params_t *p = self->params; dt_iop_colorchecker_gui_data_t *g = self->gui_data; + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); GtkAllocation allocation; gtk_widget_get_allocation(widget, &allocation); int width = allocation.width, height = allocation.height; - const float mouse_x = CLAMP(dt_gdk_event_get_x(event), 0, width); - const float mouse_y = CLAMP(dt_gdk_event_get_y(event), 0, height); + const float mouse_x = CLAMP(x, 0, width); + const float mouse_y = CLAMP(y, 0, height); int cells_x = 6, cells_y = 4; if(p->num_patches > 24) { @@ -1440,9 +1445,12 @@ static gboolean checker_button_press( const float mx = mouse_x * cells_x / (float)width; const float my = mouse_y * cells_y / (float)height; int patch = (int)mx + cells_x*(int)my; - if(dt_gdk_event_get_button(event) == GDK_BUTTON_PRIMARY && dt_gdk_event_get_type(event) == GDK_2BUTTON_PRESS) + + const guint button = gtk_gesture_single_get_current_button(gesture); + + if(button == GDK_BUTTON_PRIMARY && n_press >= 2) { // reset on double click - if(patch < 0 || patch >= p->num_patches) return FALSE; + if(patch < 0 || patch >= p->num_patches) return; p->target_L[patch] = p->source_L[patch]; p->target_a[patch] = p->source_a[patch]; p->target_b[patch] = p->source_b[patch]; @@ -1451,12 +1459,12 @@ static gboolean checker_button_press( _colorchecker_update_sliders(self); DT_LEAVE_GUI_UPDATE(); gtk_widget_queue_draw(g->area); - return TRUE; + return; } - else if(dt_gdk_event_get_button(event) == GDK_BUTTON_SECONDARY && (patch < p->num_patches)) + else if(button == GDK_BUTTON_SECONDARY && (patch < p->num_patches)) { // right click: delete patch, move others up - if(patch < 0 || patch >= p->num_patches) return FALSE; + if(patch < 0 || patch >= p->num_patches) return; memmove(p->target_L+patch, p->target_L+patch+1, sizeof(float)*(p->num_patches-1-patch)); memmove(p->target_a+patch, p->target_a+patch+1, @@ -1476,10 +1484,10 @@ static gboolean checker_button_press( _colorchecker_update_sliders(self); DT_LEAVE_GUI_UPDATE(); gtk_widget_queue_draw(g->area); - return TRUE; + return; } - else if((dt_gdk_event_get_button(event) == GDK_BUTTON_PRIMARY) && - dt_modifier_is(dt_gdk_event_get_state(event), GDK_SHIFT_MASK) && + else if(button == GDK_BUTTON_PRIMARY && + dt_modifier_is(dt_key_modifier_state(), GDK_SHIFT_MASK) && (self->request_color_pick == DT_REQUEST_COLORPICK_MODULE)) { // shift-left while colour picking: replace source colour @@ -1520,11 +1528,10 @@ static gboolean checker_button_press( g->patch = g->drawn_patch = patch; gtk_widget_queue_draw(g->area); } - return TRUE; + return; } if(patch >= p->num_patches) patch = p->num_patches-1; dt_bauhaus_combobox_set(g->combobox_patch, patch); - return FALSE; } void gui_init(dt_iop_module_t *self) @@ -1534,16 +1541,10 @@ void gui_init(dt_iop_module_t *self) // custom 24-patch widget in addition to combo box g->area = dtgtk_drawing_area_new_with_aspect_ratio(4.0/6.0); - gtk_widget_add_events(GTK_WIDGET(g->area), - GDK_POINTER_MOTION_MASK - | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - | GDK_LEAVE_NOTIFY_MASK); g_signal_connect(G_OBJECT(g->area), "draw", G_CALLBACK(checker_draw), self); - g_signal_connect(G_OBJECT(g->area), "button-press-event", - G_CALLBACK(checker_button_press), self); - g_signal_connect(G_OBJECT(g->area), "motion-notify-event", - G_CALLBACK(checker_motion_notify), self); + dt_gui_connect_click_all(g->area, checker_button_press, NULL, self); + dt_gui_connect_motion(g->area, checker_motion_notify, NULL, NULL, self); g->patch = 0; g->drawn_patch = -1; diff --git a/src/iop/colorequal.c b/src/iop/colorequal.c index 10e8be9394d..31f9c1f82ba 100644 --- a/src/iop/colorequal.c +++ b/src/iop/colorequal.c @@ -2709,76 +2709,67 @@ static gboolean _area_scrolled_callback(GtkWidget *widget, return gtk_widget_event(w, (GdkEvent*)event); } -static gboolean _area_motion_notify_callback(GtkWidget *widget, - const GdkEventMotion *event, - const dt_iop_module_t *self) +static void _area_motion_notify_callback(GtkEventControllerMotion *controller, + gdouble x, + gdouble y, + dt_iop_module_t *self) { dt_iop_colorequal_gui_data_t *g = self->gui_data; if(g->dragging && g->on_node) - _area_set_pos(g, dt_gdk_event_get_y(event)); + _area_set_pos(g, y); else { // look if close to a node const float epsilon = DT_PIXEL_APPLY_DPI(10.0); const int oldsel = g->selected; const int oldon = g->on_node; - g->selected = (int)(((float)dt_gdk_event_get_x(event) - g->points[0][0]) + g->selected = (int)(((float)x - g->points[0][0]) / (g->points[1][0] - g->points[0][0]) + 0.5f) % NODES; - g->on_node = fabsf(g->points[g->selected][1] - (float)dt_gdk_event_get_y(event)) < epsilon; + g->on_node = fabsf(g->points[g->selected][1] - (float)y) < epsilon; darktable.control->element = g->selected; if(oldsel != g->selected || oldon != g->on_node) gtk_widget_queue_draw(GTK_WIDGET(g->area)); } - - return TRUE; } -static gboolean _area_button_press_callback(GtkWidget *widget, - GdkEventButton *event, - dt_iop_module_t *self) +static void _area_button_press_callback(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, + 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(dt_gdk_event_get_button(event) == GDK_BUTTON_MIDDLE - || (dt_gdk_event_get_button(event) == GDK_BUTTON_PRIMARY // Ctrl+Click alias for macOS - && dt_modifier_is(dt_gdk_event_get_state(event), GDK_CONTROL_MASK))) + if(button == GDK_BUTTON_MIDDLE + || (button == GDK_BUTTON_PRIMARY // Ctrl+Click alias for macOS + && dt_modifier_is(dt_key_modifier_state(), GDK_CONTROL_MASK))) { dt_conf_set_bool("plugins/darkroom/colorequal/show_sliders", gtk_notebook_get_n_pages(g->notebook) != 4); gui_update(self); } - else if(dt_gdk_event_get_button(event) == GDK_BUTTON_PRIMARY) + else if(button == GDK_BUTTON_PRIMARY) { - if(dt_gdk_event_get_type(event) == GDK_2BUTTON_PRESS) - { + if(n_press >= 2) _area_reset_nodes(g); - return TRUE; - } else - { g->dragging = TRUE; - } } - else - return gtk_widget_event(_get_slider(g, g->selected), (GdkEvent*)event); - - return FALSE; + // other buttons: forward not supported with event controllers, ignored } -static gboolean _area_button_release_callback(GtkWidget *widget, - const GdkEventButton *event, - const dt_iop_module_t *self) +static void _area_button_release_callback(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, + dt_iop_module_t *self) { dt_iop_colorequal_gui_data_t *g = self->gui_data; - if(dt_gdk_event_get_button(event) == GDK_BUTTON_PRIMARY) - { + if(gtk_gesture_single_get_current_button(gesture) == GDK_BUTTON_PRIMARY) g->dragging = FALSE; - return TRUE; - } - - return FALSE; } static void _area_size_callback(GtkWidget *widget, @@ -2982,19 +2973,9 @@ void gui_init(dt_iop_module_t *self) dt_action_define_iop(self, NULL, N_("graph"), GTK_WIDGET(g->area), &_action_def_coloreq); gtk_widget_set_tooltip_text(GTK_WIDGET(g->area), _("double-click to reset the curve\nmiddle-click to toggle sliders visibility\nalt+scroll to change page")); gtk_widget_set_can_focus(GTK_WIDGET(g->area), TRUE); - gtk_widget_add_events(GTK_WIDGET(g->area), - GDK_BUTTON_PRESS_MASK - | GDK_POINTER_MOTION_MASK - | GDK_BUTTON_RELEASE_MASK - | GDK_SCROLL_MASK - | GDK_SMOOTH_SCROLL_MASK); g_signal_connect(G_OBJECT(g->area), "draw", G_CALLBACK(_iop_colorequalizer_draw), self); - g_signal_connect(G_OBJECT(g->area), "button-press-event", - G_CALLBACK(_area_button_press_callback), self); - g_signal_connect(G_OBJECT(g->area), "button-release-event", - G_CALLBACK(_area_button_release_callback), self); - g_signal_connect(G_OBJECT(g->area), "motion-notify-event", - G_CALLBACK(_area_motion_notify_callback), self); + dt_gui_connect_click_all(g->area, _area_button_press_callback, _area_button_release_callback, self); + dt_gui_connect_motion(g->area, _area_motion_notify_callback, NULL, NULL, self); g_signal_connect(G_OBJECT(g->area), "scroll-event", G_CALLBACK(_area_scrolled_callback), self); g_signal_connect(G_OBJECT(g->area), "size-allocate", diff --git a/src/iop/denoiseprofile.c b/src/iop/denoiseprofile.c index 4c5a6cbf4c8..5aab0fd1962 100644 --- a/src/iop/denoiseprofile.c +++ b/src/iop/denoiseprofile.c @@ -3442,18 +3442,20 @@ static gboolean denoiseprofile_draw(GtkWidget *widget, return FALSE; } -static gboolean denoiseprofile_motion_notify(GtkWidget *widget, - GdkEventMotion *event, - dt_iop_module_t *self) +static void denoiseprofile_motion_notify(GtkEventControllerMotion *controller, + gdouble x, + gdouble y, + dt_iop_module_t *self) { dt_iop_denoiseprofile_gui_data_t *g = self->gui_data; dt_iop_denoiseprofile_params_t *p = self->params; + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); const int inset = DT_IOP_DENOISE_PROFILE_INSET; GtkAllocation allocation; gtk_widget_get_allocation(widget, &allocation); int height = allocation.height - 2 * inset, width = allocation.width - 2 * inset; - if(!g->dragging) g->mouse_x = CLAMP(dt_gdk_event_get_x(event) - inset, 0, width) / (float)width; - g->mouse_y = 1.0 - CLAMP(dt_gdk_event_get_y(event) - inset, 0, height) / (float)height; + if(!g->dragging) g->mouse_x = CLAMP(x - inset, 0, width) / (float)width; + g->mouse_y = 1.0 - CLAMP(y - inset, 0, height) / (float)height; if(g->dragging) { *p = g->drag_params; @@ -3470,16 +3472,22 @@ static gboolean denoiseprofile_motion_notify(GtkWidget *widget, g->x_move = -1; } gtk_widget_queue_draw(widget); - return TRUE; } -static gboolean denoiseprofile_button_press(GtkWidget *widget, - GdkEventButton *event, - dt_iop_module_t *self) +static void denoiseprofile_button_press(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, + dt_iop_module_t *self) { dt_iop_denoiseprofile_gui_data_t *g = self->gui_data; const int ch = g->channel; - if(dt_gdk_event_get_button(event) == 1 && dt_gdk_event_get_type(event) == GDK_2BUTTON_PRESS) + if(gtk_gesture_single_get_current_button(gesture) != GDK_BUTTON_PRIMARY) + return; + + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + + if(n_press >= 2) { // reset current curve dt_iop_denoiseprofile_params_t *p = self->params; @@ -3493,7 +3501,7 @@ static gboolean denoiseprofile_button_press(GtkWidget *widget, dt_dev_add_history_item(darktable.develop, self, TRUE); gtk_widget_queue_draw(GTK_WIDGET(g->area)); } - else if(dt_gdk_event_get_button(event) == GDK_BUTTON_PRIMARY) + else { g->drag_params = *(dt_iop_denoiseprofile_params_t *)self->params; const int inset = DT_IOP_DENOISE_PROFILE_INSET; @@ -3502,57 +3510,46 @@ static gboolean denoiseprofile_button_press(GtkWidget *widget, int height = allocation.height - 2 * inset, width = allocation.width - 2 * inset; g->mouse_pick = dt_draw_curve_calc_value(g->transition_curve, - CLAMP(dt_gdk_event_get_x(event) - inset, 0, width) / (float)width); - g->mouse_pick -= 1.0 - CLAMP(dt_gdk_event_get_y(event) - inset, 0, height) / (float)height; + CLAMP(x - inset, 0, width) / (float)width); + g->mouse_pick -= 1.0 - CLAMP(y - inset, 0, height) / (float)height; g->dragging = 1; - return TRUE; } - return FALSE; } -static gboolean denoiseprofile_button_release(GtkWidget *widget, - GdkEventButton *event, - dt_iop_module_t *self) +static void denoiseprofile_button_release(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, + dt_iop_module_t *self) { - if(dt_gdk_event_get_button(event) == GDK_BUTTON_PRIMARY) - { - dt_iop_denoiseprofile_gui_data_t *g = self->gui_data; - g->dragging = 0; - return TRUE; - } - return FALSE; + if(gtk_gesture_single_get_current_button(gesture) != GDK_BUTTON_PRIMARY) + return; + + dt_iop_denoiseprofile_gui_data_t *g = self->gui_data; + g->dragging = 0; } -static gboolean denoiseprofile_leave_notify(GtkWidget *widget, - GdkEventCrossing *event, - dt_iop_module_t *self) +static void denoiseprofile_leave_notify(GtkEventControllerMotion *controller, + dt_iop_module_t *self) { dt_iop_denoiseprofile_gui_data_t *g = self->gui_data; if(!g->dragging) g->mouse_y = -1.0; - gtk_widget_queue_draw(widget); - return TRUE; + gtk_widget_queue_draw(gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller))); } -static gboolean denoiseprofile_scrolled(GtkWidget *widget, - GdkEventScroll *event, - dt_iop_module_t *self) +static void denoiseprofile_scrolled(GtkEventControllerScroll *controller, + gdouble dx, + gdouble dy, + dt_iop_module_t *self) { dt_iop_denoiseprofile_gui_data_t *g = self->gui_data; - if(dt_gui_ignore_scroll(event)) return FALSE; - - if(dt_modifier_is(dt_gdk_event_get_state(event), GDK_MOD1_MASK)) - return gtk_widget_event(GTK_WIDGET(g->channel > DT_DENOISE_PROFILE_B ? g->channel_tabs_Y0U0V0 : g->channel_tabs), (GdkEvent*)event); - - int delta_y; - if(dt_gui_get_scroll_unit_delta(event, &delta_y)) + if(dy != 0.0) { - g->mouse_radius = CLAMP(g->mouse_radius * (1.f - 0.1f * delta_y), + g->mouse_radius = CLAMP(g->mouse_radius * (1.f - 0.1f * dy), 0.2f / DT_IOP_DENOISE_PROFILE_BANDS, 1.f); - gtk_widget_queue_draw(widget); + gtk_widget_queue_draw(gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller))); } - - return TRUE; } static void denoiseprofile_tab_switch(GtkNotebook *notebook, @@ -3632,16 +3629,11 @@ void gui_init(dt_iop_module_t *self) dt_action_define_iop(self, NULL, N_("graph"), GTK_WIDGET(g->area), NULL); g_signal_connect(G_OBJECT(g->area), "draw", G_CALLBACK(denoiseprofile_draw), self); - g_signal_connect(G_OBJECT(g->area), "button-press-event", - G_CALLBACK(denoiseprofile_button_press), self); - g_signal_connect(G_OBJECT(g->area), "button-release-event", - G_CALLBACK(denoiseprofile_button_release), self); - g_signal_connect(G_OBJECT(g->area), "motion-notify-event", - G_CALLBACK(denoiseprofile_motion_notify), self); - g_signal_connect(G_OBJECT(g->area), "leave-notify-event", - G_CALLBACK(denoiseprofile_leave_notify), self); - g_signal_connect(G_OBJECT(g->area), "scroll-event", - G_CALLBACK(denoiseprofile_scrolled), self); + dt_gui_connect_click(g->area, denoiseprofile_button_press, denoiseprofile_button_release, self); + dt_gui_connect_motion(g->area, denoiseprofile_motion_notify, NULL, denoiseprofile_leave_notify, self); + dt_gui_connect_scroll(g->area, GTK_EVENT_CONTROLLER_SCROLL_BOTH_AXES + | GTK_EVENT_CONTROLLER_SCROLL_DISCRETE, + denoiseprofile_scrolled, self); dt_gui_box_add(g->box_wavelets, g->channel_tabs, g->channel_tabs_Y0U0V0, g->area); diff --git a/src/iop/filmicrgb.c b/src/iop/filmicrgb.c index c452b571dc7..8a33c4ffd5f 100644 --- a/src/iop/filmicrgb.c +++ b/src/iop/filmicrgb.c @@ -4165,110 +4165,101 @@ static gboolean dt_iop_tonecurve_draw(GtkWidget *widget, cairo_t *crf, dt_iop_mo return FALSE; } -static gboolean area_button_press(GtkWidget *widget, const GdkEventButton *event, dt_iop_module_t *self) +static void area_button_press(GtkGestureSingle *gesture, gint n_press, gdouble x, gdouble y, dt_iop_module_t *self) { - DT_GUARD_GUI_UPDATE(TRUE); + DT_GUARD_GUI_UPDATE(); dt_iop_filmicrgb_gui_data_t *g = self->gui_data; dt_iop_request_focus(self); - if(g->active_button != DT_FILMIC_GUI_BUTTON_LAST) + if(g->active_button == DT_FILMIC_GUI_BUTTON_LAST) + return; + + const guint button = gtk_gesture_single_get_current_button(gesture); + + if(button == GDK_BUTTON_PRIMARY && n_press >= 2) { + // double click resets view + if(g->active_button == DT_FILMIC_GUI_BUTTON_TYPE) + { + g->gui_mode = DT_FILMIC_GUI_LOOK; + gtk_widget_queue_draw(GTK_WIDGET(g->area)); + dt_conf_set_int("plugins/darkroom/filmicrgb/graph_view", g->gui_mode); + return; + } + return; + } - if(dt_gdk_event_get_button(event) == GDK_BUTTON_PRIMARY && dt_gdk_event_get_type(event) == GDK_2BUTTON_PRESS) + if(button == GDK_BUTTON_PRIMARY) + { + // simple left click cycles through modes in positive direction + if(g->active_button == DT_FILMIC_GUI_BUTTON_TYPE) { - // double click resets view - if(g->active_button == DT_FILMIC_GUI_BUTTON_TYPE) - { + // cycle type of graph + if(g->gui_mode == DT_FILMIC_GUI_RANGES) g->gui_mode = DT_FILMIC_GUI_LOOK; - gtk_widget_queue_draw(GTK_WIDGET(g->area)); - dt_conf_set_int("plugins/darkroom/filmicrgb/graph_view", g->gui_mode); - return TRUE; - } else - { - return FALSE; - } + g->gui_mode++; + + gtk_widget_queue_draw(GTK_WIDGET(g->area)); + dt_conf_set_int("plugins/darkroom/filmicrgb/graph_view", g->gui_mode); + return; } - else if(dt_gdk_event_get_button(event) == GDK_BUTTON_PRIMARY) + else if(g->active_button == DT_FILMIC_GUI_BUTTON_LABELS) { - // simple left click cycles through modes in positive direction - if(g->active_button == DT_FILMIC_GUI_BUTTON_TYPE) - { - // cycle type of graph - if(g->gui_mode == DT_FILMIC_GUI_RANGES) - g->gui_mode = DT_FILMIC_GUI_LOOK; - else - g->gui_mode++; + g->gui_show_labels = !g->gui_show_labels; + gtk_widget_queue_draw(GTK_WIDGET(g->area)); + dt_conf_set_int("plugins/darkroom/filmicrgb/graph_show_labels", g->gui_show_labels); + return; + } + return; + } - gtk_widget_queue_draw(GTK_WIDGET(g->area)); - dt_conf_set_int("plugins/darkroom/filmicrgb/graph_view", g->gui_mode); - return TRUE; - } - else if(g->active_button == DT_FILMIC_GUI_BUTTON_LABELS) - { - g->gui_show_labels = !g->gui_show_labels; - gtk_widget_queue_draw(GTK_WIDGET(g->area)); - dt_conf_set_int("plugins/darkroom/filmicrgb/graph_show_labels", g->gui_show_labels); - return TRUE; - } + if(button == GDK_BUTTON_SECONDARY) + { + // simple right click cycles through modes in negative direction + if(g->active_button == DT_FILMIC_GUI_BUTTON_TYPE) + { + if(g->gui_mode == DT_FILMIC_GUI_LOOK) + g->gui_mode = DT_FILMIC_GUI_RANGES; else - { - // we should never get there since (g->active_button != DT_FILMIC_GUI_BUTTON_LAST) - // and any other case has been processed above. - return FALSE; - } + g->gui_mode--; + + gtk_widget_queue_draw(GTK_WIDGET(g->area)); + dt_conf_set_int("plugins/darkroom/filmicrgb/graph_view", g->gui_mode); + return; } - else if(dt_gdk_event_get_button(event) == GDK_BUTTON_SECONDARY) + else if(g->active_button == DT_FILMIC_GUI_BUTTON_LABELS) { - // simple right click cycles through modes in negative direction - if(g->active_button == DT_FILMIC_GUI_BUTTON_TYPE) - { - if(g->gui_mode == DT_FILMIC_GUI_LOOK) - g->gui_mode = DT_FILMIC_GUI_RANGES; - else - g->gui_mode--; - - gtk_widget_queue_draw(GTK_WIDGET(g->area)); - dt_conf_set_int("plugins/darkroom/filmicrgb/graph_view", g->gui_mode); - return TRUE; - } - else if(g->active_button == DT_FILMIC_GUI_BUTTON_LABELS) - { - g->gui_show_labels = !g->gui_show_labels; - gtk_widget_queue_draw(GTK_WIDGET(g->area)); - dt_conf_set_int("plugins/darkroom/filmicrgb/graph_show_labels", g->gui_show_labels); - return TRUE; - } - else - { - return FALSE; - } + g->gui_show_labels = !g->gui_show_labels; + gtk_widget_queue_draw(GTK_WIDGET(g->area)); + dt_conf_set_int("plugins/darkroom/filmicrgb/graph_show_labels", g->gui_show_labels); + return; } } +} - return FALSE; +static void area_enter_notify(GtkEventControllerMotion *controller, gdouble x, gdouble y, dt_iop_module_t *self) +{ + dt_iop_filmicrgb_gui_data_t *g = self->gui_data; + g->gui_hover = TRUE; + gtk_widget_queue_draw(GTK_WIDGET(g->area)); } -static gboolean area_enter_leave_notify(GtkWidget *widget, const GdkEventCrossing *event, const dt_iop_module_t *self) +static void area_leave_notify(GtkEventControllerMotion *controller, dt_iop_module_t *self) { dt_iop_filmicrgb_gui_data_t *g = self->gui_data; - g->gui_hover = dt_gdk_event_get_type(event) == GDK_ENTER_NOTIFY; + g->gui_hover = FALSE; gtk_widget_queue_draw(GTK_WIDGET(g->area)); - return FALSE; } -static gboolean area_motion_notify(GtkWidget *widget, const GdkEventMotion *event, const dt_iop_module_t *self) +static void area_motion_notify(GtkEventControllerMotion *controller, gdouble x, gdouble y, dt_iop_module_t *self) { - DT_GUARD_GUI_UPDATE(1); + DT_GUARD_GUI_UPDATE(); dt_iop_filmicrgb_gui_data_t *g = self->gui_data; - if(!g->gui_sizes_inited) return FALSE; - - // get in-widget coordinates - const float y = dt_gdk_event_get_y(event); - const float x = dt_gdk_event_get_x(event); + if(!g->gui_sizes_inited) return; if(x > 0. && x < g->allocation.width && y > 0. && y < g->allocation.height) g->gui_hover = TRUE; @@ -4326,13 +4317,12 @@ static gboolean area_motion_notify(GtkWidget *widget, const GdkEventMotion *even } if(save_active_button != g->active_button) gtk_widget_queue_draw(GTK_WIDGET(g->area)); - return TRUE; + return; } else { g->active_button = DT_FILMIC_GUI_BUTTON_LAST; - if(save_active_button != g->active_button) (GTK_WIDGET(g->area)); - return FALSE; + if(save_active_button != g->active_button) gtk_widget_queue_draw(GTK_WIDGET(g->area)); } } @@ -4354,10 +4344,8 @@ void gui_init(dt_iop_module_t *self) gtk_widget_set_can_focus(GTK_WIDGET(g->area), TRUE); g_signal_connect(G_OBJECT(g->area), "draw", G_CALLBACK(dt_iop_tonecurve_draw), self); - g_signal_connect(G_OBJECT(g->area), "button-press-event", G_CALLBACK(area_button_press), self); - g_signal_connect(G_OBJECT(g->area), "leave-notify-event", G_CALLBACK(area_enter_leave_notify), self); - g_signal_connect(G_OBJECT(g->area), "enter-notify-event", G_CALLBACK(area_enter_leave_notify), self); - g_signal_connect(G_OBJECT(g->area), "motion-notify-event", G_CALLBACK(area_motion_notify), self); + dt_gui_connect_click_all(g->area, area_button_press, NULL, self); + dt_gui_connect_motion(g->area, area_motion_notify, area_enter_notify, area_leave_notify, self); // Init GTK notebook static struct dt_action_def_t notebook_def = { }; diff --git a/src/iop/levels.c b/src/iop/levels.c index 01d88bbafa0..16c5b692f83 100644 --- a/src/iop/levels.c +++ b/src/iop/levels.c @@ -47,11 +47,11 @@ DT_MODULE_INTROSPECTION(2, dt_iop_levels_params_t) static gboolean dt_iop_levels_area_draw(GtkWidget *widget, cairo_t *crf, dt_iop_module_t *self); -static gboolean dt_iop_levels_motion_notify(GtkWidget *widget, GdkEventMotion *event, dt_iop_module_t *self); -static gboolean dt_iop_levels_button_press(GtkWidget *widget, GdkEventButton *event, dt_iop_module_t *self); -static gboolean dt_iop_levels_button_release(GtkWidget *widget, GdkEventButton *event, dt_iop_module_t *self); -static gboolean dt_iop_levels_leave_notify(GtkWidget *widget, GdkEventCrossing *event, dt_iop_module_t *self); -static gboolean dt_iop_levels_scroll(GtkWidget *widget, GdkEventScroll *event, dt_iop_module_t *self); +static void dt_iop_levels_motion_notify(GtkEventControllerMotion *controller, gdouble x, gdouble y, dt_iop_module_t *self); +static void dt_iop_levels_button_press(GtkGestureSingle *gesture, gint n_press, gdouble x, gdouble y, dt_iop_module_t *self); +static void dt_iop_levels_button_release(GtkGestureSingle *gesture, gint n_press, gdouble x, gdouble y, dt_iop_module_t *self); +static void dt_iop_levels_leave_notify(GtkEventControllerMotion *controller, dt_iop_module_t *self); +static void dt_iop_levels_scroll(GtkEventControllerScroll *controller, gdouble dx, gdouble dy, dt_iop_module_t *self); static void dt_iop_levels_autoadjust_callback(GtkRange *range, dt_iop_module_t *self); //static void dt_iop_levels_mode_callback(GtkWidget *combo, gpointer user_data); //static void dt_iop_levels_percentiles_callback(GtkWidget *slider, gpointer user_data); @@ -637,11 +637,11 @@ void gui_init(dt_iop_module_t *self) dt_action_define_iop(self, NULL, N_("levels"), GTK_WIDGET(g->area), NULL); g_signal_connect(G_OBJECT(g->area), "draw", G_CALLBACK(dt_iop_levels_area_draw), self); - g_signal_connect(G_OBJECT(g->area), "button-press-event", G_CALLBACK(dt_iop_levels_button_press), self); - g_signal_connect(G_OBJECT(g->area), "button-release-event", G_CALLBACK(dt_iop_levels_button_release), self); - g_signal_connect(G_OBJECT(g->area), "motion-notify-event", G_CALLBACK(dt_iop_levels_motion_notify), self); - g_signal_connect(G_OBJECT(g->area), "leave-notify-event", G_CALLBACK(dt_iop_levels_leave_notify), self); - g_signal_connect(G_OBJECT(g->area), "scroll-event", G_CALLBACK(dt_iop_levels_scroll), self); + dt_gui_connect_click(g->area, dt_iop_levels_button_press, dt_iop_levels_button_release, self); + dt_gui_connect_motion(g->area, dt_iop_levels_motion_notify, NULL, dt_iop_levels_leave_notify, self); + dt_gui_connect_scroll(g->area, GTK_EVENT_CONTROLLER_SCROLL_BOTH_AXES + | GTK_EVENT_CONTROLLER_SCROLL_DISCRETE, + dt_iop_levels_scroll, self); GtkWidget *autobutton = gtk_button_new_with_label(_("auto")); gtk_widget_set_tooltip_text(autobutton, _("apply auto levels")); @@ -697,12 +697,11 @@ void gui_cleanup(dt_iop_module_t *self) g_list_free(g->modes); } -static gboolean dt_iop_levels_leave_notify(GtkWidget *widget, GdkEventCrossing *event, dt_iop_module_t *self) +static void dt_iop_levels_leave_notify(GtkEventControllerMotion *controller, dt_iop_module_t *self) { dt_iop_levels_gui_data_t *g = self->gui_data; g->mouse_x = g->mouse_y = -1.0; - gtk_widget_queue_draw(widget); - return TRUE; + gtk_widget_queue_draw(gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller))); } static gboolean dt_iop_levels_area_draw(GtkWidget *widget, cairo_t *crf, dt_iop_module_t *self) @@ -863,26 +862,27 @@ static void dt_iop_levels_move_handle(dt_iop_module_t *self, int handle_move, fl g->last_picked_color = -1; } -static gboolean dt_iop_levels_motion_notify(GtkWidget *widget, GdkEventMotion *event, dt_iop_module_t *self) +static void dt_iop_levels_motion_notify(GtkEventControllerMotion *controller, gdouble x, gdouble y, dt_iop_module_t *self) { dt_iop_levels_gui_data_t *g = self->gui_data; dt_iop_levels_params_t *p = self->params; + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); const int inset = DT_GUI_CURVE_EDITOR_INSET; GtkAllocation allocation; gtk_widget_get_allocation(widget, &allocation); int height = allocation.height - 2 * inset - DT_RESIZE_HANDLE_SIZE, width = allocation.width - 2 * inset; if(!g->dragging) { - g->mouse_x = CLAMP(dt_gdk_event_get_x(event) - inset, 0, width); + g->mouse_x = CLAMP(x - inset, 0, width); g->drag_start_percentage = (p->levels[1] - p->levels[0]) / (p->levels[2] - p->levels[0]); } - g->mouse_y = CLAMP(dt_gdk_event_get_y(event) - inset, 0, height); + g->mouse_y = CLAMP(y - inset, 0, height); if(g->dragging) { if(g->handle_move >= 0 && g->handle_move < 3) { - const float mx = (CLAMP(dt_gdk_event_get_x(event) - inset, 0, width)) / (float)width; + const float mx = (CLAMP(x - inset, 0, width)) / (float)width; dt_iop_levels_move_handle(self, g->handle_move, mx, p->levels, g->drag_start_percentage); } @@ -891,7 +891,7 @@ static gboolean dt_iop_levels_motion_notify(GtkWidget *widget, GdkEventMotion *e else { g->handle_move = 0; - const float mx = CLAMP(dt_gdk_event_get_x(event) - inset, 0, width) / (float)width; + const float mx = CLAMP(x - inset, 0, width) / (float)width; float dist = fabsf(p->levels[0] - mx); for(int k = 1; k < 3; k++) { @@ -904,77 +904,63 @@ static gboolean dt_iop_levels_motion_notify(GtkWidget *widget, GdkEventMotion *e } } gtk_widget_queue_draw(widget); - - return TRUE; } -static gboolean dt_iop_levels_button_press(GtkWidget *widget, GdkEventButton *event, dt_iop_module_t *self) +static void dt_iop_levels_button_press(GtkGestureSingle *gesture, gint n_press, gdouble x, gdouble y, dt_iop_module_t *self) { - // set active point - if(dt_gdk_event_get_button(event) == GDK_BUTTON_PRIMARY) - { - if(darktable.develop->gui_module != self) dt_iop_request_focus(self); + if(gtk_gesture_single_get_current_button(gesture) != GDK_BUTTON_PRIMARY) + return; - if(dt_gdk_event_get_type(event) == GDK_2BUTTON_PRESS) - { - // Reset - dt_iop_levels_gui_data_t *g = self->gui_data; - memcpy(self->params, self->default_params, self->params_size); + if(darktable.develop->gui_module != self) dt_iop_request_focus(self); - // Needed in case the user scrolls or drags immediately after a reset, - // as drag_start_percentage is only updated when the mouse is moved. - g->drag_start_percentage = 0.5; - dt_dev_add_history_item(darktable.develop, self, TRUE); - gtk_widget_queue_draw(GTK_WIDGET(g->area)); - } - else - { - dt_iop_levels_gui_data_t *g = self->gui_data; - g->dragging = 1; - } - return TRUE; - } - return FALSE; -} + if(n_press >= 2) + { + // Reset + dt_iop_levels_gui_data_t *g = self->gui_data; + memcpy(self->params, self->default_params, self->params_size); -static gboolean dt_iop_levels_button_release(GtkWidget *widget, GdkEventButton *event, dt_iop_module_t *self) -{ - if(dt_gdk_event_get_button(event) == GDK_BUTTON_PRIMARY) + // Needed in case the user scrolls or drags immediately after a reset, + // as drag_start_percentage is only updated when the mouse is moved. + g->drag_start_percentage = 0.5; + dt_dev_add_history_item(darktable.develop, self, TRUE); + gtk_widget_queue_draw(GTK_WIDGET(g->area)); + } + else { dt_iop_levels_gui_data_t *g = self->gui_data; - g->dragging = 0; - return TRUE; + g->dragging = 1; } - return FALSE; } -static gboolean dt_iop_levels_scroll(GtkWidget *widget, GdkEventScroll *event, dt_iop_module_t *self) +static void dt_iop_levels_button_release(GtkGestureSingle *gesture, gint n_press, gdouble x, gdouble y, dt_iop_module_t *self) { + if(gtk_gesture_single_get_current_button(gesture) != GDK_BUTTON_PRIMARY) + return; + dt_iop_levels_gui_data_t *g = self->gui_data; - dt_iop_levels_params_t *p = self->params; + g->dragging = 0; +} - if(dt_gui_ignore_scroll(event)) return FALSE; +static void dt_iop_levels_scroll(GtkEventControllerScroll *controller, gdouble dx, gdouble dy, dt_iop_module_t *self) +{ + dt_iop_levels_gui_data_t *g = self->gui_data; + dt_iop_levels_params_t *p = self->params; + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); dt_iop_color_picker_reset(self, TRUE); if(g->dragging) - { - return FALSE; - } + return; if(darktable.develop->gui_module != self) dt_iop_request_focus(self); - const float interval = 0.002 * dt_accel_get_speed_multiplier(widget, dt_gdk_event_get_state(event)); // Distance moved for each scroll event - int delta_y; - if(dt_gui_get_scroll_unit_delta(event, &delta_y)) + if(dy != 0.0) { - float new_position = p->levels[g->handle_move] - interval * delta_y; + const float interval = 0.002 * dt_accel_get_speed_multiplier(widget, dt_key_modifier_state()); + float new_position = p->levels[g->handle_move] - interval * dy; dt_iop_levels_move_handle(self, g->handle_move, new_position, p->levels, g->drag_start_percentage); dt_dev_add_history_item(darktable.develop, self, TRUE); - return TRUE; } - - return TRUE; // Ensure that scrolling the widget cannot move side panel } static void dt_iop_levels_autoadjust_callback(GtkRange *range, dt_iop_module_t *self) diff --git a/src/iop/lowlight.c b/src/iop/lowlight.c index 2cd9602b218..50fd9caa171 100644 --- a/src/iop/lowlight.c +++ b/src/iop/lowlight.c @@ -664,22 +664,23 @@ static gboolean lowlight_draw(GtkWidget *widget, cairo_t *crf, dt_iop_module_t * return FALSE; } -static gboolean lowlight_motion_notify(GtkWidget *widget, GdkEventMotion *event, dt_iop_module_t *self) +static void lowlight_motion_notify(GtkEventControllerMotion *controller, gdouble x, gdouble y, dt_iop_module_t *self) { dt_iop_lowlight_gui_data_t *g = self->gui_data; dt_iop_lowlight_params_t *p = self->params; + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); const int inset = DT_IOP_LOWLIGHT_INSET; GtkAllocation allocation; gtk_widget_get_allocation(widget, &allocation); int height = allocation.height - 2 * inset - DT_RESIZE_HANDLE_SIZE, width = allocation.width - 2 * inset; - if(!g->dragging) g->mouse_x = CLAMP(dt_gdk_event_get_x(event) - inset, 0, width) / (float)width; - g->mouse_y = 1.0 - CLAMP(dt_gdk_event_get_y(event) - inset, 0, height) / (float)height; + if(!g->dragging) g->mouse_x = CLAMP(x - inset, 0, width) / (float)width; + g->mouse_y = 1.0 - CLAMP(y - inset, 0, height) / (float)height; if(g->dragging) { *p = g->drag_params; if(g->x_move >= 0) { - const float mx = CLAMP(dt_gdk_event_get_x(event) - inset, 0, width) / (float)width; + const float mx = CLAMP(x - inset, 0, width) / (float)width; if(g->x_move > 0 && g->x_move < DT_IOP_LOWLIGHT_BANDS - 1) { const float minx = p->transition_x[g->x_move - 1] + 0.001f; @@ -694,7 +695,7 @@ static gboolean lowlight_motion_notify(GtkWidget *widget, GdkEventMotion *event, gtk_widget_queue_draw(widget); dt_dev_add_history_item_target(darktable.develop, self, TRUE, widget); } - else if(dt_gdk_event_get_y(event) > height) + else if(y > height) { g->x_move = 0; float dist = fabs(p->transition_x[0] - g->mouse_x); @@ -714,13 +715,17 @@ static gboolean lowlight_motion_notify(GtkWidget *widget, GdkEventMotion *event, g->x_move = -1; gtk_widget_queue_draw(widget); } - return TRUE; } -static gboolean lowlight_button_press(GtkWidget *widget, GdkEventButton *event, dt_iop_module_t *self) +static void lowlight_button_press(GtkGestureSingle *gesture, gint n_press, gdouble x, gdouble y, dt_iop_module_t *self) { dt_iop_lowlight_gui_data_t *g = self->gui_data; - if(dt_gdk_event_get_button(event) == GDK_BUTTON_PRIMARY && dt_gdk_event_get_type(event) == GDK_2BUTTON_PRESS) + if(gtk_gesture_single_get_current_button(gesture) != GDK_BUTTON_PRIMARY) + return; + + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + + if(n_press >= 2) { // reset current curve dt_iop_lowlight_params_t *p = self->params; @@ -733,7 +738,7 @@ static gboolean lowlight_button_press(GtkWidget *widget, GdkEventButton *event, dt_dev_add_history_item_target(darktable.develop, self, TRUE, widget); gtk_widget_queue_draw(GTK_WIDGET(g->area)); } - else if(dt_gdk_event_get_button(event) == GDK_BUTTON_PRIMARY) + else { g->drag_params = *(dt_iop_lowlight_params_t *)self->params; const int inset = DT_IOP_LOWLIGHT_INSET; @@ -741,47 +746,37 @@ static gboolean lowlight_button_press(GtkWidget *widget, GdkEventButton *event, gtk_widget_get_allocation(widget, &allocation); int height = allocation.height - 2 * inset - DT_RESIZE_HANDLE_SIZE, width = allocation.width - 2 * inset; g->mouse_pick - = dt_draw_curve_calc_value(g->transition_curve, CLAMP(dt_gdk_event_get_x(event) - inset, 0, width) / (float)width); - g->mouse_pick -= 1.0 - CLAMP(dt_gdk_event_get_y(event) - inset, 0, height) / (float)height; + = dt_draw_curve_calc_value(g->transition_curve, CLAMP(x - inset, 0, width) / (float)width); + g->mouse_pick -= 1.0 - CLAMP(y - inset, 0, height) / (float)height; g->dragging = 1; - return TRUE; } - return FALSE; } -static gboolean lowlight_button_release(GtkWidget *widget, GdkEventButton *event, dt_iop_module_t *self) +static void lowlight_button_release(GtkGestureSingle *gesture, gint n_press, gdouble x, gdouble y, dt_iop_module_t *self) { - if(dt_gdk_event_get_button(event) == GDK_BUTTON_PRIMARY) - { - dt_iop_lowlight_gui_data_t *g = self->gui_data; - g->dragging = 0; - return TRUE; - } - return FALSE; + if(gtk_gesture_single_get_current_button(gesture) != GDK_BUTTON_PRIMARY) + return; + + dt_iop_lowlight_gui_data_t *g = self->gui_data; + g->dragging = 0; } -static gboolean lowlight_leave_notify(GtkWidget *widget, GdkEventCrossing *event, dt_iop_module_t *self) +static void lowlight_leave_notify(GtkEventControllerMotion *controller, dt_iop_module_t *self) { dt_iop_lowlight_gui_data_t *g = self->gui_data; if(!g->dragging) g->mouse_y = -1.0; - gtk_widget_queue_draw(widget); - return TRUE; + gtk_widget_queue_draw(gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller))); } -static gboolean lowlight_scrolled(GtkWidget *widget, GdkEventScroll *event, dt_iop_module_t *self) +static void lowlight_scrolled(GtkEventControllerScroll *controller, gdouble dx, gdouble dy, dt_iop_module_t *self) { dt_iop_lowlight_gui_data_t *g = self->gui_data; - if(dt_gui_ignore_scroll(event)) return FALSE; - - int delta_y; - if(dt_gui_get_scroll_unit_delta(event, &delta_y)) + if(dy != 0.0) { - g->mouse_radius = CLAMP(g->mouse_radius * (1.0 - 0.1 * delta_y), 0.2 / DT_IOP_LOWLIGHT_BANDS, 1.0); - gtk_widget_queue_draw(widget); + g->mouse_radius = CLAMP(g->mouse_radius * (1.0 - 0.1 * dy), 0.2 / DT_IOP_LOWLIGHT_BANDS, 1.0); + gtk_widget_queue_draw(gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller))); } - - return TRUE; } void gui_init(dt_iop_module_t *self) @@ -809,11 +804,11 @@ void gui_init(dt_iop_module_t *self) self->widget = dt_gui_vbox(g->area); g_signal_connect(G_OBJECT(g->area), "draw", G_CALLBACK(lowlight_draw), self); - g_signal_connect(G_OBJECT(g->area), "button-press-event", G_CALLBACK(lowlight_button_press), self); - g_signal_connect(G_OBJECT(g->area), "button-release-event", G_CALLBACK(lowlight_button_release), self); - g_signal_connect(G_OBJECT(g->area), "motion-notify-event", G_CALLBACK(lowlight_motion_notify), self); - g_signal_connect(G_OBJECT(g->area), "leave-notify-event", G_CALLBACK(lowlight_leave_notify), self); - g_signal_connect(G_OBJECT(g->area), "scroll-event", G_CALLBACK(lowlight_scrolled), self); + dt_gui_connect_click(g->area, lowlight_button_press, lowlight_button_release, self); + dt_gui_connect_motion(g->area, lowlight_motion_notify, NULL, lowlight_leave_notify, self); + dt_gui_connect_scroll(g->area, GTK_EVENT_CONTROLLER_SCROLL_BOTH_AXES + | GTK_EVENT_CONTROLLER_SCROLL_DISCRETE, + lowlight_scrolled, self); g->scale_blueness = dt_bauhaus_slider_from_params(self, "blueness"); dt_bauhaus_slider_set_format(g->scale_blueness, "%"); diff --git a/src/iop/monochrome.c b/src/iop/monochrome.c index 60ab8669185..d18d90d11d7 100644 --- a/src/iop/monochrome.c +++ b/src/iop/monochrome.c @@ -449,7 +449,7 @@ void color_picker_apply(dt_iop_module_t *self, GtkWidget *picker, dt_dev_pixelpi dt_control_queue_redraw_widget(self->widget); } -static gboolean _monochrome_motion_notify(GtkWidget *widget, GdkEventMotion *event, dt_iop_module_t *self) +static void _monochrome_motion_notify(GtkEventControllerMotion *controller, gdouble x, gdouble y, dt_iop_module_t *self) { dt_iop_monochrome_gui_data_t *g = self->gui_data; dt_iop_monochrome_params_t *p = self->params; @@ -457,94 +457,87 @@ static gboolean _monochrome_motion_notify(GtkWidget *widget, GdkEventMotion *eve { const float old_a = p->a, old_b = p->b; const int inset = DT_COLORCORRECTION_INSET; + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); GtkAllocation allocation; gtk_widget_get_allocation(widget, &allocation); int width = allocation.width - 2 * inset, height = allocation.height - 2 * inset; - const float mouse_x = CLAMP(dt_gdk_event_get_x(event) - inset, 0, width); - const float mouse_y = CLAMP(height - 1 - dt_gdk_event_get_y(event) + inset, 0, height); + const float mouse_x = CLAMP(x - inset, 0, width); + const float mouse_y = CLAMP(height - 1 - y + inset, 0, height); p->a = PANEL_WIDTH * (mouse_x - width * 0.5f) / (float)width; p->b = PANEL_WIDTH * (mouse_y - height * 0.5f) / (float)height; if(old_a != p->a || old_b != p->b) dt_dev_add_history_item(darktable.develop, self, TRUE); gtk_widget_queue_draw(GTK_WIDGET(g->area)); } - return TRUE; } -static gboolean _monochrome_button_press(GtkWidget *widget, GdkEventButton *event, dt_iop_module_t *self) +static void _monochrome_button_press(GtkGestureSingle *gesture, gint n_press, gdouble x, gdouble y, dt_iop_module_t *self) { - if(dt_gdk_event_get_button(event) == GDK_BUTTON_PRIMARY) + if(gtk_gesture_single_get_current_button(gesture) != GDK_BUTTON_PRIMARY) + return; + + dt_iop_monochrome_gui_data_t *g = self->gui_data; + dt_iop_monochrome_params_t *p = self->params; + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + + dt_iop_color_picker_reset(self, TRUE); + if(n_press >= 2) { - dt_iop_monochrome_gui_data_t *g = self->gui_data; - dt_iop_monochrome_params_t *p = self->params; - dt_iop_color_picker_reset(self, TRUE); - if(dt_gdk_event_get_type(event) == GDK_2BUTTON_PRESS) - { - // reset - const dt_iop_monochrome_params_t *const p0 = self->default_params; - p->a = p0->a; - p->b = p0->b; - p->size = p0->size; - } - else - { - const int inset = DT_COLORCORRECTION_INSET; - GtkAllocation allocation; - gtk_widget_get_allocation(widget, &allocation); - int width = allocation.width - 2 * inset, height = allocation.height - 2 * inset; - const float mouse_x = CLAMP(dt_gdk_event_get_x(event) - inset, 0, width); - const float mouse_y = CLAMP(height - 1 - dt_gdk_event_get_y(event) + inset, 0, height); - p->a = PANEL_WIDTH * (mouse_x - width * 0.5f) / (float)width; - p->b = PANEL_WIDTH * (mouse_y - height * 0.5f) / (float)height; - g->dragging = 1; - g_object_set(G_OBJECT(widget), "has-tooltip", FALSE, (gchar *)0); - } - gtk_widget_queue_draw(GTK_WIDGET(g->area)); - return TRUE; + // reset + const dt_iop_monochrome_params_t *const p0 = self->default_params; + p->a = p0->a; + p->b = p0->b; + p->size = p0->size; + } + else + { + const int inset = DT_COLORCORRECTION_INSET; + GtkAllocation allocation; + gtk_widget_get_allocation(widget, &allocation); + int width = allocation.width - 2 * inset, height = allocation.height - 2 * inset; + const float mouse_x = CLAMP(x - inset, 0, width); + const float mouse_y = CLAMP(height - 1 - y + inset, 0, height); + p->a = PANEL_WIDTH * (mouse_x - width * 0.5f) / (float)width; + p->b = PANEL_WIDTH * (mouse_y - height * 0.5f) / (float)height; + g->dragging = 1; + g_object_set(G_OBJECT(widget), "has-tooltip", FALSE, (gchar *)0); } - return FALSE; + gtk_widget_queue_draw(GTK_WIDGET(g->area)); } -static gboolean _monochrome_button_release(GtkWidget *widget, GdkEventButton *event, dt_iop_module_t *self) +static void _monochrome_button_release(GtkGestureSingle *gesture, gint n_press, gdouble x, gdouble y, dt_iop_module_t *self) { - if(dt_gdk_event_get_button(event) == GDK_BUTTON_PRIMARY) - { - dt_iop_monochrome_gui_data_t *g = self->gui_data; - dt_iop_color_picker_reset(self, TRUE); - g->dragging = 0; - dt_dev_add_history_item(darktable.develop, self, TRUE); - g_object_set(G_OBJECT(widget), "has-tooltip", TRUE, (gchar *)0); - return TRUE; - } - return FALSE; + if(gtk_gesture_single_get_current_button(gesture) != GDK_BUTTON_PRIMARY) + return; + + dt_iop_monochrome_gui_data_t *g = self->gui_data; + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + dt_iop_color_picker_reset(self, TRUE); + g->dragging = 0; + dt_dev_add_history_item(darktable.develop, self, TRUE); + g_object_set(G_OBJECT(widget), "has-tooltip", TRUE, (gchar *)0); } -static gboolean _monochrome_leave_notify(GtkWidget *widget, GdkEventCrossing *event, dt_iop_module_t *self) +static void _monochrome_leave_notify(GtkEventControllerMotion *controller, dt_iop_module_t *self) { dt_iop_monochrome_gui_data_t *g = self->gui_data; g->dragging = 0; gtk_widget_queue_draw(GTK_WIDGET(g->area)); - return TRUE; } -static gboolean _monochrome_scrolled(GtkWidget *widget, GdkEventScroll *event, dt_iop_module_t *self) +static void _monochrome_scrolled(GtkEventControllerScroll *controller, gdouble dx, gdouble dy, dt_iop_module_t *self) { dt_iop_monochrome_params_t *p = self->params; - if(dt_gui_ignore_scroll(event)) return FALSE; - dt_iop_color_picker_reset(self, TRUE); - int delta_y; - if(dt_gui_get_scroll_unit_delta(event, &delta_y)) + if(dy != 0.0) { const float old_size = p->size; - p->size = CLAMP(p->size - delta_y * 0.1, 0.5f, 3.0f); + p->size = CLAMP(p->size - dy * 0.1, 0.5f, 3.0f); if(old_size != p->size) dt_dev_add_history_item(darktable.develop, self, TRUE); - gtk_widget_queue_draw(widget); + gtk_widget_queue_draw(gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller))); } - - return TRUE; } void gui_init(dt_iop_module_t *self) @@ -558,17 +551,12 @@ void gui_init(dt_iop_module_t *self) gtk_widget_set_tooltip_text(GTK_WIDGET(g->area), _("drag and scroll mouse wheel to adjust the virtual color filter")); dt_action_define_iop(self, NULL, N_("grid"), GTK_WIDGET(g->area), NULL); - gtk_widget_add_events(GTK_WIDGET(g->area), GDK_POINTER_MOTION_MASK - | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - | GDK_LEAVE_NOTIFY_MASK | darktable.gui->scroll_mask); g_signal_connect(G_OBJECT(g->area), "draw", G_CALLBACK(_monochrome_draw), self); - g_signal_connect(G_OBJECT(g->area), "button-press-event", G_CALLBACK(_monochrome_button_press), self); - g_signal_connect(G_OBJECT(g->area), "button-release-event", G_CALLBACK(_monochrome_button_release), - self); - g_signal_connect(G_OBJECT(g->area), "motion-notify-event", G_CALLBACK(_monochrome_motion_notify), - self); - g_signal_connect(G_OBJECT(g->area), "leave-notify-event", G_CALLBACK(_monochrome_leave_notify), self); - g_signal_connect(G_OBJECT(g->area), "scroll-event", G_CALLBACK(_monochrome_scrolled), self); + dt_gui_connect_click(g->area, _monochrome_button_press, _monochrome_button_release, self); + dt_gui_connect_motion(g->area, _monochrome_motion_notify, NULL, _monochrome_leave_notify, self); + dt_gui_connect_scroll(g->area, GTK_EVENT_CONTROLLER_SCROLL_BOTH_AXES + | GTK_EVENT_CONTROLLER_SCROLL_DISCRETE, + _monochrome_scrolled, self); g->highlights = dt_color_picker_new(self, DT_COLOR_PICKER_AREA, dt_bauhaus_slider_from_params(self, N_("highlights"))); diff --git a/src/iop/rawdenoise.c b/src/iop/rawdenoise.c index 3c6e445e134..a175e5dfc96 100644 --- a/src/iop/rawdenoise.c +++ b/src/iop/rawdenoise.c @@ -766,16 +766,17 @@ static gboolean rawdenoise_draw(GtkWidget *widget, cairo_t *crf, dt_iop_module_t return FALSE; } -static gboolean rawdenoise_motion_notify(GtkWidget *widget, GdkEventMotion *event, dt_iop_module_t *self) +static void rawdenoise_motion_notify(GtkEventControllerMotion *controller, gdouble x, gdouble y, dt_iop_module_t *self) { dt_iop_rawdenoise_gui_data_t *g = self->gui_data; dt_iop_rawdenoise_params_t *p = self->params; + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); const int inset = DT_IOP_RAWDENOISE_INSET; GtkAllocation allocation; gtk_widget_get_allocation(widget, &allocation); int height = allocation.height - 2 * inset, width = allocation.width - 2 * inset; - if(!g->dragging) g->mouse_x = CLAMP(dt_gdk_event_get_x(event) - inset, 0, width) / (float)width; - g->mouse_y = 1.0 - CLAMP(dt_gdk_event_get_y(event) - inset, 0, height) / (float)height; + if(!g->dragging) g->mouse_x = CLAMP(x - inset, 0, width) / (float)width; + g->mouse_y = 1.0 - CLAMP(y - inset, 0, height) / (float)height; if(g->dragging) { *p = g->drag_params; @@ -791,14 +792,18 @@ static gboolean rawdenoise_motion_notify(GtkWidget *widget, GdkEventMotion *even g->x_move = -1; gtk_widget_queue_draw(widget); } - return TRUE; } -static gboolean rawdenoise_button_press(GtkWidget *widget, GdkEventButton *event, dt_iop_module_t *self) +static void rawdenoise_button_press(GtkGestureSingle *gesture, gint n_press, gdouble x, gdouble y, dt_iop_module_t *self) { dt_iop_rawdenoise_gui_data_t *g = self->gui_data; const int ch = g->channel; - if(dt_gdk_event_get_button(event) == GDK_BUTTON_PRIMARY && dt_gdk_event_get_type(event) == GDK_2BUTTON_PRESS) + if(gtk_gesture_single_get_current_button(gesture) != GDK_BUTTON_PRIMARY) + return; + + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + + if(n_press >= 2) { // reset current curve dt_iop_rawdenoise_params_t *p = self->params; @@ -811,7 +816,7 @@ static gboolean rawdenoise_button_press(GtkWidget *widget, GdkEventButton *event dt_dev_add_history_item_target(darktable.develop, self, TRUE, widget + ch); gtk_widget_queue_draw(GTK_WIDGET(g->area)); } - else if(dt_gdk_event_get_button(event) == GDK_BUTTON_PRIMARY) + else { g->drag_params = *(dt_iop_rawdenoise_params_t *)self->params; const int inset = DT_IOP_RAWDENOISE_INSET; @@ -819,50 +824,37 @@ static gboolean rawdenoise_button_press(GtkWidget *widget, GdkEventButton *event gtk_widget_get_allocation(widget, &allocation); int height = allocation.height - 2 * inset, width = allocation.width - 2 * inset; g->mouse_pick - = dt_draw_curve_calc_value(g->transition_curve, CLAMP(dt_gdk_event_get_x(event) - inset, 0, width) / (float)width); - g->mouse_pick -= 1.0 - CLAMP(dt_gdk_event_get_y(event) - inset, 0, height) / (float)height; + = dt_draw_curve_calc_value(g->transition_curve, CLAMP(x - inset, 0, width) / (float)width); + g->mouse_pick -= 1.0 - CLAMP(y - inset, 0, height) / (float)height; g->dragging = 1; - return TRUE; } - return FALSE; } -static gboolean rawdenoise_button_release(GtkWidget *widget, GdkEventButton *event, dt_iop_module_t *self) +static void rawdenoise_button_release(GtkGestureSingle *gesture, gint n_press, gdouble x, gdouble y, dt_iop_module_t *self) { - if(dt_gdk_event_get_button(event) == GDK_BUTTON_PRIMARY) - { - dt_iop_rawdenoise_gui_data_t *g = self->gui_data; - g->dragging = 0; - return TRUE; - } - return FALSE; + if(gtk_gesture_single_get_current_button(gesture) != GDK_BUTTON_PRIMARY) + return; + + dt_iop_rawdenoise_gui_data_t *g = self->gui_data; + g->dragging = 0; } -static gboolean rawdenoise_leave_notify(GtkWidget *widget, GdkEventCrossing *event, dt_iop_module_t *self) +static void rawdenoise_leave_notify(GtkEventControllerMotion *controller, dt_iop_module_t *self) { dt_iop_rawdenoise_gui_data_t *g = self->gui_data; if(!g->dragging) g->mouse_y = -1.0; - gtk_widget_queue_draw(widget); - return TRUE; + gtk_widget_queue_draw(gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller))); } -static gboolean rawdenoise_scrolled(GtkWidget *widget, GdkEventScroll *event, dt_iop_module_t *self) +static void rawdenoise_scrolled(GtkEventControllerScroll *controller, gdouble dx, gdouble dy, dt_iop_module_t *self) { dt_iop_rawdenoise_gui_data_t *g = self->gui_data; - if(dt_gui_ignore_scroll(event)) return FALSE; - - if(dt_modifier_is(dt_gdk_event_get_state(event), GDK_MOD1_MASK)) - return gtk_widget_event(GTK_WIDGET(g->channel_tabs), (GdkEvent*)event); - - int delta_y; - if(dt_gui_get_scroll_unit_delta(event, &delta_y)) + if(dy != 0.0) { - g->mouse_radius = CLAMP(g->mouse_radius * (1.0 - 0.1 * delta_y), 0.2 / DT_IOP_RAWDENOISE_BANDS, 1.0); - gtk_widget_queue_draw(widget); + g->mouse_radius = CLAMP(g->mouse_radius * (1.0 - 0.1 * dy), 0.2 / DT_IOP_RAWDENOISE_BANDS, 1.0); + gtk_widget_queue_draw(gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller))); } - - return TRUE; } static void rawdenoise_tab_switch(GtkNotebook *notebook, GtkWidget *page, guint page_num, dt_iop_module_t *self) @@ -913,11 +905,11 @@ void gui_init(dt_iop_module_t *self) GtkWidget *box_raw = self->widget = dt_gui_vbox(g->channel_tabs, g->area); g_signal_connect(G_OBJECT(g->area), "draw", G_CALLBACK(rawdenoise_draw), self); - g_signal_connect(G_OBJECT(g->area), "button-press-event", G_CALLBACK(rawdenoise_button_press), self); - g_signal_connect(G_OBJECT(g->area), "button-release-event", G_CALLBACK(rawdenoise_button_release), self); - g_signal_connect(G_OBJECT(g->area), "motion-notify-event", G_CALLBACK(rawdenoise_motion_notify), self); - g_signal_connect(G_OBJECT(g->area), "leave-notify-event", G_CALLBACK(rawdenoise_leave_notify), self); - g_signal_connect(G_OBJECT(g->area), "scroll-event", G_CALLBACK(rawdenoise_scrolled), self); + dt_gui_connect_click(g->area, rawdenoise_button_press, rawdenoise_button_release, self); + dt_gui_connect_motion(g->area, rawdenoise_motion_notify, NULL, rawdenoise_leave_notify, self); + dt_gui_connect_scroll(g->area, GTK_EVENT_CONTROLLER_SCROLL_BOTH_AXES + | GTK_EVENT_CONTROLLER_SCROLL_DISCRETE, + rawdenoise_scrolled, self); g->threshold = dt_bauhaus_slider_from_params(self, "threshold"); dt_bauhaus_slider_set_soft_max(g->threshold, 0.1); diff --git a/src/iop/retouch.c b/src/iop/retouch.c index 7a825417a93..9acc137fe2d 100644 --- a/src/iop/retouch.c +++ b/src/iop/retouch.c @@ -1229,9 +1229,7 @@ static void rt_merge_from_scale_update(const int _merge_from_scale, dt_dev_add_history_item(darktable.develop, self, TRUE); } -static gboolean rt_wdbar_leave_notify(GtkWidget *widget, - GdkEventCrossing *event, - dt_iop_module_t *self) +static void rt_wdbar_leave_notify(GtkEventControllerMotion *controller, dt_iop_module_t *self) { dt_iop_retouch_gui_data_t *g = self->gui_data; @@ -1241,25 +1239,23 @@ static gboolean rt_wdbar_leave_notify(GtkWidget *widget, g->lower_margin = g->upper_margin = FALSE; gtk_widget_queue_draw(g->wd_bar); - return TRUE; } -static gboolean rt_wdbar_button_press(GtkWidget *widget, - GdkEventButton *event, - dt_iop_module_t *self) +static void rt_wdbar_button_press(GtkGestureSingle *gesture, gint n_press, gdouble x, gdouble y, dt_iop_module_t *self) { if(DT_IN_GUI_UPDATE()) - return TRUE; + return; dt_iop_request_focus(self); dt_iop_retouch_gui_data_t *g = self->gui_data; + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); GtkAllocation allocation; gtk_widget_get_allocation(widget, &allocation); const int inset = round(RT_WDBAR_INSET * allocation.height); const float box_w = (allocation.width - 2.0f * inset) / (float)RETOUCH_NO_SCALES; - if(dt_gdk_event_get_button(event) == GDK_BUTTON_PRIMARY) + if(gtk_gesture_single_get_current_button(gesture) == GDK_BUTTON_PRIMARY) { if(g->lower_margin) // bottom slider { @@ -1280,58 +1276,49 @@ static gboolean rt_wdbar_button_press(GtkWidget *widget, } gtk_widget_queue_draw(g->wd_bar); - return TRUE; } -static gboolean rt_wdbar_button_release(GtkWidget *widget, - GdkEventButton *event, - dt_iop_module_t *self) +static void rt_wdbar_button_release(GtkGestureSingle *gesture, gint n_press, gdouble x, gdouble y, dt_iop_module_t *self) { dt_iop_retouch_gui_data_t *g = self->gui_data; - if(dt_gdk_event_get_button(event) == GDK_BUTTON_PRIMARY) + if(gtk_gesture_single_get_current_button(gesture) == GDK_BUTTON_PRIMARY) g->is_dragging = 0; gtk_widget_queue_draw(g->wd_bar); - return TRUE; } -static gboolean rt_wdbar_scrolled(GtkWidget *widget, - GdkEventScroll *event, - dt_iop_module_t *self) +static void rt_wdbar_scrolled(GtkEventControllerScroll *controller, gdouble dx, gdouble dy, dt_iop_module_t *self) { - if(dt_gui_ignore_scroll(event)) - return FALSE; - if(DT_IN_GUI_UPDATE()) - return TRUE; + return; dt_iop_retouch_params_t *p = self->params; dt_iop_retouch_gui_data_t *g = self->gui_data; dt_iop_request_focus(self); - int delta_y; - if(dt_gui_get_scroll_unit_delta(event, &delta_y)) + if(dy != 0.0) { if(g->lower_margin) // bottom slider - rt_num_scales_update(p->num_scales - delta_y, self); + rt_num_scales_update(p->num_scales - dy, self); else if(g->upper_margin) // top slider - rt_merge_from_scale_update(p->merge_from_scale - delta_y, self); + rt_merge_from_scale_update(p->merge_from_scale - dy, self); else if(g->curr_scale >= 0) - rt_curr_scale_update(p->curr_scale - delta_y, self); + rt_curr_scale_update(p->curr_scale - dy, self); } gtk_widget_queue_draw(g->wd_bar); - return TRUE; } -static gboolean rt_wdbar_motion_notify(GtkWidget *widget, - GdkEventMotion *event, - dt_iop_module_t *self) +static void rt_wdbar_motion_notify(GtkEventControllerMotion *controller, + gdouble x, + gdouble y, + dt_iop_module_t *self) { dt_iop_retouch_gui_data_t *g = self->gui_data; dt_iop_retouch_params_t *p = self->params; + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); GtkAllocation allocation; gtk_widget_get_allocation(widget, &allocation); @@ -1341,8 +1328,8 @@ static gboolean rt_wdbar_motion_notify(GtkWidget *widget, /* record mouse position within control */ - g->wdbar_mouse_x = CLAMP(dt_gdk_event_get_x(event) - inset, 0, allocation.width - 2.0f * inset - 1.0f); - g->wdbar_mouse_y = dt_gdk_event_get_y(event); + g->wdbar_mouse_x = CLAMP(x - inset, 0, allocation.width - 2.0f * inset - 1.0f); + g->wdbar_mouse_y = y; g->curr_scale = g->wdbar_mouse_x / box_w; g->lower_cursor = g->upper_cursor = FALSE; @@ -1374,7 +1361,6 @@ static gboolean rt_wdbar_motion_notify(GtkWidget *widget, rt_merge_from_scale_update(g->curr_scale, self); gtk_widget_queue_draw(g->wd_bar); - return TRUE; } static int rt_scale_has_shapes(dt_iop_retouch_params_t *p, @@ -2532,20 +2518,11 @@ void gui_init(dt_iop_module_t *self) g_signal_connect(G_OBJECT(g->wd_bar), "draw", G_CALLBACK(rt_wdbar_draw), self); - g_signal_connect(G_OBJECT(g->wd_bar), "motion-notify-event", - G_CALLBACK(rt_wdbar_motion_notify), self); - g_signal_connect(G_OBJECT(g->wd_bar), "leave-notify-event", - G_CALLBACK(rt_wdbar_leave_notify), self); - g_signal_connect(G_OBJECT(g->wd_bar), "button-press-event", - G_CALLBACK(rt_wdbar_button_press), self); - g_signal_connect(G_OBJECT(g->wd_bar), "button-release-event", - G_CALLBACK(rt_wdbar_button_release), self); - g_signal_connect(G_OBJECT(g->wd_bar), "scroll-event", - G_CALLBACK(rt_wdbar_scrolled), self); - gtk_widget_add_events(GTK_WIDGET(g->wd_bar), - GDK_POINTER_MOTION_MASK - | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - | GDK_LEAVE_NOTIFY_MASK | darktable.gui->scroll_mask); + dt_gui_connect_click(g->wd_bar, rt_wdbar_button_press, rt_wdbar_button_release, self); + dt_gui_connect_motion(g->wd_bar, rt_wdbar_motion_notify, NULL, rt_wdbar_leave_notify, self); + dt_gui_connect_scroll(g->wd_bar, GTK_EVENT_CONTROLLER_SCROLL_BOTH_AXES + | GTK_EVENT_CONTROLLER_SCROLL_DISCRETE, + rt_wdbar_scrolled, self); gtk_widget_set_size_request(g->wd_bar, -1, DT_PIXEL_APPLY_DPI(40)); // toolbar display current scale / cut&paste / suppress&display masks diff --git a/src/iop/rgblevels.c b/src/iop/rgblevels.c index 3dfa1c9b0e8..ba557b08902 100644 --- a/src/iop/rgblevels.c +++ b/src/iop/rgblevels.c @@ -360,14 +360,12 @@ void gui_post_expose(dt_iop_module_t *self, cairo_stroke(cr); } -static gboolean _area_leave_notify_callback(GtkWidget *widget, - GdkEventCrossing *event, - dt_iop_module_t *self) +static void _area_leave_notify_callback(GtkEventControllerMotion *controller, + dt_iop_module_t *self) { dt_iop_rgblevels_gui_data_t *g = self->gui_data; g->mouse_x = g->mouse_y = -1.0; - gtk_widget_queue_draw(widget); - return TRUE; + gtk_widget_queue_draw(gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller))); } static gboolean _area_draw_callback(GtkWidget *widget, @@ -549,28 +547,30 @@ static void _rgblevels_move_handle(dt_iop_module_t *self, gtk_widget_queue_draw(GTK_WIDGET(g->area)); } -static gboolean _area_motion_notify_callback(GtkWidget *widget, - GdkEventMotion *event, - dt_iop_module_t *self) +static void _area_motion_notify_callback(GtkEventControllerMotion *controller, + gdouble x, + gdouble y, + dt_iop_module_t *self) { dt_iop_rgblevels_gui_data_t *g = self->gui_data; dt_iop_rgblevels_params_t *p = self->params; + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); const int inset = DT_GUI_CURVE_EDITOR_INSET; GtkAllocation allocation; gtk_widget_get_allocation(widget, &allocation); int height = allocation.height - 2 * inset - DT_RESIZE_HANDLE_SIZE, width = allocation.width - 2 * inset; if(!g->dragging) { - g->mouse_x = CLAMP(dt_gdk_event_get_x(event) - inset, 0, width); + g->mouse_x = CLAMP(x - inset, 0, width); g->drag_start_percentage = (p->levels[g->channel][1] - p->levels[g->channel][0]) / (p->levels[g->channel][2] - p->levels[g->channel][0]); } - g->mouse_y = CLAMP(dt_gdk_event_get_y(event) - inset, 0, height); + g->mouse_y = CLAMP(y - inset, 0, height); if(g->dragging) { if(g->handle_move >= 0 && g->handle_move < 3) { - const float mx = (CLAMP(dt_gdk_event_get_x(event) - inset, 0, width)) / (float)width; + const float mx = (CLAMP(x - inset, 0, width)) / (float)width; _rgblevels_move_handle(self, g->handle_move, mx, p->levels[g->channel], g->drag_start_percentage); } @@ -578,7 +578,7 @@ static gboolean _area_motion_notify_callback(GtkWidget *widget, else { g->handle_move = 0; - const float mx = CLAMP(dt_gdk_event_get_x(event) - inset, 0, width) / (float)width; + const float mx = CLAMP(x - inset, 0, width) / (float)width; float dist = fabsf(p->levels[g->channel][0] - mx); for(int k = 1; k < 3; k++) { @@ -594,91 +594,81 @@ static gboolean _area_motion_notify_callback(GtkWidget *widget, gtk_widget_queue_draw(widget); } - - return TRUE; } -static gboolean _area_button_press_callback(GtkWidget *widget, - GdkEventButton *event, - dt_iop_module_t *self) +static void _area_button_press_callback(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, + dt_iop_module_t *self) { - // set active point - if(dt_gdk_event_get_button(event) == GDK_BUTTON_PRIMARY) - { - if(darktable.develop->gui_module != self) dt_iop_request_focus(self); + if(gtk_gesture_single_get_current_button(gesture) != GDK_BUTTON_PRIMARY) + return; - if(dt_gdk_event_get_type(event) == GDK_2BUTTON_PRESS) - { - _turn_selregion_picker_off(self); + if(darktable.develop->gui_module != self) dt_iop_request_focus(self); - // Reset - dt_iop_rgblevels_gui_data_t *g = self->gui_data; - dt_iop_rgblevels_params_t *p = self->params; - const dt_iop_rgblevels_params_t *const default_params = self->default_params; + if(n_press >= 2) + { + _turn_selregion_picker_off(self); - for(int i = 0; i < 3; i++) - p->levels[g->channel][i] = default_params->levels[g->channel][i]; + // Reset + dt_iop_rgblevels_gui_data_t *g = self->gui_data; + dt_iop_rgblevels_params_t *p = self->params; + const dt_iop_rgblevels_params_t *const default_params = self->default_params; - // Needed in case the user scrolls or drags immediately after a reset, - // as drag_start_percentage is only updated when the mouse is moved. - g->drag_start_percentage = 0.5; - dt_dev_add_history_item(darktable.develop, self, TRUE); - gtk_widget_queue_draw(GTK_WIDGET(g->area)); - } - else - { - _turn_selregion_picker_off(self); + for(int i = 0; i < 3; i++) + p->levels[g->channel][i] = default_params->levels[g->channel][i]; - dt_iop_rgblevels_gui_data_t *g = self->gui_data; - g->dragging = 1; - } - return TRUE; + // Needed in case the user scrolls or drags immediately after a reset, + // as drag_start_percentage is only updated when the mouse is moved. + g->drag_start_percentage = 0.5; + dt_dev_add_history_item(darktable.develop, self, TRUE); + gtk_widget_queue_draw(GTK_WIDGET(g->area)); } - return FALSE; -} - -static gboolean _area_button_release_callback(GtkWidget *widget, - GdkEventButton *event, - dt_iop_module_t *self) -{ - if(dt_gdk_event_get_button(event) == GDK_BUTTON_PRIMARY) + else { + _turn_selregion_picker_off(self); + dt_iop_rgblevels_gui_data_t *g = self->gui_data; - g->dragging = 0; - return TRUE; + g->dragging = 1; } - return FALSE; } -static gboolean _area_scroll_callback(GtkWidget *widget, - GdkEventScroll *event, - dt_iop_module_t *self) +static void _area_button_release_callback(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, + dt_iop_module_t *self) { + if(gtk_gesture_single_get_current_button(gesture) != GDK_BUTTON_PRIMARY) + return; + dt_iop_rgblevels_gui_data_t *g = self->gui_data; - dt_iop_rgblevels_params_t *p = self->params; + g->dragging = 0; +} - if(dt_gui_ignore_scroll(event)) return FALSE; +static void _area_scroll_callback(GtkEventControllerScroll *controller, + gdouble dx, + gdouble dy, + dt_iop_module_t *self) +{ + dt_iop_rgblevels_gui_data_t *g = self->gui_data; + dt_iop_rgblevels_params_t *p = self->params; + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); _turn_selregion_picker_off(self); if(g->dragging) - { - return FALSE; - } + return; if(darktable.develop->gui_module != self) dt_iop_request_focus(self); - const float interval = 0.002 * dt_accel_get_speed_multiplier(widget, dt_gdk_event_get_state(event)); - // Distance moved for each scroll event - int delta_y; - if(dt_gui_get_scroll_unit_delta(event, &delta_y)) + if(dy != 0.0) { - const float new_position = p->levels[g->channel][g->handle_move] - interval * delta_y; + const float interval = 0.002 * dt_accel_get_speed_multiplier(widget, dt_key_modifier_state()); + const float new_position = p->levels[g->channel][g->handle_move] - interval * dy; _rgblevels_move_handle(self, g->handle_move, new_position, p->levels[g->channel], g->drag_start_percentage); - return TRUE; } - - return TRUE; // Ensure that scrolling the widget cannot move side panel } static void _auto_levels_callback(GtkButton *button, @@ -1055,16 +1045,11 @@ void gui_init(dt_iop_module_t *self) "operates on L channel.")); g_signal_connect(G_OBJECT(g->area), "draw", G_CALLBACK(_area_draw_callback), self); - g_signal_connect(G_OBJECT(g->area), "button-press-event", - G_CALLBACK(_area_button_press_callback), self); - g_signal_connect(G_OBJECT(g->area), "button-release-event", - G_CALLBACK(_area_button_release_callback), self); - g_signal_connect(G_OBJECT(g->area), "motion-notify-event", - G_CALLBACK(_area_motion_notify_callback), self); - g_signal_connect(G_OBJECT(g->area), "leave-notify-event", - G_CALLBACK(_area_leave_notify_callback), self); - g_signal_connect(G_OBJECT(g->area), "scroll-event", - G_CALLBACK(_area_scroll_callback), self); + dt_gui_connect_click(g->area, _area_button_press_callback, _area_button_release_callback, self); + dt_gui_connect_motion(g->area, _area_motion_notify_callback, NULL, _area_leave_notify_callback, self); + dt_gui_connect_scroll(g->area, GTK_EVENT_CONTROLLER_SCROLL_BOTH_AXES + | GTK_EVENT_CONTROLLER_SCROLL_DISCRETE, + _area_scroll_callback, self); #define PICKER_SETUP(color, name, tooltip) \ g->color##pick = dt_color_picker_new(self, DT_COLOR_PICKER_POINT, NULL); \ diff --git a/src/iop/toneequal.c b/src/iop/toneequal.c index a9ae96e994f..26db2cbbf47 100644 --- a/src/iop/toneequal.c +++ b/src/iop/toneequal.c @@ -2941,12 +2941,10 @@ static gboolean area_draw(GtkWidget *widget, } -static gboolean area_enter_leave_notify(GtkWidget *widget, - const GdkEventCrossing *event, - dt_iop_module_t *self) +static void area_leave_notify(GtkEventControllerMotion *controller, + dt_iop_module_t *self) { - DT_GUARD_GUI_UPDATE(TRUE); - if(!self->enabled) return FALSE; + if(!self->enabled) return; dt_iop_toneequalizer_gui_data_t *g = self->gui_data; @@ -2960,33 +2958,35 @@ static gboolean area_enter_leave_notify(GtkWidget *widget, dt_dev_add_history_item(darktable.develop, self, FALSE); } dt_iop_gui_enter_critical_section(self); - g->area_x = (dt_gdk_event_get_x(event) - g->inset); - g->area_y = (dt_gdk_event_get_y(event) - g->inset); + g->area_x = g->inset; + g->area_y = g->inset; g->area_dragging = FALSE; g->area_active_node = -1; - g->area_cursor_valid = (g->area_x > 0.0f - && g->area_x < g->graph_width - && g->area_y > 0.0f - && g->area_y < g->graph_height); + g->area_cursor_valid = FALSE; dt_iop_gui_leave_critical_section(self); gtk_widget_queue_draw(GTK_WIDGET(g->area)); - return FALSE; } -static gboolean area_button_press(GtkWidget *widget, - const GdkEventButton *event, - dt_iop_module_t *self) +static void area_button_press(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, + dt_iop_module_t *self) { - - DT_GUARD_GUI_UPDATE(TRUE); - dt_iop_toneequalizer_gui_data_t *g = self->gui_data; dt_iop_request_focus(self); - if(dt_gdk_event_get_button(event) == GDK_BUTTON_PRIMARY && dt_gdk_event_get_type(event) == GDK_2BUTTON_PRESS) + if(gtk_gesture_single_get_current_button(gesture) != GDK_BUTTON_PRIMARY) + { + // Unlock the colour picker so we can display our own custom cursor + dt_iop_color_picker_reset(self, TRUE); + return; + } + + if(n_press >= 2) { dt_iop_toneequalizer_params_t *p = self->params; const dt_iop_toneequalizer_params_t *const d = self->default_params; @@ -3008,35 +3008,27 @@ static gboolean area_button_press(GtkWidget *widget, // Redraw graph gtk_widget_queue_draw(GTK_WIDGET(g->area)); dt_dev_add_history_item(darktable.develop, self, TRUE); - return TRUE; + return; } - else if(dt_gdk_event_get_button(event) == GDK_BUTTON_PRIMARY) + + if(self->enabled) { - if(self->enabled) - { - g->area_dragging = TRUE; - gtk_widget_queue_draw(GTK_WIDGET(g->area)); - } - else - { - dt_dev_add_history_item(darktable.develop, self, TRUE); - } - return TRUE; + g->area_dragging = TRUE; + gtk_widget_queue_draw(GTK_WIDGET(g->area)); + } + else + { + dt_dev_add_history_item(darktable.develop, self, TRUE); } - - // Unlock the colour picker so we can display our own custom cursor - dt_iop_color_picker_reset(self, TRUE); - - return FALSE; } -static gboolean area_motion_notify(GtkWidget *widget, - const GdkEventMotion *event, - dt_iop_module_t *self) +static void area_motion_notify(GtkEventControllerMotion *controller, + gdouble x, + gdouble y, + dt_iop_module_t *self) { - DT_GUARD_GUI_UPDATE(TRUE); - if(!self->enabled) return FALSE; + if(!self->enabled) return; dt_iop_toneequalizer_gui_data_t *g = self->gui_data; dt_iop_toneequalizer_params_t *p = self->params; @@ -3046,7 +3038,7 @@ static gboolean area_motion_notify(GtkWidget *widget, // vertical distance travelled since button_pressed event dt_iop_gui_enter_critical_section(self); // graph spans over 4 EV - const float offset = (-dt_gdk_event_get_y(event) + g->area_y) / g->graph_height * 4.0f; + const float offset = (-y + g->area_y) / g->graph_height * 4.0f; const float cursor_exposure = g->area_x / g->graph_width * 8.0f - 8.0f; // Get the desired correction on exposure channels @@ -3056,8 +3048,8 @@ static gboolean area_motion_notify(GtkWidget *widget, } dt_iop_gui_enter_critical_section(self); - g->area_x = dt_gdk_event_get_x(event) - g->inset; - g->area_y = dt_gdk_event_get_y(event); + g->area_x = x - g->inset; + g->area_y = y; g->area_cursor_valid = (g->area_x > 0.0f && g->area_x < g->graph_width && g->area_y > 0.0f @@ -3081,41 +3073,38 @@ static gboolean area_motion_notify(GtkWidget *widget, dt_iop_gui_leave_critical_section(self); gtk_widget_queue_draw(GTK_WIDGET(g->area)); - return TRUE; } -static gboolean area_button_release(GtkWidget *widget, - const GdkEventButton *event, - dt_iop_module_t *self) +static void area_button_release(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, + dt_iop_module_t *self) { - DT_GUARD_GUI_UPDATE(TRUE); - if(!self->enabled) return FALSE; + if(!self->enabled) return; + + if(gtk_gesture_single_get_current_button(gesture) != GDK_BUTTON_PRIMARY) + return; dt_iop_toneequalizer_gui_data_t *g = self->gui_data; // Give focus to module dt_iop_request_focus(self); - if(dt_gdk_event_get_button(event) == GDK_BUTTON_PRIMARY) - { - const dt_iop_toneequalizer_params_t *p = self->params; - - if(g->area_dragging) - { - // Update GUI with new params - update_exposure_sliders(g, p); + const dt_iop_toneequalizer_params_t *p = self->params; - dt_dev_add_history_item(darktable.develop, self, FALSE); + if(g->area_dragging) + { + // Update GUI with new params + update_exposure_sliders(g, p); - dt_iop_gui_enter_critical_section(self); - g->area_dragging = FALSE; - dt_iop_gui_leave_critical_section(self); + dt_dev_add_history_item(darktable.develop, self, FALSE); - return TRUE; - } + dt_iop_gui_enter_critical_section(self); + g->area_dragging = FALSE; + dt_iop_gui_leave_critical_section(self); } - return FALSE; } static gboolean area_scroll(GtkWidget *widget, @@ -3126,19 +3115,17 @@ static gboolean area_scroll(GtkWidget *widget, return !dt_gui_ignore_scroll(event); } -static gboolean notebook_button_press(GtkWidget *widget, - GdkEventButton *event, - dt_iop_module_t *self) +static void notebook_button_press(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, + dt_iop_module_t *self) { - DT_GUARD_GUI_UPDATE(TRUE); - // Give focus to module dt_iop_request_focus(self); // Unlock the colour picker so we can display our own custom cursor dt_iop_color_picker_reset(self, TRUE); - - return FALSE; } GSList *mouse_actions(dt_iop_module_t *self) @@ -3283,23 +3270,11 @@ void gui_init(dt_iop_module_t *self) g_object_set_data(G_OBJECT(wrapper), "iop-instance", self); gtk_widget_set_name(GTK_WIDGET(wrapper), "toneeqgraph"); dt_action_define_iop(self, NULL, N_("graph"), GTK_WIDGET(wrapper), NULL); - gtk_widget_add_events(GTK_WIDGET(g->area), - GDK_POINTER_MOTION_MASK | darktable.gui->scroll_mask - | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK); gtk_widget_set_vexpand(GTK_WIDGET(g->area), TRUE); gtk_widget_set_can_focus(GTK_WIDGET(g->area), TRUE); g_signal_connect(G_OBJECT(g->area), "draw", G_CALLBACK(area_draw), self); - g_signal_connect(G_OBJECT(g->area), "button-press-event", - G_CALLBACK(area_button_press), self); - g_signal_connect(G_OBJECT(g->area), "button-release-event", - G_CALLBACK(area_button_release), self); - g_signal_connect(G_OBJECT(g->area), "leave-notify-event", - G_CALLBACK(area_enter_leave_notify), self); - g_signal_connect(G_OBJECT(g->area), "enter-notify-event", - G_CALLBACK(area_enter_leave_notify), self); - g_signal_connect(G_OBJECT(g->area), "motion-notify-event", - G_CALLBACK(area_motion_notify), self); + dt_gui_connect_click(g->area, area_button_press, area_button_release, self); + dt_gui_connect_motion(g->area, area_motion_notify, NULL, area_leave_notify, self); g_signal_connect(G_OBJECT(g->area), "scroll-event", G_CALLBACK(area_scroll), self); gtk_widget_set_tooltip_text(GTK_WIDGET(g->area), _("double-click to reset the curve")); @@ -3401,8 +3376,7 @@ void gui_init(dt_iop_module_t *self) gtk_widget_show(gtk_notebook_get_nth_page(g->notebook, active_page)); gtk_notebook_set_current_page(g->notebook, active_page); - g_signal_connect(G_OBJECT(g->notebook), "button-press-event", - G_CALLBACK(notebook_button_press), self); + dt_gui_connect_click(g->notebook, notebook_button_press, NULL, self); g->show_luminance_mask = dt_iop_togglebutton_new (self, NULL, diff --git a/src/iop/zonesystem.c b/src/iop/zonesystem.c index b455b081412..611af790951 100644 --- a/src/iop/zonesystem.c +++ b/src/iop/zonesystem.c @@ -386,16 +386,16 @@ static gboolean dt_iop_zonesystem_preview_draw(GtkWidget *widget, cairo_t *crf, dt_iop_module_t *self); static gboolean dt_iop_zonesystem_bar_draw(GtkWidget *widget, cairo_t *crf, dt_iop_module_t *self); -static gboolean dt_iop_zonesystem_bar_motion_notify(GtkWidget *widget, GdkEventMotion *event, - dt_iop_module_t *self); -static gboolean dt_iop_zonesystem_bar_leave_notify(GtkWidget *widget, GdkEventCrossing *event, - dt_iop_module_t *self); -static gboolean dt_iop_zonesystem_bar_button_press(GtkWidget *widget, GdkEventButton *event, +static void dt_iop_zonesystem_bar_motion_notify(GtkEventControllerMotion *controller, gdouble x, gdouble y, dt_iop_module_t *self); -static gboolean dt_iop_zonesystem_bar_button_release(GtkWidget *widget, GdkEventButton *event, - dt_iop_module_t *self); -static gboolean dt_iop_zonesystem_bar_scrolled(GtkWidget *widget, GdkEventScroll *event, - dt_iop_module_t *self); +static void dt_iop_zonesystem_bar_leave_notify(GtkEventControllerMotion *controller, + dt_iop_module_t *self); +static void dt_iop_zonesystem_bar_button_press(GtkGestureSingle *gesture, gint n_press, gdouble x, gdouble y, + dt_iop_module_t *self); +static void dt_iop_zonesystem_bar_button_release(GtkGestureSingle *gesture, gint n_press, gdouble x, gdouble y, + dt_iop_module_t *self); +static void dt_iop_zonesystem_bar_scrolled(GtkEventControllerScroll *controller, gdouble dx, gdouble dy, + dt_iop_module_t *self); static void size_allocate_callback(GtkWidget *widget, GtkAllocation *allocation, dt_iop_module_t *self) @@ -443,18 +443,11 @@ void gui_init(dt_iop_module_t *self) "left-click on a border to create a marker\n" "right-click on a marker to delete it")); g_signal_connect(G_OBJECT(g->zones), "draw", G_CALLBACK(dt_iop_zonesystem_bar_draw), self); - g_signal_connect(G_OBJECT(g->zones), "motion-notify-event", G_CALLBACK(dt_iop_zonesystem_bar_motion_notify), - self); - g_signal_connect(G_OBJECT(g->zones), "leave-notify-event", G_CALLBACK(dt_iop_zonesystem_bar_leave_notify), - self); - g_signal_connect(G_OBJECT(g->zones), "button-press-event", G_CALLBACK(dt_iop_zonesystem_bar_button_press), - self); - g_signal_connect(G_OBJECT(g->zones), "button-release-event", - G_CALLBACK(dt_iop_zonesystem_bar_button_release), self); - g_signal_connect(G_OBJECT(g->zones), "scroll-event", G_CALLBACK(dt_iop_zonesystem_bar_scrolled), self); - gtk_widget_add_events(GTK_WIDGET(g->zones), GDK_POINTER_MOTION_MASK - | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - | GDK_LEAVE_NOTIFY_MASK | darktable.gui->scroll_mask); + dt_gui_connect_click_all(g->zones, dt_iop_zonesystem_bar_button_press, dt_iop_zonesystem_bar_button_release, self); + dt_gui_connect_motion(g->zones, dt_iop_zonesystem_bar_motion_notify, NULL, dt_iop_zonesystem_bar_leave_notify, self); + dt_gui_connect_scroll(g->zones, GTK_EVENT_CONTROLLER_SCROLL_BOTH_AXES + | GTK_EVENT_CONTROLLER_SCROLL_DISCRETE, + dt_iop_zonesystem_bar_scrolled, self); gtk_widget_set_size_request(g->zones, -1, DT_PIXEL_APPLY_DPI(40)); self->widget = dt_gui_vbox(g->preview, g->zones); @@ -572,15 +565,16 @@ static gboolean dt_iop_zonesystem_bar_draw(GtkWidget *widget, cairo_t *crf, dt_i return TRUE; } -static gboolean dt_iop_zonesystem_bar_button_press(GtkWidget *widget, GdkEventButton *event, - dt_iop_module_t *self) +static void dt_iop_zonesystem_bar_button_press(GtkGestureSingle *gesture, gint n_press, gdouble x, gdouble y, + dt_iop_module_t *self) { dt_iop_zonesystem_params_t *p = self->params; dt_iop_zonesystem_gui_data_t *g = self->gui_data; + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); const int inset = DT_ZONESYSTEM_INSET; GtkAllocation allocation; gtk_widget_get_allocation(widget, &allocation); - int width = allocation.width - 2 * inset; /*, height = allocation.height - 2*inset;*/ + int width = allocation.width - 2 * inset; /* calculate zonemap */ float zonemap[MAX_ZONE_SYSTEM_SIZE] = { -1 }; @@ -591,8 +585,9 @@ static gboolean dt_iop_zonesystem_bar_button_press(GtkWidget *widget, GdkEventBu float zw = zonemap[k + 1] - zonemap[k]; if((g->mouse_x / width) > zonemap[k] + (zw / 2)) k++; + const guint button = gtk_gesture_single_get_current_button(gesture); - if(dt_gdk_event_get_button(event) == GDK_BUTTON_PRIMARY) + if(button == GDK_BUTTON_PRIMARY) { if(p->zone[k] == -1) { @@ -602,60 +597,51 @@ static gboolean dt_iop_zonesystem_bar_button_press(GtkWidget *widget, GdkEventBu g->is_dragging = TRUE; g->current_zone = k; } - else if(dt_gdk_event_get_button(event) == GDK_BUTTON_SECONDARY) + else if(button == GDK_BUTTON_SECONDARY) { /* clear the controlpoint */ p->zone[k] = -1; dt_dev_add_history_item(darktable.develop, self, TRUE); } - - return TRUE; } -static gboolean dt_iop_zonesystem_bar_button_release(GtkWidget *widget, GdkEventButton *event, - dt_iop_module_t *self) +static void dt_iop_zonesystem_bar_button_release(GtkGestureSingle *gesture, gint n_press, gdouble x, gdouble y, + dt_iop_module_t *self) { dt_iop_zonesystem_gui_data_t *g = self->gui_data; - if(dt_gdk_event_get_button(event) == GDK_BUTTON_PRIMARY) - { + if(gtk_gesture_single_get_current_button(gesture) == GDK_BUTTON_PRIMARY) g->is_dragging = FALSE; - } - return TRUE; } -static gboolean dt_iop_zonesystem_bar_scrolled(GtkWidget *widget, GdkEventScroll *event, dt_iop_module_t *self) +static void dt_iop_zonesystem_bar_scrolled(GtkEventControllerScroll *controller, gdouble dx, gdouble dy, + dt_iop_module_t *self) { dt_iop_zonesystem_params_t *p = self->params; int cs = CLAMP(p->size, 4, MAX_ZONE_SYSTEM_SIZE); - if(dt_gui_ignore_scroll(event)) return FALSE; - - int delta_y; - if(dt_gui_get_scroll_unit_delta(event, &delta_y)) + if(dy != 0.0) { - p->size = CLAMP(p->size - delta_y, 4, MAX_ZONE_SYSTEM_SIZE); + p->size = CLAMP(p->size - dy, 4, MAX_ZONE_SYSTEM_SIZE); p->zone[cs] = -1; dt_dev_add_history_item(darktable.develop, self, TRUE); - gtk_widget_queue_draw(widget); + gtk_widget_queue_draw(gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller))); } - - return TRUE; } -static gboolean dt_iop_zonesystem_bar_leave_notify(GtkWidget *widget, GdkEventCrossing *event, - dt_iop_module_t *self) +static void dt_iop_zonesystem_bar_leave_notify(GtkEventControllerMotion *controller, + dt_iop_module_t *self) { dt_iop_zonesystem_gui_data_t *g = self->gui_data; g->hilite_zone = FALSE; gtk_widget_queue_draw(g->preview); - return TRUE; } -static gboolean dt_iop_zonesystem_bar_motion_notify(GtkWidget *widget, GdkEventMotion *event, - dt_iop_module_t *self) +static void dt_iop_zonesystem_bar_motion_notify(GtkEventControllerMotion *controller, gdouble x, gdouble y, + dt_iop_module_t *self) { dt_iop_zonesystem_params_t *p = self->params; dt_iop_zonesystem_gui_data_t *g = self->gui_data; + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); const int inset = DT_ZONESYSTEM_INSET; GtkAllocation allocation; gtk_widget_get_allocation(widget, &allocation); @@ -666,8 +652,8 @@ static gboolean dt_iop_zonesystem_bar_motion_notify(GtkWidget *widget, GdkEventM _iop_zonesystem_calculate_zonemap(p, zonemap); /* record mouse position within control */ - g->mouse_x = CLAMP(dt_gdk_event_get_x(event) - inset, 0, width); - g->mouse_y = CLAMP(height - 1 - dt_gdk_event_get_y(event) + inset, 0, height); + g->mouse_x = CLAMP(x - inset, 0, width); + g->mouse_y = CLAMP(height - 1 - y + inset, 0, height); if(g->is_dragging) { @@ -704,7 +690,6 @@ static gboolean dt_iop_zonesystem_bar_motion_notify(GtkWidget *widget, GdkEventM gtk_widget_queue_draw(self->widget); gtk_widget_queue_draw(g->preview); - return TRUE; } diff --git a/src/libs/modulegroups.c b/src/libs/modulegroups.c index ca199e82d4f..57ea2085861 100644 --- a/src/libs/modulegroups.c +++ b/src/libs/modulegroups.c @@ -402,9 +402,12 @@ static void _basics_hide(dt_lib_module_t *self) d->vbox_basic = NULL; } -static gboolean _basics_goto_module(GtkWidget *w, GdkEventButton *e, gpointer user_data) +static void _basics_goto_module(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, + dt_iop_module_t *module) { - dt_iop_module_t *module = (dt_iop_module_t *)(user_data); dt_dev_modulegroups_switch(darktable.develop, module); const gboolean single = dt_conf_get_bool("darkroom/ui/single_module"); dt_iop_gui_set_expanded(module, TRUE, single); @@ -413,13 +416,15 @@ static gboolean _basics_goto_module(GtkWidget *w, GdkEventButton *e, gpointer us // this second call ensures the module ends up expanded. if(single) dt_iop_gui_set_expanded(module, TRUE, FALSE); - return TRUE; } -static gboolean _basics_on_off_label_callback(GtkWidget *widget, GdkEventButton *e, GtkToggleButton *btn) +static void _basics_on_off_label_callback(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, + GtkWidget *btn) { - gtk_toggle_button_set_active(btn, !gtk_toggle_button_get_active(btn)); - return TRUE; + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(btn), !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(btn))); } static void _sync_visibility(GtkWidget *widget, @@ -434,7 +439,11 @@ static void _sync_visibility(GtkWidget *widget, gtk_widget_set_visible(item->box, !dt_action_widget_invisible(item->temp_widget)); } -static gboolean _manage_direct_module_popup(GtkWidget *widget, GdkEventButton *event, dt_lib_module_t *self); +static void _manage_direct_module_popup(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, + dt_lib_module_t *self); static void _basics_add_widget(dt_lib_module_t *self, dt_lib_modulegroups_basic_item_t *item, GtkWidget *w, dt_lib_modulegroups_basic_item_position_t item_pos) @@ -476,7 +485,7 @@ static void _basics_add_widget(dt_lib_module_t *self, dt_lib_modulegroups_basic_ gtk_label_set_xalign(GTK_LABEL(lb), 0.0); gtk_widget_set_name(lb, "basics-iop_name"); gtk_container_add(GTK_CONTAINER(evb), lb); - g_signal_connect(G_OBJECT(evb), "button-press-event", G_CALLBACK(_basics_on_off_label_callback), btn); + dt_gui_connect_click(evb, _basics_on_off_label_callback, NULL, btn); gtk_box_pack_start(GTK_BOX(item->box), evb, FALSE, TRUE, 0); // disable widget if needed (multiinstance) @@ -599,7 +608,8 @@ static void _basics_add_widget(dt_lib_module_t *self, dt_lib_modulegroups_basic_ gtk_container_add(GTK_CONTAINER(evb), header_box); gtk_widget_show_all(evb); g_object_set_data(G_OBJECT(evb), "module", item->module->so); - g_signal_connect(evb, "button-press-event", G_CALLBACK(_manage_direct_module_popup), self); + GtkGestureSingle *g_evb = dt_gui_connect_click(evb, _manage_direct_module_popup, NULL, self); + gtk_gesture_single_set_button(g_evb, GDK_BUTTON_SECONDARY); gtk_widget_set_name(header_box, "basics-header-box"); dt_gui_add_class(header_box, "dt_big_btn_canvas"); gtk_box_pack_start(GTK_BOX(d->vbox_basic), evb, FALSE, FALSE, 0); @@ -620,7 +630,7 @@ static void _basics_add_widget(dt_lib_module_t *self, dt_lib_modulegroups_basic_ gtk_widget_set_name(wbt, "basics-link"); gtk_widget_set_valign(wbt, GTK_ALIGN_CENTER); g_free(tt); - g_signal_connect(G_OBJECT(wbt), "button-press-event", G_CALLBACK(_basics_goto_module), item->module); + dt_gui_connect_click(wbt, _basics_goto_module, NULL, item->module); gtk_box_pack_end(GTK_BOX(compact_ui ? hbox_basic : header_box), wbt, FALSE, FALSE, 0); // we create a button to open the presets menu @@ -2670,53 +2680,54 @@ static gboolean _presets_pressed(GtkWidget *widget, return FALSE; } -static gboolean _manage_direct_popup(GtkWidget *widget, - GdkEventButton *event, - dt_lib_module_t *self) +static void _manage_direct_popup(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, + dt_lib_module_t *self) { - if(dt_gdk_event_get_type(event) == GDK_BUTTON_PRESS && dt_gdk_event_get_button(event) == GDK_BUTTON_SECONDARY) - { - dt_lib_modulegroups_group_t *gr = g_object_get_data(G_OBJECT(widget), "group"); - if(!g_strcmp0(gr->name, C_("modulegroup", "deprecated"))) return FALSE; - _manage_module_add_popup(widget, gr, - G_CALLBACK(_manage_direct_module_toggle), self, TRUE); - return TRUE; - } - return FALSE; + if(gtk_gesture_single_get_current_button(gesture) != GDK_BUTTON_SECONDARY) + return; + + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + dt_lib_modulegroups_group_t *gr = g_object_get_data(G_OBJECT(widget), "group"); + if(!g_strcmp0(gr->name, C_("modulegroup", "deprecated"))) return; + _manage_module_add_popup(widget, gr, + G_CALLBACK(_manage_direct_module_toggle), self, TRUE); } -static gboolean _manage_direct_basic_popup(GtkWidget *widget, - GdkEventButton *event, - dt_lib_module_t *self) +static void _manage_direct_basic_popup(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, + dt_lib_module_t *self) { - if(dt_gdk_event_get_type(event) == GDK_BUTTON_PRESS && dt_gdk_event_get_button(event) == GDK_BUTTON_SECONDARY) - { - _manage_basics_add_popup(widget, self, TRUE); - return TRUE; - } - return FALSE; + if(gtk_gesture_single_get_current_button(gesture) != GDK_BUTTON_SECONDARY) + return; + + _manage_basics_add_popup(gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)), self, TRUE); } -static gboolean _manage_direct_module_popup(GtkWidget *widget, - GdkEventButton *event, - dt_lib_module_t *self) +static void _manage_direct_module_popup(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, + dt_lib_module_t *self) { - dt_action_t *module = g_object_get_data(G_OBJECT(widget), "module"); + if(gtk_gesture_single_get_current_button(gesture) != GDK_BUTTON_SECONDARY) + return; - if(dt_gdk_event_get_type(event) == GDK_BUTTON_PRESS && dt_gdk_event_get_button(event) == GDK_BUTTON_SECONDARY) - { - int nba = 0; // nb of already present items - GtkWidget *pop = gtk_menu_new(); - gtk_widget_set_name(pop, "modulegroups-popup"); + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + dt_action_t *module = g_object_get_data(G_OBJECT(widget), "module"); - GtkWidget *this_module = _build_menu_from_actions(module->target, self, - NULL, pop, TRUE, &nba); + int nba = 0; // nb of already present items + GtkWidget *pop = gtk_menu_new(); + gtk_widget_set_name(pop, "modulegroups-popup"); - dt_gui_menu_popup(GTK_MENU(this_module), NULL, GDK_GRAVITY_SOUTH, GDK_GRAVITY_NORTH); + GtkWidget *this_module = _build_menu_from_actions(module->target, self, + NULL, pop, TRUE, &nba); - return TRUE; - } - return FALSE; + dt_gui_menu_popup(GTK_MENU(this_module), NULL, GDK_GRAVITY_SOUTH, GDK_GRAVITY_NORTH); } static void _manage_direct_full_active_toggled(GtkWidget *widget, @@ -2730,31 +2741,32 @@ static void _manage_direct_full_active_toggled(GtkWidget *widget, _lib_modulegroups_update_iop_visibility(self); } -static gboolean _manage_direct_active_popup(GtkWidget *widget, - GdkEventButton *event, - dt_lib_module_t *self) +static void _manage_direct_active_popup(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, + dt_lib_module_t *self) { - if(dt_gdk_event_get_type(event) == GDK_BUTTON_PRESS && dt_gdk_event_get_button(event) == GDK_BUTTON_SECONDARY) - { - dt_lib_modulegroups_t *d = self->data; - GtkWidget *pop = gtk_menu_new(); - gtk_widget_set_name(pop, "modulegroups-popup"); - - GtkWidget *smt = gtk_check_menu_item_new_with_label(_("show all history modules")); - gtk_widget_set_tooltip_text( - smt, - _("show modules that are present in the history stack," - " regardless of whether or not they are currently enabled")); - gtk_widget_set_name(smt, "modulegroups-popup-item"); - gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(smt), d->full_active); - g_signal_connect(G_OBJECT(smt), "toggled", - G_CALLBACK(_manage_direct_full_active_toggled), self); - gtk_menu_shell_append(GTK_MENU_SHELL(pop), smt); + if(gtk_gesture_single_get_current_button(gesture) != GDK_BUTTON_SECONDARY) + return; - dt_gui_menu_popup(GTK_MENU(pop), widget, GDK_GRAVITY_SOUTH, GDK_GRAVITY_NORTH); - return TRUE; - } - return FALSE; + dt_lib_modulegroups_t *d = self->data; + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + GtkWidget *pop = gtk_menu_new(); + gtk_widget_set_name(pop, "modulegroups-popup"); + + GtkWidget *smt = gtk_check_menu_item_new_with_label(_("show all history modules")); + gtk_widget_set_tooltip_text( + smt, + _("show modules that are present in the history stack," + " regardless of whether or not they are currently enabled")); + gtk_widget_set_name(smt, "modulegroups-popup-item"); + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(smt), d->full_active); + g_signal_connect(G_OBJECT(smt), "toggled", + G_CALLBACK(_manage_direct_full_active_toggled), self); + gtk_menu_shell_append(GTK_MENU_SHELL(pop), smt); + + dt_gui_menu_popup(GTK_MENU(pop), widget, GDK_GRAVITY_SOUTH, GDK_GRAVITY_NORTH); } static void _dt_dev_image_changed_callback(gpointer instance, @@ -2834,13 +2846,16 @@ static void _dt_dev_image_changed_callback(gpointer instance, } -static gboolean _scroll_group_buttons(GtkWidget *widget, - GdkEventScroll *event, - dt_lib_module_t *self) +static void _scroll_group_buttons(GtkEventControllerScroll *controller, + gdouble dx, + gdouble dy, + dt_lib_module_t *self) { dt_lib_modulegroups_t *d = self->data; - int delta; - if(dt_gui_get_scroll_unit_delta(event, &delta)) + int delta = (dy > 0) ? 1 : (dy < 0) ? -1 : 0; + if(delta == 0) + delta = (dx > 0) ? -1 : (dx < 0) ? 1 : 0; + if(delta != 0) { GtkWidget *adjacent = d->current == DT_MODULEGROUP_BASICS && delta < 0 ? d->active_btn @@ -2849,8 +2864,6 @@ static gboolean _scroll_group_buttons(GtkWidget *widget, : _buttons_get_from_pos(self, d->current - delta); if(adjacent) gtk_button_clicked(GTK_BUTTON(adjacent)); } - - return TRUE; } // cycle module groups action @@ -2963,15 +2976,18 @@ void gui_init(dt_lib_module_t *self) d->hbox_groups = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); GtkWidget *scrollbox = gtk_event_box_new(); gtk_container_add(GTK_CONTAINER(scrollbox), d->hbox_groups); - g_signal_connect(scrollbox, "scroll-event", - G_CALLBACK(_scroll_group_buttons), self); - gtk_widget_add_events(scrollbox, darktable.gui->scroll_mask); + dt_gui_connect_scroll(scrollbox, + GTK_EVENT_CONTROLLER_SCROLL_VERTICAL + | GTK_EVENT_CONTROLLER_SCROLL_DISCRETE, + _scroll_group_buttons, self); gtk_box_pack_start(GTK_BOX(d->hbox_buttons), scrollbox, TRUE, TRUE, 0); // basic group button d->basic_btn = dtgtk_togglebutton_new(dtgtk_cairo_paint_modulegroup_basics, 0, NULL); - g_signal_connect(d->basic_btn, "button-press-event", - G_CALLBACK(_manage_direct_basic_popup), self); + { + GtkGestureSingle *g = dt_gui_connect_click(d->basic_btn, _manage_direct_basic_popup, NULL, self); + gtk_gesture_single_set_button(g, GDK_BUTTON_SECONDARY); + } g_signal_connect(d->basic_btn, "toggled", G_CALLBACK(_lib_modulegroups_toggle), self); gtk_widget_set_tooltip_text(d->basic_btn, _("quick access panel\n" "right-click tab icon to add/remove widgets")); @@ -2984,8 +3000,10 @@ void gui_init(dt_lib_module_t *self) // active group button d->active_btn = dtgtk_togglebutton_new(dtgtk_cairo_paint_modulegroup_active, 0, NULL); - g_signal_connect(d->active_btn, "button-press-event", - G_CALLBACK(_manage_direct_active_popup), self); + { + GtkGestureSingle *g = dt_gui_connect_click(d->active_btn, _manage_direct_active_popup, NULL, self); + gtk_gesture_single_set_button(g, GDK_BUTTON_SECONDARY); + } g_signal_connect(d->active_btn, "toggled", G_CALLBACK(_lib_modulegroups_toggle), self); gtk_widget_set_tooltip_text(d->active_btn, _("show only active modules")); @@ -3138,7 +3156,10 @@ static void _buttons_update(dt_lib_module_t *self) dt_lib_modulegroups_group_t *gr = l->data; GtkWidget *bt = dtgtk_togglebutton_new(_buttons_get_icon_fct(gr->icon), 0, NULL); g_object_set_data(G_OBJECT(bt), "group", gr); - g_signal_connect(bt, "button-press-event", G_CALLBACK(_manage_direct_popup), self); + { + GtkGestureSingle *g_bt = dt_gui_connect_click(bt, _manage_direct_popup, NULL, self); + gtk_gesture_single_set_button(g_bt, GDK_BUTTON_SECONDARY); + } g_signal_connect(bt, "toggled", G_CALLBACK(_lib_modulegroups_toggle), self); char *tooltip = g_strdup_printf(_("%s\nright-click tab icon to add/remove modules"), gr->name); gtk_widget_set_tooltip_text(bt, tooltip); @@ -3256,10 +3277,13 @@ static void _manage_editor_group_name_changed(GtkWidget *tb, gr->name = g_strdup(txt); } -static gboolean _manage_editor_group_icon_changed(GtkWidget *widget, - GdkEventButton *event, - dt_lib_modulegroups_group_t *gr) +static void _manage_editor_group_icon_changed(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, + dt_lib_modulegroups_group_t *gr) { + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); const char *ic = (char *)g_object_get_data(G_OBJECT(widget), "ic_name"); g_free(gr->icon); gr->icon = g_strdup(ic); @@ -3267,7 +3291,6 @@ static gboolean _manage_editor_group_icon_changed(GtkWidget *widget, GtkWidget *btn = gtk_popover_get_relative_to(GTK_POPOVER(pop)); dtgtk_button_set_paint(DTGTK_BUTTON(btn), _buttons_get_icon_fct(ic), 0, NULL); gtk_popover_popdown(GTK_POPOVER(pop)); - return TRUE; } static void _manage_editor_group_icon_popup(GtkWidget *btn, @@ -3286,8 +3309,7 @@ static void _manage_editor_group_icon_popup(GtkWidget *btn, gtk_box_pack_start(GTK_BOX(hb), ic, FALSE, TRUE, 0); gtk_box_pack_start(GTK_BOX(hb), gtk_label_new(_("basic icon")), TRUE, TRUE, 0); g_object_set_data(G_OBJECT(eb), "ic_name", "basic"); - g_signal_connect(G_OBJECT(eb), "button-press-event", - G_CALLBACK(_manage_editor_group_icon_changed), gr); + dt_gui_connect_click_all(eb, _manage_editor_group_icon_changed, NULL, gr); gtk_container_add(GTK_CONTAINER(eb), hb); gtk_box_pack_start(GTK_BOX(vb), eb, FALSE, TRUE, 0); @@ -3297,8 +3319,7 @@ static void _manage_editor_group_icon_popup(GtkWidget *btn, gtk_box_pack_start(GTK_BOX(hb), ic, FALSE, TRUE, 0); gtk_box_pack_start(GTK_BOX(hb), gtk_label_new(_("active icon")), TRUE, TRUE, 0); g_object_set_data(G_OBJECT(eb), "ic_name", "active"); - g_signal_connect(G_OBJECT(eb), "button-press-event", - G_CALLBACK(_manage_editor_group_icon_changed), gr); + dt_gui_connect_click_all(eb, _manage_editor_group_icon_changed, NULL, gr); gtk_container_add(GTK_CONTAINER(eb), hb); gtk_box_pack_start(GTK_BOX(vb), eb, FALSE, TRUE, 0); @@ -3308,8 +3329,7 @@ static void _manage_editor_group_icon_popup(GtkWidget *btn, gtk_box_pack_start(GTK_BOX(hb), ic, FALSE, TRUE, 0); gtk_box_pack_start(GTK_BOX(hb), gtk_label_new(_("color icon")), TRUE, TRUE, 0); g_object_set_data(G_OBJECT(eb), "ic_name", "color"); - g_signal_connect(G_OBJECT(eb), "button-press-event", - G_CALLBACK(_manage_editor_group_icon_changed), gr); + dt_gui_connect_click_all(eb, _manage_editor_group_icon_changed, NULL, gr); gtk_container_add(GTK_CONTAINER(eb), hb); gtk_box_pack_start(GTK_BOX(vb), eb, FALSE, TRUE, 0); @@ -3319,8 +3339,7 @@ static void _manage_editor_group_icon_popup(GtkWidget *btn, gtk_box_pack_start(GTK_BOX(hb), ic, FALSE, TRUE, 0); gtk_box_pack_start(GTK_BOX(hb), gtk_label_new(_("correct icon")), TRUE, TRUE, 0); g_object_set_data(G_OBJECT(eb), "ic_name", "correct"); - g_signal_connect(G_OBJECT(eb), "button-press-event", - G_CALLBACK(_manage_editor_group_icon_changed), gr); + dt_gui_connect_click_all(eb, _manage_editor_group_icon_changed, NULL, gr); gtk_container_add(GTK_CONTAINER(eb), hb); gtk_box_pack_start(GTK_BOX(vb), eb, FALSE, TRUE, 0); @@ -3330,8 +3349,7 @@ static void _manage_editor_group_icon_popup(GtkWidget *btn, gtk_box_pack_start(GTK_BOX(hb), ic, FALSE, TRUE, 0); gtk_box_pack_start(GTK_BOX(hb), gtk_label_new(_("effect icon")), TRUE, TRUE, 0); g_object_set_data(G_OBJECT(eb), "ic_name", "effect"); - g_signal_connect(G_OBJECT(eb), "button-press-event", - G_CALLBACK(_manage_editor_group_icon_changed), gr); + dt_gui_connect_click_all(eb, _manage_editor_group_icon_changed, NULL, gr); gtk_container_add(GTK_CONTAINER(eb), hb); gtk_box_pack_start(GTK_BOX(vb), eb, FALSE, TRUE, 0); @@ -3341,8 +3359,7 @@ static void _manage_editor_group_icon_popup(GtkWidget *btn, gtk_box_pack_start(GTK_BOX(hb), ic, FALSE, TRUE, 0); gtk_box_pack_start(GTK_BOX(hb), gtk_label_new(_("favorites icon")), TRUE, TRUE, 0); g_object_set_data(G_OBJECT(eb), "ic_name", "favorites"); - g_signal_connect(G_OBJECT(eb), "button-press-event", - G_CALLBACK(_manage_editor_group_icon_changed), gr); + dt_gui_connect_click_all(eb, _manage_editor_group_icon_changed, NULL, gr); gtk_container_add(GTK_CONTAINER(eb), hb); gtk_box_pack_start(GTK_BOX(vb), eb, FALSE, TRUE, 0); @@ -3352,8 +3369,7 @@ static void _manage_editor_group_icon_popup(GtkWidget *btn, gtk_box_pack_start(GTK_BOX(hb), ic, FALSE, TRUE, 0); gtk_box_pack_start(GTK_BOX(hb), gtk_label_new(_("tone icon")), TRUE, TRUE, 0); g_object_set_data(G_OBJECT(eb), "ic_name", "tone"); - g_signal_connect(G_OBJECT(eb), "button-press-event", - G_CALLBACK(_manage_editor_group_icon_changed), gr); + dt_gui_connect_click_all(eb, _manage_editor_group_icon_changed, NULL, gr); gtk_container_add(GTK_CONTAINER(eb), hb); gtk_box_pack_start(GTK_BOX(vb), eb, FALSE, TRUE, 0); @@ -3363,8 +3379,7 @@ static void _manage_editor_group_icon_popup(GtkWidget *btn, gtk_box_pack_start(GTK_BOX(hb), ic, FALSE, TRUE, 0); gtk_box_pack_start(GTK_BOX(hb), gtk_label_new(_("grading icon")), TRUE, TRUE, 0); g_object_set_data(G_OBJECT(eb), "ic_name", "grading"); - g_signal_connect(G_OBJECT(eb), "button-press-event", - G_CALLBACK(_manage_editor_group_icon_changed), gr); + dt_gui_connect_click_all(eb, _manage_editor_group_icon_changed, NULL, gr); gtk_container_add(GTK_CONTAINER(eb), hb); gtk_box_pack_start(GTK_BOX(vb), eb, FALSE, TRUE, 0); @@ -3374,8 +3389,7 @@ static void _manage_editor_group_icon_popup(GtkWidget *btn, gtk_box_pack_start(GTK_BOX(hb), ic, FALSE, TRUE, 0); gtk_box_pack_start(GTK_BOX(hb), gtk_label_new(_("technical icon")), TRUE, TRUE, 0); g_object_set_data(G_OBJECT(eb), "ic_name", "technical"); - g_signal_connect(G_OBJECT(eb), "button-press-event", - G_CALLBACK(_manage_editor_group_icon_changed), gr); + dt_gui_connect_click_all(eb, _manage_editor_group_icon_changed, NULL, gr); gtk_container_add(GTK_CONTAINER(eb), hb); gtk_box_pack_start(GTK_BOX(vb), eb, FALSE, TRUE, 0); From 144517da1346898cc1d21733e4930a742e98d0bc Mon Sep 17 00:00:00 2001 From: Arecsu Date: Sun, 26 Jul 2026 22:49:07 -0300 Subject: [PATCH 02/95] gtk4-prep: basecurve event controllers --- src/iop/basecurve.c | 110 +++++++++++++++++++++----------------------- 1 file changed, 52 insertions(+), 58 deletions(-) diff --git a/src/iop/basecurve.c b/src/iop/basecurve.c index c1ed5ffaad0..e64f8968c19 100644 --- a/src/iop/basecurve.c +++ b/src/iop/basecurve.c @@ -1530,15 +1530,13 @@ void cleanup_global(dt_iop_module_so_t *self) self->data = NULL; } -static gboolean dt_iop_basecurve_leave_notify(GtkWidget *widget, - GdkEventCrossing *event, - dt_iop_module_t *self) +static void dt_iop_basecurve_leave_notify(GtkEventControllerMotion *controller, + dt_iop_module_t *self) { dt_iop_basecurve_gui_data_t *g = self->gui_data; - if(!(dt_gdk_event_get_state(event) & GDK_BUTTON1_MASK)) + if(!(dt_key_modifier_state() & GDK_BUTTON1_MASK)) g->selected = -1; - gtk_widget_queue_draw(widget); - return FALSE; + gtk_widget_queue_draw(gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller))); } static float to_log(const float x, const float base) @@ -1775,10 +1773,12 @@ static gboolean _move_point_internal(dt_iop_module_t *self, float dy, const guint state); -static gboolean dt_iop_basecurve_motion_notify(GtkWidget *widget, - GdkEventMotion *event, - dt_iop_module_t *self) +static void dt_iop_basecurve_motion_notify(GtkEventControllerMotion *controller, + gdouble x, + gdouble y, + dt_iop_module_t *self) { + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); dt_iop_basecurve_gui_data_t *g = self->gui_data; dt_iop_basecurve_params_t *p = self->params; int ch = 0; @@ -1791,14 +1791,14 @@ static gboolean dt_iop_basecurve_motion_notify(GtkWidget *widget, int height = allocation.height - 2 * inset, width = allocation.width - 2 * inset; const double old_m_x = g->mouse_x; const double old_m_y = g->mouse_y; - g->mouse_x = dt_gdk_event_get_x(event) - inset; - g->mouse_y = dt_gdk_event_get_y(event) - inset; + g->mouse_x = x - inset; + g->mouse_y = y - inset; const float mx = CLAMP(g->mouse_x, 0, width) / (float)width; const float my = 1.0f - CLAMP(g->mouse_y, 0, height) / (float)height; const float linx = to_lin(mx, g->loglogscale), liny = to_lin(my, g->loglogscale); - if(dt_gdk_event_get_state(event) & GDK_BUTTON1_MASK) + if(dt_key_modifier_state() & GDK_BUTTON1_MASK) { // got a vertex selected: if(g->selected >= 0) @@ -1812,7 +1812,7 @@ static gboolean dt_iop_basecurve_motion_notify(GtkWidget *widget, const float dy = to_lin(1 - g->mouse_y / height - translate_mouse_y, g->loglogscale) - to_lin(1 - old_m_y / height - translate_mouse_y, g->loglogscale); - return _move_point_internal(self, widget, dx, dy, dt_gdk_event_get_state(event)); + _move_point_internal(self, widget, dx, dy, dt_key_modifier_state()); } else if(nodes < MAXNODES && g->selected >= -1) { @@ -1842,13 +1842,15 @@ static gboolean dt_iop_basecurve_motion_notify(GtkWidget *widget, } if(g->selected >= 0) gtk_widget_grab_focus(widget); gtk_widget_queue_draw(widget); - return TRUE; } -static gboolean dt_iop_basecurve_button_press(GtkWidget *widget, - GdkEventButton *event, - dt_iop_module_t *self) +static void dt_iop_basecurve_button_press(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, + dt_iop_module_t *self) { + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); dt_iop_basecurve_params_t *p = self->params; const dt_iop_basecurve_params_t *const d = self->default_params; dt_iop_basecurve_gui_data_t *g = self->gui_data; @@ -1857,9 +1859,9 @@ static gboolean dt_iop_basecurve_button_press(GtkWidget *widget, int nodes = p->basecurve_nodes[ch]; dt_iop_basecurve_node_t *basecurve = p->basecurve[ch]; - if(dt_gdk_event_get_button(event) == GDK_BUTTON_PRIMARY) + if(gtk_gesture_single_get_current_button(gesture) == GDK_BUTTON_PRIMARY) { - if(dt_gdk_event_get_type(event) == GDK_BUTTON_PRESS && dt_modifier_is(dt_gdk_event_get_state(event), GDK_CONTROL_MASK) + if(dt_modifier_is(dt_key_modifier_state(), GDK_CONTROL_MASK) && nodes < MAXNODES && g->selected == -1) { // if we are not on a node -> add a new node at the current x of the pointer and y of the curve at that x @@ -1867,8 +1869,8 @@ static gboolean dt_iop_basecurve_button_press(GtkWidget *widget, GtkAllocation allocation; gtk_widget_get_allocation(widget, &allocation); int width = allocation.width - 2 * inset; - g->mouse_x = dt_gdk_event_get_x(event) - inset; - g->mouse_y = dt_gdk_event_get_y(event) - inset; + g->mouse_x = x - inset; + g->mouse_y = y - inset; const float mx = CLAMP(g->mouse_x, 0, width) / (float)width; const float linx = to_lin(mx, g->loglogscale); @@ -1895,12 +1897,12 @@ static gboolean dt_iop_basecurve_button_press(GtkWidget *widget, (selected < nodes && basecurve[selected].x - linx <= 0.025))) { // evaluate the curve at the current x position - const float y = dt_draw_curve_calc_value(g->minmax_curve, linx); + const float curve_y = dt_draw_curve_calc_value(g->minmax_curve, linx); - if(y >= 0.0 && y <= 1.0) // never add something outside the viewport, you couldn't change it afterwards + if(curve_y >= 0.0 && curve_y <= 1.0) // never add something outside the viewport, you couldn't change it afterwards { // create a new node - selected = _add_node(basecurve, &p->basecurve_nodes[ch], linx, y); + selected = _add_node(basecurve, &p->basecurve_nodes[ch], linx, curve_y); // maybe set the new one as being selected float min = .04f; @@ -1908,7 +1910,7 @@ static gboolean dt_iop_basecurve_button_press(GtkWidget *widget, for(int k = 0; k < nodes; k++) { float other_y = to_log(basecurve[k].y, g->loglogscale); - float dist = (y - other_y) * (y - other_y); + float dist = (curve_y - other_y) * (curve_y - other_y); if(dist < min) g->selected = selected; } @@ -1916,9 +1918,8 @@ static gboolean dt_iop_basecurve_button_press(GtkWidget *widget, gtk_widget_queue_draw(GTK_WIDGET(g->area)); } } - return TRUE; } - else if(dt_gdk_event_get_type(event) == GDK_2BUTTON_PRESS) + else if(n_press >= 2) { // reset current curve p->basecurve_nodes[ch] = d->basecurve_nodes[ch]; @@ -1931,10 +1932,9 @@ static gboolean dt_iop_basecurve_button_press(GtkWidget *widget, g->selected = -2; // avoid motion notify re-inserting immediately. dt_dev_add_history_item_target(darktable.develop, self, TRUE, widget); gtk_widget_queue_draw(GTK_WIDGET(g->area)); - return TRUE; } } - else if(dt_gdk_event_get_button(event) == GDK_BUTTON_SECONDARY && g->selected >= 0) + else if(gtk_gesture_single_get_current_button(gesture) == GDK_BUTTON_SECONDARY && g->selected >= 0) { if(g->selected == 0 || g->selected == nodes - 1) { @@ -1942,7 +1942,6 @@ static gboolean dt_iop_basecurve_button_press(GtkWidget *widget, basecurve[g->selected].y = basecurve[g->selected].x = reset_value; gtk_widget_queue_draw(GTK_WIDGET(g->area)); dt_dev_add_history_item_target(darktable.develop, self, TRUE, widget); - return TRUE; } for(int k = g->selected; k < nodes - 1; k++) @@ -1955,9 +1954,7 @@ static gboolean dt_iop_basecurve_button_press(GtkWidget *widget, p->basecurve_nodes[ch]--; gtk_widget_queue_draw(GTK_WIDGET(g->area)); dt_dev_add_history_item_target(darktable.develop, self, TRUE, widget); - return TRUE; } - return FALSE; } static gboolean _move_point_internal(dt_iop_module_t *self, @@ -1988,50 +1985,49 @@ static gboolean _move_point_internal(dt_iop_module_t *self, #define BASECURVE_DEFAULT_STEP (0.001f) -static gboolean _scrolled(GtkWidget *widget, GdkEventScroll *event, dt_iop_module_t *self) +static void _scrolled(GtkEventControllerScroll *controller, gdouble dx, gdouble dy, dt_iop_module_t *self) { dt_iop_basecurve_gui_data_t *g = self->gui_data; + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); - if(dt_gui_ignore_scroll(event)) return FALSE; - - if(g->selected < 0) return TRUE; + if(g->selected < 0) return; - gdouble delta_y; - if(dt_gui_get_scroll_delta(event, &delta_y)) + if(dy != 0.0) { - delta_y *= -BASECURVE_DEFAULT_STEP; - return _move_point_internal(self, widget, 0.0, delta_y, dt_gdk_event_get_state(event)); + dy *= -BASECURVE_DEFAULT_STEP; + _move_point_internal(self, widget, 0.0, dy, dt_key_modifier_state()); } - - return TRUE; } -static gboolean dt_iop_basecurve_key_press(GtkWidget *widget, - GdkEventKey *event, - dt_iop_module_t *self) +static gboolean dt_iop_basecurve_key_press(GtkEventControllerKey *controller, + guint keyval, + guint keycode, + GdkModifierType state, + dt_iop_module_t *self) { + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); dt_iop_basecurve_gui_data_t *g = self->gui_data; if(g->selected < 0) return TRUE; int handled = 0; float dx = 0.0f, dy = 0.0f; - if(dt_gdk_event_get_keyval(event) == GDK_KEY_Up || dt_gdk_event_get_keyval(event) == GDK_KEY_KP_Up) + if(keyval == GDK_KEY_Up || keyval == GDK_KEY_KP_Up) { handled = 1; dy = BASECURVE_DEFAULT_STEP; } - else if(dt_gdk_event_get_keyval(event) == GDK_KEY_Down || dt_gdk_event_get_keyval(event) == GDK_KEY_KP_Down) + else if(keyval == GDK_KEY_Down || keyval == GDK_KEY_KP_Down) { handled = 1; dy = -BASECURVE_DEFAULT_STEP; } - else if(dt_gdk_event_get_keyval(event) == GDK_KEY_Right || dt_gdk_event_get_keyval(event) == GDK_KEY_KP_Right) + else if(keyval == GDK_KEY_Right || keyval == GDK_KEY_KP_Right) { handled = 1; dx = BASECURVE_DEFAULT_STEP; } - else if(dt_gdk_event_get_keyval(event) == GDK_KEY_Left || dt_gdk_event_get_keyval(event) == GDK_KEY_KP_Left) + else if(keyval == GDK_KEY_Left || keyval == GDK_KEY_KP_Left) { handled = 1; dx = -BASECURVE_DEFAULT_STEP; @@ -2039,7 +2035,7 @@ static gboolean dt_iop_basecurve_key_press(GtkWidget *widget, if(!handled) return FALSE; - return _move_point_internal(self, widget, dx, dy, dt_gdk_event_get_state(event)); + return _move_point_internal(self, widget, dx, dy, state); } #undef BASECURVE_DEFAULT_STEP @@ -2124,16 +2120,14 @@ void gui_init(dt_iop_module_t *self) g_signal_connect(G_OBJECT(g->logbase), "value-changed", G_CALLBACK(logbase_callback), self); dt_gui_box_add(self->widget, g->logbase); - gtk_widget_add_events(GTK_WIDGET(g->area), GDK_POINTER_MOTION_MASK | darktable.gui->scroll_mask - | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK); gtk_widget_set_can_focus(GTK_WIDGET(g->area), TRUE); g_signal_connect(G_OBJECT(g->area), "draw", G_CALLBACK(dt_iop_basecurve_draw), self); - g_signal_connect(G_OBJECT(g->area), "button-press-event", G_CALLBACK(dt_iop_basecurve_button_press), self); - g_signal_connect(G_OBJECT(g->area), "motion-notify-event", G_CALLBACK(dt_iop_basecurve_motion_notify), self); - g_signal_connect(G_OBJECT(g->area), "leave-notify-event", G_CALLBACK(dt_iop_basecurve_leave_notify), self); - g_signal_connect(G_OBJECT(g->area), "scroll-event", G_CALLBACK(_scrolled), self); - g_signal_connect(G_OBJECT(g->area), "key-press-event", G_CALLBACK(dt_iop_basecurve_key_press), self); + dt_gui_connect_click(g->area, dt_iop_basecurve_button_press, NULL, self); + dt_gui_connect_motion(g->area, dt_iop_basecurve_motion_notify, NULL, dt_iop_basecurve_leave_notify, self); + dt_gui_connect_scroll(g->area, GTK_EVENT_CONTROLLER_SCROLL_BOTH_AXES + | GTK_EVENT_CONTROLLER_SCROLL_DISCRETE, + _scrolled, self); + dt_gui_connect_key(g->area, dt_iop_basecurve_key_press, self); } void gui_cleanup(dt_iop_module_t *self) From d22b1c397d89b959239f9da06eb13da2ac84ab53 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Sun, 26 Jul 2026 22:56:12 -0300 Subject: [PATCH 03/95] gtk4-prep: colorcorrection event controllers --- src/iop/colorcorrection.c | 100 ++++++++++++++++++++------------------ 1 file changed, 52 insertions(+), 48 deletions(-) diff --git a/src/iop/colorcorrection.c b/src/iop/colorcorrection.c index 93c19dd2337..d8058967d25 100644 --- a/src/iop/colorcorrection.c +++ b/src/iop/colorcorrection.c @@ -220,16 +220,26 @@ void gui_update(dt_iop_module_t *self) static gboolean dt_iop_colorcorrection_draw(GtkWidget *widget, cairo_t *cr, dt_iop_module_t *self); -static gboolean dt_iop_colorcorrection_motion_notify(GtkWidget *widget, GdkEventMotion *event, - dt_iop_module_t *self); -static gboolean dt_iop_colorcorrection_button_press(GtkWidget *widget, GdkEventButton *event, - dt_iop_module_t *self); -static gboolean dt_iop_colorcorrection_leave_notify(GtkWidget *widget, GdkEventCrossing *event, - dt_iop_module_t *self); -static gboolean dt_iop_colorcorrection_scrolled(GtkWidget *widget, GdkEventScroll *event, - dt_iop_module_t *self); -static gboolean dt_iop_colorcorrection_key_press(GtkWidget *widget, GdkEventKey *event, +static void dt_iop_colorcorrection_motion_notify(GtkEventControllerMotion *controller, + gdouble x, + gdouble y, + dt_iop_module_t *self); +static void dt_iop_colorcorrection_button_press(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, dt_iop_module_t *self); +static void dt_iop_colorcorrection_leave_notify(GtkEventControllerMotion *controller, + dt_iop_module_t *self); +static void dt_iop_colorcorrection_scrolled(GtkEventControllerScroll *controller, + gdouble dx, + gdouble dy, + dt_iop_module_t *self); +static gboolean dt_iop_colorcorrection_key_press(GtkEventControllerKey *controller, + guint keyval, + guint keycode, + GdkModifierType state, + dt_iop_module_t *self); void gui_init(dt_iop_module_t *self) { @@ -243,19 +253,14 @@ void gui_init(dt_iop_module_t *self) gtk_widget_set_tooltip_text(GTK_WIDGET(g->area), _("drag the line for split-toning. " "bright means highlights, dark means shadows. " "use mouse wheel to change saturation.")); - gtk_widget_add_events(GTK_WIDGET(g->area), GDK_POINTER_MOTION_MASK | darktable.gui->scroll_mask - | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK); gtk_widget_set_can_focus(GTK_WIDGET(g->area), TRUE); g_signal_connect(G_OBJECT(g->area), "draw", G_CALLBACK(dt_iop_colorcorrection_draw), self); - g_signal_connect(G_OBJECT(g->area), "button-press-event", G_CALLBACK(dt_iop_colorcorrection_button_press), - self); - g_signal_connect(G_OBJECT(g->area), "motion-notify-event", G_CALLBACK(dt_iop_colorcorrection_motion_notify), - self); - g_signal_connect(G_OBJECT(g->area), "leave-notify-event", G_CALLBACK(dt_iop_colorcorrection_leave_notify), - self); - g_signal_connect(G_OBJECT(g->area), "scroll-event", G_CALLBACK(dt_iop_colorcorrection_scrolled), self); - g_signal_connect(G_OBJECT(g->area), "key-press-event", G_CALLBACK(dt_iop_colorcorrection_key_press), self); + dt_gui_connect_click(g->area, dt_iop_colorcorrection_button_press, NULL, self); + dt_gui_connect_motion(g->area, dt_iop_colorcorrection_motion_notify, NULL, dt_iop_colorcorrection_leave_notify, self); + dt_gui_connect_scroll(g->area, GTK_EVENT_CONTROLLER_SCROLL_BOTH_AXES + | GTK_EVENT_CONTROLLER_SCROLL_DISCRETE, + dt_iop_colorcorrection_scrolled, self); + dt_gui_connect_key(g->area, dt_iop_colorcorrection_key_press, self); self->widget = dt_gui_vbox(g->area); g->slider = dt_bauhaus_slider_from_params(self, N_("saturation")); @@ -347,20 +352,23 @@ static gboolean dt_iop_colorcorrection_draw(GtkWidget *widget, cairo_t *crf, dt_ return TRUE; } -static gboolean dt_iop_colorcorrection_motion_notify(GtkWidget *widget, GdkEventMotion *event, - dt_iop_module_t *self) +static void dt_iop_colorcorrection_motion_notify(GtkEventControllerMotion *controller, + gdouble x, + gdouble y, + dt_iop_module_t *self) { + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); dt_iop_colorcorrection_gui_data_t *g = self->gui_data; dt_iop_colorcorrection_params_t *p = self->params; const int inset = DT_COLORCORRECTION_INSET; GtkAllocation allocation; gtk_widget_get_allocation(widget, &allocation); int width = allocation.width - 2 * inset, height = allocation.height - 2 * inset; - const float mouse_x = CLAMP(dt_gdk_event_get_x(event) - inset, 0, width); - const float mouse_y = CLAMP(height - 1 - dt_gdk_event_get_y(event) + inset, 0, height); + const float mouse_x = CLAMP(x - inset, 0, width); + const float mouse_y = CLAMP(height - 1 - y + inset, 0, height); const float ma = (2.0 * mouse_x - width) * DT_COLORCORRECTION_MAX / (float)width; const float mb = (2.0 * mouse_y - height) * DT_COLORCORRECTION_MAX / (float)height; - if(dt_gdk_event_get_state(event) & GDK_BUTTON1_MASK) + if(dt_key_modifier_state() & GDK_BUTTON1_MASK) { if(g->selected == 1) { @@ -388,13 +396,15 @@ static gboolean dt_iop_colorcorrection_motion_notify(GtkWidget *widget, GdkEvent } if(g->selected > 0) gtk_widget_grab_focus(widget); gtk_widget_queue_draw(GTK_WIDGET(g->area)); - return TRUE; } -static gboolean dt_iop_colorcorrection_button_press(GtkWidget *widget, GdkEventButton *event, - dt_iop_module_t *self) +static void dt_iop_colorcorrection_button_press(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, + dt_iop_module_t *self) { - if(dt_gdk_event_get_button(event) == GDK_BUTTON_PRIMARY && dt_gdk_event_get_type(event) == GDK_2BUTTON_PRESS) + if(gtk_gesture_single_get_current_button(gesture) == GDK_BUTTON_PRIMARY && n_press >= 2) { // double click resets: dt_iop_colorcorrection_gui_data_t *g = self->gui_data; @@ -416,63 +426,57 @@ static gboolean dt_iop_colorcorrection_button_press(GtkWidget *widget, GdkEventB dt_dev_add_history_item(darktable.develop, self, TRUE); } } - return TRUE; } - return FALSE; } -static gboolean dt_iop_colorcorrection_leave_notify(GtkWidget *widget, GdkEventCrossing *event, - dt_iop_module_t *self) +static void dt_iop_colorcorrection_leave_notify(GtkEventControllerMotion *controller, + dt_iop_module_t *self) { dt_iop_colorcorrection_gui_data_t *g = self->gui_data; gtk_widget_queue_draw(GTK_WIDGET(g->area)); - return TRUE; } -static gboolean dt_iop_colorcorrection_scrolled(GtkWidget *widget, GdkEventScroll *event, dt_iop_module_t *self) +static void dt_iop_colorcorrection_scrolled(GtkEventControllerScroll *controller, gdouble dx, gdouble dy, dt_iop_module_t *self) { + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); dt_iop_colorcorrection_gui_data_t *g = self->gui_data; dt_iop_colorcorrection_params_t *p = self->params; - if(dt_gui_ignore_scroll(event)) return FALSE; - - int delta_y; - if(dt_gui_get_scroll_unit_delta(event, &delta_y)) + if(dy != 0.0) { - p->saturation = CLAMP(p->saturation - 0.1 * delta_y, -3.0, 3.0); + p->saturation = CLAMP(p->saturation - 0.1 * dy, -3.0, 3.0); dt_bauhaus_slider_set(g->slider, p->saturation); gtk_widget_queue_draw(widget); } - - return TRUE; } #define COLORCORRECTION_DEFAULT_STEP (0.5f) -static gboolean dt_iop_colorcorrection_key_press(GtkWidget *widget, GdkEventKey *event, dt_iop_module_t *self) +static gboolean dt_iop_colorcorrection_key_press(GtkEventControllerKey *controller, guint keyval, guint keycode, GdkModifierType state, dt_iop_module_t *self) { + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); dt_iop_colorcorrection_gui_data_t *g = self->gui_data; dt_iop_colorcorrection_params_t *p = self->params; if(g->selected < 1) return FALSE; int handled = 0; float dx = 0.0f, dy = 0.0f; - if(dt_gdk_event_get_keyval(event) == GDK_KEY_Up || dt_gdk_event_get_keyval(event) == GDK_KEY_KP_Up) + if(keyval == GDK_KEY_Up || keyval == GDK_KEY_KP_Up) { handled = 1; dy = COLORCORRECTION_DEFAULT_STEP; } - else if(dt_gdk_event_get_keyval(event) == GDK_KEY_Down || dt_gdk_event_get_keyval(event) == GDK_KEY_KP_Down) + else if(keyval == GDK_KEY_Down || keyval == GDK_KEY_KP_Down) { handled = 1; dy = -COLORCORRECTION_DEFAULT_STEP; } - else if(dt_gdk_event_get_keyval(event) == GDK_KEY_Right || dt_gdk_event_get_keyval(event) == GDK_KEY_KP_Right) + else if(keyval == GDK_KEY_Right || keyval == GDK_KEY_KP_Right) { handled = 1; dx = COLORCORRECTION_DEFAULT_STEP; } - else if(dt_gdk_event_get_keyval(event) == GDK_KEY_Left || dt_gdk_event_get_keyval(event) == GDK_KEY_KP_Left) + else if(keyval == GDK_KEY_Left || keyval == GDK_KEY_KP_Left) { handled = 1; dx = -COLORCORRECTION_DEFAULT_STEP; @@ -480,7 +484,7 @@ static gboolean dt_iop_colorcorrection_key_press(GtkWidget *widget, GdkEventKey if(!handled) return FALSE; - float multiplier = dt_accel_get_speed_multiplier(widget, dt_gdk_event_get_state(event)); + float multiplier = dt_accel_get_speed_multiplier(widget, state); dx *= multiplier; dy *= multiplier; From 36b71d89f961d6f9d348176bcc8c58c71d08e415 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Sun, 26 Jul 2026 23:02:33 -0300 Subject: [PATCH 04/95] gtk4-prep: rgbcurve event controllers --- src/iop/rgbcurve.c | 140 ++++++++++++++++++++------------------------- 1 file changed, 61 insertions(+), 79 deletions(-) diff --git a/src/iop/rgbcurve.c b/src/iop/rgbcurve.c index 149ae6c059d..3eab46584f6 100644 --- a/src/iop/rgbcurve.c +++ b/src/iop/rgbcurve.c @@ -643,20 +643,18 @@ static gboolean _move_point_internal(dt_iop_module_t *self, #define RGBCURVE_DEFAULT_STEP (0.001f) -static gboolean _area_scrolled_callback(GtkWidget *widget, - GdkEventScroll *event, - dt_iop_module_t *self) +static void _area_scrolled_callback(GtkEventControllerScroll *controller, + gdouble dx, + gdouble dy, + dt_iop_module_t *self) { + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); dt_iop_rgbcurve_params_t *p = self->params; dt_iop_rgbcurve_gui_data_t *g = self->gui_data; - gdouble delta_y; - - if(dt_gui_ignore_scroll(event)) return FALSE; - if(darktable.develop->darkroom_skip_mouse_events) { - if(dt_gui_get_scroll_deltas(event, NULL, &delta_y)) + if(dy != 0.0) { GtkAllocation allocation; gtk_widget_get_allocation(widget, &allocation); @@ -666,7 +664,7 @@ static gboolean _area_scrolled_callback(GtkWidget *widget, const float linx = _mouse_to_curve(mx, g->zoom_factor, g->offset_x), liny = _mouse_to_curve(my, g->zoom_factor, g->offset_y); - g->zoom_factor *= 1.0 - 0.1 * delta_y; + g->zoom_factor *= 1.0 - 0.1 * dy; if(g->zoom_factor < 1.f) g->zoom_factor = 1.f; g->offset_x = linx - (mx / g->zoom_factor); @@ -677,32 +675,30 @@ static gboolean _area_scrolled_callback(GtkWidget *widget, gtk_widget_queue_draw(GTK_WIDGET(g->area)); } - - return TRUE; } // if autoscale is on: do not modify g and b curves if((p->curve_autoscale != DT_S_SCALE_MANUAL_RGB) && g->channel != DT_IOP_RGBCURVE_R) - return TRUE; - if(g->selected < 0) return TRUE; + if(g->selected < 0) return; dt_iop_color_picker_reset(self, TRUE); - if(dt_gui_get_scroll_delta(event, &delta_y)) + if(dy != 0.0) { - delta_y *= -RGBCURVE_DEFAULT_STEP; - return _move_point_internal(self, widget, 0.0, delta_y, dt_gdk_event_get_state(event)); + dy *= -RGBCURVE_DEFAULT_STEP; + _move_point_internal(self, widget, 0.0, dy, dt_key_modifier_state()); } - - return TRUE; } -static gboolean _area_key_press_callback(GtkWidget *widget, - GdkEventKey *event, - dt_iop_module_t *self) +static gboolean _area_key_press_callback(GtkEventControllerKey *controller, + guint keyval, + guint keycode, + GdkModifierType state, + dt_iop_module_t *self) { + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); dt_iop_rgbcurve_params_t *p = self->params; dt_iop_rgbcurve_gui_data_t *g = self->gui_data; @@ -717,22 +713,22 @@ static gboolean _area_key_press_callback(GtkWidget *widget, int handled = 0; float dx = 0.0f, dy = 0.0f; - if(dt_gdk_event_get_keyval(event) == GDK_KEY_Up || dt_gdk_event_get_keyval(event) == GDK_KEY_KP_Up) + if(keyval == GDK_KEY_Up || keyval == GDK_KEY_KP_Up) { handled = 1; dy = RGBCURVE_DEFAULT_STEP; } - else if(dt_gdk_event_get_keyval(event) == GDK_KEY_Down || dt_gdk_event_get_keyval(event) == GDK_KEY_KP_Down) + else if(keyval == GDK_KEY_Down || keyval == GDK_KEY_KP_Down) { handled = 1; dy = -RGBCURVE_DEFAULT_STEP; } - else if(dt_gdk_event_get_keyval(event) == GDK_KEY_Right || dt_gdk_event_get_keyval(event) == GDK_KEY_KP_Right) + else if(keyval == GDK_KEY_Right || keyval == GDK_KEY_KP_Right) { handled = 1; dx = RGBCURVE_DEFAULT_STEP; } - else if(dt_gdk_event_get_keyval(event) == GDK_KEY_Left || dt_gdk_event_get_keyval(event) == GDK_KEY_KP_Left) + else if(keyval == GDK_KEY_Left || keyval == GDK_KEY_KP_Left) { handled = 1; dx = -RGBCURVE_DEFAULT_STEP; @@ -741,21 +737,19 @@ static gboolean _area_key_press_callback(GtkWidget *widget, if(!handled) return FALSE; dt_iop_color_picker_reset(self, TRUE); - return _move_point_internal(self, widget, dx, dy, dt_gdk_event_get_state(event)); + return _move_point_internal(self, widget, dx, dy, state); } #undef RGBCURVE_DEFAULT_STEP -static gboolean _area_leave_notify_callback(GtkWidget *widget, - GdkEventCrossing *event, - dt_iop_module_t *self) +static void _area_leave_notify_callback(GtkEventControllerMotion *controller, + dt_iop_module_t *self) { dt_iop_rgbcurve_gui_data_t *g = self->gui_data; - if(!(dt_gdk_event_get_state(event) & GDK_BUTTON1_MASK)) + if(!(dt_key_modifier_state() & GDK_BUTTON1_MASK)) g->selected = -1; - gtk_widget_queue_draw(widget); - return FALSE; + gtk_widget_queue_draw(gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller))); } static gboolean _area_draw_callback(GtkWidget *widget, @@ -1166,10 +1160,12 @@ static gboolean _area_draw_callback(GtkWidget *widget, return TRUE; } -static gboolean _area_motion_notify_callback(GtkWidget *widget, - GdkEventMotion *event, - dt_iop_module_t *self) +static void _area_motion_notify_callback(GtkEventControllerMotion *controller, + gdouble x, + gdouble y, + dt_iop_module_t *self) { + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); dt_iop_rgbcurve_gui_data_t *g = self->gui_data; dt_iop_rgbcurve_params_t *p = self->params; @@ -1186,10 +1182,10 @@ static gboolean _area_motion_notify_callback(GtkWidget *widget, const float mx = g->mouse_x; const float my = g->mouse_y; - g->mouse_x = CLAMP(dt_gdk_event_get_x(event) - inset, 0, width) / (float)width; - g->mouse_y = 1.0 - CLAMP(dt_gdk_event_get_y(event) - inset, 0, height) / (float)height; + g->mouse_x = CLAMP(x - inset, 0, width) / (float)width; + g->mouse_y = 1.0 - CLAMP(y - inset, 0, height) / (float)height; - if(dt_gdk_event_get_state(event) & GDK_BUTTON1_MASK) + if(dt_key_modifier_state() & GDK_BUTTON1_MASK) { g->offset_x += (mx - g->mouse_x) / g->zoom_factor; g->offset_y += (my - g->mouse_y) / g->zoom_factor; @@ -1199,7 +1195,6 @@ static gboolean _area_motion_notify_callback(GtkWidget *widget, gtk_widget_queue_draw(GTK_WIDGET(g->area)); } - return TRUE; } const int ch = g->channel; @@ -1218,15 +1213,15 @@ static gboolean _area_motion_notify_callback(GtkWidget *widget, const double old_m_x = g->mouse_x; const double old_m_y = g->mouse_y; - g->mouse_x = CLAMP(dt_gdk_event_get_x(event) - inset, 0, width) / (float)width; - g->mouse_y = 1.0 - CLAMP(dt_gdk_event_get_y(event) - inset, 0, height) / (float)height; + g->mouse_x = CLAMP(x - inset, 0, width) / (float)width; + g->mouse_y = 1.0 - CLAMP(y - inset, 0, height) / (float)height; const float mx = g->mouse_x; const float my = g->mouse_y; const float linx = _mouse_to_curve(mx, g->zoom_factor, g->offset_x), liny = _mouse_to_curve(my, g->zoom_factor, g->offset_y); - if(dt_gdk_event_get_state(event) & GDK_BUTTON1_MASK) + if(dt_key_modifier_state() & GDK_BUTTON1_MASK) { // got a vertex selected: if(g->selected >= 0) @@ -1250,7 +1245,7 @@ static gboolean _area_motion_notify_callback(GtkWidget *widget, g->zoom_factor, g->offset_y); dt_iop_color_picker_reset(self, TRUE); - return _move_point_internal(self, widget, dx, dy, dt_gdk_event_get_state(event)); + _move_point_internal(self, widget, dx, dy, dt_key_modifier_state()); } else if(nodes < DT_IOP_RGBCURVE_MAXNODES && g->selected >= -1) { @@ -1286,29 +1281,30 @@ static gboolean _area_motion_notify_callback(GtkWidget *widget, finally: if(g->selected >= 0) gtk_widget_grab_focus(widget); gtk_widget_queue_draw(widget); - return TRUE; } -static gboolean _area_button_press_callback(GtkWidget *widget, - GdkEventButton *event, - dt_iop_module_t *self) +static void _area_button_press_callback(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, + dt_iop_module_t *self) { + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); dt_iop_rgbcurve_params_t *p = self->params; const dt_iop_rgbcurve_params_t *const d = self->default_params; dt_iop_rgbcurve_gui_data_t *g = self->gui_data; if(darktable.develop->darkroom_skip_mouse_events) - return TRUE; + return; const int ch = g->channel; const int autoscale = p->curve_autoscale; const int nodes = p->curve_num_nodes[ch]; dt_iop_rgbcurve_node_t *curve_nodes = p->curve_nodes[ch]; - if(dt_gdk_event_get_button(event) == GDK_BUTTON_PRIMARY) + if(gtk_gesture_single_get_current_button(gesture) == GDK_BUTTON_PRIMARY) { - if(dt_gdk_event_get_type(event) == GDK_BUTTON_PRESS - && dt_modifier_is(dt_gdk_event_get_state(event), GDK_CONTROL_MASK) + if(dt_modifier_is(dt_key_modifier_state(), GDK_CONTROL_MASK) && nodes < DT_IOP_RGBCURVE_MAXNODES && g->selected == -1) { // if we are not on a node -> add a new node at the current x of @@ -1319,8 +1315,8 @@ static gboolean _area_button_press_callback(GtkWidget *widget, const int width = allocation.width - 2 * inset; const int height = allocation.height - 2 * inset; - g->mouse_x = CLAMP(dt_gdk_event_get_x(event) - inset, 0, width) / (float)width; - g->mouse_y = 1.0 - CLAMP(dt_gdk_event_get_y(event) - inset, 0, height) / (float)height; + g->mouse_x = CLAMP(x - inset, 0, width) / (float)width; + g->mouse_y = 1.0 - CLAMP(y - inset, 0, height) / (float)height; const float mx = g->mouse_x; const float linx = _mouse_to_curve(mx, g->zoom_factor, g->offset_x); @@ -1344,14 +1340,14 @@ static gboolean _area_button_press_callback(GtkWidget *widget, if(selected == -1) selected = nodes; // evaluate the curve at the current x position - const float y = dt_draw_curve_calc_value(g->minmax_curve[ch], linx); + const float curve_y = dt_draw_curve_calc_value(g->minmax_curve[ch], linx); - if(y >= 0.0f && y <= 1.0f) // never add something outside the + if(curve_y >= 0.0f && curve_y <= 1.0f) // never add something outside the // viewport, you couldn't change it // afterwards { // create a new node - selected = _add_node(curve_nodes, &p->curve_num_nodes[ch], linx, y); + selected = _add_node(curve_nodes, &p->curve_num_nodes[ch], linx, curve_y); // maybe set the new one as being selected const float min = .04f * .04f; // comparing against square @@ -1359,7 +1355,7 @@ static gboolean _area_button_press_callback(GtkWidget *widget, { const float other_y = _curve_to_mouse(curve_nodes[k].y, g->zoom_factor, g->offset_y); - const float dist = (y - other_y) * (y - other_y); + const float dist = (curve_y - other_y) * (curve_y - other_y); if(dist < min) g->selected = selected; } @@ -1367,10 +1363,8 @@ static gboolean _area_button_press_callback(GtkWidget *widget, dt_dev_add_history_item_target(darktable.develop, self, TRUE, widget + ch); gtk_widget_queue_draw(GTK_WIDGET(g->area)); } - - return TRUE; } - else if(dt_gdk_event_get_type(event) == GDK_2BUTTON_PRESS) + else if(n_press >= 2) { // reset current curve // if autoscale is on: allow only reset of L curve @@ -1401,10 +1395,9 @@ static gboolean _area_button_press_callback(GtkWidget *widget, gtk_widget_queue_draw(GTK_WIDGET(g->area)); } } - return TRUE; } } - else if(dt_gdk_event_get_button(event) == GDK_BUTTON_SECONDARY && g->selected >= 0) + else if(gtk_gesture_single_get_current_button(gesture) == GDK_BUTTON_SECONDARY && g->selected >= 0) { if(g->selected == 0 || g->selected == nodes - 1) { @@ -1413,7 +1406,6 @@ static gboolean _area_button_press_callback(GtkWidget *widget, dt_iop_color_picker_reset(self, TRUE); dt_dev_add_history_item_target(darktable.develop, self, TRUE, widget + ch); gtk_widget_queue_draw(GTK_WIDGET(g->area)); - return TRUE; } for(int k = g->selected; k < nodes - 1; k++) @@ -1427,9 +1419,7 @@ static gboolean _area_button_press_callback(GtkWidget *widget, dt_iop_color_picker_reset(self, TRUE); dt_dev_add_history_item_target(darktable.develop, self, TRUE, widget + ch); gtk_widget_queue_draw(GTK_WIDGET(g->area)); - return TRUE; } - return FALSE; } void gui_reset(dt_iop_module_t *self) @@ -1528,23 +1518,15 @@ void gui_init(dt_iop_module_t *self) // gtk_widget_set_tooltip_text(GTK_WIDGET(g->area), _("double click // to reset curve")); - gtk_widget_add_events(GTK_WIDGET(g->area), - GDK_POINTER_MOTION_MASK | darktable.gui->scroll_mask - | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK); gtk_widget_set_can_focus(GTK_WIDGET(g->area), TRUE); g_signal_connect(G_OBJECT(g->area), "draw", G_CALLBACK(_area_draw_callback), self); - g_signal_connect(G_OBJECT(g->area), "button-press-event", - G_CALLBACK(_area_button_press_callback), self); - g_signal_connect(G_OBJECT(g->area), "motion-notify-event", - G_CALLBACK(_area_motion_notify_callback), self); - g_signal_connect(G_OBJECT(g->area), "leave-notify-event", - G_CALLBACK(_area_leave_notify_callback), self); - g_signal_connect(G_OBJECT(g->area), "scroll-event", - G_CALLBACK(_area_scrolled_callback), self); - g_signal_connect(G_OBJECT(g->area), "key-press-event", - G_CALLBACK(_area_key_press_callback), self); + dt_gui_connect_click(g->area, _area_button_press_callback, NULL, self); + dt_gui_connect_motion(g->area, _area_motion_notify_callback, NULL, _area_leave_notify_callback, self); + dt_gui_connect_scroll(g->area, GTK_EVENT_CONTROLLER_SCROLL_BOTH_AXES + | GTK_EVENT_CONTROLLER_SCROLL_DISCRETE, + _area_scrolled_callback, self); + dt_gui_connect_key(g->area, _area_key_press_callback, self); g->interpolator = dt_bauhaus_combobox_new_interpolation(self); gtk_widget_set_tooltip_text(g->interpolator, From 311734915e4b57ee57ca3ce92ba3958f80e264ca Mon Sep 17 00:00:00 2001 From: Arecsu Date: Sun, 26 Jul 2026 23:20:19 -0300 Subject: [PATCH 05/95] gtk4-prep: tonecurve and lut3d event controllers --- src/iop/lut3d.c | 11 ++- src/iop/tonecurve.c | 166 +++++++++++++++++++++----------------------- 2 files changed, 89 insertions(+), 88 deletions(-) diff --git a/src/iop/lut3d.c b/src/iop/lut3d.c index e79efc56643..30fef567fb4 100644 --- a/src/iop/lut3d.c +++ b/src/iop/lut3d.c @@ -1473,15 +1473,18 @@ static void _lutname_callback(GtkTreeSelection *selection, dt_iop_module_t *self } } -static gboolean _mouse_scroll(GtkWidget *view, GdkEventScroll *event, dt_lib_module_t *self) +static void _mouse_scroll(GtkEventControllerScroll *controller, + gdouble dx, gdouble dy, + dt_lib_module_t *self) { + GtkWidget *view = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(view)); GtkTreeIter iter; GtkTreeModel *model = gtk_tree_view_get_model((GtkTreeView *)view); if(gtk_tree_selection_get_selected(selection, &model, &iter)) { gboolean next = FALSE; - if(dt_gdk_event_get_scroll_delta_y(event) > 0) + if(dy > 0) next = gtk_tree_model_iter_next(model, &iter); else next = gtk_tree_model_iter_previous(model, &iter); @@ -1748,7 +1751,9 @@ void gui_init(dt_iop_module_t *self) dt_gui_box_add(self->widget, g->lutwindow); g_signal_connect(G_OBJECT(g->lutentry), "changed", G_CALLBACK(_entry_callback), self); - g_signal_connect(G_OBJECT((GtkTreeView *)g->lutname), "scroll-event", G_CALLBACK(_mouse_scroll), (gpointer)self); + dt_gui_connect_scroll(g->lutname, GTK_EVENT_CONTROLLER_SCROLL_BOTH_AXES + | GTK_EVENT_CONTROLLER_SCROLL_DISCRETE, + _mouse_scroll, self); #endif // HAVE_GMIC g->colorspace = dt_bauhaus_combobox_from_params(self, "colorspace"); diff --git a/src/iop/tonecurve.c b/src/iop/tonecurve.c index 192a8b6fe1f..1e4fe8a1127 100644 --- a/src/iop/tonecurve.c +++ b/src/iop/tonecurve.c @@ -51,18 +51,22 @@ DT_MODULE_INTROSPECTION(5, dt_iop_tonecurve_params_t) static gboolean dt_iop_tonecurve_draw(GtkWidget *widget, cairo_t *crf, dt_iop_module_t *self); -static gboolean dt_iop_tonecurve_motion_notify(GtkWidget *widget, - GdkEventMotion *event, - dt_iop_module_t *self); -static gboolean dt_iop_tonecurve_button_press(GtkWidget *widget, - GdkEventButton *event, - dt_iop_module_t *self); -static gboolean dt_iop_tonecurve_leave_notify(GtkWidget *widget, - GdkEventCrossing *event, - dt_iop_module_t *self); -static gboolean dt_iop_tonecurve_key_press(GtkWidget *widget, - GdkEventKey *event, +static void dt_iop_tonecurve_motion_notify(GtkEventControllerMotion *controller, + gdouble x, + gdouble y, + dt_iop_module_t *self); +static void dt_iop_tonecurve_button_press(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, dt_iop_module_t *self); +static void dt_iop_tonecurve_leave_notify(GtkEventControllerMotion *controller, + dt_iop_module_t *self); +static gboolean dt_iop_tonecurve_key_press(GtkEventControllerKey *controller, + guint keyval, + guint keycode, + GdkModifierType state, + dt_iop_module_t *self); typedef enum tonecurve_channel_t @@ -1158,40 +1162,36 @@ static gboolean _move_point_internal(dt_iop_module_t *self, #define TONECURVE_DEFAULT_STEP (0.001f) -static gboolean _scrolled(GtkWidget *widget, - GdkEventScroll *event, +static void _scrolled(GtkEventControllerScroll *controller, + gdouble dx, + gdouble dy, dt_iop_module_t *self) { + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); dt_iop_tonecurve_params_t *p = self->params; dt_iop_tonecurve_gui_data_t *g = self->gui_data; - if(dt_gui_ignore_scroll(event)) - return FALSE; + if(dy == 0.0) return; const int ch = g->channel; const int autoscale_ab = p->tonecurve_autoscale_ab; // if autoscale_ab is on: do not modify a and b curves - if((autoscale_ab != DT_S_SCALE_MANUAL) && ch != ch_L) - return TRUE; + if((autoscale_ab != DT_S_SCALE_MANUAL) && ch != ch_L) return; - if(g->selected < 0) - return TRUE; - - gdouble delta_y; - if(dt_gui_get_scroll_delta(event, &delta_y)) - { - delta_y *= -TONECURVE_DEFAULT_STEP; - return _move_point_internal(self, widget, 0.0, delta_y, dt_gdk_event_get_state(event)); - } + if(g->selected < 0) return; - return TRUE; + dy *= -TONECURVE_DEFAULT_STEP; + _move_point_internal(self, widget, 0.0, dy, dt_key_modifier_state()); } -static gboolean dt_iop_tonecurve_key_press(GtkWidget *widget, - GdkEventKey *event, - dt_iop_module_t *self) +static gboolean dt_iop_tonecurve_key_press(GtkEventControllerKey *controller, + guint keyval, + guint keycode, + GdkModifierType state, + dt_iop_module_t *self) { + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); dt_iop_tonecurve_params_t *p = self->params; dt_iop_tonecurve_gui_data_t *g = self->gui_data; @@ -1207,22 +1207,22 @@ static gboolean dt_iop_tonecurve_key_press(GtkWidget *widget, int handled = 0; float dx = 0.0f, dy = 0.0f; - if(dt_gdk_event_get_keyval(event) == GDK_KEY_Up || dt_gdk_event_get_keyval(event) == GDK_KEY_KP_Up) + if(keyval == GDK_KEY_Up || keyval == GDK_KEY_KP_Up) { handled = 1; dy = TONECURVE_DEFAULT_STEP; } - else if(dt_gdk_event_get_keyval(event) == GDK_KEY_Down || dt_gdk_event_get_keyval(event) == GDK_KEY_KP_Down) + else if(keyval == GDK_KEY_Down || keyval == GDK_KEY_KP_Down) { handled = 1; dy = -TONECURVE_DEFAULT_STEP; } - else if(dt_gdk_event_get_keyval(event) == GDK_KEY_Right || dt_gdk_event_get_keyval(event) == GDK_KEY_KP_Right) + else if(keyval == GDK_KEY_Right || keyval == GDK_KEY_KP_Right) { handled = 1; dx = TONECURVE_DEFAULT_STEP; } - else if(dt_gdk_event_get_keyval(event) == GDK_KEY_Left || dt_gdk_event_get_keyval(event) == GDK_KEY_KP_Left) + else if(keyval == GDK_KEY_Left || keyval == GDK_KEY_KP_Left) { handled = 1; dx = -TONECURVE_DEFAULT_STEP; @@ -1230,7 +1230,7 @@ static gboolean dt_iop_tonecurve_key_press(GtkWidget *widget, if(!handled) return FALSE; - return _move_point_internal(self, widget, dx, dy, dt_gdk_event_get_state(event)); + return _move_point_internal(self, widget, dx, dy, dt_key_modifier_state()); } #undef TONECURVE_DEFAULT_STEP @@ -1291,21 +1291,14 @@ void gui_init(dt_iop_module_t *self) // FIXME: that tooltip goes in the way of the numbers when you hover a node to get a reading //gtk_widget_set_tooltip_text(GTK_WIDGET(g->area), _("double click to reset curve")); - gtk_widget_add_events(GTK_WIDGET(g->area), GDK_POINTER_MOTION_MASK | darktable.gui->scroll_mask - | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK); gtk_widget_set_can_focus(GTK_WIDGET(g->area), TRUE); g_signal_connect(G_OBJECT(g->area), "draw", G_CALLBACK(dt_iop_tonecurve_draw), self); - g_signal_connect(G_OBJECT(g->area), "button-press-event", - G_CALLBACK(dt_iop_tonecurve_button_press), self); - g_signal_connect(G_OBJECT(g->area), "motion-notify-event", - G_CALLBACK(dt_iop_tonecurve_motion_notify), self); - g_signal_connect(G_OBJECT(g->area), "leave-notify-event", - G_CALLBACK(dt_iop_tonecurve_leave_notify), self); - g_signal_connect(G_OBJECT(g->area), "scroll-event", - G_CALLBACK(_scrolled), self); - g_signal_connect(G_OBJECT(g->area), "key-press-event", - G_CALLBACK(dt_iop_tonecurve_key_press), self); + dt_gui_connect_click(g->area, dt_iop_tonecurve_button_press, NULL, self); + dt_gui_connect_motion(g->area, dt_iop_tonecurve_motion_notify, NULL, dt_iop_tonecurve_leave_notify, self); + dt_gui_connect_scroll(g->area, GTK_EVENT_CONTROLLER_SCROLL_BOTH_AXES + | GTK_EVENT_CONTROLLER_SCROLL_DISCRETE, + _scrolled, self); + dt_gui_connect_key(g->area, dt_iop_tonecurve_key_press, self); g->interpolator = dt_bauhaus_combobox_new_interpolation(self); gtk_widget_set_tooltip_text @@ -1344,15 +1337,13 @@ void gui_cleanup(dt_iop_module_t *self) dt_draw_curve_destroy(g->minmax_curve[ch_b]); } -static gboolean dt_iop_tonecurve_leave_notify(GtkWidget *widget, - GdkEventCrossing *event, - dt_iop_module_t *self) +static void dt_iop_tonecurve_leave_notify(GtkEventControllerMotion *controller, + dt_iop_module_t *self) { dt_iop_tonecurve_gui_data_t *g = self->gui_data; - if(!(dt_gdk_event_get_state(event) & GDK_BUTTON1_MASK)) + if(!(dt_key_modifier_state() & GDK_BUTTON1_MASK)) g->selected = -1; - gtk_widget_queue_draw(widget); - return FALSE; + gtk_widget_queue_draw(gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller))); } static void picker_scale(const float *in, float *out) @@ -1752,10 +1743,12 @@ static inline int _add_node(dt_iop_tonecurve_node_t *tonecurve, return selected; } -static gboolean dt_iop_tonecurve_motion_notify(GtkWidget *widget, - GdkEventMotion *event, - dt_iop_module_t *self) +static void dt_iop_tonecurve_motion_notify(GtkEventControllerMotion *controller, + gdouble x, + gdouble y, + dt_iop_module_t *self) { + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); dt_iop_tonecurve_gui_data_t *g = self->gui_data; dt_iop_tonecurve_params_t *p = self->params; @@ -1765,7 +1758,12 @@ static gboolean dt_iop_tonecurve_motion_notify(GtkWidget *widget, int autoscale_ab = p->tonecurve_autoscale_ab; // if autoscale_ab is on: do not modify a and b curves - if((autoscale_ab != DT_S_SCALE_MANUAL) && ch != ch_L) goto finally; + if((autoscale_ab != DT_S_SCALE_MANUAL) && ch != ch_L) + { + if(g->selected >= 0) gtk_widget_grab_focus(widget); + gtk_widget_queue_draw(widget); + return; + } const int inset = DT_GUI_CURVE_EDITOR_INSET; GtkAllocation allocation; @@ -1773,15 +1771,15 @@ static gboolean dt_iop_tonecurve_motion_notify(GtkWidget *widget, int height = allocation.height - 2 * inset, width = allocation.width - 2 * inset; double old_m_x = g->mouse_x; double old_m_y = g->mouse_y; - g->mouse_x = dt_gdk_event_get_x(event) - inset; - g->mouse_y = dt_gdk_event_get_y(event) - inset; + g->mouse_x = x - inset; + g->mouse_y = y - inset; const float mx = CLAMP(g->mouse_x, 0, width) / width; const float my = 1.0f - CLAMP(g->mouse_y, 0, height) / height; const float linx = to_lin(mx, g->loglogscale, ch, g->semilog, 0), liny = to_lin(my, g->loglogscale, ch, g->semilog, 1); - if(dt_gdk_event_get_state(event) & GDK_BUTTON1_MASK) + if(dt_key_modifier_state() & GDK_BUTTON1_MASK) { // got a vertex selected: if(g->selected >= 0) @@ -1795,7 +1793,7 @@ static gboolean dt_iop_tonecurve_motion_notify(GtkWidget *widget, - to_lin(old_m_x / width - translate_mouse_x, g->loglogscale, ch, g->semilog, 0); const float dy = to_lin(1 - g->mouse_y / height - translate_mouse_y, g->loglogscale, ch, g->semilog, 1) - to_lin(1 - old_m_y / height - translate_mouse_y, g->loglogscale, ch, g->semilog, 1); - return _move_point_internal(self, widget, dx, dy, dt_gdk_event_get_state(event)); + _move_point_internal(self, widget, dx, dy, dt_key_modifier_state()); } else if(nodes < DT_IOP_TONECURVE_MAXNODES && g->selected >= -1) { @@ -1823,16 +1821,17 @@ static gboolean dt_iop_tonecurve_motion_notify(GtkWidget *widget, } g->selected = nearest; } -finally: if(g->selected >= 0) gtk_widget_grab_focus(widget); gtk_widget_queue_draw(widget); - return TRUE; } -static gboolean dt_iop_tonecurve_button_press(GtkWidget *widget, - GdkEventButton *event, - dt_iop_module_t *self) +static void dt_iop_tonecurve_button_press(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, + dt_iop_module_t *self) { + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); dt_iop_tonecurve_params_t *p = self->params; const dt_iop_tonecurve_params_t *const d = self->default_params; dt_iop_tonecurve_gui_data_t *g = self->gui_data; @@ -1842,10 +1841,10 @@ static gboolean dt_iop_tonecurve_button_press(GtkWidget *widget, int nodes = p->tonecurve_nodes[ch]; dt_iop_tonecurve_node_t *tonecurve = p->tonecurve[ch]; - if(dt_gdk_event_get_button(event) == GDK_BUTTON_PRIMARY) + if(gtk_gesture_single_get_current_button(gesture) == GDK_BUTTON_PRIMARY) { - if(dt_gdk_event_get_type(event) == GDK_BUTTON_PRESS - && dt_modifier_is(dt_gdk_event_get_state(event), GDK_CONTROL_MASK) + if(n_press >= 1 + && dt_modifier_is(dt_key_modifier_state(), GDK_CONTROL_MASK) && nodes < DT_IOP_TONECURVE_MAXNODES && g->selected == -1) { @@ -1855,8 +1854,8 @@ static gboolean dt_iop_tonecurve_button_press(GtkWidget *widget, GtkAllocation allocation; gtk_widget_get_allocation(widget, &allocation); int width = allocation.width - 2 * inset; - g->mouse_x = dt_gdk_event_get_x(event) - inset; - g->mouse_y = dt_gdk_event_get_y(event) - inset; + g->mouse_x = x - inset; + g->mouse_y = y - inset; const float mx = CLAMP(g->mouse_x, 0, width) / (float)width; const float linx = to_lin(mx, g->loglogscale, ch, g->semilog, 0); @@ -1883,12 +1882,12 @@ static gboolean dt_iop_tonecurve_button_press(GtkWidget *widget, (selected < nodes && tonecurve[selected].x - linx <= 0.025))) { // evaluate the curve at the current x position - const float y = dt_draw_curve_calc_value(g->minmax_curve[ch], linx); + const float curve_y = dt_draw_curve_calc_value(g->minmax_curve[ch], linx); - if(y >= 0.0 && y <= 1.0) // never add something outside the viewport, you couldn't change it afterwards + if(curve_y >= 0.0 && curve_y <= 1.0) // never add something outside the viewport, you couldn't change it afterwards { // create a new node - selected = _add_node(tonecurve, &p->tonecurve_nodes[ch], linx, y); + selected = _add_node(tonecurve, &p->tonecurve_nodes[ch], linx, curve_y); // maybe set the new one as being selected float min = .04f; @@ -1896,7 +1895,7 @@ static gboolean dt_iop_tonecurve_button_press(GtkWidget *widget, for(int k = 0; k < nodes; k++) { float other_y = to_log(tonecurve[k].y, g->loglogscale, ch, g->semilog, 1); - float dist = (y - other_y) * (y - other_y); + float dist = (curve_y - other_y) * (curve_y - other_y); if(dist < min) g->selected = selected; } @@ -1904,9 +1903,9 @@ static gboolean dt_iop_tonecurve_button_press(GtkWidget *widget, gtk_widget_queue_draw(GTK_WIDGET(g->area)); } } - return TRUE; + } - else if(dt_gdk_event_get_type(event) == GDK_2BUTTON_PRESS) + else if(n_press >= 2) { // reset current curve // if autoscale_ab is on: allow only reset of L curve @@ -1935,10 +1934,10 @@ static gboolean dt_iop_tonecurve_button_press(GtkWidget *widget, gtk_widget_queue_draw(GTK_WIDGET(g->area)); } } - return TRUE; + } } - else if(dt_gdk_event_get_button(event) == GDK_BUTTON_SECONDARY && g->selected >= 0) + else if(gtk_gesture_single_get_current_button(gesture) == GDK_BUTTON_SECONDARY && g->selected >= 0) { if(g->selected == 0 || g->selected == nodes - 1) { @@ -1946,8 +1945,7 @@ static gboolean dt_iop_tonecurve_button_press(GtkWidget *widget, tonecurve[g->selected].y = tonecurve[g->selected].x = reset_value; gtk_widget_queue_draw(GTK_WIDGET(g->area)); dt_dev_add_history_item_target(darktable.develop, self, TRUE, widget + ch); - return TRUE; - } +} for(int k = g->selected; k < nodes - 1; k++) { @@ -1959,9 +1957,7 @@ static gboolean dt_iop_tonecurve_button_press(GtkWidget *widget, p->tonecurve_nodes[ch]--; gtk_widget_queue_draw(GTK_WIDGET(g->area)); dt_dev_add_history_item_target(darktable.develop, self, TRUE, widget + ch); - return TRUE; - } - return FALSE; +} } // clang-format off From 31c45b369be26860d732f01b9dcf0b9a75abdcfa Mon Sep 17 00:00:00 2001 From: Arecsu Date: Sun, 26 Jul 2026 23:32:37 -0300 Subject: [PATCH 06/95] gtk4-prep: colorzones and ashift event controllers --- src/iop/ashift.c | 127 ++++++++++++------------ src/iop/colorzones.c | 229 +++++++++++++++++++------------------------ 2 files changed, 165 insertions(+), 191 deletions(-) diff --git a/src/iop/ashift.c b/src/iop/ashift.c index 55b45f5c4b2..86c18afdd50 100644 --- a/src/iop/ashift.c +++ b/src/iop/ashift.c @@ -5318,19 +5318,21 @@ static void cropmode_callback(GtkWidget *widget, dt_iop_module_t *self) _swap_shadow_crop_box(p,g); } -static int _event_fit_v_button_clicked(GtkWidget *widget, - const GdkEventButton *event, - dt_iop_module_t *self) +static void _event_fit_v_button_clicked(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, + dt_iop_module_t *self) { - DT_GUARD_GUI_UPDATE(FALSE); + DT_GUARD_GUI_UPDATE(); - if(dt_gdk_event_get_button(event) == GDK_BUTTON_PRIMARY) + if(gtk_gesture_single_get_current_button(gesture) == GDK_BUTTON_PRIMARY) { dt_iop_ashift_params_t *p = self->params; dt_iop_ashift_gui_data_t *g = self->gui_data; - const int control = dt_modifiers_include(dt_gdk_event_get_state(event), GDK_CONTROL_MASK); - const int shift = dt_modifiers_include(dt_gdk_event_get_state(event), GDK_SHIFT_MASK); + const int control = dt_modifiers_include(dt_key_modifier_state(), GDK_CONTROL_MASK); + const int shift = dt_modifiers_include(dt_key_modifier_state(), GDK_SHIFT_MASK); dt_iop_ashift_fitaxis_t fitaxis = ASHIFT_FIT_NONE; @@ -5361,24 +5363,25 @@ static int _event_fit_v_button_clicked(GtkWidget *widget, //also calls dt_control_queue_redraw_center dt_dev_add_history_item(darktable.develop, self, TRUE); _swap_shadow_crop_box(p, g); - return TRUE; + } - return FALSE; } -static int _event_fit_h_button_clicked(GtkWidget *widget, - const GdkEventButton *event, - dt_iop_module_t *self) +static void _event_fit_h_button_clicked(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, + dt_iop_module_t *self) { - DT_GUARD_GUI_UPDATE(FALSE); + DT_GUARD_GUI_UPDATE(); - if(dt_gdk_event_get_button(event) == GDK_BUTTON_PRIMARY) + if(gtk_gesture_single_get_current_button(gesture) == GDK_BUTTON_PRIMARY) { dt_iop_ashift_params_t *p = self->params; dt_iop_ashift_gui_data_t *g = self->gui_data; - const int control = dt_modifiers_include(dt_gdk_event_get_state(event), GDK_CONTROL_MASK); - const int shift = dt_modifiers_include(dt_gdk_event_get_state(event), GDK_SHIFT_MASK); + const int control = dt_modifiers_include(dt_key_modifier_state(), GDK_CONTROL_MASK); + const int shift = dt_modifiers_include(dt_key_modifier_state(), GDK_SHIFT_MASK); dt_iop_ashift_fitaxis_t fitaxis = ASHIFT_FIT_NONE; @@ -5409,24 +5412,25 @@ static int _event_fit_h_button_clicked(GtkWidget *widget, //also calls dt_control_queue_redraw_center dt_dev_add_history_item(darktable.develop, self, TRUE); _swap_shadow_crop_box(p, g); - return TRUE; + } - return FALSE; } -static int _event_fit_both_button_clicked(GtkWidget *widget, - const GdkEventButton *event, - dt_iop_module_t *self) +static void _event_fit_both_button_clicked(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, + dt_iop_module_t *self) { - DT_GUARD_GUI_UPDATE(FALSE); + DT_GUARD_GUI_UPDATE(); - if(dt_gdk_event_get_button(event) == GDK_BUTTON_PRIMARY) + if(gtk_gesture_single_get_current_button(gesture) == GDK_BUTTON_PRIMARY) { dt_iop_ashift_params_t *p = self->params; dt_iop_ashift_gui_data_t *g = self->gui_data; - const int control = dt_modifiers_include(dt_gdk_event_get_state(event), GDK_CONTROL_MASK); - const int shift = dt_modifiers_include(dt_gdk_event_get_state(event), GDK_SHIFT_MASK); + const int control = dt_modifiers_include(dt_key_modifier_state(), GDK_CONTROL_MASK); + const int shift = dt_modifiers_include(dt_key_modifier_state(), GDK_SHIFT_MASK); dt_iop_ashift_fitaxis_t fitaxis = ASHIFT_FIT_NONE; @@ -5459,26 +5463,28 @@ static int _event_fit_both_button_clicked(GtkWidget *widget, //also calls dt_control_queue_redraw_center dt_dev_add_history_item(darktable.develop, self, TRUE); _swap_shadow_crop_box(p, g); - return TRUE; + } - return FALSE; } -static int _event_structure_auto_clicked(GtkWidget *widget, - const GdkEventButton *event, - dt_iop_module_t *self) +static void _event_structure_auto_clicked(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, + dt_iop_module_t *self) { - DT_GUARD_GUI_UPDATE(FALSE); + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + DT_GUARD_GUI_UPDATE(); - if(dt_gdk_event_get_button(event) == GDK_BUTTON_PRIMARY) + if(gtk_gesture_single_get_current_button(gesture) == GDK_BUTTON_PRIMARY) { dt_iop_ashift_params_t *p = self->params; dt_iop_ashift_gui_data_t *g = self->gui_data; _do_clean_structure(self, p, TRUE); - const int control = dt_modifiers_include(dt_gdk_event_get_state(event), GDK_CONTROL_MASK); - const int shift = dt_modifiers_include(dt_gdk_event_get_state(event), GDK_SHIFT_MASK); + const int control = dt_modifiers_include(dt_key_modifier_state(), GDK_CONTROL_MASK); + const int shift = dt_modifiers_include(dt_key_modifier_state(), GDK_SHIFT_MASK); dt_iop_ashift_enhance_t enhance; @@ -5497,7 +5503,7 @@ static int _event_structure_auto_clicked(GtkWidget *widget, { _gui_update_structure_states(self, widget); dt_control_queue_redraw_center(); - return TRUE; + } else { @@ -5526,9 +5532,8 @@ static int _event_structure_auto_clicked(GtkWidget *widget, // also calls dt_control_queue_redraw_center dt_dev_add_history_item(darktable.develop, self, TRUE); - return TRUE; + } - return FALSE; } // routine that is called after preview image has been processed. we @@ -5853,12 +5858,14 @@ static float log2_curve(const float inval, const dt_bauhaus_curve_t dir) return outval; } -static int _event_structure_quad_clicked(GtkWidget *widget, - GdkEventButton *event, - dt_iop_module_t *self) +static void _event_structure_quad_clicked(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, + dt_iop_module_t *self) { dt_iop_ashift_gui_data_t *g = self->gui_data; - DT_GUARD_GUI_UPDATE(FALSE); + DT_GUARD_GUI_UPDATE(); dt_iop_request_focus(self); @@ -5878,15 +5885,17 @@ static int _event_structure_quad_clicked(GtkWidget *widget, // also calls dt_control_queue_redraw_center dt_dev_add_history_item(darktable.develop, self, TRUE); - return TRUE; + } -static int _event_structure_lines_clicked(GtkWidget *widget, - GdkEventButton *event, - dt_iop_module_t *self) +static void _event_structure_lines_clicked(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, + dt_iop_module_t *self) { dt_iop_ashift_gui_data_t *g = self->gui_data; - DT_GUARD_GUI_UPDATE(FALSE); + DT_GUARD_GUI_UPDATE(); dt_iop_request_focus(self); @@ -5906,7 +5915,7 @@ static int _event_structure_lines_clicked(GtkWidget *widget, // also calls dt_control_queue_redraw_center dt_dev_add_history_item(darktable.develop, self, TRUE); - return TRUE; + } void gui_init(dt_iop_module_t *self) @@ -6108,24 +6117,12 @@ void gui_init(dt_iop_module_t *self) (g->structure_quad, _("manually define perspective rectangle")); gtk_widget_set_tooltip_text(g->structure_lines, _("manually draw structure lines")); - g_signal_connect(G_OBJECT(g->fit_v), "button-press-event", - G_CALLBACK(_event_fit_v_button_clicked), - (gpointer)self); - g_signal_connect(G_OBJECT(g->fit_h), "button-press-event", - G_CALLBACK(_event_fit_h_button_clicked), - (gpointer)self); - g_signal_connect(G_OBJECT(g->fit_both), "button-press-event", - G_CALLBACK(_event_fit_both_button_clicked), - (gpointer)self); - g_signal_connect(G_OBJECT(g->structure_quad), "button-press-event", - G_CALLBACK(_event_structure_quad_clicked), - (gpointer)self); - g_signal_connect(G_OBJECT(g->structure_lines), "button-press-event", - G_CALLBACK(_event_structure_lines_clicked), - (gpointer)self); - g_signal_connect(G_OBJECT(g->structure_auto), "button-press-event", - G_CALLBACK(_event_structure_auto_clicked), - (gpointer)self); + dt_gui_connect_click(g->fit_v, _event_fit_v_button_clicked, NULL, self); + dt_gui_connect_click(g->fit_h, _event_fit_h_button_clicked, NULL, self); + dt_gui_connect_click(g->fit_both, _event_fit_both_button_clicked, NULL, self); + dt_gui_connect_click(g->structure_quad, _event_structure_quad_clicked, NULL, self); + dt_gui_connect_click(g->structure_lines, _event_structure_lines_clicked, NULL, self); + dt_gui_connect_click(g->structure_auto, _event_structure_auto_clicked, NULL, self); g_signal_connect(G_OBJECT(self->widget), "draw", G_CALLBACK(_event_draw), self); dt_action_define_iop(self, N_("fit"), diff --git a/src/iop/colorzones.c b/src/iop/colorzones.c index e3ab99c47a8..4aed5b4b9a5 100644 --- a/src/iop/colorzones.c +++ b/src/iop/colorzones.c @@ -1657,24 +1657,22 @@ static gboolean _bottom_area_draw_callback(GtkWidget *widget, #undef DT_COLORZONES_CELLSI #undef DT_COLORZONES_CELLSJ -static gboolean _bottom_area_button_press_callback(GtkWidget *widget, - GdkEventButton *event, - dt_iop_module_t *self) +static void _bottom_area_button_press_callback(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, + dt_iop_module_t *self) { dt_iop_colorzones_gui_data_t *g = self->gui_data; - if(dt_gdk_event_get_button(event) == GDK_BUTTON_PRIMARY && dt_gdk_event_get_type(event) == GDK_2BUTTON_PRESS) + if(gtk_gesture_single_get_current_button(gesture) == GDK_BUTTON_PRIMARY && n_press >= 2) { // reset zoom level g->zoom_factor = 1.f; g->offset_x = g->offset_y = 0.f; gtk_widget_queue_draw(GTK_WIDGET(g->area)); - - return TRUE; } - - return FALSE; } static gboolean _sanity_check(const float x, @@ -1775,8 +1773,7 @@ static gboolean _move_point_internal(dt_iop_module_t *self, gtk_widget_queue_draw(widget); - return TRUE; -} + return TRUE;} static void _delete_node(dt_iop_module_t *self, dt_iop_colorzones_node_t *curve, @@ -1857,73 +1854,70 @@ static inline int _add_node(dt_iop_colorzones_node_t *curve, return selected; } -static gboolean _area_scrolled_callback(GtkWidget *widget, - GdkEventScroll *event, +static void _area_scrolled_callback(GtkEventControllerScroll *controller, + gdouble dx, + gdouble dy, dt_iop_module_t *self) { + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); dt_iop_colorzones_gui_data_t *g = self->gui_data; dt_iop_colorzones_params_t *p = self->params; - if(dt_gui_ignore_scroll(event)) return FALSE; - - if(dt_modifier_is(dt_gdk_event_get_state(event), GDK_MOD1_MASK)) - return gtk_widget_event(GTK_WIDGET(g->channel_tabs), (GdkEvent*)event); + if(dy == 0.0) return; - int delta_y; + if(dt_modifier_is(dt_key_modifier_state(), GDK_MOD1_MASK)) + { + // FIXME: event forwarding to g->channel_tabs removed + return; + } if(darktable.develop->darkroom_skip_mouse_events) { - if(dt_gui_get_scroll_unit_delta(event, &delta_y)) - { - GtkAllocation allocation; - gtk_widget_get_allocation(widget, &allocation); + GtkAllocation allocation; + gtk_widget_get_allocation(widget, &allocation); - const float mx = g->mouse_x; - const float my = g->mouse_y; - const float linx = _mouse_to_curve(mx, g->zoom_factor, g->offset_x), - liny = _mouse_to_curve(my, g->zoom_factor, g->offset_y); - - g->zoom_factor *= 1.0 - 0.1 * delta_y; - if(g->zoom_factor < 1.f) g->zoom_factor = 1.f; + const float mx = g->mouse_x; + const float my = g->mouse_y; + const float linx = _mouse_to_curve(mx, g->zoom_factor, g->offset_x), + liny = _mouse_to_curve(my, g->zoom_factor, g->offset_y); - g->offset_x = linx - (mx / g->zoom_factor); - g->offset_y = liny - (my / g->zoom_factor); + g->zoom_factor *= 1.0 - 0.1 * dy; + if(g->zoom_factor < 1.f) g->zoom_factor = 1.f; - g->offset_x = CLAMP(g->offset_x, 0.f, (g->zoom_factor - 1.f) / g->zoom_factor); - g->offset_y = CLAMP(g->offset_y, 0.f, (g->zoom_factor - 1.f) / g->zoom_factor); + g->offset_x = linx - (mx / g->zoom_factor); + g->offset_y = liny - (my / g->zoom_factor); - gtk_widget_queue_draw(GTK_WIDGET(g->area)); - } + g->offset_x = CLAMP(g->offset_x, 0.f, (g->zoom_factor - 1.f) / g->zoom_factor); + g->offset_y = CLAMP(g->offset_y, 0.f, (g->zoom_factor - 1.f) / g->zoom_factor); - return TRUE; + gtk_widget_queue_draw(GTK_WIDGET(g->area)); + return; } - if(g->selected < 0 && !g->edit_by_area) return TRUE; + if(g->selected < 0 && !g->edit_by_area) return; - if(dt_gui_get_scroll_unit_delta(event, &delta_y)) - { - dt_iop_color_picker_reset(self, TRUE); + dt_iop_color_picker_reset(self, TRUE); - if(g->edit_by_area) - { - const int bands = p->curve_num_nodes[g->channel]; - g->mouse_radius = CLAMP(g->mouse_radius * (1.0 - 0.1 * delta_y), 0.2 / bands, 1.0); - gtk_widget_queue_draw(widget); - } - else - { - const float dy = delta_y * -DT_IOP_COLORZONES_DEFAULT_STEP; - return _move_point_internal(self, widget, g->selected, 0.f, dy, dt_gdk_event_get_state(event)); - } + if(g->edit_by_area) + { + const int bands = p->curve_num_nodes[g->channel]; + g->mouse_radius = CLAMP(g->mouse_radius * (1.0 - 0.1 * dy), 0.2 / bands, 1.0); + gtk_widget_queue_draw(widget); + } + else + { + dy *= -DT_IOP_COLORZONES_DEFAULT_STEP; + _move_point_internal(self, widget, g->selected, 0.f, dy, dt_key_modifier_state()); + gtk_widget_queue_draw(widget); } - - return TRUE; } -static gboolean _area_motion_notify_callback(GtkWidget *widget, - GdkEventMotion *event, +static void _area_motion_notify_callback(GtkEventControllerMotion *controller, + gdouble x, + gdouble y, dt_iop_module_t *self) { + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); dt_iop_colorzones_gui_data_t *g = self->gui_data; dt_iop_colorzones_params_t *p = self->params; @@ -1941,10 +1935,10 @@ static gboolean _area_motion_notify_callback(GtkWidget *widget, const float mx = g->mouse_x; const float my = g->mouse_y; - g->mouse_x = CLAMP(dt_gdk_event_get_x(event) - inset, 0, width) / (float)width; - g->mouse_y = 1.0 - CLAMP(dt_gdk_event_get_y(event) - inset, 0, height) / (float)height; + g->mouse_x = CLAMP(x - inset, 0, width) / (float)width; + g->mouse_y = 1.0 - CLAMP(y - inset, 0, height) / (float)height; - if(dt_gdk_event_get_state(event) & GDK_BUTTON1_MASK) + if(dt_key_modifier_state() & GDK_BUTTON1_MASK) { g->offset_x += (mx - g->mouse_x) / g->zoom_factor; g->offset_y += (my - g->mouse_y) / g->zoom_factor; @@ -1954,7 +1948,6 @@ static gboolean _area_motion_notify_callback(GtkWidget *widget, gtk_widget_queue_draw(GTK_WIDGET(g->area)); } - return TRUE; } const int ch = g->channel; @@ -1964,8 +1957,8 @@ static gboolean _area_motion_notify_callback(GtkWidget *widget, const double old_m_x = g->mouse_x; const double old_m_y = fabs(g->mouse_y); - g->mouse_x = CLAMP(dt_gdk_event_get_x(event) - inset, 0, width) / (float)width; - g->mouse_y = 1.0 - CLAMP(dt_gdk_event_get_y(event) - inset, 0, height) / (float)height; + g->mouse_x = CLAMP(x - inset, 0, width) / (float)width; + g->mouse_y = 1.0 - CLAMP(y - inset, 0, height) / (float)height; darktable.control->element = (int)(8.0 * @@ -1973,7 +1966,7 @@ static gboolean _area_motion_notify_callback(GtkWidget *widget, g->zoom_factor, g->offset_x) + 0.5f) % 8; // move a node - if(dt_gdk_event_get_state(event) & GDK_BUTTON1_MASK) + if(dt_key_modifier_state() & GDK_BUTTON1_MASK) { if(g->edit_by_area) { @@ -2004,7 +1997,7 @@ static gboolean _area_motion_notify_callback(GtkWidget *widget, g->zoom_factor, g->offset_y); dt_iop_color_picker_reset(self, TRUE); - return _move_point_internal(self, widget, g->selected, dx, dy, dt_gdk_event_get_state(event)); + _move_point_internal(self, widget, g->selected, dx, dy, dt_key_modifier_state()); } } @@ -2020,7 +2013,7 @@ static gboolean _area_motion_notify_callback(GtkWidget *widget, dt_dev_add_history_item_target(darktable.develop, self, TRUE, widget + ch); } } - else if(dt_gdk_event_get_y(event) > height) + else if(y > height) { g->x_move = 0; const int bands = p->curve_num_nodes[g->channel]; @@ -2043,7 +2036,7 @@ static gboolean _area_motion_notify_callback(GtkWidget *widget, } else { - if(dt_gdk_event_get_state(event) & GDK_BUTTON1_MASK) + if(dt_key_modifier_state() & GDK_BUTTON1_MASK) { if(nodes < DT_IOP_COLORZONES_MAXNODES && g->selected == -1) { @@ -2086,33 +2079,34 @@ static gboolean _area_motion_notify_callback(GtkWidget *widget, } gtk_widget_queue_draw(widget); - return TRUE; } -static gboolean _area_button_press_callback(GtkWidget *widget, - GdkEventButton *event, +static void _area_button_press_callback(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, dt_iop_module_t *self) { + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); dt_iop_colorzones_gui_data_t *g = self->gui_data; dt_iop_colorzones_params_t *p = self->params; const dt_iop_colorzones_params_t *const d = self->default_params; - if(darktable.develop->darkroom_skip_mouse_events) return TRUE; + if(darktable.develop->darkroom_skip_mouse_events) return; int ch = g->channel; int nodes = p->curve_num_nodes[ch]; dt_iop_colorzones_node_t *curve = p->curve[ch]; - if(dt_gdk_event_get_button(event) == GDK_BUTTON_PRIMARY) + if(gtk_gesture_single_get_current_button(gesture) == GDK_BUTTON_PRIMARY) { - if(g->edit_by_area && dt_gdk_event_get_type(event) != GDK_2BUTTON_PRESS - && !dt_modifier_is(dt_gdk_event_get_state(event), GDK_CONTROL_MASK)) + if(g->edit_by_area && n_press < 2 + && !dt_modifier_is(dt_key_modifier_state(), GDK_CONTROL_MASK)) { g->dragging = 1; - return TRUE; } - else if(dt_gdk_event_get_type(event) == GDK_BUTTON_PRESS - && dt_modifier_is(dt_gdk_event_get_state(event), GDK_CONTROL_MASK) + else if(n_press >= 1 + && dt_modifier_is(dt_key_modifier_state(), GDK_CONTROL_MASK) && nodes < DT_IOP_COLORZONES_MAXNODES && (g->selected == -1 || g->edit_by_area)) { @@ -2124,8 +2118,8 @@ static gboolean _area_button_press_callback(GtkWidget *widget, const int height = allocation.height - 2 * inset; const int width = allocation.width - 2 * inset; - g->mouse_x = CLAMP(dt_gdk_event_get_x(event) - inset, 0, width) / (float)width; - g->mouse_y = 1.0 - CLAMP(dt_gdk_event_get_y(event) - inset, 0, height) / (float)height; + g->mouse_x = CLAMP(x - inset, 0, width) / (float)width; + g->mouse_y = 1.0 - CLAMP(y - inset, 0, height) / (float)height; const float mx = _mouse_to_curve(g->mouse_x, g->zoom_factor, g->offset_x); @@ -2147,14 +2141,14 @@ static gboolean _area_button_press_callback(GtkWidget *widget, if(selected == -1) selected = nodes; // evaluate the curve at the current x position - const float y = dt_draw_curve_calc_value(g->minmax_curve[ch], mx); + const float curve_y = dt_draw_curve_calc_value(g->minmax_curve[ch], mx); if(y >= 0.0f && y <= 1.0f) // never add something outside the // viewport, you couldn't change it // afterwards { // create a new node - selected = _add_node(curve, &p->curve_num_nodes[ch], mx, y); + selected = _add_node(curve, &p->curve_num_nodes[ch], mx, curve_y); // maybe set the new one as being selected const float min = .04f * .04f; // comparing against square @@ -2170,10 +2164,8 @@ static gboolean _area_button_press_callback(GtkWidget *widget, dt_dev_add_history_item_target(darktable.develop, self, TRUE, widget + ch); gtk_widget_queue_draw(GTK_WIDGET(g->area)); } - - return TRUE; } - else if(dt_gdk_event_get_type(event) == GDK_2BUTTON_PRESS) + else if(n_press >= 2) { // reset current curve p->curve_num_nodes[ch] = d->curve_num_nodes[ch]; @@ -2188,11 +2180,9 @@ static gboolean _area_button_press_callback(GtkWidget *widget, dt_iop_color_picker_reset(self, TRUE); dt_dev_add_history_item_target(darktable.develop, self, TRUE, widget + ch); gtk_widget_queue_draw(GTK_WIDGET(g->area)); - - return TRUE; } } - else if(dt_gdk_event_get_button(event) == GDK_BUTTON_SECONDARY && g->selected >= 0) + else if(gtk_gesture_single_get_current_button(gesture) == GDK_BUTTON_SECONDARY && g->selected >= 0) { if((g->selected == 0 || g->selected == nodes - 1) && p->splines_version == DT_IOP_COLORZONES_SPLINES_V1) @@ -2214,54 +2204,50 @@ static gboolean _area_button_press_callback(GtkWidget *widget, dt_iop_color_picker_reset(self, TRUE); gtk_widget_queue_draw(GTK_WIDGET(g->area)); dt_dev_add_history_item_target(darktable.develop, self, TRUE, widget + ch); - return TRUE; } // right click deletes the node, ctrl+right click reset the node to y-zero _delete_node(self, curve, &p->curve_num_nodes[ch], - g->selected, dt_modifier_is(dt_gdk_event_get_state(event), GDK_CONTROL_MASK)); + g->selected, dt_modifier_is(dt_key_modifier_state(), GDK_CONTROL_MASK)); g->selected = -2; // avoid re-insertion of that point immediately after this - - return TRUE; } - - return FALSE; } -static gboolean _area_button_release_callback(GtkWidget *widget, - GdkEventButton *event, +static void _area_button_release_callback(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, dt_iop_module_t *self) { - if(darktable.develop->darkroom_skip_mouse_events) return TRUE; + if(darktable.develop->darkroom_skip_mouse_events) return; - if(dt_gdk_event_get_button(event) == GDK_BUTTON_PRIMARY) + if(gtk_gesture_single_get_current_button(gesture) == GDK_BUTTON_PRIMARY) { dt_iop_colorzones_gui_data_t *g = self->gui_data; g->dragging = 0; - return TRUE; } - return FALSE; } -static gboolean _area_leave_notify_callback(GtkWidget *widget, - GdkEventCrossing *event, +static void _area_leave_notify_callback(GtkEventControllerMotion *controller, dt_iop_module_t *self) { - if(darktable.develop->darkroom_skip_mouse_events) return TRUE; + if(darktable.develop->darkroom_skip_mouse_events) return; dt_iop_colorzones_gui_data_t *g = self->gui_data; // for fluxbox g->mouse_y = -fabs(g->mouse_y); - if(!(dt_gdk_event_get_state(event) & GDK_BUTTON1_MASK)) + if(!(dt_key_modifier_state() & GDK_BUTTON1_MASK)) g->selected = -1; - gtk_widget_queue_draw(widget); - return TRUE; + gtk_widget_queue_draw(gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller))); } -static gboolean _area_key_press_callback(GtkWidget *widget, - GdkEventKey *event, +static gboolean _area_key_press_callback(GtkEventControllerKey *controller, + guint keyval, + guint keycode, + GdkModifierType state, dt_iop_module_t *self) { + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); dt_iop_colorzones_gui_data_t *g = self->gui_data; if(darktable.develop->darkroom_skip_mouse_events) return FALSE; @@ -2270,22 +2256,22 @@ static gboolean _area_key_press_callback(GtkWidget *widget, int handled = 0; float dx = 0.0f, dy = 0.0f; - if(dt_gdk_event_get_keyval(event) == GDK_KEY_Up || dt_gdk_event_get_keyval(event) == GDK_KEY_KP_Up) + if(keyval == GDK_KEY_Up || keyval == GDK_KEY_KP_Up) { handled = 1; dy = DT_IOP_COLORZONES_DEFAULT_STEP; } - else if(dt_gdk_event_get_keyval(event) == GDK_KEY_Down || dt_gdk_event_get_keyval(event) == GDK_KEY_KP_Down) + else if(keyval == GDK_KEY_Down || keyval == GDK_KEY_KP_Down) { handled = 1; dy = -DT_IOP_COLORZONES_DEFAULT_STEP; } - else if(dt_gdk_event_get_keyval(event) == GDK_KEY_Right || dt_gdk_event_get_keyval(event) == GDK_KEY_KP_Right) + else if(keyval == GDK_KEY_Right || keyval == GDK_KEY_KP_Right) { handled = 1; dx = DT_IOP_COLORZONES_DEFAULT_STEP; } - else if(dt_gdk_event_get_keyval(event) == GDK_KEY_Left || dt_gdk_event_get_keyval(event) == GDK_KEY_KP_Left) + else if(keyval == GDK_KEY_Left || keyval == GDK_KEY_KP_Left) { handled = 1; dx = -DT_IOP_COLORZONES_DEFAULT_STEP; @@ -2294,7 +2280,7 @@ static gboolean _area_key_press_callback(GtkWidget *widget, if(!handled) return FALSE; dt_iop_color_picker_reset(self, TRUE); - return _move_point_internal(self, widget, g->selected, dx, dy, dt_gdk_event_get_state(event)); + return _move_point_internal(self, widget, g->selected, dx, dy, dt_key_modifier_state()); } static void _channel_tabs_switch_callback(GtkNotebook *notebook, @@ -2711,25 +2697,16 @@ void gui_init(dt_iop_module_t *self) gtk_widget_set_can_focus(GTK_WIDGET(g->area), TRUE); g_signal_connect(G_OBJECT(g->area), "draw", G_CALLBACK(_area_draw_callback), self); - g_signal_connect(G_OBJECT(g->area), "button-press-event", - G_CALLBACK(_area_button_press_callback), self); - g_signal_connect(G_OBJECT(g->area), "button-release-event", - G_CALLBACK(_area_button_release_callback), self); - g_signal_connect(G_OBJECT(g->area), "motion-notify-event", - G_CALLBACK(_area_motion_notify_callback), self); - g_signal_connect(G_OBJECT(g->area), "leave-notify-event", - G_CALLBACK(_area_leave_notify_callback), self); - g_signal_connect(G_OBJECT(g->area), "scroll-event", - G_CALLBACK(_area_scrolled_callback), self); - g_signal_connect(G_OBJECT(g->area), "key-press-event", - G_CALLBACK(_area_key_press_callback), self); - - gtk_widget_add_events(GTK_WIDGET(g->bottom_area), GDK_BUTTON_PRESS_MASK); + dt_gui_connect_click(g->area, _area_button_press_callback, _area_button_release_callback, self); + dt_gui_connect_motion(g->area, _area_motion_notify_callback, NULL, _area_leave_notify_callback, self); + dt_gui_connect_scroll(g->area, GTK_EVENT_CONTROLLER_SCROLL_BOTH_AXES + | GTK_EVENT_CONTROLLER_SCROLL_DISCRETE, + _area_scrolled_callback, self); + dt_gui_connect_key(g->area, _area_key_press_callback, self); + g_signal_connect(G_OBJECT(g->bottom_area), "draw", G_CALLBACK(_bottom_area_draw_callback), self); - g_signal_connect(G_OBJECT(g->bottom_area), "button-press-event", - G_CALLBACK(_bottom_area_button_press_callback), - self); + dt_gui_connect_click(g->bottom_area, _bottom_area_button_press_callback, NULL, self); g->interpolator = dt_bauhaus_combobox_new_interpolation(self); dt_gui_box_add(self->widget, g->interpolator); From 71143ea92311d1e76bfb31113df7b4600576e8fb Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 00:05:02 -0300 Subject: [PATCH 07/95] gtk4-prep: imageop event controllers --- src/develop/imageop.c | 283 +++++++++++++++++++++++++++++------------- 1 file changed, 196 insertions(+), 87 deletions(-) diff --git a/src/develop/imageop.c b/src/develop/imageop.c index 59b385ef18b..35a868ae726 100644 --- a/src/develop/imageop.c +++ b/src/develop/imageop.c @@ -449,27 +449,27 @@ void dt_iop_init_pipe(dt_iop_module_t *module, piece->blendop_data = calloc(1, sizeof(dt_develop_blend_params_t)); } -static gboolean _header_enter_notify_callback(GtkWidget *eventbox, - GdkEventCrossing *event, - gpointer user_data) +static void _header_enter_notify_callback(GtkEventControllerMotion *controller, + gdouble x, + gdouble y, + gpointer user_data) { darktable.control->element = GPOINTER_TO_INT(user_data); - return FALSE; } -static gboolean _header_motion_notify_show_callback(GtkWidget *eventbox, - GdkEventCrossing *event, - dt_iop_module_t *module) +static void _header_motion_notify_show_callback(GtkEventControllerMotion *controller, + gdouble x, + gdouble y, + dt_iop_module_t *module) { darktable.control->element = DT_ACTION_ELEMENT_SHOW; - return dt_iop_show_hide_header_buttons(module, event, TRUE, FALSE); + dt_iop_show_hide_header_buttons(module, NULL, TRUE, FALSE); } -static gboolean _header_motion_notify_hide_callback(GtkWidget *eventbox, - GdkEventCrossing *event, - dt_iop_module_t *module) +static void _header_motion_notify_hide_callback(GtkEventControllerMotion *controller, + dt_iop_module_t *module) { - return dt_iop_show_hide_header_buttons(module, event, FALSE, FALSE); + dt_iop_show_hide_header_buttons(module, NULL, FALSE, FALSE); } static void _header_menu_deactivate_callback(GtkMenuShell *menushell, @@ -824,6 +824,12 @@ static void _gui_duplicate_callback(GtkButton *button, dt_iop_module_t *base) dt_iop_gui_rename_module(module); } +static gboolean _rename_module_key_pressed(GtkEventControllerKey *controller, + guint keyval, + guint keycode, + GdkModifierType state, + dt_iop_module_t *module); + static gboolean _rename_module_key_press(GtkWidget *entry, GdkEventKey *event, dt_iop_module_t *module) @@ -919,17 +925,15 @@ void dt_iop_gui_rename_module(dt_iop_module_t *module) gtk_widget_hide(module->instance_name); gtk_widget_add_events(entry, GDK_FOCUS_CHANGE_MASK); - g_signal_connect(entry, "key-press-event", - G_CALLBACK(_rename_module_key_press), module); + dt_gui_connect_key(entry, _rename_module_key_pressed, module); g_signal_connect(entry, "focus-out-event", G_CALLBACK(_rename_module_key_press), module); g_signal_connect(entry, "style-updated", G_CALLBACK(_rename_module_resize), module); g_signal_connect(entry, "changed", G_CALLBACK(_rename_module_resize), module); - g_signal_connect(entry, "enter-notify-event", - G_CALLBACK(_header_enter_notify_callback), - GINT_TO_POINTER(DT_ACTION_ELEMENT_SHOW)); + dt_gui_connect_motion(entry, NULL, _header_enter_notify_callback, NULL, + GINT_TO_POINTER(DT_ACTION_ELEMENT_SHOW)); dt_iop_show_hide_header_buttons(module, NULL, FALSE, TRUE); // before adding entry gtk_box_pack_start(GTK_BOX(module->header), entry, TRUE, TRUE, 0); @@ -1056,18 +1060,77 @@ static gboolean _gui_multiinstance_callback(GtkButton *button, return TRUE; } -static gboolean _gui_off_button_press(GtkButton *w, - GdkEventButton *e, - dt_iop_module_t *module) +static void _gui_off_button_clicked(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, + dt_iop_module_t *module) { if(module->operation_tags() & IOP_TAG_DISTORT) { DT_CONTROL_SIGNAL_RAISE(DT_SIGNAL_DEVELOP_DISTORT); } - if(!DT_IN_GUI_UPDATE() && dt_modifier_is(e->state, GDK_CONTROL_MASK)) + if(!DT_IN_GUI_UPDATE() && (dt_key_modifier_state() & GDK_CONTROL_MASK)) { dt_iop_request_focus(dt_dev_gui_module() == module ? NULL : module); + } +} + +static void _gui_multiinstance_clicked(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, + dt_iop_module_t *module) +{ + _gui_multiinstance_callback(NULL, NULL, module); +} + +static gboolean _rename_module_key_pressed(GtkEventControllerKey *controller, + guint keyval, + guint keycode, + GdkModifierType state, + dt_iop_module_t *module) +{ + GtkWidget *entry = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); + gboolean ended = FALSE; + + if(keyval == GDK_KEY_Return || keyval == GDK_KEY_KP_Enter) + { + if(gtk_entry_get_text_length(GTK_ENTRY(entry)) > 0) + { + const gchar *name = gtk_entry_get_text(GTK_ENTRY(entry)); + gchar *current_name = dt_util_localize_segmented_name(module->multi_name, FALSE); + if(g_strcmp0(current_name, name) != 0) + { + dt_iop_update_multi_name(module, name, TRUE, TRUE, TRUE); + } + g_free(current_name); + } + else + { + dt_iop_update_multi_name(module, "", FALSE, FALSE, TRUE); + } + + dt_dev_write_history(darktable.develop); + dt_image_synch_xmp(darktable.develop->image_storage.id); + ended = TRUE; + } + else if(keyval == GDK_KEY_Escape) + { + ended = TRUE; + } + + if(ended) + { + gtk_widget_show(module->instance_name); + g_signal_handlers_disconnect_by_func(entry, + G_CALLBACK(_rename_module_key_press), + module); + gtk_widget_destroy(entry); + dt_iop_show_hide_header_buttons(module, NULL, TRUE, FALSE); + dt_iop_gui_update_header(module); + dt_masks_group_update_name(module); return TRUE; } @@ -2352,6 +2415,7 @@ void dt_iop_gui_reset(dt_iop_module_t *module) DT_LEAVE_GUI_UPDATE(); } +// kept for direct callers from accelerators static gboolean _gui_reset_callback(GtkButton *button, GdkEventButton *event, dt_iop_module_t *module) @@ -2392,6 +2456,46 @@ static gboolean _gui_reset_callback(GtkButton *button, return TRUE; } +static void _gui_reset_clicked(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, + dt_iop_module_t *module) +{ + // never use the callback if module is always disabled + const gboolean disabled = !module->default_enabled && module->hide_enable_button; + if(disabled) return; + + // Ctrl is used to apply any auto-presets to the current module + // If Ctrl was not pressed, or no auto-presets were applied, reset the module parameters + if(!((dt_key_modifier_state() & GDK_CONTROL_MASK) + && dt_gui_presets_autoapply_for_module(module, NULL))) + { + // if a drawn mask is set, remove it from the list + if(dt_is_valid_maskid(module->blend_params->mask_id)) + { + dt_masks_form_t *grp = + dt_masks_get_from_id(darktable.develop, module->blend_params->mask_id); + if(grp) dt_masks_form_remove(module, NULL, grp); + } + /* reset to default params */ + dt_iop_reload_defaults(module); + dt_iop_commit_blend_params(module, module->default_blendop_params); + + /* reset ui to its defaults */ + dt_iop_gui_reset(module); + + /* update ui to default params*/ + dt_iop_gui_update(module); + + dt_dev_add_history_item(module->dev, module, TRUE); + } + + // rebuild the accelerators + dt_iop_connect_accels_multi(module->so); +} + +// kept for direct callers from accelerators static gboolean _presets_popup_callback(GtkButton *button, GdkEventButton *event, dt_iop_module_t *module) @@ -2410,21 +2514,35 @@ static gboolean _presets_popup_callback(GtkButton *button, return TRUE; } -static gboolean _presets_scroll_callback(GtkWidget *widget, - GdkEventScroll *event, - dt_iop_module_t *module) +static void _presets_popup_clicked(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, + dt_iop_module_t *module) { - if(dt_gui_ignore_scroll(event)) return FALSE; + const gboolean disabled = !module->default_enabled && module->hide_enable_button; + if(disabled) return; - // preset cycling: right==down==next - int delta_x = 0, delta_y = 0; - if(dt_gui_get_scroll_unit_deltas(event, &delta_x, &delta_y)) - { - const int delta = abs(delta_x) > abs(delta_y) ? delta_x : delta_y; - dt_gui_presets_apply_adjacent_preset(module, delta); - } + GtkWidget *button = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + GtkMenu *menu = dt_gui_presets_popup_menu_show_for_module(module); - return TRUE; + g_signal_connect(G_OBJECT(menu), "deactivate", + G_CALLBACK(_header_menu_deactivate_callback), module); + + dt_gui_menu_popup(menu, + button, GDK_GRAVITY_SOUTH_EAST, GDK_GRAVITY_NORTH_EAST); +} + +static void _presets_scrolled(GtkEventControllerScroll *controller, + gdouble dx, + gdouble dy, + dt_iop_module_t *module) +{ + if(dy == 0.0 && dx == 0.0) return; + + // preset cycling: right==down==next + const int delta = fabs(dx) > fabs(dy) ? dx : dy; + dt_gui_presets_apply_adjacent_preset(module, delta); } gboolean dt_iop_has_focus(const dt_iop_module_t *module) @@ -2633,48 +2751,46 @@ void dt_iop_gui_update_expanded(dt_iop_module_t *module) dtgtk_expander_set_expanded(DTGTK_EXPANDER(module->expander), expanded); } -static gboolean _iop_plugin_body_button_press(GtkWidget *w, - GdkEventButton *e, - gpointer user_data) +static void _iop_plugin_body_pressed(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, + dt_iop_module_t *module) { - dt_iop_module_t *module = (dt_iop_module_t *)user_data; - if(e->button == GDK_BUTTON_PRIMARY) + if(gtk_gesture_single_get_current_button(gesture) == GDK_BUTTON_PRIMARY) { dt_iop_request_focus(module); - return TRUE; } - else if(e->button == GDK_BUTTON_SECONDARY) + else if(gtk_gesture_single_get_current_button(gesture) == GDK_BUTTON_SECONDARY) { _presets_popup_callback(NULL, NULL, module); - - return TRUE; } - return FALSE; } -static gboolean _iop_plugin_header_button_release(GtkWidget *w, - GdkEventButton *e, - gpointer user_data) +static void _iop_plugin_header_released(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, + dt_iop_module_t *module) { - if(e->type == GDK_2BUTTON_PRESS || e->type == GDK_3BUTTON_PRESS) return TRUE; - if(GTK_IS_BUTTON(gtk_get_event_widget((GdkEvent*)e))) return FALSE; + if(n_press >= 2) return; - dt_iop_module_t *module = (dt_iop_module_t *)user_data; + const guint button = gtk_gesture_single_get_current_button(gesture); - if(e->button == GDK_BUTTON_PRIMARY) + if(button == GDK_BUTTON_PRIMARY) { - if(dt_modifier_is(e->state, GDK_SHIFT_MASK | GDK_CONTROL_MASK)) + if(dt_modifier_is(dt_key_modifier_state(), GDK_SHIFT_MASK | GDK_CONTROL_MASK)) ; // do nothing (for easier dragging) - else if(dt_modifier_is(e->state, GDK_CONTROL_MASK)) + else if(dt_modifier_is(dt_key_modifier_state(), GDK_CONTROL_MASK)) { dt_iop_gui_rename_module(module); - return TRUE; + return; } else { const gboolean collapse_others = !dt_conf_get_bool("darkroom/ui/single_module") - != (!dt_modifier_is(e->state, GDK_SHIFT_MASK)); + != (!dt_modifier_is(dt_key_modifier_state(), GDK_SHIFT_MASK)); dt_iop_gui_set_expanded(module, !module->expanded, collapse_others); @@ -2684,16 +2800,14 @@ static gboolean _iop_plugin_header_button_release(GtkWidget *w, //used to take focus away from module search text input box when module selected gtk_widget_grab_focus(dt_ui_center(darktable.gui->ui)); - return TRUE; + return; } } - else if(e->button == GDK_BUTTON_SECONDARY) + else if(button == GDK_BUTTON_SECONDARY) { _presets_popup_callback(NULL, NULL, module); - - return TRUE; + return; } - return FALSE; } static void _header_size_callback(GtkWidget *widget, @@ -3070,12 +3184,10 @@ GtkWidget *dt_iop_gui_header_button(dt_iop_module_t *module, GtkWidget *header) { GtkWidget *button; - gpointer callback = _gui_multiinstance_callback; if(element == DT_ACTION_ELEMENT_ENABLE) { button = dtgtk_togglebutton_new(paint, 0, module); - callback = _gui_off_button_press; char tooltip[512]; gchar *module_label = dt_history_item_get_name(module); @@ -3094,23 +3206,27 @@ GtkWidget *dt_iop_gui_header_button(dt_iop_module_t *module, button = dtgtk_button_new(paint, 0, NULL); if(element == DT_ACTION_ELEMENT_RESET) { - callback = _gui_reset_callback; gtk_widget_set_tooltip_text (button, _("reset parameters\nctrl+click to reapply any automatic presets")); } else if(element == DT_ACTION_ELEMENT_PRESETS) { - callback = _presets_popup_callback; - g_signal_connect(button, "scroll-event", - G_CALLBACK(_presets_scroll_callback), module); - gtk_widget_add_events(button, darktable.gui->scroll_mask); + dt_gui_connect_scroll(button, GTK_EVENT_CONTROLLER_SCROLL_BOTH_AXES + | GTK_EVENT_CONTROLLER_SCROLL_DISCRETE, + _presets_scrolled, module); } gtk_box_pack_end(GTK_BOX(header), button, FALSE, FALSE, 0); } - g_signal_connect(button, "enter-notify-event", - G_CALLBACK(_header_enter_notify_callback), - GINT_TO_POINTER(element)); - g_signal_connect_data(button, "button-press-event", G_CALLBACK(callback), module, NULL, 0); + dt_gui_connect_motion(button, NULL, _header_enter_notify_callback, NULL, + GINT_TO_POINTER(element)); + dt_gui_connect_click(button, (element == DT_ACTION_ELEMENT_ENABLE) + ? _gui_off_button_clicked + : (element == DT_ACTION_ELEMENT_RESET) + ? _gui_reset_clicked + : (element == DT_ACTION_ELEMENT_PRESETS) + ? _presets_popup_clicked + : _gui_multiinstance_clicked, + NULL, module); dt_action_define(&module->so->actions, NULL, NULL, button, NULL); gtk_widget_show(button); @@ -3227,22 +3343,16 @@ void dt_iop_gui_set_expander(dt_iop_module_t *module) module->header = header; /* setup the header box */ - g_signal_connect(G_OBJECT(header_evb), "button-release-event", - G_CALLBACK(_iop_plugin_header_button_release), module); - gtk_widget_add_events(header_evb, GDK_POINTER_MOTION_MASK); - g_signal_connect(G_OBJECT(header_evb), "enter-notify-event", - G_CALLBACK(_header_motion_notify_show_callback), module); - g_signal_connect(G_OBJECT(header_evb), "leave-notify-event", - G_CALLBACK(_header_motion_notify_hide_callback), module); + dt_gui_connect_click(header_evb, NULL, _iop_plugin_header_released, module); + dt_gui_connect_motion(header_evb, NULL, + _header_motion_notify_show_callback, + _header_motion_notify_hide_callback, module); /* connect mouse button callbacks for focus and presets */ - g_signal_connect(G_OBJECT(body_evb), "button-press-event", - G_CALLBACK(_iop_plugin_body_button_press), module); - gtk_widget_add_events(body_evb, GDK_POINTER_MOTION_MASK); - g_signal_connect(G_OBJECT(body_evb), "enter-notify-event", - G_CALLBACK(_header_motion_notify_show_callback), module); - g_signal_connect(G_OBJECT(body_evb), "leave-notify-event", - G_CALLBACK(_header_motion_notify_hide_callback), module); + dt_gui_connect_click(body_evb, _iop_plugin_body_pressed, NULL, module); + dt_gui_connect_motion(body_evb, NULL, + _header_motion_notify_show_callback, + _header_motion_notify_hide_callback, module); /* * initialize the header widgets @@ -3283,9 +3393,8 @@ void dt_iop_gui_set_expander(dt_iop_module_t *module) } dt_action_define(&module->so->actions, NULL, NULL, lab, NULL); - g_signal_connect(lab, "enter-notify-event", - G_CALLBACK(_header_enter_notify_callback), - GINT_TO_POINTER(DT_ACTION_ELEMENT_SHOW)); + dt_gui_connect_motion(lab, NULL, _header_enter_notify_callback, NULL, + GINT_TO_POINTER(DT_ACTION_ELEMENT_SHOW)); /* add right side header buttons */ module->presets_button = dt_iop_gui_header_button(module, From 6b8d9698448f9285849d9bfa7ebe3176ff4549fc Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 00:05:05 -0300 Subject: [PATCH 08/95] gtk4-prep: colorbalance and temperature event controllers --- src/iop/colorbalance.c | 9 ++++++--- src/iop/temperature.c | 12 ++++++------ 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/iop/colorbalance.c b/src/iop/colorbalance.c index 975af9eeb29..98876e14ace 100644 --- a/src/iop/colorbalance.c +++ b/src/iop/colorbalance.c @@ -1797,7 +1797,11 @@ static void _configure_slider_blocks(gpointer instance, dt_iop_module_t *self) if(old_container) gtk_widget_show(new_container); } -static gboolean _cycle_layout_callback(GtkWidget *label, GdkEventButton *event, dt_iop_module_t *self) +static void _cycle_layout_callback(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, + dt_iop_module_t *self) { gchar *layout = dt_conf_get_string("plugins/darkroom/colorbalance/layout"); @@ -1808,7 +1812,6 @@ static gboolean _cycle_layout_callback(GtkWidget *label, GdkEventButton *event, g_free(layout); _configure_slider_blocks(NULL, self); - return TRUE; } #define HSL_CALLBACK(which) \ @@ -1898,7 +1901,7 @@ void gui_init(dt_iop_module_t *self) gtk_widget_set_tooltip_text(g->main_label, _("click to cycle layout")); GtkWidget *main_label_box = gtk_event_box_new(); gtk_container_add(GTK_CONTAINER(main_label_box), g->main_label); - g_signal_connect(G_OBJECT(main_label_box), "button-release-event", G_CALLBACK(_cycle_layout_callback), self); + dt_gui_connect_click(main_label_box, NULL, _cycle_layout_callback, self); g->main_box = gtk_event_box_new(); // is filled in _configure_slider_blocks diff --git a/src/iop/temperature.c b/src/iop/temperature.c index 55f6e284fa8..da14913030c 100644 --- a/src/iop/temperature.c +++ b/src/iop/temperature.c @@ -1995,9 +1995,11 @@ static void _gui_sliders_update(dt_iop_module_t *self) gtk_widget_set_visible(GTK_WIDGET(g->scale_y), (img->flags & DT_IMAGE_4BAYER)); } -static gboolean temp_label_click(GtkWidget *label, - GdkEventButton *event, - dt_iop_module_t *self) +static void temp_label_click(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, + dt_iop_module_t *self) { dt_iop_temperature_gui_data_t *g = self->gui_data; @@ -2027,7 +2029,6 @@ static gboolean temp_label_click(GtkWidget *label, _color_temptint_sliders(self); _color_rgb_sliders(self); _color_finetuning_slider(self); - return TRUE; } static void _preference_changed(gpointer instance, dt_iop_module_t *self) @@ -2130,8 +2131,7 @@ void gui_init(dt_iop_module_t *self) gtk_widget_set_tooltip_text(g->temp_label, _("click to cycle color mode on sliders")); gtk_container_add(GTK_CONTAINER(temp_label_box), g->temp_label); - g_signal_connect(G_OBJECT(temp_label_box), "button-release-event", - G_CALLBACK(temp_label_click), self); + dt_gui_connect_click(temp_label_box, NULL, temp_label_click, self); //Match UI order: temp first, then tint (like every other app ever) g->scale_k = dt_bauhaus_slider_new_with_range_and_feedback From 8b7ab3e813d8ec5b6dcd5be3f5302e28300ecae2 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 00:05:08 -0300 Subject: [PATCH 09/95] gtk4-prep: resetlabel event controllers --- src/dtgtk/resetlabel.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/dtgtk/resetlabel.c b/src/dtgtk/resetlabel.c index 78198de16e0..195fcf17e86 100644 --- a/src/dtgtk/resetlabel.c +++ b/src/dtgtk/resetlabel.c @@ -17,6 +17,7 @@ */ #include "common/gdk_event_utils.h" +#include "gui/gtk.h" #include "dtgtk/resetlabel.h" G_DEFINE_TYPE(GtkDarktableResetLabel, dtgtk_reset_label, GTK_TYPE_EVENT_BOX); @@ -29,17 +30,20 @@ static void dtgtk_reset_label_init(GtkDarktableResetLabel *label) { } -static gboolean _reset_label_callback(GtkDarktableResetLabel *label, GdkEventButton *event, gpointer user_data) +static void _reset_label_callback(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, + gpointer user_data) { - if(dt_gdk_event_get_type(event) == GDK_2BUTTON_PRESS) + if(n_press >= 2) { + GtkDarktableResetLabel *label = DTGTK_RESET_LABEL(gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture))); memcpy(((char *)label->module->params) + label->offset, ((char *)label->module->default_params) + label->offset, label->size); dt_iop_gui_update(label->module); dt_dev_add_history_item(darktable.develop, label->module, FALSE); - return TRUE; } - return FALSE; } // public functions @@ -64,8 +68,7 @@ GtkWidget *dtgtk_reset_label_new(const gchar *text, dt_iop_module_t *module, voi gtk_event_box_set_visible_window(GTK_EVENT_BOX(label), FALSE); gtk_widget_set_tooltip_text(GTK_WIDGET(label), _("double-click to reset")); gtk_container_add(GTK_CONTAINER(label), GTK_WIDGET(label->lb)); - gtk_widget_add_events(GTK_WIDGET(label), GDK_BUTTON_PRESS_MASK); - g_signal_connect(G_OBJECT(label), "button-press-event", G_CALLBACK(_reset_label_callback), (gpointer)NULL); + dt_gui_connect_click(label, _reset_label_callback, NULL, NULL); return (GtkWidget *)label; } From f82bdf21bcb4b885cafb5fa6615adab2bcda6504 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 00:05:11 -0300 Subject: [PATCH 10/95] gtk4-prep: color_picker_proxy event controllers --- src/gui/color_picker_proxy.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/gui/color_picker_proxy.c b/src/gui/color_picker_proxy.c index 5d41713689e..da4f6999f4c 100644 --- a/src/gui/color_picker_proxy.c +++ b/src/gui/color_picker_proxy.c @@ -262,6 +262,16 @@ static void _color_picker_callback(GtkWidget *button, _color_picker_callback_button_press(button, NULL, self); } +static void _color_picker_clicked(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, + dt_iop_color_picker_t *self) +{ + GtkWidget *button = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + _color_picker_callback_button_press(button, NULL, self); +} + void dt_iop_color_picker_set_cst(dt_iop_module_t *module, const dt_iop_colorspace_type_t picker_cst) { @@ -401,9 +411,7 @@ static GtkWidget *_color_picker_new(dt_iop_module_t *module, color_picker->picker_cst = cst; color_picker->fixed_cst = TRUE; } - g_signal_connect_data(G_OBJECT(button), "button-press-event", - G_CALLBACK(_color_picker_callback_button_press), - color_picker, (GClosureNotify)_color_picker_destroy, 0); + dt_gui_connect_click(button, _color_picker_clicked, NULL, color_picker); if(w) gtk_box_pack_start(GTK_BOX(w), button, FALSE, FALSE, 0); return button; From 14cacb206262dc80f9692db4f7b6b2e7976ff4a9 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 00:05:14 -0300 Subject: [PATCH 11/95] gtk4-prep: filter widgets event controllers --- src/libs/filters/colors.c | 59 +++++++++++++++++++++++++++++++++++-- src/libs/filters/filename.c | 15 +++++----- src/libs/filters/misc.c | 19 +++++++----- 3 files changed, 75 insertions(+), 18 deletions(-) diff --git a/src/libs/filters/colors.c b/src/libs/filters/colors.c index b497d068bef..7ed06d8b40a 100644 --- a/src/libs/filters/colors.c +++ b/src/libs/filters/colors.c @@ -52,7 +52,8 @@ static void _set_mask(dt_lib_filtering_rule_t *rule , const int mask, const gboo g_free(txt); } -static gboolean _colors_clicked(GtkWidget *w, GdkEventButton *e, _widgets_colors_t *colors) +// kept for direct callers from accelerators +static gboolean _colors_clicked_old(GtkWidget *w, GdkEventButton *e, _widgets_colors_t *colors) { // double click reset the widget if(e->button == GDK_BUTTON_PRIMARY && e->type == GDK_2BUTTON_PRESS) @@ -102,6 +103,58 @@ static gboolean _colors_clicked(GtkWidget *w, GdkEventButton *e, _widgets_colors return FALSE; } +static void _colors_clicked_gesture(GtkGestureSingle *gesture, gint n_press, gdouble x, gdouble y, _widgets_colors_t *colors) +{ + GtkWidget *w = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + + // double click reset the widget + if(gtk_gesture_single_get_current_button(gesture) == GDK_BUTTON_PRIMARY && n_press >= 2) + { + _set_mask(colors->rule, CL_AND_MASK, TRUE); + _colors_update(colors->rule); + return; + } + + dt_lib_filtering_rule_t *rule = colors->rule; + const int mask = _get_mask(rule->raw_text); + const int k = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(w), "colors_index")); + const GdkModifierType state = dt_key_modifier_state(); + const int mask_k = (1 << k) | (1 << (k + 12)); + int new_mask = mask_k; + if(k == DT_COLORLABELS_LAST) + { + if(mask & mask_k) + new_mask = 0; + else if(state & GDK_CONTROL_MASK) + new_mask = CL_ALL_EXCLUDED | CL_GREY_EXCLUDED; + else + new_mask = CL_ALL_INCLUDED | CL_GREY_INCLUDED; + new_mask |= (mask & CL_AND_MASK); + } + else + { + if(mask & mask_k) + new_mask = 0; + else if(state & GDK_CONTROL_MASK) + new_mask = 1 << (k + 12); + else + new_mask = 1 << k; + new_mask |= (mask & ~mask_k); + } + + if((new_mask & CL_ALL_EXCLUDED) == CL_ALL_EXCLUDED) + new_mask |= CL_GREY_EXCLUDED; + else + new_mask &= ~CL_GREY_EXCLUDED; + if((new_mask & CL_ALL_INCLUDED) == CL_ALL_INCLUDED) + new_mask |= CL_GREY_INCLUDED; + else + new_mask &= ~CL_GREY_INCLUDED; + + _set_mask(colors->rule, new_mask, TRUE); + _colors_update(rule); +} + static void _colors_operator_clicked(GtkWidget *w, _widgets_colors_t *colors) { dt_lib_filtering_rule_t *rule = colors->rule; @@ -236,7 +289,7 @@ static float _action_process_colors(gpointer target, dt_action_element_t element && (mask || effect != DT_ACTION_EFFECT_OFF)) { if(element) - _colors_clicked(w, &e, colors); + _colors_clicked_old(w, &e, colors); else _colors_operator_clicked(w, colors); } @@ -295,7 +348,7 @@ static void _colors_widget_init(dt_lib_filtering_rule_t *rule, const dt_collecti "\nclick to toggle the color label selection" "\nctrl+click to exclude the color label" "\nthe gray button affects all color labels")); - g_signal_connect(G_OBJECT(colors->colors[k]), "button-press-event", G_CALLBACK(_colors_clicked), colors); + dt_gui_connect_click(colors->colors[k], _colors_clicked_gesture, NULL, colors); g_signal_connect(G_OBJECT(colors->colors[k]), "enter-notify-event", G_CALLBACK(_colors_enter_notify), GINT_TO_POINTER(k)); dt_action_define(DT_ACTION(self), N_("rules"), N_("color label"), colors->colors[k], &dt_action_def_colors_rule); diff --git a/src/libs/filters/filename.c b/src/libs/filters/filename.c index 95a91cbae1e..cd49a30a7b3 100644 --- a/src/libs/filters/filename.c +++ b/src/libs/filters/filename.c @@ -235,9 +235,11 @@ static void _filename_update_selection(_widgets_filename_t *filename) filename->internal_change--; } -static gboolean _filename_press(GtkWidget *w, GdkEventButton *e, _widgets_filename_t *filename) +static void _filename_press(GtkGestureSingle *gesture, gint n_press, gdouble x, gdouble y, _widgets_filename_t *filename) { - if(e->button == GDK_BUTTON_SECONDARY) + GtkWidget *w = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + + if(gtk_gesture_single_get_current_button(gesture) == GDK_BUTTON_SECONDARY) { _filename_tree_update_visibility(w, filename); gtk_popover_set_default_widget(GTK_POPOVER(filename->pop), w); @@ -247,14 +249,13 @@ static gboolean _filename_press(GtkWidget *w, GdkEventButton *e, _widgets_filena _filename_update_selection(filename); gtk_widget_show_all(filename->pop); - return TRUE; } - else if(e->button == GDK_BUTTON_PRIMARY && e->type == GDK_2BUTTON_PRESS) + else if(gtk_gesture_single_get_current_button(gesture) == GDK_BUTTON_PRIMARY + && n_press >= 2) { gtk_entry_set_text(GTK_ENTRY(w), ""); _filename_changed(w, filename); } - return FALSE; } static gboolean _filename_update(dt_lib_filtering_rule_t *rule) @@ -371,7 +372,7 @@ static void _filename_widget_init(dt_lib_filtering_rule_t *rule, const dt_collec gtk_box_pack_start(GTK_BOX(hb), filename->name, TRUE, TRUE, 0); g_signal_connect(G_OBJECT(filename->name), "activate", G_CALLBACK(_filename_changed), filename); g_signal_connect(G_OBJECT(filename->name), "focus-out-event", G_CALLBACK(_filename_focus_out), filename); - g_signal_connect(G_OBJECT(filename->name), "button-press-event", G_CALLBACK(_filename_press), filename); + dt_gui_connect_click(filename->name, _filename_press, NULL, filename); filename->ext = dt_ui_entry_new(top ? 5 : 0); gtk_widget_set_can_default(filename->ext, TRUE); @@ -383,7 +384,7 @@ static void _filename_widget_init(dt_lib_filtering_rule_t *rule, const dt_collec gtk_box_pack_start(GTK_BOX(hb), filename->ext, TRUE, TRUE, 0); g_signal_connect(G_OBJECT(filename->ext), "activate", G_CALLBACK(_filename_changed), filename); g_signal_connect(G_OBJECT(filename->ext), "focus-out-event", G_CALLBACK(_filename_focus_out), filename); - g_signal_connect(G_OBJECT(filename->ext), "button-press-event", G_CALLBACK(_filename_press), filename); + dt_gui_connect_click(filename->ext, _filename_press, NULL, filename); if(top) { dt_gui_add_class(hb, "dt_quick_filter"); diff --git a/src/libs/filters/misc.c b/src/libs/filters/misc.c index 2b6172bc932..a07ecc551c6 100644 --- a/src/libs/filters/misc.c +++ b/src/libs/filters/misc.c @@ -261,11 +261,15 @@ static void _misc_update_selection(_widgets_misc_t *misc) misc->internal_change--; } -static gboolean _misc_press(GtkWidget *w, - GdkEventButton *e, - _widgets_misc_t *misc) +static void _misc_press(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, + _widgets_misc_t *misc) { - if(e->button == GDK_BUTTON_SECONDARY) + GtkWidget *w = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + + if(gtk_gesture_single_get_current_button(gesture) == GDK_BUTTON_SECONDARY) { _misc_tree_update_visibility(w, misc); gtk_popover_set_default_widget(GTK_POPOVER(misc->pop), w); @@ -275,14 +279,13 @@ static gboolean _misc_press(GtkWidget *w, _misc_update_selection(misc); gtk_widget_show_all(misc->pop); - return TRUE; } - else if(e->button == GDK_BUTTON_PRIMARY && e->type == GDK_2BUTTON_PRESS) + else if(gtk_gesture_single_get_current_button(gesture) == GDK_BUTTON_PRIMARY + && n_press >= 2) { gtk_entry_set_text(GTK_ENTRY(misc->name), ""); _misc_changed(w, misc); } - return FALSE; } static gboolean _misc_update(dt_lib_filtering_rule_t *rule) @@ -459,7 +462,7 @@ static void _misc_widget_init(dt_lib_filtering_rule_t *rule, gtk_box_pack_start(GTK_BOX(hb), misc->name, TRUE, TRUE, 0); g_signal_connect(G_OBJECT(misc->name), "activate", G_CALLBACK(_misc_changed), misc); g_signal_connect(G_OBJECT(misc->name), "focus-out-event", G_CALLBACK(_misc_focus_out), misc); - g_signal_connect(G_OBJECT(misc->name), "button-press-event", G_CALLBACK(_misc_press), misc); + dt_gui_connect_click(misc->name, _misc_press, NULL, misc); if(top) { From 050bfe23a8eccf51697d69da28ef52cebc715cf4 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 00:05:18 -0300 Subject: [PATCH 12/95] gtk4-prep: lib module event controllers --- src/libs/duplicate.c | 32 +++++++++++----------- src/libs/history.c | 58 +++++++++++++++++++++------------------- src/libs/location.c | 21 +++++++-------- src/libs/map_locations.c | 32 +++++++++++++--------- src/libs/metadata_view.c | 8 +++--- src/libs/snapshots.c | 15 ++++++----- 6 files changed, 86 insertions(+), 80 deletions(-) diff --git a/src/libs/duplicate.c b/src/libs/duplicate.c index a0b054e5d3e..021a775fdd1 100644 --- a/src/libs/duplicate.c +++ b/src/libs/duplicate.c @@ -176,40 +176,42 @@ static void _lib_duplicate_delete(GtkButton *button, dt_lib_module_t *self) g_list_prepend(NULL, GINT_TO_POINTER(imgid))); } -static gboolean _lib_duplicate_thumb_press_callback(GtkWidget *widget, - GdkEventButton *event, - dt_lib_module_t *self) +static void _lib_duplicate_thumb_press_callback(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, + dt_lib_module_t *self) { dt_lib_duplicate_t *d = self->data; + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); dt_thumbnail_t *thumb = (dt_thumbnail_t *)g_object_get_data(G_OBJECT(widget), "thumb"); const dt_imgid_t imgid = thumb->imgid; - if(dt_gdk_event_get_button(event) == GDK_BUTTON_PRIMARY) + if(gtk_gesture_single_get_current_button(gesture) == GDK_BUTTON_PRIMARY) { - if(dt_gdk_event_get_type(event) == GDK_BUTTON_PRESS) + if(n_press == 1) { d->imgid = imgid; dt_control_queue_redraw_center(); } - else if(dt_gdk_event_get_type(event) == GDK_2BUTTON_PRESS) + else if(n_press >= 2) { // let's switch to the new image DT_CONTROL_SIGNAL_RAISE(DT_SIGNAL_VIEWMANAGER_THUMBTABLE_ACTIVATE, imgid); } } - return TRUE; } -static gboolean _lib_duplicate_thumb_release_callback(GtkWidget *widget, - GdkEventButton *event, - dt_lib_module_t *self) +static void _lib_duplicate_thumb_release_callback(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, + dt_lib_module_t *self) { dt_lib_duplicate_t *d = self->data; d->imgid = NO_IMGID; dt_control_queue_redraw_center(); - - return TRUE; } void view_leave(struct dt_lib_module_t *self, @@ -336,10 +338,8 @@ static void _lib_duplicate_init_callback(gpointer instance, dt_lib_module_t *sel if(imgid != dev->image_storage.id) { - g_signal_connect(G_OBJECT(thumb->w_main), "button-press-event", - G_CALLBACK(_lib_duplicate_thumb_press_callback), self); - g_signal_connect(G_OBJECT(thumb->w_main), "button-release-event", - G_CALLBACK(_lib_duplicate_thumb_release_callback), self); + dt_gui_connect_click(thumb->w_main, _lib_duplicate_thumb_press_callback, + _lib_duplicate_thumb_release_callback, self); } gchar chl[256]; diff --git a/src/libs/history.c b/src/libs/history.c index 4f181c05f01..792a6d9328d 100644 --- a/src/libs/history.c +++ b/src/libs/history.c @@ -71,13 +71,17 @@ typedef struct dt_lib_history_t static void _lib_history_compress_clicked_callback(GtkButton *widget, gpointer user_data); -static gboolean _lib_history_compress_pressed_callback(GtkWidget *widget, - GdkEventButton *e, - gpointer user_data); - -static gboolean _lib_history_button_clicked_callback(GtkWidget *widget, - GdkEventButton *e, - dt_lib_module_t *self); +static void _lib_history_compress_pressed_callback(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, + dt_lib_module_t *self); + +static void _lib_history_button_clicked_callback(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, + dt_lib_module_t *self); static void _lib_history_create_style_button_clicked_callback(GtkWidget *widget, gpointer user_data); @@ -140,8 +144,7 @@ void gui_init(dt_lib_module_t *self) (self, N_("compress history stack"), _lib_history_compress_clicked_callback, self, _("create a minimal history stack which produces the same image\n" "ctrl+click to truncate history to the selected item"), 0, 0); - g_signal_connect(G_OBJECT(d->compress_button), "button-press-event", - G_CALLBACK(_lib_history_compress_pressed_callback), self); + dt_gui_connect_click(d->compress_button, _lib_history_compress_pressed_callback, NULL, self); /* add toolbar button for creating style */ d->create_button = dtgtk_button_new(dtgtk_cairo_paint_styles, CPF_NONE, NULL); @@ -236,8 +239,7 @@ static GtkWidget *_lib_history_create_button(dt_lib_module_t *self, if(selected) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), TRUE); /* set callback when clicked */ - g_signal_connect(G_OBJECT(widget), "button-press-event", - G_CALLBACK(_lib_history_button_clicked_callback), self); + dt_gui_connect_click(widget, _lib_history_button_clicked_callback, NULL, self); /* associate the history number */ g_object_set_data(G_OBJECT(widget), "history-number", GINT_TO_POINTER(num + 1)); @@ -1241,31 +1243,34 @@ static void _lib_history_compress_clicked_callback(GtkButton *widget, gpointer u _lib_history_truncate(TRUE); } -static gboolean _lib_history_compress_pressed_callback(GtkWidget *widget, - GdkEventButton *e, - gpointer user_data) +static void _lib_history_compress_pressed_callback(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, + dt_lib_module_t *self) { - const gboolean compress = !dt_modifier_is(e->state, GDK_CONTROL_MASK); + const gboolean compress = !(dt_key_modifier_state() & GDK_CONTROL_MASK); _lib_history_truncate(compress); - - return TRUE; } -static gboolean _lib_history_button_clicked_callback(GtkWidget *widget, - GdkEventButton *e, - dt_lib_module_t *self) +static void _lib_history_button_clicked_callback(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, + dt_lib_module_t *self) { + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); const dt_imgid_t imgid = darktable.develop->image_storage.id; - if(!dt_is_valid_imgid(imgid)) return FALSE; + if(!dt_is_valid_imgid(imgid)) return; static gboolean reset = FALSE; - if(reset) return FALSE; + if(reset) return; - if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) return FALSE; + if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) return; // shift-click just show the corresponding module in modulegroups - if(dt_modifier_is(e->state, GDK_SHIFT_MASK)) + if(dt_key_modifier_state() & GDK_SHIFT_MASK) { const int num = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "history-number")); dt_dev_history_item_t *hist = g_list_nth_data(darktable.develop->history, num - 1); @@ -1274,7 +1279,7 @@ static gboolean _lib_history_button_clicked_callback(GtkWidget *widget, dt_dev_modulegroups_switch(darktable.develop, hist->module); dt_iop_gui_set_expanded(hist->module, TRUE, TRUE); } - return TRUE; + return; } dt_lib_history_t *d = self->data; @@ -1292,7 +1297,7 @@ static gboolean _lib_history_button_clicked_callback(GtkWidget *widget, g_list_free(children); reset = FALSE; - DT_GUARD_GUI_UPDATE(FALSE); + if(dt_atomic_get_int(&darktable.gui->reset) != 0) return; dt_dev_undo_start_record(darktable.develop); @@ -1310,7 +1315,6 @@ static gboolean _lib_history_button_clicked_callback(GtkWidget *widget, dt_iop_connect_accels_all(); dt_dev_modulegroups_set(darktable.develop, dt_dev_modulegroups_get(darktable.develop)); - return FALSE; } static void _lib_history_create_style_button_clicked_callback(GtkWidget *widget, diff --git a/src/libs/location.c b/src/libs/location.c index 225353e6af0..c09fdc888c6 100644 --- a/src/libs/location.c +++ b/src/libs/location.c @@ -156,16 +156,16 @@ void gui_cleanup(dt_lib_module_t *self) self->data = NULL; } -static gboolean _event_box_enter_leave(GtkWidget *widget, - GdkEventCrossing *event, - gpointer user_data) +static void _event_box_enter(GtkEventControllerMotion *controller, gdouble x, gdouble y, gpointer user_data) { - if(dt_gdk_event_get_type(event) == GDK_ENTER_NOTIFY) - gtk_widget_set_state_flags(widget, GTK_STATE_FLAG_PRELIGHT, FALSE); - else - gtk_widget_unset_state_flags(widget, GTK_STATE_FLAG_PRELIGHT); + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); + gtk_widget_set_state_flags(widget, GTK_STATE_FLAG_PRELIGHT, FALSE); +} - return FALSE; +static void _event_box_leave(GtkEventControllerMotion *controller, gpointer user_data) +{ + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); + gtk_widget_unset_state_flags(widget, GTK_STATE_FLAG_PRELIGHT); } static GtkWidget *_lib_location_place_widget_new(dt_lib_location_t *lib, @@ -174,10 +174,7 @@ static GtkWidget *_lib_location_place_widget_new(dt_lib_location_t *lib, GtkWidget *eb, *vb, *w; eb = gtk_event_box_new(); gtk_widget_set_name(eb, "dt-map-location"); - g_signal_connect(G_OBJECT(eb), "enter-notify-event", - G_CALLBACK(_event_box_enter_leave), NULL); - g_signal_connect(G_OBJECT(eb), "leave-notify-event", - G_CALLBACK(_event_box_enter_leave), NULL); + dt_gui_connect_motion(eb, NULL, _event_box_enter, _event_box_leave, NULL); vb = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); diff --git a/src/libs/map_locations.c b/src/libs/map_locations.c index d0ebe63e79b..f1618b07ac0 100644 --- a/src/libs/map_locations.c +++ b/src/libs/map_locations.c @@ -831,42 +831,47 @@ static void _selection_changed(GtkTreeSelection *selection, dt_lib_module_t *sel _display_buttons(self); } -static gboolean _click_on_view(GtkWidget *view, GdkEventButton *event, dt_lib_module_t *self) +static void _click_on_view(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, + dt_lib_module_t *self) { dt_lib_map_locations_t *d = self->data; + GtkWidget *view = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); gboolean editing; g_object_get(G_OBJECT(d->renderer), "editing", &editing, NULL); if(editing) { dt_control_log(_("terminate edit (press enter or escape) before selecting another location")); - return TRUE; + return; } - const int button_pressed = (dt_gdk_event_get_type(event) == GDK_BUTTON_PRESS) ? dt_gdk_event_get_button(event) : 0; - const gboolean ctrl_pressed = dt_modifier_is(dt_gdk_event_get_state(event), GDK_CONTROL_MASK); + const guint button_pressed = gtk_gesture_single_get_current_button(gesture); + const gboolean ctrl_pressed = dt_key_modifier_state() & GDK_CONTROL_MASK; if(button_pressed == GDK_BUTTON_SECONDARY || button_pressed == GDK_BUTTON_PRIMARY) { GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(view)); GtkTreePath *path = NULL; // Get tree path for row that was clicked - if(gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(view), (gint)dt_gdk_event_get_x(event), - (gint)dt_gdk_event_get_y(event), &path, NULL, NULL, NULL)) + if(gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(view), (gint)x, + (gint)y, &path, NULL, NULL, NULL)) { if(button_pressed == GDK_BUTTON_SECONDARY) { gtk_tree_selection_select_path(selection, path); - _pop_menu_view(view, event, self); + _pop_menu_view(view, NULL, self); gtk_tree_path_free(path); _display_buttons(self); - return TRUE; + return; } else if(button_pressed == GDK_BUTTON_PRIMARY && !ctrl_pressed) { if(gtk_tree_selection_path_is_selected(selection, path)) g_timeout_add(100, (GSourceFunc)_force_selection_changed, self); gtk_tree_path_free(path); - return FALSE; + return; } else if(button_pressed == GDK_BUTTON_PRIMARY && ctrl_pressed) { @@ -875,18 +880,19 @@ static gboolean _click_on_view(GtkWidget *view, GdkEventButton *event, dt_lib_mo gtk_tree_view_set_cursor(GTK_TREE_VIEW(d->view), path, d->name_col, TRUE); gtk_tree_path_free(path); _display_buttons(self); - return TRUE; + return; } } else { g_timeout_add(10, (GSourceFunc)_force_selection_changed, self); - return FALSE; + return; } } - return FALSE; } +void gui_init + void gui_init(dt_lib_module_t *self) { dt_lib_map_locations_t *d = g_malloc0(sizeof(dt_lib_map_locations_t)); @@ -921,7 +927,7 @@ void gui_init(dt_lib_module_t *self) gtk_tree_selection_set_mode(selection, GTK_SELECTION_SINGLE); gtk_tree_view_set_model(view, GTK_TREE_MODEL(treestore)); g_object_unref(treestore); - g_signal_connect(G_OBJECT(view), "button-press-event", G_CALLBACK(_click_on_view), self); + dt_gui_connect_click(view, _click_on_view, NULL, self); gtk_widget_set_tooltip_text(GTK_WIDGET(view), _("list of user locations," "\nclick to show or hide a location on the map:" diff --git a/src/libs/metadata_view.c b/src/libs/metadata_view.c index ed0c4ecb7cd..4354ab110a9 100644 --- a/src/libs/metadata_view.c +++ b/src/libs/metadata_view.c @@ -1154,11 +1154,10 @@ static void _jump_to() } } -static gboolean _filmroll_clicked(GtkWidget *widget, GdkEventButton *event, gpointer null) +static void _filmroll_clicked(GtkGestureSingle *gesture, gint n_press, gdouble x, gdouble y, gpointer null) { - if(dt_gdk_event_get_type(event) != GDK_2BUTTON_PRESS) return FALSE; + if(n_press < 2) return; _jump_to(); - return TRUE; } static void _jump_to_accel(dt_action_t *data) @@ -1219,8 +1218,7 @@ static void _lib_metadata_refill_grid(dt_lib_module_t *self) if(d->filmroll_event && GTK_IS_WIDGET(d->filmroll_event)) g_signal_handlers_disconnect_by_func(d->filmroll_event, G_CALLBACK(_filmroll_clicked), NULL); - g_signal_connect(G_OBJECT(w_value), "button-press-event", - G_CALLBACK(_filmroll_clicked), NULL); + dt_gui_connect_click(w_value, _filmroll_clicked, NULL, NULL); d->filmroll_event = G_OBJECT(w_value); } diff --git a/src/libs/snapshots.c b/src/libs/snapshots.c index 18cec1fa392..ae25f49dce7 100644 --- a/src/libs/snapshots.c +++ b/src/libs/snapshots.c @@ -562,15 +562,18 @@ static void _entry_activated_callback(GtkEntry *entry, dt_lib_module_t *self) gtk_widget_grab_focus(d->snapshot[index].button); } -static gboolean _lib_button_button_pressed_callback(GtkWidget *widget, - GdkEventButton *event, - dt_lib_module_t *self) +static void _lib_button_button_pressed_callback(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, + dt_lib_module_t *self) { dt_lib_snapshots_t *d = self->data; + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); const int index = _look_for_widget(self, widget, FALSE); - if(dt_modifier_is(dt_gdk_event_get_state(event), GDK_CONTROL_MASK)) + if(dt_key_modifier_state() & GDK_CONTROL_MASK) { gtk_widget_hide(d->snapshot[index].name); gtk_widget_show(d->snapshot[index].entry); @@ -578,7 +581,6 @@ static gboolean _lib_button_button_pressed_callback(GtkWidget *widget, } gtk_widget_set_focus_on_click(widget, FALSE); - return gtk_widget_has_focus(d->snapshot[index].entry); } static void _init_snapshot_entry(dt_lib_module_t *self, @@ -589,8 +591,7 @@ static void _init_snapshot_entry(dt_lib_module_t *self, gtk_widget_set_name(s->button, "snapshot-button"); g_signal_connect(G_OBJECT(s->button), "toggled", G_CALLBACK(_lib_snapshots_toggled_callback), self); - g_signal_connect(G_OBJECT(s->button), "button-press-event", - G_CALLBACK(_lib_button_button_pressed_callback), self); + dt_gui_connect_click(s->button, _lib_button_button_pressed_callback, NULL, self); s->num = gtk_label_new(""); gtk_widget_set_name(s->num, "history-number"); From c171fc94ea0bbc145aeea54ac315733e6eac9ede Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 00:05:21 -0300 Subject: [PATCH 13/95] gtk4-prep: toolbar event controllers --- src/libs/tools/darktable.c | 20 +++++++++++--------- src/libs/tools/filter.c | 10 +++++++--- src/libs/tools/global_toolbox.c | 30 ++++++++++++++++-------------- 3 files changed, 34 insertions(+), 26 deletions(-) diff --git a/src/libs/tools/darktable.c b/src/libs/tools/darktable.c index b954ba96795..ef19ebd0b3b 100644 --- a/src/libs/tools/darktable.c +++ b/src/libs/tools/darktable.c @@ -55,9 +55,11 @@ static gboolean _lib_darktable_draw_callback(GtkWidget *widget, cairo_t *cr, dt_lib_module_t *self); /* button press callback */ -static gboolean _lib_darktable_button_press_callback(GtkWidget *widget, - GdkEventButton *event, - dt_lib_module_t *self); +static void _lib_darktable_clicked(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, + dt_lib_module_t *self); const char *name(dt_lib_module_t *self) { @@ -96,8 +98,7 @@ void gui_init(dt_lib_module_t *self) /* connect callbacks */ g_signal_connect(G_OBJECT(self->widget), "draw", G_CALLBACK(_lib_darktable_draw_callback), self); - g_signal_connect(G_OBJECT(self->widget), "button-press-event", - G_CALLBACK(_lib_darktable_button_press_callback), self); + dt_gui_connect_click(self->widget, _lib_darktable_clicked, NULL, self); /* create a cairo surface of dt icon */ @@ -275,13 +276,14 @@ static gboolean _lib_darktable_draw_callback(GtkWidget *widget, return TRUE; } -static gboolean _lib_darktable_button_press_callback(GtkWidget *widget, - GdkEventButton *event, - dt_lib_module_t *self) +static void _lib_darktable_clicked(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, + dt_lib_module_t *self) { /* show about box */ darktable_show_about_dialog(); - return TRUE; } // clang-format off diff --git a/src/libs/tools/filter.c b/src/libs/tools/filter.c index 1274619849a..93f747098df 100644 --- a/src/libs/tools/filter.c +++ b/src/libs/tools/filter.c @@ -85,10 +85,14 @@ static GtkWidget *_lib_filter_get_count(dt_lib_module_t *self) return d->count; } -static gboolean _pref_show(GtkWidget *widget, GdkEventButton *event, dt_lib_module_t *self) +static void _pref_show(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, + dt_lib_module_t *self) { + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); dt_view_filtering_show_pref_menu(darktable.view_manager, widget); - return TRUE; } void gui_init(dt_lib_module_t *self) @@ -102,7 +106,7 @@ void gui_init(dt_lib_module_t *self) GtkWidget *bt = dtgtk_button_new(dtgtk_cairo_paint_filtering_menu, 0, NULL); gtk_widget_set_tooltip_text(bt, _("filter preferences")); - g_signal_connect(G_OBJECT(bt), "button-press-event", G_CALLBACK(_pref_show), self); + dt_gui_connect_click(bt, _pref_show, NULL, self); gtk_box_pack_start(GTK_BOX(self->widget), bt, FALSE, TRUE, 0); d->filter_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); diff --git a/src/libs/tools/global_toolbox.c b/src/libs/tools/global_toolbox.c index ca92f0a4fb5..7d961b4f8cf 100644 --- a/src/libs/tools/global_toolbox.c +++ b/src/libs/tools/global_toolbox.c @@ -54,7 +54,8 @@ static void _lib_preferences_button_clicked(GtkWidget *widget, gpointer user_dat static void _lib_help_button_clicked(GtkWidget *widget, gpointer user_data); /* callbacks for key mapping button */ static void _lib_keymap_button_clicked(GtkWidget *widget, gpointer user_data); -static gboolean _lib_keymap_button_press_release(GtkWidget *button, GdkEventButton *event, gpointer user_data); +static void _lib_keymap_button_pressed(GtkGestureSingle *gesture, gint n_press, gdouble x, gdouble y, gpointer user_data); +static void _lib_keymap_button_released(GtkGestureSingle *gesture, gint n_press, gdouble x, gdouble y, gpointer user_data); const char *name(dt_lib_module_t *self) { @@ -502,8 +503,7 @@ void gui_init(dt_lib_module_t *self) "\n" "right-click to exit mapping mode")); g_signal_connect(G_OBJECT(d->keymap_button), "clicked", G_CALLBACK(_lib_keymap_button_clicked), d); - g_signal_connect(G_OBJECT(d->keymap_button), "button-press-event", G_CALLBACK(_lib_keymap_button_press_release), d); - g_signal_connect(G_OBJECT(d->keymap_button), "button-release-event", G_CALLBACK(_lib_keymap_button_press_release), d); + dt_gui_connect_click(d->keymap_button, _lib_keymap_button_pressed, _lib_keymap_button_released, (gpointer)(d)); // the rest of these is added in reverse order as they are always put at the end of the container. // that's done so that buttons added via Lua will come first. @@ -792,26 +792,28 @@ static void _lib_keymap_button_clicked(GtkWidget *widget, gpointer user_data) } } -static gboolean _lib_keymap_button_press_release(GtkWidget *button, GdkEventButton *event, gpointer user_data) +static void _lib_keymap_button_pressed(GtkGestureSingle *gesture, gint n_press, gdouble x, gdouble y, gpointer user_data) { - static guint start_time = 0; + darktable.control->confirm_mapping = !(dt_key_modifier_state() & GDK_CONTROL_MASK); - darktable.control->confirm_mapping = !dt_modifier_is(dt_gdk_event_get_state(event), GDK_CONTROL_MASK); + if(gtk_gesture_single_get_current_button(gesture) == GDK_BUTTON_SECONDARY) + { + _show_shortcuts_prefs(NULL); + } +} +static void _lib_keymap_button_released(GtkGestureSingle *gesture, gint n_press, gdouble x, gdouble y, gpointer user_data) +{ + static guint start_time = 0; + guint current_time = gtk_get_current_event_time(); int delay = 0; g_object_get(gtk_settings_get_default(), "gtk-long-press-time", &delay, NULL); - if((dt_gdk_event_get_type(event) == GDK_BUTTON_PRESS && dt_gdk_event_get_button(event) == GDK_BUTTON_SECONDARY) || - (dt_gdk_event_get_type(event) == GDK_BUTTON_RELEASE && dt_gdk_event_get_time(event) - start_time > delay)) + if(current_time - start_time > (guint)delay) { _show_shortcuts_prefs(NULL); - return TRUE; - } - else - { - start_time = dt_gdk_event_get_time(event); - return FALSE; } + start_time = current_time; } #ifdef USE_LUA From 3a3fa7b8d1f41b90e376c5dc767844356a3f09e7 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 00:17:41 -0300 Subject: [PATCH 14/95] gtk4-prep: fix scroll mask regression in colorequal and toneequal Restore the scroll event masks that were removed when cleaning up gtk_widget_add_events() calls during the event controller conversion. Both widgets still use the old g_signal_connect('scroll-event', ...) for event forwarding (colorequal forwards to notebook/sliders, tonequal controls propagation), which requires GDK_SCROLL_MASK in the widget's event mask to function. --- src/iop/colorequal.c | 1 + src/iop/toneequal.c | 1 + 2 files changed, 2 insertions(+) diff --git a/src/iop/colorequal.c b/src/iop/colorequal.c index 31f9c1f82ba..96b2c40320e 100644 --- a/src/iop/colorequal.c +++ b/src/iop/colorequal.c @@ -2976,6 +2976,7 @@ void gui_init(dt_iop_module_t *self) g_signal_connect(G_OBJECT(g->area), "draw", G_CALLBACK(_iop_colorequalizer_draw), self); dt_gui_connect_click_all(g->area, _area_button_press_callback, _area_button_release_callback, self); dt_gui_connect_motion(g->area, _area_motion_notify_callback, NULL, NULL, self); + gtk_widget_add_events(GTK_WIDGET(g->area), darktable.gui->scroll_mask); g_signal_connect(G_OBJECT(g->area), "scroll-event", G_CALLBACK(_area_scrolled_callback), self); g_signal_connect(G_OBJECT(g->area), "size-allocate", diff --git a/src/iop/toneequal.c b/src/iop/toneequal.c index 26db2cbbf47..8d5ec7734de 100644 --- a/src/iop/toneequal.c +++ b/src/iop/toneequal.c @@ -3275,6 +3275,7 @@ void gui_init(dt_iop_module_t *self) g_signal_connect(G_OBJECT(g->area), "draw", G_CALLBACK(area_draw), self); dt_gui_connect_click(g->area, area_button_press, area_button_release, self); dt_gui_connect_motion(g->area, area_motion_notify, NULL, area_leave_notify, self); + gtk_widget_add_events(GTK_WIDGET(g->area), darktable.gui->scroll_mask); g_signal_connect(G_OBJECT(g->area), "scroll-event", G_CALLBACK(area_scroll), self); gtk_widget_set_tooltip_text(GTK_WIDGET(g->area), _("double-click to reset the curve")); From b645f22c4b811529a1a50836aa3e8050a56daaa7 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 00:17:45 -0300 Subject: [PATCH 15/95] gtk4-prep: fix code style issues in event-controller conversions - Properly indent closing brace in tonecurve.c secondary-button handler - Add missing newline before closing brace in colorzones.c - Remove stray duplicate void gui_init line in map_locations.c --- src/iop/colorzones.c | 3 ++- src/iop/tonecurve.c | 4 ++-- src/libs/map_locations.c | 2 -- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/iop/colorzones.c b/src/iop/colorzones.c index 4aed5b4b9a5..7fc40bbdb4d 100644 --- a/src/iop/colorzones.c +++ b/src/iop/colorzones.c @@ -1773,7 +1773,8 @@ static gboolean _move_point_internal(dt_iop_module_t *self, gtk_widget_queue_draw(widget); - return TRUE;} + return TRUE; +} static void _delete_node(dt_iop_module_t *self, dt_iop_colorzones_node_t *curve, diff --git a/src/iop/tonecurve.c b/src/iop/tonecurve.c index 1e4fe8a1127..caef05148ab 100644 --- a/src/iop/tonecurve.c +++ b/src/iop/tonecurve.c @@ -1945,7 +1945,7 @@ static void dt_iop_tonecurve_button_press(GtkGestureSingle *gesture, tonecurve[g->selected].y = tonecurve[g->selected].x = reset_value; gtk_widget_queue_draw(GTK_WIDGET(g->area)); dt_dev_add_history_item_target(darktable.develop, self, TRUE, widget + ch); -} + } for(int k = g->selected; k < nodes - 1; k++) { @@ -1957,7 +1957,7 @@ static void dt_iop_tonecurve_button_press(GtkGestureSingle *gesture, p->tonecurve_nodes[ch]--; gtk_widget_queue_draw(GTK_WIDGET(g->area)); dt_dev_add_history_item_target(darktable.develop, self, TRUE, widget + ch); -} + } } // clang-format off diff --git a/src/libs/map_locations.c b/src/libs/map_locations.c index f1618b07ac0..24ac6004a2b 100644 --- a/src/libs/map_locations.c +++ b/src/libs/map_locations.c @@ -891,8 +891,6 @@ static void _click_on_view(GtkGestureSingle *gesture, } } -void gui_init - void gui_init(dt_lib_module_t *self) { dt_lib_map_locations_t *d = g_malloc0(sizeof(dt_lib_map_locations_t)); From 8cbcc524b625891ea664ec8b31836e98f94351e0 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 00:17:49 -0300 Subject: [PATCH 16/95] gtk4-prep: update copyright years for modified files Update copyright end-year to 2026 in files touched by event controller conversion that still had outdated ranges. --- src/libs/filters/colors.c | 2 +- src/libs/filters/filename.c | 2 +- src/libs/filters/misc.c | 2 +- src/libs/tools/filter.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libs/filters/colors.c b/src/libs/filters/colors.c index 7ed06d8b40a..e366fe4a0cc 100644 --- a/src/libs/filters/colors.c +++ b/src/libs/filters/colors.c @@ -1,6 +1,6 @@ /* This file is part of darktable, - Copyright (C) 2022 darktable developers. + Copyright (C) 2022-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 diff --git a/src/libs/filters/filename.c b/src/libs/filters/filename.c index cd49a30a7b3..da7655462f1 100644 --- a/src/libs/filters/filename.c +++ b/src/libs/filters/filename.c @@ -1,6 +1,6 @@ /* This file is part of darktable, - Copyright (C) 2022 darktable developers. + Copyright (C) 2022-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 diff --git a/src/libs/filters/misc.c b/src/libs/filters/misc.c index a07ecc551c6..fc18805bcf8 100644 --- a/src/libs/filters/misc.c +++ b/src/libs/filters/misc.c @@ -1,6 +1,6 @@ /* This file is part of darktable, - Copyright (C) 2024 darktable developers. + Copyright (C) 2024-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 diff --git a/src/libs/tools/filter.c b/src/libs/tools/filter.c index 93f747098df..0fd692968e1 100644 --- a/src/libs/tools/filter.c +++ b/src/libs/tools/filter.c @@ -1,6 +1,6 @@ /* This file is part of darktable, - Copyright (C) 2011-2022 darktable developers. + Copyright (C) 2011-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 From 9bfc904677919dff014872c53fa865892a4f752f Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 00:41:34 -0300 Subject: [PATCH 17/95] gtk4-prep: convert thumbnail event signals to event controllers --- src/dtgtk/thumbnail.c | 296 ++++++++++++++++++------------------------ 1 file changed, 126 insertions(+), 170 deletions(-) diff --git a/src/dtgtk/thumbnail.c b/src/dtgtk/thumbnail.c index 16d300b1021..cdbe41067e5 100644 --- a/src/dtgtk/thumbnail.c +++ b/src/dtgtk/thumbnail.c @@ -15,7 +15,6 @@ You should have received a copy of the GNU General Public License along with darktable. If not, see . */ -#include "common/gdk_event_utils.h" /** this is the thumbnail class for the lighttable module. */ #include "common/extra_optimizations.h" @@ -1025,38 +1024,41 @@ static void _thumbs_show_overlays(dt_thumbnail_t *thumb) } } -static gboolean _event_main_motion(GtkWidget *widget, - GdkEventMotion *event, - gpointer user_data) +static void _event_main_motion_cb(GtkEventControllerMotion *controller, + gdouble x, + gdouble y, + dt_thumbnail_t *thumb) { - if(!user_data) return TRUE; - dt_thumbnail_t *thumb = (dt_thumbnail_t *)user_data; + if(!thumb) return; // first, we hide the block overlays after a delay if the mouse hasn't move _thumbs_show_overlays(thumb); if(!thumb->mouse_over && !thumb->disable_mouseover) dt_control_set_mouse_over_id(thumb->imgid); - return FALSE; } -static gboolean _event_rating_press(GtkWidget *widget, - GdkEventButton *event, - gpointer user_data) +static void _event_rating_press_cb(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, + dt_thumbnail_t *thumb) { - return TRUE; + // claims the click via the gesture } -static gboolean _event_rating_release(GtkWidget *widget, - GdkEventButton *event, - gpointer user_data) +static void _event_rating_release_cb(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, + dt_thumbnail_t *thumb) { - dt_thumbnail_t *thumb = (dt_thumbnail_t *)user_data; + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); if(thumb->disable_actions) - return FALSE; + return; if(dtgtk_thumbnail_btn_is_hidden(widget)) - return FALSE; + return; - if(dt_gdk_event_get_button(event) == GDK_BUTTON_PRIMARY && !thumb->moved) + if(!thumb->moved) { dt_view_image_over_t rating = DT_VIEW_DESERT; if(widget == thumb->w_reject) @@ -1081,25 +1083,28 @@ static gboolean _event_rating_release(GtkWidget *widget, g_list_prepend(NULL, GINT_TO_POINTER(thumb->imgid))); } } - return TRUE; } -static gboolean _event_grouping_release(GtkWidget *widget, - GdkEventButton *event, - gpointer user_data) +static void _event_grouping_release_cb(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, + dt_thumbnail_t *thumb) { - dt_thumbnail_t *thumb = (dt_thumbnail_t *)user_data; + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); if(thumb->disable_actions) - return FALSE; + return; if(dtgtk_thumbnail_btn_is_hidden(widget)) - return FALSE; + return; - if(dt_gdk_event_get_button(event) == GDK_BUTTON_PRIMARY && !thumb->moved) + if(!thumb->moved) { + GdkModifierType state; + gtk_get_current_event_state(&state); //TODO: will succeed if either or *both* of Shift and Control are //pressed. Do we want this? - if(dt_modifier_is(dt_gdk_event_get_state(event), GDK_SHIFT_MASK) - | dt_modifier_is(dt_gdk_event_get_state(event), GDK_CONTROL_MASK)) + if(dt_modifier_is(state, GDK_SHIFT_MASK) + | dt_modifier_is(state, GDK_CONTROL_MASK)) { // just add the whole group to the selection. TODO: make this // also work for collapsed groups. @@ -1131,20 +1136,21 @@ static gboolean _event_grouping_release(GtkWidget *widget, DT_COLLECTION_PROP_UNDEF, NULL); } - return FALSE; } -static gboolean _event_audio_release(GtkWidget *widget, - GdkEventButton *event, - gpointer user_data) +static void _event_audio_release_cb(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, + dt_thumbnail_t *thumb) { - dt_thumbnail_t *thumb = (dt_thumbnail_t *)user_data; + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); if(thumb->disable_actions) - return FALSE; + return; if(dtgtk_thumbnail_btn_is_hidden(widget)) - return FALSE; + return; - if(dt_gdk_event_get_button(event) == GDK_BUTTON_PRIMARY && !thumb->moved) + if(!thumb->moved) { gboolean start_audio = TRUE; if(darktable.view_manager->audio.audio_player_id != -1) @@ -1160,7 +1166,6 @@ static gboolean _event_audio_release(GtkWidget *widget, dt_view_audio_start(darktable.view_manager, thumb->imgid); } } - return FALSE; } // this is called each time the images info change @@ -1308,69 +1313,81 @@ static void _dt_mipmaps_updated_callback(gpointer instance, gtk_widget_queue_draw(thumb->w_main); } -static gboolean _event_box_enter_leave(GtkWidget *widget, - GdkEventCrossing *event, - gpointer user_data) +static void _event_box_enter_cb(GtkEventControllerMotion *controller, + gdouble x, + gdouble y, + dt_thumbnail_t *thumb) { - dt_thumbnail_t *thumb = (dt_thumbnail_t *)user_data; + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); - if(dt_gdk_event_get_type(event) == GDK_ENTER_NOTIFY && !thumb->disable_mouseover) + if(!thumb->disable_mouseover) dt_control_set_mouse_over_id(thumb->imgid); - _set_flag(widget, GTK_STATE_FLAG_PRELIGHT, (dt_gdk_event_get_type(event) == GDK_ENTER_NOTIFY)); - _set_flag(thumb->w_image_box, GTK_STATE_FLAG_PRELIGHT, - (dt_gdk_event_get_type(event) == GDK_ENTER_NOTIFY)); - return FALSE; + _set_flag(widget, GTK_STATE_FLAG_PRELIGHT, TRUE); + _set_flag(thumb->w_image_box, GTK_STATE_FLAG_PRELIGHT, TRUE); } -static gboolean _event_image_enter_leave(GtkWidget *widget, - GdkEventCrossing *event, - gpointer user_data) +static void _event_box_leave_cb(GtkEventControllerMotion *controller, + dt_thumbnail_t *thumb) { - dt_thumbnail_t *thumb = (dt_thumbnail_t *)user_data; + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); - if(dt_gdk_event_get_type(event) == GDK_ENTER_NOTIFY && !thumb->disable_mouseover) + _set_flag(widget, GTK_STATE_FLAG_PRELIGHT, FALSE); + _set_flag(thumb->w_image_box, GTK_STATE_FLAG_PRELIGHT, FALSE); +} + +static void _event_image_enter_cb(GtkEventControllerMotion *controller, + gdouble x, + gdouble y, + dt_thumbnail_t *thumb) +{ + if(!thumb->disable_mouseover) dt_control_set_mouse_over_id(thumb->imgid); - _set_flag(thumb->w_image_box, GTK_STATE_FLAG_PRELIGHT, - (dt_gdk_event_get_type(event) == GDK_ENTER_NOTIFY)); - return FALSE; + _set_flag(thumb->w_image_box, GTK_STATE_FLAG_PRELIGHT, TRUE); } -static gboolean _event_btn_enter_leave(GtkWidget *widget, - GdkEventCrossing *event, - gpointer user_data) +static void _event_image_leave_cb(GtkEventControllerMotion *controller, + dt_thumbnail_t *thumb) { - dt_thumbnail_t *thumb = (dt_thumbnail_t *)user_data; + _set_flag(thumb->w_image_box, GTK_STATE_FLAG_PRELIGHT, FALSE); +} - if(dt_gdk_event_get_type(event) == GDK_ENTER_NOTIFY) - { - if(widget == thumb->w_reject) - darktable.control->element = DT_VIEW_REJECT; +static void _event_btn_enter_cb(GtkEventControllerMotion *controller, + gdouble x, + gdouble y, + dt_thumbnail_t *thumb) +{ + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); - if(thumb->disable_actions) - return TRUE; + if(widget == thumb->w_reject) + darktable.control->element = DT_VIEW_REJECT; - if(!thumb->disable_mouseover) - dt_control_set_mouse_over_id(thumb->imgid); - _set_flag(thumb->w_image_box, GTK_STATE_FLAG_PRELIGHT, TRUE); - _thumb_update_tags_tooltip(thumb); - } - else if(dt_gdk_event_get_type(event) == GDK_LEAVE_NOTIFY) - { - if(widget == thumb->w_reject) - darktable.control->element = -1; - } + if(thumb->disable_actions) + return; - return FALSE; + if(!thumb->disable_mouseover) + dt_control_set_mouse_over_id(thumb->imgid); + _set_flag(thumb->w_image_box, GTK_STATE_FLAG_PRELIGHT, TRUE); + _thumb_update_tags_tooltip(thumb); } -static gboolean _event_star_enter(GtkWidget *widget, - GdkEventCrossing *event, - gpointer user_data) +static void _event_btn_leave_cb(GtkEventControllerMotion *controller, + dt_thumbnail_t *thumb) { - dt_thumbnail_t *thumb = (dt_thumbnail_t *)user_data; - if(thumb->disable_actions) return TRUE; + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); + + if(widget == thumb->w_reject) + darktable.control->element = -1; +} + +static void _event_star_enter_cb(GtkEventControllerMotion *controller, + gdouble x, + gdouble y, + dt_thumbnail_t *thumb) +{ + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); + if(thumb->disable_actions) return; if(!thumb->disable_mouseover) dt_control_set_mouse_over_id(thumb->imgid); @@ -1390,21 +1407,18 @@ static gboolean _event_star_enter(GtkWidget *widget, pre = FALSE; } } - return TRUE; } -static gboolean _event_star_leave(GtkWidget *widget, - GdkEventCrossing *event, - gpointer user_data) + +static void _event_star_leave_cb(GtkEventControllerMotion *controller, + dt_thumbnail_t *thumb) { - dt_thumbnail_t *thumb = (dt_thumbnail_t *)user_data; - if(thumb->disable_actions) return TRUE; + if(thumb->disable_actions) return; for(int i = 0; i < MAX_STARS; i++) { _set_flag(thumb->w_stars[i], GTK_STATE_FLAG_PRELIGHT, FALSE); gtk_widget_queue_draw(thumb->w_stars[i]); } - return TRUE; } // we only want to specify that the mouse is hovereing the thumbnail @@ -1415,7 +1429,14 @@ static gboolean _event_main_drag_motion(GtkWidget *widget, const guint time, gpointer user_data) { - _event_main_motion(widget, NULL, user_data); + if(user_data) + { + dt_thumbnail_t *thumb = (dt_thumbnail_t *)user_data; + _thumbs_show_overlays(thumb); + + if(!thumb->mouse_over && !thumb->disable_mouseover) + dt_control_set_mouse_over_id(thumb->imgid); + } return TRUE; } @@ -1476,14 +1497,8 @@ GtkWidget *dt_thumbnail_create_widget(dt_thumbnail_t *thumb, // the background thumb->w_back = gtk_event_box_new(); - gtk_widget_set_events(thumb->w_back, - GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - | GDK_STRUCTURE_MASK - | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK - | GDK_POINTER_MOTION_MASK); gtk_widget_set_name(thumb->w_back, "thumb-back"); - g_signal_connect(G_OBJECT(thumb->w_back), "motion-notify-event", - G_CALLBACK(_event_main_motion), thumb); + dt_gui_connect_motion(thumb->w_back, _event_main_motion_cb, NULL, NULL, thumb); gtk_widget_show(thumb->w_back); gtk_container_add(GTK_CONTAINER(thumb->w_main), thumb->w_back); @@ -1509,16 +1524,7 @@ GtkWidget *dt_thumbnail_create_widget(dt_thumbnail_t *thumb, GtkWidget *evt_image = gtk_event_box_new(); gtk_widget_set_valign(evt_image, GTK_ALIGN_FILL); gtk_widget_set_halign(evt_image, GTK_ALIGN_FILL); - gtk_widget_set_events(evt_image, GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - | GDK_STRUCTURE_MASK - | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK - | GDK_POINTER_MOTION_MASK); - g_signal_connect(G_OBJECT(evt_image), "motion-notify-event", - G_CALLBACK(_event_main_motion), thumb); - g_signal_connect(G_OBJECT(evt_image), "enter-notify-event", - G_CALLBACK(_event_image_enter_leave), thumb); - g_signal_connect(G_OBJECT(evt_image), "leave-notify-event", - G_CALLBACK(_event_image_enter_leave), thumb); + dt_gui_connect_motion(evt_image, _event_main_motion_cb, _event_image_enter_cb, _event_image_leave_cb, thumb); gtk_widget_show(evt_image); gtk_overlay_add_overlay(GTK_OVERLAY(thumb->w_image_box), evt_image); thumb->w_image = gtk_drawing_area_new(); @@ -1526,18 +1532,9 @@ GtkWidget *dt_thumbnail_create_widget(dt_thumbnail_t *thumb, gtk_widget_set_valign(thumb->w_image, GTK_ALIGN_CENTER); gtk_widget_set_halign(thumb->w_image, GTK_ALIGN_CENTER); // the size will be defined at the end, inside dt_thumbnail_resize - gtk_widget_set_events(thumb->w_image, GDK_BUTTON_PRESS_MASK - | GDK_BUTTON_RELEASE_MASK | GDK_STRUCTURE_MASK - | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK - | GDK_POINTER_MOTION_MASK); g_signal_connect(G_OBJECT(thumb->w_image), "draw", G_CALLBACK(_event_image_draw), thumb); - g_signal_connect(G_OBJECT(thumb->w_image), "motion-notify-event", - G_CALLBACK(_event_main_motion), thumb); - g_signal_connect(G_OBJECT(thumb->w_image), "enter-notify-event", - G_CALLBACK(_event_image_enter_leave), thumb); - g_signal_connect(G_OBJECT(thumb->w_image), "leave-notify-event", - G_CALLBACK(_event_image_enter_leave), thumb); + dt_gui_connect_motion(thumb->w_image, _event_main_motion_cb, _event_image_enter_cb, _event_image_leave_cb, thumb); g_signal_connect(G_OBJECT(thumb->w_image), "style-updated", G_CALLBACK(_event_image_style_updated), thumb); gtk_widget_show(thumb->w_image); @@ -1561,12 +1558,7 @@ GtkWidget *dt_thumbnail_create_widget(dt_thumbnail_t *thumb, // the infos background thumb->w_bottom_eb = gtk_event_box_new(); gtk_widget_set_name(thumb->w_bottom_eb, "thumb-bottom"); - g_signal_connect(G_OBJECT(thumb->w_bottom_eb), "enter-notify-event", - G_CALLBACK(_event_box_enter_leave), - thumb); - g_signal_connect(G_OBJECT(thumb->w_bottom_eb), "leave-notify-event", - G_CALLBACK(_event_box_enter_leave), - thumb); + dt_gui_connect_motion(thumb->w_bottom_eb, NULL, _event_box_enter_cb, _event_box_leave_cb, thumb); gtk_widget_set_valign(thumb->w_bottom_eb, GTK_ALIGN_END); gtk_widget_set_halign(thumb->w_bottom_eb, GTK_ALIGN_CENTER); gtk_widget_show(thumb->w_bottom_eb); @@ -1600,29 +1592,16 @@ GtkWidget *dt_thumbnail_create_widget(dt_thumbnail_t *thumb, gtk_widget_set_valign(thumb->w_reject, GTK_ALIGN_END); gtk_widget_set_halign(thumb->w_reject, GTK_ALIGN_START); gtk_widget_show(thumb->w_reject); - g_signal_connect(G_OBJECT(thumb->w_reject), "button-press-event", - G_CALLBACK(_event_rating_press), thumb); - g_signal_connect(G_OBJECT(thumb->w_reject), "button-release-event", - G_CALLBACK(_event_rating_release), thumb); - g_signal_connect(G_OBJECT(thumb->w_reject), "enter-notify-event", - G_CALLBACK(_event_btn_enter_leave), thumb); - g_signal_connect(G_OBJECT(thumb->w_reject), "leave-notify-event", - G_CALLBACK(_event_btn_enter_leave), thumb); + dt_gui_connect_click(thumb->w_reject, _event_rating_press_cb, _event_rating_release_cb, thumb); + dt_gui_connect_motion(thumb->w_reject, NULL, _event_btn_enter_cb, _event_btn_leave_cb, thumb); gtk_overlay_add_overlay(GTK_OVERLAY(overlays_parent), thumb->w_reject); // the stars for(int i = 0; i < MAX_STARS; i++) { thumb->w_stars[i] = dtgtk_thumbnail_btn_new(dtgtk_cairo_paint_star, 0, NULL); - g_signal_connect(G_OBJECT(thumb->w_stars[i]), "enter-notify-event", - G_CALLBACK(_event_star_enter), thumb); - g_signal_connect(G_OBJECT(thumb->w_stars[i]), "leave-notify-event", - G_CALLBACK(_event_star_leave), thumb); - g_signal_connect(G_OBJECT(thumb->w_stars[i]), "button-press-event", - G_CALLBACK(_event_rating_press), thumb); - g_signal_connect(G_OBJECT(thumb->w_stars[i]), "button-release-event", - G_CALLBACK(_event_rating_release), - thumb); + dt_gui_connect_click(thumb->w_stars[i], _event_rating_press_cb, _event_rating_release_cb, thumb); + dt_gui_connect_motion(thumb->w_stars[i], NULL, _event_star_enter_cb, _event_star_leave_cb, thumb); gtk_widget_set_name(thumb->w_stars[i], "thumb-star"); dt_action_define(&darktable.control->actions_thumb, NULL, "rating", thumb->w_stars[i], &dt_action_def_rating); @@ -1641,10 +1620,7 @@ GtkWidget *dt_thumbnail_create_widget(dt_thumbnail_t *thumb, gtk_widget_set_valign(thumb->w_color, GTK_ALIGN_END); gtk_widget_set_halign(thumb->w_color, GTK_ALIGN_END); gtk_widget_set_no_show_all(thumb->w_color, TRUE); - g_signal_connect(G_OBJECT(thumb->w_color), "enter-notify-event", - G_CALLBACK(_event_btn_enter_leave), thumb); - g_signal_connect(G_OBJECT(thumb->w_color), "leave-notify-event", - G_CALLBACK(_event_btn_enter_leave), thumb); + dt_gui_connect_motion(thumb->w_color, NULL, _event_btn_enter_cb, _event_btn_leave_cb, thumb); gtk_overlay_add_overlay(GTK_OVERLAY(overlays_parent), thumb->w_color); // the local copy indicator @@ -1654,12 +1630,7 @@ GtkWidget *dt_thumbnail_create_widget(dt_thumbnail_t *thumb, gtk_widget_set_valign(thumb->w_local_copy, GTK_ALIGN_START); gtk_widget_set_halign(thumb->w_local_copy, GTK_ALIGN_END); gtk_widget_set_no_show_all(thumb->w_local_copy, TRUE); - g_signal_connect(G_OBJECT(thumb->w_local_copy), "enter-notify-event", - G_CALLBACK(_event_btn_enter_leave), - thumb); - g_signal_connect(G_OBJECT(thumb->w_local_copy), "leave-notify-event", - G_CALLBACK(_event_btn_enter_leave), - thumb); + dt_gui_connect_motion(thumb->w_local_copy, NULL, _event_btn_enter_cb, _event_btn_leave_cb, thumb); gtk_overlay_add_overlay(GTK_OVERLAY(overlays_parent), thumb->w_local_copy); // the altered icon @@ -1668,10 +1639,7 @@ GtkWidget *dt_thumbnail_create_widget(dt_thumbnail_t *thumb, gtk_widget_set_valign(thumb->w_altered, GTK_ALIGN_START); gtk_widget_set_halign(thumb->w_altered, GTK_ALIGN_END); gtk_widget_set_no_show_all(thumb->w_altered, TRUE); - g_signal_connect(G_OBJECT(thumb->w_altered), "enter-notify-event", - G_CALLBACK(_event_btn_enter_leave), thumb); - g_signal_connect(G_OBJECT(thumb->w_altered), "leave-notify-event", - G_CALLBACK(_event_btn_enter_leave), thumb); + dt_gui_connect_motion(thumb->w_altered, NULL, _event_btn_enter_cb, _event_btn_leave_cb, thumb); gtk_overlay_add_overlay(GTK_OVERLAY(overlays_parent), thumb->w_altered); // the tags icon @@ -1680,21 +1648,14 @@ GtkWidget *dt_thumbnail_create_widget(dt_thumbnail_t *thumb, gtk_widget_set_valign(thumb->w_tags, GTK_ALIGN_START); gtk_widget_set_halign(thumb->w_tags, GTK_ALIGN_END); gtk_widget_set_no_show_all(thumb->w_tags, TRUE); - g_signal_connect(G_OBJECT(thumb->w_tags), "enter-notify-event", - G_CALLBACK(_event_btn_enter_leave), thumb); - g_signal_connect(G_OBJECT(thumb->w_tags), "leave-notify-event", - G_CALLBACK(_event_btn_enter_leave), thumb); + dt_gui_connect_motion(thumb->w_tags, NULL, _event_btn_enter_cb, _event_btn_leave_cb, thumb); gtk_overlay_add_overlay(GTK_OVERLAY(overlays_parent), thumb->w_tags); // the group bouton thumb->w_group = dtgtk_thumbnail_btn_new(dtgtk_cairo_paint_grouping, 0, NULL); gtk_widget_set_name(thumb->w_group, "thumb-group-audio"); - g_signal_connect(G_OBJECT(thumb->w_group), "button-release-event", - G_CALLBACK(_event_grouping_release), thumb); - g_signal_connect(G_OBJECT(thumb->w_group), "enter-notify-event", - G_CALLBACK(_event_btn_enter_leave), thumb); - g_signal_connect(G_OBJECT(thumb->w_group), "leave-notify-event", - G_CALLBACK(_event_btn_enter_leave), thumb); + dt_gui_connect_click(thumb->w_group, _event_rating_press_cb, _event_grouping_release_cb, thumb); + dt_gui_connect_motion(thumb->w_group, NULL, _event_btn_enter_cb, _event_btn_leave_cb, thumb); gtk_widget_set_valign(thumb->w_group, GTK_ALIGN_START); gtk_widget_set_halign(thumb->w_group, GTK_ALIGN_END); gtk_widget_set_no_show_all(thumb->w_group, TRUE); @@ -1703,12 +1664,8 @@ GtkWidget *dt_thumbnail_create_widget(dt_thumbnail_t *thumb, // the sound icon thumb->w_audio = dtgtk_thumbnail_btn_new(dtgtk_cairo_paint_audio, 0, NULL); gtk_widget_set_name(thumb->w_audio, "thumb-group-audio"); - g_signal_connect(G_OBJECT(thumb->w_audio), "button-release-event", - G_CALLBACK(_event_audio_release), thumb); - g_signal_connect(G_OBJECT(thumb->w_audio), "enter-notify-event", - G_CALLBACK(_event_btn_enter_leave), thumb); - g_signal_connect(G_OBJECT(thumb->w_audio), "leave-notify-event", - G_CALLBACK(_event_btn_enter_leave), thumb); + dt_gui_connect_click(thumb->w_audio, _event_rating_press_cb, _event_audio_release_cb, thumb); + dt_gui_connect_motion(thumb->w_audio, NULL, _event_btn_enter_cb, _event_btn_leave_cb, thumb); gtk_widget_set_valign(thumb->w_audio, GTK_ALIGN_START); gtk_widget_set_halign(thumb->w_audio, GTK_ALIGN_END); gtk_widget_set_no_show_all(thumb->w_audio, TRUE); @@ -1716,8 +1673,7 @@ GtkWidget *dt_thumbnail_create_widget(dt_thumbnail_t *thumb, // the zoom indicator thumb->w_zoom_eb = gtk_event_box_new(); - g_signal_connect(G_OBJECT(thumb->w_zoom_eb), "enter-notify-event", - G_CALLBACK(_event_btn_enter_leave), thumb); + dt_gui_connect_motion(thumb->w_zoom_eb, NULL, _event_btn_enter_cb, NULL, thumb); gtk_widget_set_name(thumb->w_zoom_eb, "thumb-zoom"); gtk_widget_set_valign(thumb->w_zoom_eb, GTK_ALIGN_START); gtk_widget_set_halign(thumb->w_zoom_eb, GTK_ALIGN_START); From 8618ccd8e8af99ae329558f895295e4f45da5bf1 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 00:45:03 -0300 Subject: [PATCH 18/95] gtk4-prep: convert lib module event signals to event controllers --- src/libs/lib.c | 133 ++++++++++++++++++++++++------------------------- 1 file changed, 66 insertions(+), 67 deletions(-) diff --git a/src/libs/lib.c b/src/libs/lib.c index ac184700f84..1734132c0e9 100644 --- a/src/libs/lib.c +++ b/src/libs/lib.c @@ -964,28 +964,34 @@ void _lib_unload_module(dt_lib_module_t *module) g_module_close(module->module); } -static gboolean _lib_gui_reset_callback(GtkButton *button, - GdkEventButton *e, - gpointer user_data) +static void _lib_gui_reset_callback(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, + dt_lib_module_t *module) { - dt_lib_module_t *module = (dt_lib_module_t *)user_data; module->gui_reset(module); if(module->has_preset_label(module)) gtk_label_set_text(GTK_LABEL(module->preset_label), ""); - return TRUE; } -static gboolean _presets_popup_callback(GtkButton *button, - GdkEventButton *e, - dt_lib_module_t *module) +static void _presets_popup_callback(GtkWidget *button, + dt_lib_module_t *module) { dt_lib_module_info_t *mi = _get_module_info_for_module(module); - _dt_lib_presets_popup_menu_show(mi, GTK_WIDGET(button)); + _dt_lib_presets_popup_menu_show(mi, button); if(button) dtgtk_button_set_active(DTGTK_BUTTON(button), FALSE); +} - return TRUE; +static void _presets_popup_gesture_cb(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, + dt_lib_module_t *module) +{ + _presets_popup_callback(gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)), module); } void dt_lib_gui_set_expanded(dt_lib_module_t *module, const gboolean expanded) @@ -1029,24 +1035,27 @@ gboolean dt_lib_gui_get_expanded(dt_lib_module_t *module) return dtgtk_expander_get_expanded(DTGTK_EXPANDER(module->expander)); } -static gboolean _lib_plugin_arrow_button_press(GtkWidget *w, - GdkEventButton *e, - gpointer user_data) +static void _lib_plugin_arrow_button_press_cb(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, + dt_lib_module_t *module) { - if(e->type == GDK_2BUTTON_PRESS || e->type == GDK_3BUTTON_PRESS) return TRUE; + if(n_press > 1) return; + const guint button = gtk_gesture_single_get_button(gesture); + GdkModifierType state; + gtk_get_current_event_state(&state); - dt_lib_module_t *module = (dt_lib_module_t *)user_data; - - if(e->button == GDK_BUTTON_PRIMARY) + if(button == GDK_BUTTON_PRIMARY) { /* bail out if module is static */ - if(!module->expandable(module)) return FALSE; + if(!module->expandable(module)) return; - if(dt_modifier_is(e->state, GDK_SHIFT_MASK | GDK_CONTROL_MASK)) + if(dt_modifier_is(state, GDK_SHIFT_MASK | GDK_CONTROL_MASK)) ; // do nothing (for easier dragging) /* handle shiftclick on expander, hide all except this */ else if(!dt_conf_get_bool("lighttable/ui/single_module") != - !dt_modifier_is(e->state, GDK_SHIFT_MASK)) + !dt_modifier_is(state, GDK_SHIFT_MASK)) { const dt_view_t *v = dt_view_manager_get_current_view(darktable.view_manager); const uint32_t side = dt_lib_get_container(module); @@ -1082,24 +1091,24 @@ static gboolean _lib_plugin_arrow_button_press(GtkWidget *w, //ensure that any gtkentry fields lose focus gtk_widget_grab_focus(dt_ui_center(darktable.gui->ui)); - return TRUE; + return; } - else if(e->button == GDK_BUTTON_SECONDARY) + else if(button == GDK_BUTTON_SECONDARY) { if(gtk_widget_get_sensitive(module->presets_button)) - _presets_popup_callback(NULL, NULL, module); + _presets_popup_callback(NULL, module); - return TRUE; + return; } - return FALSE; } -static gboolean _lib_plugin_header_button_release(GtkWidget *w, - GdkEventButton *e, - gpointer user_data) +static void _lib_plugin_header_button_release_cb(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, + dt_lib_module_t *module) { - if(GTK_IS_BUTTON(gtk_get_event_widget((GdkEvent*)e))) return FALSE; - return _lib_plugin_arrow_button_press(w, e, user_data); + _lib_plugin_arrow_button_press_cb(gesture, n_press, x, y, module); } static void show_module_callback(dt_lib_module_t *module) @@ -1140,23 +1149,28 @@ static void show_module_callback(dt_lib_module_t *module) } } -static gboolean _header_enter_notify_callback(GtkWidget *eventbox, - GdkEventCrossing *event, - gpointer user_data) +static void _header_enter_notify_callback(GtkEventControllerMotion *controller, + gdouble x, + gdouble y, + gpointer user_data) { darktable.control->element = GPOINTER_TO_INT(user_data); - return FALSE; } -static gboolean _body_enter_leave_callback(GtkWidget *widget, - GdkEventCrossing *e, - gpointer user_data) +static void _body_enter_callback(GtkEventControllerMotion *controller, + gdouble x, + gdouble y, + dt_lib_module_t *module) { - // set or clear focused module when entering or leaving (not when opening popup) - if(e->detail != GDK_NOTIFY_INFERIOR && e->mode == GDK_CROSSING_NORMAL) - darktable.lib->gui_module = e->type == GDK_ENTER_NOTIFY ? user_data : NULL; + // set focused module when entering (not when opening popup) + darktable.lib->gui_module = module; +} - return FALSE; +static void _body_leave_callback(GtkEventControllerMotion *controller, + dt_lib_module_t *module) +{ + // clear focused module when leaving + darktable.lib->gui_module = NULL; } static gboolean _on_drag_motion(GtkWidget *widget, @@ -1278,8 +1292,7 @@ GtkWidget *dt_lib_gui_get_expander(dt_lib_module_t *module) // FIXME separately define as darkroom widget shortcut/action, // because not automatically registered via lib if presets btn // has been loaded to be shown outside expander - g_signal_connect(G_OBJECT(module->presets_button), "button-press-event", - G_CALLBACK(_presets_popup_callback), module); + dt_gui_connect_click(module->presets_button, _presets_popup_gesture_cb, NULL, module); } module->expander = NULL; return NULL; @@ -1305,18 +1318,11 @@ GtkWidget *dt_lib_gui_get_expander(dt_lib_module_t *module) } /* setup the header box */ - g_signal_connect(G_OBJECT(header_evb), "button-release-event", - G_CALLBACK(_lib_plugin_header_button_release), - module); - g_signal_connect(G_OBJECT(header_evb), "enter-notify-event", - G_CALLBACK(_header_enter_notify_callback), - GINT_TO_POINTER(DT_ACTION_ELEMENT_SHOW)); + dt_gui_connect_click(header_evb, _lib_plugin_arrow_button_press_cb, _lib_plugin_header_button_release_cb, module); + dt_gui_connect_motion(header_evb, NULL, _header_enter_notify_callback, NULL, GINT_TO_POINTER(DT_ACTION_ELEMENT_SHOW)); /* (un)focus module when entering/leaving body */ - g_signal_connect(G_OBJECT(body_evb), "enter-notify-event", - G_CALLBACK(_body_enter_leave_callback), module); - g_signal_connect(G_OBJECT(body_evb), "leave-notify-event", - G_CALLBACK(_body_enter_leave_callback), module); + dt_gui_connect_motion(body_evb, NULL, _body_enter_callback, _body_leave_callback, module); /* * initialize the header widgets @@ -1325,8 +1331,7 @@ GtkWidget *dt_lib_gui_get_expander(dt_lib_module_t *module) module->arrow = dtgtk_button_new(dtgtk_cairo_paint_solid_arrow, 0, NULL); gtk_widget_set_tooltip_text(module->arrow, _("show module")); - g_signal_connect(G_OBJECT(module->arrow), "button-press-event", - G_CALLBACK(_lib_plugin_arrow_button_press), module); + dt_gui_connect_click_all(module->arrow, _lib_plugin_arrow_button_press_cb, NULL, module); dt_action_define(&module->actions, NULL, NULL, module->arrow, NULL); gtk_box_pack_start(GTK_BOX(header), module->arrow, FALSE, FALSE, 0); @@ -1358,11 +1363,8 @@ GtkWidget *dt_lib_gui_get_expander(dt_lib_module_t *module) /* add preset button if module has implementation */ module->presets_button = dtgtk_button_new(dtgtk_cairo_paint_presets, 0, NULL); gtk_widget_set_tooltip_text(module->presets_button, _("presets and preferences")); - g_signal_connect(G_OBJECT(module->presets_button), "button-press-event", - G_CALLBACK(_presets_popup_callback), module); - g_signal_connect(G_OBJECT(module->presets_button), "enter-notify-event", - G_CALLBACK(_header_enter_notify_callback), - GINT_TO_POINTER(DT_ACTION_ELEMENT_PRESETS)); + dt_gui_connect_click(module->presets_button, _lib_gui_reset_callback, _presets_popup_gesture_cb, module); + dt_gui_connect_motion(module->presets_button, NULL, _header_enter_notify_callback, NULL, GINT_TO_POINTER(DT_ACTION_ELEMENT_PRESETS)); if(!module->get_params && !module->set_preferences) gtk_widget_set_sensitive(GTK_WIDGET(module->presets_button), FALSE); @@ -1372,11 +1374,8 @@ GtkWidget *dt_lib_gui_get_expander(dt_lib_module_t *module) /* add reset button if module has implementation */ module->reset_button = dtgtk_button_new(dtgtk_cairo_paint_reset, 0, NULL); - g_signal_connect(G_OBJECT(module->reset_button), "button-press-event", - G_CALLBACK(_lib_gui_reset_callback), module); - g_signal_connect(G_OBJECT(module->reset_button), "enter-notify-event", - G_CALLBACK(_header_enter_notify_callback), - GINT_TO_POINTER(DT_ACTION_ELEMENT_RESET)); + dt_gui_connect_click(module->reset_button, _lib_gui_reset_callback, NULL, module); + dt_gui_connect_motion(module->reset_button, NULL, _header_enter_notify_callback, NULL, GINT_TO_POINTER(DT_ACTION_ELEMENT_RESET)); if(!module->gui_reset) gtk_widget_set_sensitive(module->reset_button, FALSE); dt_action_define(&module->actions, NULL, NULL, module->reset_button, NULL); gtk_box_pack_end(GTK_BOX(header), module->reset_button, FALSE, FALSE, 0); @@ -1712,11 +1711,11 @@ static float _action_process(gpointer target, break; case DT_ACTION_ELEMENT_RESET: if(module->gui_reset) - _lib_gui_reset_callback(NULL, NULL, module); + _lib_gui_reset_callback(NULL, 1, 0.0, 0.0, module); break; case DT_ACTION_ELEMENT_PRESETS: if(module->get_params || module->set_preferences) - _presets_popup_callback(NULL, NULL, module); + _presets_popup_callback(module->presets_button, module); break; } } From b2d6f364d9e073c1138c208fd8b9dc07349c9ea9 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 00:47:27 -0300 Subject: [PATCH 19/95] gtk4-prep: convert colorpicker event signals to event controllers --- src/libs/colorpicker.c | 76 +++++++++++++++--------------------------- 1 file changed, 26 insertions(+), 50 deletions(-) diff --git a/src/libs/colorpicker.c b/src/libs/colorpicker.c index dcb68aec120..a06f19b2b45 100644 --- a/src/libs/colorpicker.c +++ b/src/libs/colorpicker.c @@ -270,17 +270,17 @@ static void _update_picker_output(dt_lib_module_t *self) darktable.lib->proxy.colorpicker.picker_proxy != NULL); } -static gboolean _large_patch_toggle(GtkWidget *widget, - GdkEvent *event, - dt_lib_colorpicker_t *data) +static void _large_patch_toggle_cb(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, + dt_lib_colorpicker_t *data) { const gboolean show_large_patch = !dt_conf_get_bool("ui_last/colorpicker_large"); dt_conf_set_bool("ui_last/colorpicker_large", show_large_patch); gtk_widget_set_visible(gtk_widget_get_parent(data->large_color_patch), show_large_patch); - - return FALSE; } static void _picker_button_toggled(GtkToggleButton *button, @@ -474,9 +474,10 @@ static void _label_size_allocate_callback(GtkWidget *widget, } } -static gboolean _sample_enter_callback(GtkWidget *widget, - GdkEvent *event, - dt_colorpicker_sample_t *sample) +static void _sample_enter_callback(GtkEventControllerMotion *controller, + gdouble x, + gdouble y, + dt_colorpicker_sample_t *sample) { darktable.lib->proxy.colorpicker.selected_sample = sample; @@ -484,16 +485,11 @@ static gboolean _sample_enter_callback(GtkWidget *widget, dt_dev_invalidate_all(darktable.develop); dt_control_queue_redraw_center(); - - return FALSE; } -static gboolean _sample_leave_callback(GtkWidget *widget, - GdkEvent *event, - gpointer data) +static void _sample_leave_callback(GtkEventControllerMotion *controller, + dt_colorpicker_sample_t *sample) { - if(event->crossing.detail == GDK_NOTIFY_INFERIOR) return FALSE; - if(darktable.lib->proxy.colorpicker.selected_sample) { darktable.lib->proxy.colorpicker.selected_sample = NULL; @@ -502,8 +498,6 @@ static gboolean _sample_leave_callback(GtkWidget *widget, dt_control_queue_redraw_center(); } - - return FALSE; } static void _remove_sample(dt_colorpicker_sample_t *sample) @@ -521,16 +515,20 @@ static void _remove_sample_cb(GtkButton *widget, dt_dev_invalidate_all(darktable.develop); } -static gboolean _live_sample_button(GtkWidget *widget, - GdkEventButton *event, - dt_colorpicker_sample_t *sample) +static void _live_sample_button_cb(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, + dt_colorpicker_sample_t *sample) { - if(dt_gdk_event_get_button(event) == GDK_BUTTON_PRIMARY) + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + const guint button = gtk_gesture_single_get_button(gesture); + if(button == GDK_BUTTON_PRIMARY) { sample->locked = !sample->locked; gtk_widget_queue_draw(widget); } - else if(dt_gdk_event_get_button(event) == GDK_BUTTON_SECONDARY) + else if(button == GDK_BUTTON_SECONDARY) { // copy to active picker dt_lib_module_t *self = darktable.lib->proxy.colorpicker.module; @@ -592,7 +590,6 @@ static gboolean _live_sample_button(GtkWidget *widget, } dt_control_queue_redraw_center(); } - return FALSE; } static void _add_sample(GtkButton *widget, @@ -616,22 +613,15 @@ static void _add_sample(GtkButton *widget, sample->copied = FALSE; sample->container = gtk_event_box_new(); - gtk_widget_add_events(sample->container, - GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK); - g_signal_connect(G_OBJECT(sample->container), "enter-notify-event", - G_CALLBACK(_sample_enter_callback), sample); - g_signal_connect(G_OBJECT(sample->container), "leave-notify-event", - G_CALLBACK(_sample_leave_callback), sample); + dt_gui_connect_motion(sample->container, NULL, _sample_enter_callback, _sample_leave_callback, sample); sample->color_patch = gtk_drawing_area_new(); - gtk_widget_add_events(sample->color_patch, GDK_BUTTON_PRESS_MASK); gtk_widget_set_tooltip_text (sample->color_patch, _("hover to highlight sample on canvas,\n" "click to lock sample,\n" "right-click to load sample area into active color picker")); - g_signal_connect(G_OBJECT(sample->color_patch), "button-press-event", - G_CALLBACK(_live_sample_button), sample); + dt_gui_connect_click_all(sample->color_patch, _live_sample_button_cb, NULL, sample); g_signal_connect(G_OBJECT(sample->color_patch), "draw", G_CALLBACK(_sample_draw_callback), sample); @@ -734,18 +724,10 @@ void gui_init(dt_lib_module_t *self) GtkWidget *color_patch = gtk_drawing_area_new(); data->large_color_patch = color_patch; gtk_widget_set_tooltip_text(color_patch, _("click to (un)hide large color patch")); - gtk_widget_set_events(color_patch, - GDK_BUTTON_PRESS_MASK - | GDK_ENTER_NOTIFY_MASK - | GDK_LEAVE_NOTIFY_MASK); g_signal_connect(G_OBJECT(color_patch), "draw", G_CALLBACK(_sample_draw_callback), &data->primary_sample); - g_signal_connect(G_OBJECT(color_patch), "button-press-event", - G_CALLBACK(_large_patch_toggle), data); - g_signal_connect(G_OBJECT(color_patch), "enter-notify-event", - G_CALLBACK(_sample_enter_callback), &data->primary_sample); - g_signal_connect(G_OBJECT(color_patch), "leave-notify-event", - G_CALLBACK(_sample_leave_callback), &data->primary_sample); + dt_gui_connect_click(color_patch, _large_patch_toggle_cb, NULL, data); + dt_gui_connect_motion(color_patch, NULL, _sample_enter_callback, _sample_leave_callback, &data->primary_sample); GtkWidget *color_patch_wrapper = dt_gui_hbox(dt_gui_expand(color_patch)); gtk_widget_set_name(GTK_WIDGET(color_patch_wrapper), "color-picker-area"); gtk_widget_show(color_patch); @@ -786,17 +768,11 @@ void gui_init(dt_lib_module_t *self) // The small sample, label and add button GtkWidget *sample_row_events = gtk_event_box_new(); - gtk_widget_add_events(sample_row_events, GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK); - g_signal_connect(G_OBJECT(sample_row_events), "enter-notify-event", - G_CALLBACK(_sample_enter_callback), &data->primary_sample); - g_signal_connect(G_OBJECT(sample_row_events), "leave-notify-event", - G_CALLBACK(_sample_leave_callback), &data->primary_sample); + dt_gui_connect_motion(sample_row_events, NULL, _sample_enter_callback, _sample_leave_callback, &data->primary_sample); data->primary_sample.color_patch = color_patch = gtk_drawing_area_new(); gtk_widget_set_tooltip_text(color_patch, _("click to (un)hide large color patch")); - gtk_widget_set_events(color_patch, GDK_BUTTON_PRESS_MASK); - g_signal_connect(G_OBJECT(color_patch), "button-press-event", - G_CALLBACK(_large_patch_toggle), data); + dt_gui_connect_click(color_patch, _large_patch_toggle_cb, NULL, data); g_signal_connect(G_OBJECT(color_patch), "draw", G_CALLBACK(_sample_draw_callback), &data->primary_sample); From 283517f399ec6ac3b0e58a948967355bcc9034df Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 00:55:31 -0300 Subject: [PATCH 20/95] gtk4-prep: convert darkroom view event signals to event controllers --- src/views/darkroom.c | 198 ++++++++++++++++++++----------------------- 1 file changed, 94 insertions(+), 104 deletions(-) diff --git a/src/views/darkroom.c b/src/views/darkroom.c index 60170072eca..1c3143642c2 100644 --- a/src/views/darkroom.c +++ b/src/views/darkroom.c @@ -2768,38 +2768,41 @@ const dt_action_def_t _action_def_move _action_elements_move, NULL, TRUE }; -static gboolean _quickbutton_press_release(GtkWidget *button, - GdkEventButton *event, - GtkWidget *popover) +static void _quickbutton_pressed_cb(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, + GtkWidget *popover) { - static guint start_time = 0; + GtkWidget *button = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); - int delay = 0; - g_object_get(gtk_settings_get_default(), "gtk-long-press-time", &delay, NULL); - - if((dt_gdk_event_get_type(event) == GDK_BUTTON_PRESS && dt_gdk_event_get_button(event) == GDK_BUTTON_SECONDARY) || - (dt_gdk_event_get_type(event) == GDK_BUTTON_RELEASE && dt_gdk_event_get_time(event) - start_time > delay)) + /* secondary click: show popup immediately */ + if(gtk_gesture_single_get_button(gesture) == GDK_BUTTON_SECONDARY) { gtk_popover_set_relative_to(GTK_POPOVER(popover), button); - g_object_set(G_OBJECT(popover), "transitions-enabled", FALSE, NULL); - _toolbar_show_popup(popover); - return TRUE; } - else +} + +static void _quickbutton_released_cb(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, + GtkWidget *popover) +{ + /* primary button long-press: show popup */ + if(gtk_gesture_single_get_button(gesture) == GDK_BUTTON_PRIMARY) { - start_time = dt_gdk_event_get_time(event); - return FALSE; + int delay = 0; + g_object_get(gtk_settings_get_default(), "gtk-long-press-time", &delay, NULL); + _toolbar_show_popup(popover); } } void connect_button_press_release(GtkWidget *w, GtkWidget *p) { - g_signal_connect(w, "button-press-event", - G_CALLBACK(_quickbutton_press_release), p); - g_signal_connect(w, "button-release-event", - G_CALLBACK(_quickbutton_press_release), p); + dt_gui_connect_click_all(w, _quickbutton_pressed_cb, _quickbutton_released_cb, p); } // cycle modules begins @@ -4989,82 +4992,90 @@ static gboolean _second_window_draw_callback(GtkWidget *widget, return TRUE; } -static gboolean _second_window_scrolled_callback(GtkWidget *widget, - GdkEventScroll *event, - dt_develop_t *dev) +static void _second_window_scrolled_callback(GtkEventControllerScroll *controller, + gdouble dx, + gdouble dy, + dt_develop_t *dev) { - if(dev->gui_leaving) return TRUE; - int delta_y; - if(dt_gui_get_scroll_unit_delta(event, &delta_y)) - { - // Use pinned viewport if pinned, otherwise main dev's preview2 - dt_develop_t *pinned_dev = dev->preview2_pinned ? dev->preview2_pinned_dev : NULL; - if(pinned_dev && pinned_dev->gui_leaving) pinned_dev = NULL; + if(dev->gui_leaving) return; - dt_dev_viewport_t *port = pinned_dev ? &pinned_dev->preview2 : &dev->preview2; + // Use pinned viewport if pinned, otherwise main dev's preview2 + dt_develop_t *pinned_dev = dev->preview2_pinned ? dev->preview2_pinned_dev : NULL; + if(pinned_dev && pinned_dev->gui_leaving) pinned_dev = NULL; - const gboolean constrained = - dev->constrain_zoom && !dt_modifier_is(dt_gdk_event_get_state(event), GDK_CONTROL_MASK); - dt_dev_zoom_move(port, DT_ZOOM_SCROLL, 0.0f, delta_y < 0 ? 1 : 0, - dt_gdk_event_get_x(event), dt_gdk_event_get_y(event), constrained); - } + dt_dev_viewport_t *port = pinned_dev ? &pinned_dev->preview2 : &dev->preview2; - return TRUE; + GdkModifierType state; + gtk_get_current_event_state(&state); + const gboolean constrained = + dev->constrain_zoom && !dt_modifier_is(state, GDK_CONTROL_MASK); + gdouble x = 0.0, y = 0.0; + const GdkEvent *current = gtk_get_current_event(); + if(current) gdk_event_get_coords(current, &x, &y); + dt_dev_zoom_move(port, DT_ZOOM_SCROLL, 0.0f, dy < 0 ? 1 : 0, + x, y, constrained); } -static gboolean _second_window_button_pressed_callback(GtkWidget *w, - GdkEventButton *event, - dt_develop_t *dev) +static void _second_window_button_pressed_callback(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, + dt_develop_t *dev) { - if(dev->gui_leaving) return FALSE; + if(dev->gui_leaving) return; // Use pinned viewport if pinned, otherwise main dev's preview2 dt_develop_t *pinned_dev = dev->preview2_pinned ? dev->preview2_pinned_dev : NULL; if(pinned_dev && pinned_dev->gui_leaving) pinned_dev = NULL; dt_dev_viewport_t *port = pinned_dev ? &pinned_dev->preview2 : &dev->preview2; + const guint button = gtk_gesture_single_get_button(gesture); // Handle double-click to reset zoom and center - if(dt_gdk_event_get_type(event) == GDK_2BUTTON_PRESS && dt_gdk_event_get_button(event) == GDK_BUTTON_PRIMARY) + if(n_press == 2 && button == GDK_BUTTON_PRIMARY) { - dt_dev_zoom_move(port, DT_ZOOM_FIT, 0.0f, 0, - dt_gdk_event_get_x(event), dt_gdk_event_get_y(event), TRUE); - return TRUE; + dt_dev_zoom_move(port, DT_ZOOM_FIT, 0.0f, 0, x, y, TRUE); + return; } - if(dt_gdk_event_get_button(event) == GDK_BUTTON_PRIMARY) + if(button == GDK_BUTTON_PRIMARY) { // store coordinates in logical pixels (as delivered by event) - darktable.control->button_x = dt_gdk_event_get_x(event); - darktable.control->button_y = dt_gdk_event_get_y(event); + darktable.control->button_x = x; + darktable.control->button_y = y; _dt_second_window_change_cursor(dev, "grabbing"); - return TRUE; + return; } - if(dt_gdk_event_get_button(event) == GDK_BUTTON_MIDDLE) + if(button == GDK_BUTTON_MIDDLE) { - dt_dev_zoom_move(port, DT_ZOOM_1, 0.0f, -2, - dt_gdk_event_get_x(event), dt_gdk_event_get_y(event), !dt_modifier_is(dt_gdk_event_get_state(event), GDK_CONTROL_MASK)); - return TRUE; + GdkModifierType state; + gtk_get_current_event_state(&state); + dt_dev_zoom_move(port, DT_ZOOM_1, 0.0f, -2, x, y, !dt_modifier_is(state, GDK_CONTROL_MASK)); + return; } - return FALSE; } -static gboolean _second_window_button_released_callback(GtkWidget *w, - GdkEventButton *event, - dt_develop_t *dev) +static void _second_window_button_released_callback(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, + dt_develop_t *dev) { - if(dt_gdk_event_get_button(event) == GDK_BUTTON_PRIMARY) _dt_second_window_change_cursor(dev, "default"); + if(gtk_gesture_single_get_button(gesture) == GDK_BUTTON_PRIMARY) _dt_second_window_change_cursor(dev, "default"); + GtkWidget *w = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); gtk_widget_queue_draw(w); - return TRUE; } -static gboolean _second_window_mouse_moved_callback(GtkWidget *w, - GdkEventMotion *event, - dt_develop_t *dev) +static void _second_window_mouse_moved_callback(GtkEventControllerMotion *controller, + gdouble x, + gdouble y, + dt_develop_t *dev) { - if(dev->gui_leaving) return FALSE; + if(dev->gui_leaving) return; - if(dt_gdk_event_get_state(event) & GDK_BUTTON1_MASK) + GdkModifierType state; + gtk_get_current_event_state(&state); + if(state & GDK_BUTTON1_MASK) { dt_control_t *ctl = darktable.control; @@ -5075,20 +5086,16 @@ static gboolean _second_window_mouse_moved_callback(GtkWidget *w, dt_dev_viewport_t *port = pinned_dev ? &pinned_dev->preview2 : &dev->preview2; dt_dev_zoom_move(port, DT_ZOOM_MOVE, -1.f, 0, - dt_gdk_event_get_x(event) - ctl->button_x, dt_gdk_event_get_y(event) - ctl->button_y, TRUE); - ctl->button_x = dt_gdk_event_get_x(event); - ctl->button_y = dt_gdk_event_get_y(event); - return TRUE; + x - ctl->button_x, y - ctl->button_y, TRUE); + ctl->button_x = x; + ctl->button_y = y; } - return FALSE; } -static gboolean _second_window_leave_callback(GtkWidget *widget, - GdkEventCrossing *event, - dt_develop_t *dev) +static void _second_window_leave_callback(GtkEventControllerMotion *controller, + dt_develop_t *dev) { _second_window_leave(dev); - return TRUE; } static gboolean _second_window_configure_callback(GtkWidget *da, @@ -5149,9 +5156,10 @@ static gboolean _second_window_configure_callback(GtkWidget *da, return TRUE; } -static gboolean _second_window_buttons_enter_notify_callback(GtkWidget *widget, - GdkEventCrossing *event, - GtkWidget *button_box) +static void _second_window_buttons_enter_notify_callback(GtkEventControllerMotion *controller, + gdouble x, + gdouble y, + GtkWidget *button_box) { // Make buttons visible and interactive. Using opacity instead of hide/show // keeps the GdkWindow (and its NSView tracking areas on macOS) always alive, @@ -5159,22 +5167,14 @@ static gboolean _second_window_buttons_enter_notify_callback(GtkWidget *widget, gtk_widget_set_opacity(button_box, 1.0); gtk_overlay_set_overlay_pass_through(GTK_OVERLAY(gtk_widget_get_parent(button_box)), button_box, FALSE); - return FALSE; } -static gboolean _second_window_buttons_leave_notify_callback(GtkWidget *widget, - GdkEventCrossing *event, - GtkWidget *button_box) +static void _second_window_buttons_leave_notify_callback(GtkEventControllerMotion *controller, + GtkWidget *button_box) { - // GDK_NOTIFY_INFERIOR means the pointer moved into a child window (still - // within the second window); keep the buttons visible in that case. - if(event->detail != GDK_NOTIFY_INFERIOR) - { - gtk_widget_set_opacity(button_box, 0.0); - gtk_overlay_set_overlay_pass_through(GTK_OVERLAY(gtk_widget_get_parent(button_box)), - button_box, TRUE); - } - return FALSE; + gtk_widget_set_opacity(button_box, 0.0); + gtk_overlay_set_overlay_pass_through(GTK_OVERLAY(gtk_widget_get_parent(button_box)), + button_box, TRUE); } // Callback for the pin button in the overlay @@ -5236,13 +5236,8 @@ static void _darkroom_ui_second_window_init(GtkWidget *overlay, // Needed to display/hide the widgets. // Must be done before the window is realized. - gtk_widget_add_events(window, GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK); - // Show / hide controls on enter/leave events. - g_signal_connect(G_OBJECT(window), "enter-notify-event", - G_CALLBACK(_second_window_buttons_enter_notify_callback), event_box); - g_signal_connect(G_OBJECT(window), "leave-notify-event", - G_CALLBACK(_second_window_buttons_leave_notify_callback), event_box); + dt_gui_connect_motion(window, NULL, _second_window_buttons_enter_notify_callback, _second_window_buttons_leave_notify_callback, event_box); dev->preview2.pin_button = pin_button; @@ -5437,16 +5432,11 @@ static void _darkroom_display_second_window(dt_develop_t *dev) /* connect callbacks */ g_signal_connect(G_OBJECT(dev->preview2.widget), "draw", G_CALLBACK(_second_window_draw_callback), dev); - g_signal_connect(G_OBJECT(dev->preview2.widget), "scroll-event", - G_CALLBACK(_second_window_scrolled_callback), dev); - g_signal_connect(G_OBJECT(dev->preview2.widget), "button-press-event", - G_CALLBACK(_second_window_button_pressed_callback), dev); - g_signal_connect(G_OBJECT(dev->preview2.widget), "button-release-event", - G_CALLBACK(_second_window_button_released_callback), dev); - g_signal_connect(G_OBJECT(dev->preview2.widget), "motion-notify-event", - G_CALLBACK(_second_window_mouse_moved_callback), dev); - g_signal_connect(G_OBJECT(dev->preview2.widget), "leave-notify-event", - G_CALLBACK(_second_window_leave_callback), dev); + dt_gui_connect_scroll(dev->preview2.widget, GTK_EVENT_CONTROLLER_SCROLL_BOTH_AXES + | GTK_EVENT_CONTROLLER_SCROLL_DISCRETE, + _second_window_scrolled_callback, dev); + dt_gui_connect_click_all(dev->preview2.widget, _second_window_button_pressed_callback, _second_window_button_released_callback, dev); + dt_gui_connect_motion(dev->preview2.widget, _second_window_mouse_moved_callback, NULL, _second_window_leave_callback, dev); g_signal_connect(G_OBJECT(dev->preview2.widget), "configure-event", G_CALLBACK(_second_window_configure_callback), dev); From fa3621d44341bce57b788a1d08b3c541d51fdcda Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 00:58:05 -0300 Subject: [PATCH 21/95] gtk4-prep: convert preferences event signals to event controllers --- src/gui/preferences.c | 83 ++++++++++++++++++++----------------------- 1 file changed, 39 insertions(+), 44 deletions(-) diff --git a/src/gui/preferences.c b/src/gui/preferences.c index a33784ecc2d..19b4bb2981e 100644 --- a/src/gui/preferences.c +++ b/src/gui/preferences.c @@ -281,16 +281,16 @@ static void language_callback(GtkWidget *widget, restart_required = TRUE; } -static gboolean reset_language_widget(GtkWidget *label, - GdkEventButton *event, +static void reset_language_widget_cb(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, GtkWidget *widget) { - if(dt_gdk_event_get_type(event) == GDK_2BUTTON_PRESS) + if(n_press == 2) { dt_bauhaus_combobox_set(widget, darktable.l10n->sys_default); - return TRUE; } - return FALSE; } static gboolean _remove_panel_config(gpointer key, @@ -323,10 +323,12 @@ static void _reset_panels_clicked(GtkButton *button, gpointer user_data) } // forward declaration for use in init_tab_general -static gboolean -_gui_preferences_bool_click(GtkWidget *label, - GdkEventButton *event, - GtkWidget *widget); +static void +gui_preferences_bool_click_cb(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, + GtkWidget *widget); static void init_tab_general(GtkWidget *dialog, GtkWidget *stack, @@ -374,8 +376,7 @@ static void init_tab_general(GtkWidget *dialog, "(restart required)")); gtk_grid_attach(GTK_GRID(grid), labelev, 0, line++, 1, 1); gtk_grid_attach_next_to(GTK_GRID(grid), widget, labelev, GTK_POS_RIGHT, 1, 1); - g_signal_connect(G_OBJECT(labelev), "button-press-event", - G_CALLBACK(reset_language_widget), (gpointer)widget); + dt_gui_connect_click(labelev, reset_language_widget_cb, NULL, widget); // theme @@ -439,8 +440,7 @@ static void init_tab_general(GtkWidget *dialog, dt_conf_get_bool("use_system_font")); g_signal_connect(G_OBJECT(usesysfont), "toggled", G_CALLBACK(use_sys_font_callback), (gpointer)fontsize); - g_signal_connect(G_OBJECT(labelev), "button-press-event", - G_CALLBACK(_gui_preferences_bool_click), (gpointer)usesysfont); + dt_gui_connect_click(labelev, gui_preferences_bool_click_cb, NULL, usesysfont); //font size selector @@ -507,8 +507,7 @@ static void init_tab_general(GtkWidget *dialog, dt_conf_get_bool("themes/usercss")); g_signal_connect(G_OBJECT(tw->apply_toggle), "toggled", G_CALLBACK(usercss_callback), 0); - g_signal_connect(G_OBJECT(labelev), "button-press-event", - G_CALLBACK(_gui_preferences_bool_click), (gpointer)tw->apply_toggle); + dt_gui_connect_click(labelev, gui_preferences_bool_click_cb, NULL, tw->apply_toggle); //scrollable textarea with save button to allow user to directly modify user.css file GtkWidget *usercssbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); @@ -1345,23 +1344,22 @@ void dt_gui_preferences_bool_reset(GtkWidget *widget) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), def); } -static gboolean -_gui_preferences_bool_click(GtkWidget *label, - GdkEventButton *event, - GtkWidget *widget) +static void +gui_preferences_bool_click_cb(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, + GtkWidget *widget) { - if(dt_gdk_event_get_type(event) == GDK_BUTTON_PRESS) + if(n_press == 1) { const gboolean cur = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), !cur); - return TRUE; } - if(dt_gdk_event_get_type(event) == GDK_2BUTTON_PRESS) + else if(n_press == 2) { dt_gui_preferences_bool_reset(widget); - return TRUE; } - return FALSE; } void dt_gui_preferences_bool_update(GtkWidget *widget) @@ -1390,8 +1388,7 @@ GtkWidget *dt_gui_preferences_bool(GtkGrid *grid, gtk_grid_attach(GTK_GRID(grid), w, swap ? col : (col + 1), line, 1, 1); g_signal_connect(G_OBJECT(w), "toggled", G_CALLBACK(_gui_preferences_bool_callback), (gpointer)key); - g_signal_connect(G_OBJECT(labelev), "button-press-event", - G_CALLBACK(_gui_preferences_bool_click), (gpointer)w); + dt_gui_connect_click(labelev, gui_preferences_bool_click_cb, NULL, w); return w; } @@ -1410,17 +1407,17 @@ void dt_gui_preferences_int_reset(GtkWidget *widget) gtk_spin_button_set_value(GTK_SPIN_BUTTON(widget), def); } -static gboolean -_gui_preferences_int_reset(GtkWidget *label, - GdkEventButton *event, - GtkWidget *widget) +static void +gui_preferences_int_reset_cb(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, + GtkWidget *widget) { - if(dt_gdk_event_get_type(event) == GDK_2BUTTON_PRESS) + if(n_press == 2) { dt_gui_preferences_int_reset(widget); - return TRUE; } - return FALSE; } void dt_gui_preferences_int_update(GtkWidget *widget) @@ -1451,8 +1448,7 @@ GtkWidget *dt_gui_preferences_int(GtkGrid *grid, gtk_grid_attach(GTK_GRID(grid), w, col + 1, line, 1, 1); g_signal_connect(G_OBJECT(w), "value-changed", G_CALLBACK(_gui_preferences_int_callback), (gpointer)key); - g_signal_connect(G_OBJECT(labelev), "button-press-event", - G_CALLBACK(_gui_preferences_int_reset), (gpointer)w); + dt_gui_connect_click(labelev, gui_preferences_int_reset_cb, NULL, w); return w; } @@ -1521,17 +1517,17 @@ void dt_gui_preferences_string_reset(GtkWidget *widget) gtk_entry_set_text(GTK_ENTRY(widget), str); } -static gboolean -_gui_preferences_string_reset(GtkWidget *label, - GdkEventButton *event, - GtkWidget *widget) +static void +gui_preferences_string_reset_cb(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, + GtkWidget *widget) { - if(dt_gdk_event_get_type(event) == GDK_2BUTTON_PRESS) + if(n_press == 2) { dt_gui_preferences_string_reset(widget); - return TRUE; } - return FALSE; } void dt_gui_preferences_string_update(GtkWidget *widget) @@ -1562,8 +1558,7 @@ GtkWidget *dt_gui_preferences_string(GtkGrid *grid, gtk_grid_attach(GTK_GRID(grid), w, col + 1, line, 1, 1); g_signal_connect(G_OBJECT(w), "changed", G_CALLBACK(_gui_preferences_string_callback), (gpointer)key); - g_signal_connect(G_OBJECT(labelev), "button-press-event", - G_CALLBACK(_gui_preferences_string_reset), (gpointer)w); + dt_gui_connect_click(labelev, gui_preferences_string_reset_cb, NULL, w); return w; } From 44887060d63f675c7d5f3a7737a6984b72dc5cad Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 01:00:26 -0300 Subject: [PATCH 22/95] gtk4-prep: convert lua preferences event signals to event controllers --- src/lua/preferences.c | 69 ++++++++++++++++--------------------------- 1 file changed, 26 insertions(+), 43 deletions(-) diff --git a/src/lua/preferences.c b/src/lua/preferences.c index fde7439b76f..9311440f708 100644 --- a/src/lua/preferences.c +++ b/src/lua/preferences.c @@ -1,6 +1,6 @@ /* This file is part of darktable, - Copyright (C) 2013-2023 darktable developers. + Copyright (C) 2013-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 @@ -410,94 +410,79 @@ static void response_callback_lua(GtkDialog *dialog, gint response_id, pref_elem } -static gboolean reset_widget_enum(GtkWidget *label, GdkEventButton *event, pref_element *cur_elt) +static void reset_widget_enum_cb(GtkGestureSingle *gesture, gint n_press, gdouble x, gdouble y, pref_element *cur_elt) { - if(event->type == GDK_2BUTTON_PRESS) + if(n_press == 2) { gtk_combo_box_set_active(GTK_COMBO_BOX(cur_elt->widget), 0); - return TRUE; } - return FALSE; } -static gboolean reset_widget_dir(GtkWidget *label, GdkEventButton *event, pref_element *cur_elt) +static void reset_widget_dir_cb(GtkGestureSingle *gesture, gint n_press, gdouble x, gdouble y, pref_element *cur_elt) { - if(event->type == GDK_2BUTTON_PRESS) + if(n_press == 2) { gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(cur_elt->widget), cur_elt->type_data.dir_data.default_value); - return TRUE; } - return FALSE; } -static gboolean reset_widget_file(GtkWidget *label, GdkEventButton *event, pref_element *cur_elt) +static void reset_widget_file_cb(GtkGestureSingle *gesture, gint n_press, gdouble x, gdouble y, pref_element *cur_elt) { - if(event->type == GDK_2BUTTON_PRESS) + if(n_press == 2) { gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(cur_elt->widget), cur_elt->type_data.file_data.default_value); - return TRUE; } - return FALSE; } -static gboolean reset_widget_string(GtkWidget *label, GdkEventButton *event, pref_element *cur_elt) +static void reset_widget_string_cb(GtkGestureSingle *gesture, gint n_press, gdouble x, gdouble y, pref_element *cur_elt) { - if(event->type == GDK_2BUTTON_PRESS) + if(n_press == 2) { gtk_entry_set_text(GTK_ENTRY(cur_elt->widget), cur_elt->type_data.string_data.default_value); - return TRUE; } - return FALSE; } -static gboolean click_widget_bool(GtkWidget *label, GdkEventButton *event, pref_element *cur_elt) +static void click_widget_bool_cb(GtkGestureSingle *gesture, gint n_press, gdouble x, gdouble y, pref_element *cur_elt) { - if(event->type == GDK_BUTTON_PRESS) + if(n_press == 1) { gtk_button_clicked(GTK_BUTTON(cur_elt->widget)); - return TRUE; } - if(event->type == GDK_2BUTTON_PRESS) + else if(n_press == 2) { gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cur_elt->widget), cur_elt->type_data.bool_data.default_value); - return TRUE; } - return FALSE; } -static gboolean reset_widget_int(GtkWidget *label, GdkEventButton *event, pref_element *cur_elt) +static void reset_widget_int_cb(GtkGestureSingle *gesture, gint n_press, gdouble x, gdouble y, pref_element *cur_elt) { - if(event->type == GDK_2BUTTON_PRESS) + if(n_press == 2) { gtk_spin_button_set_value(GTK_SPIN_BUTTON(cur_elt->widget), cur_elt->type_data.int_data.default_value); - return TRUE; } - return FALSE; } -static gboolean reset_widget_float(GtkWidget *label, GdkEventButton *event, pref_element *cur_elt) +static void reset_widget_float_cb(GtkGestureSingle *gesture, gint n_press, gdouble x, gdouble y, pref_element *cur_elt) { - if(event->type == GDK_2BUTTON_PRESS) + if(n_press == 2) { gtk_spin_button_set_value(GTK_SPIN_BUTTON(cur_elt->widget), cur_elt->type_data.float_data.default_value); - return TRUE; } - return FALSE; } -static gboolean reset_widget_lua(GtkWidget *label, GdkEventButton *event, pref_element *cur_elt) +static void reset_widget_lua_cb(GtkGestureSingle *gesture, gint n_press, gdouble x, gdouble y, pref_element *cur_elt) { - if(event->type == GDK_2BUTTON_PRESS) + if(n_press == 2) { char pref_name[1024]; get_pref_name(pref_name, sizeof(pref_name), cur_elt->script, cur_elt->name); @@ -513,9 +498,7 @@ static gboolean reset_widget_lua(GtkWidget *label, GdkEventButton *event, pref_e dt_lua_unlock(); dt_conf_set_string(pref_name, old_str); g_free(old_str); - return TRUE; } - return FALSE; } @@ -523,7 +506,7 @@ static void update_widget_enum(pref_element* cur_elt, GtkWidget* dialog, GtkWidg { char pref_name[1024]; get_pref_name(pref_name, sizeof(pref_name), cur_elt->script, cur_elt->name); - g_signal_connect(G_OBJECT(labelev), "button-press-event", G_CALLBACK(reset_widget_enum), cur_elt); + dt_gui_connect_click(labelev, reset_widget_enum_cb, NULL, cur_elt); g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK(response_callback_enum), cur_elt); gtk_combo_box_set_active(GTK_COMBO_BOX(cur_elt->widget), 0); const char *value = dt_conf_get_string_const(pref_name); @@ -555,7 +538,7 @@ static void update_widget_dir(pref_element* cur_elt, GtkWidget* dialog, GtkWidge get_pref_name(pref_name, sizeof(pref_name), cur_elt->script, cur_elt->name); const char *str = dt_conf_get_string_const(pref_name); gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(cur_elt->widget), str); - g_signal_connect(G_OBJECT(labelev), "button-press-event", G_CALLBACK(reset_widget_dir), cur_elt); + dt_gui_connect_click(labelev, reset_widget_dir_cb, NULL, cur_elt); g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK(response_callback_filechooser), cur_elt); } @@ -566,7 +549,7 @@ static void update_widget_file(pref_element* cur_elt, GtkWidget* dialog, GtkWidg get_pref_name(pref_name, sizeof(pref_name), cur_elt->script, cur_elt->name); const char *str = dt_conf_get_string_const(pref_name); gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(cur_elt->widget), str); - g_signal_connect(G_OBJECT(labelev), "button-press-event", G_CALLBACK(reset_widget_file), cur_elt); + dt_gui_connect_click(labelev, reset_widget_file_cb, NULL, cur_elt); g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK(response_callback_filechooser), cur_elt); } @@ -575,7 +558,7 @@ static void update_widget_string(pref_element* cur_elt, GtkWidget* dialog, GtkWi { char pref_name[1024]; get_pref_name(pref_name, sizeof(pref_name), cur_elt->script, cur_elt->name); - g_signal_connect(G_OBJECT(labelev), "button-press-event", G_CALLBACK(reset_widget_string), cur_elt); + dt_gui_connect_click(labelev, reset_widget_string_cb, NULL, cur_elt); g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK(response_callback_string), cur_elt); const char *str = dt_conf_get_string_const(pref_name); gtk_entry_set_text(GTK_ENTRY(cur_elt->widget), str); @@ -586,7 +569,7 @@ static void update_widget_bool(pref_element* cur_elt, GtkWidget* dialog, GtkWidg { char pref_name[1024]; get_pref_name(pref_name, sizeof(pref_name), cur_elt->script, cur_elt->name); - g_signal_connect(G_OBJECT(labelev), "button-press-event", G_CALLBACK(click_widget_bool), cur_elt); + dt_gui_connect_click(labelev, click_widget_bool_cb, NULL, cur_elt); g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK(response_callback_bool), cur_elt); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cur_elt->widget), dt_conf_get_bool(pref_name)); } @@ -597,7 +580,7 @@ static void update_widget_int(pref_element* cur_elt, GtkWidget* dialog, GtkWidge char pref_name[1024]; get_pref_name(pref_name, sizeof(pref_name), cur_elt->script, cur_elt->name); gtk_spin_button_set_value(GTK_SPIN_BUTTON(cur_elt->widget), dt_conf_get_int(pref_name)); - g_signal_connect(G_OBJECT(labelev), "button-press-event", G_CALLBACK(reset_widget_int), cur_elt); + dt_gui_connect_click(labelev, reset_widget_int_cb, NULL, cur_elt); g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK(response_callback_int), cur_elt); } @@ -607,7 +590,7 @@ static void update_widget_float(pref_element* cur_elt, GtkWidget* dialog, GtkWid char pref_name[1024]; get_pref_name(pref_name, sizeof(pref_name), cur_elt->script, cur_elt->name); gtk_spin_button_set_value(GTK_SPIN_BUTTON(cur_elt->widget), dt_conf_get_float(pref_name)); - g_signal_connect(G_OBJECT(labelev), "button-press-event", G_CALLBACK(reset_widget_float), cur_elt); + dt_gui_connect_click(labelev, reset_widget_float_cb, NULL, cur_elt); g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK(response_callback_float), cur_elt); } @@ -621,7 +604,7 @@ static void update_widget_lua(pref_element* cur_elt, GtkWidget* dialog, GtkWidge lua_pushstring(L, "reset"); lua_call(L, 2, 0); dt_lua_unlock(); - g_signal_connect(G_OBJECT(labelev), "button-press-event", G_CALLBACK(reset_widget_lua), cur_elt); + dt_gui_connect_click(labelev, reset_widget_lua_cb, NULL, cur_elt); g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK(response_callback_lua), cur_elt); } From 5087242c79a9ad23aa655a176db647087b02fba8 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 01:33:30 -0300 Subject: [PATCH 23/95] gtk4-prep: convert range select event signals to event controllers --- src/dtgtk/range.c | 66 ++++++++++++++++++++--------------------------- 1 file changed, 28 insertions(+), 38 deletions(-) diff --git a/src/dtgtk/range.c b/src/dtgtk/range.c index a376ef8b190..89f11d50a32 100644 --- a/src/dtgtk/range.c +++ b/src/dtgtk/range.c @@ -1181,15 +1181,13 @@ static void _popup_show(GtkDarktableRangeSelect *range, GtkWidget *w) } } -static gboolean _event_entry_press(GtkWidget *w, GdkEventButton *e, gpointer user_data) +static void _event_entry_press_cb(GtkGestureSingle *gesture, int n_press, double x, double y, GtkDarktableRangeSelect *range) { - GtkDarktableRangeSelect *range = (GtkDarktableRangeSelect *)user_data; - if(e->button == GDK_BUTTON_SECONDARY) + GtkWidget *w = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + if(gtk_gesture_single_get_button(gesture) == GDK_BUTTON_SECONDARY) { _popup_show(range, w); - return TRUE; } - return FALSE; } static void _event_entry_activated(GtkWidget *entry, gpointer user_data) @@ -1509,10 +1507,9 @@ void dtgtk_range_select_redraw(GtkDarktableRangeSelect *range) gtk_widget_queue_draw(range->band); } -static gboolean _event_band_motion(GtkWidget *widget, GdkEventMotion *event, gpointer user_data) +static void _event_band_motion_cb(GtkEventControllerMotion *controller, double x, double y, GtkDarktableRangeSelect *range) { - GtkDarktableRangeSelect *range = (GtkDarktableRangeSelect *)user_data; - range->current_x_px = dt_gdk_event_get_x(event) - range->alloc_padding.x; + range->current_x_px = x - range->alloc_padding.x; // if we are outside the graph, don't go further const gboolean inside = (range->current_x_px >= 0 && range->current_x_px <= range->alloc_padding.width); @@ -1521,13 +1518,13 @@ static gboolean _event_band_motion(GtkWidget *widget, GdkEventMotion *event, gpo range->mouse_inside = HOVER_OUTSIDE; dt_control_change_cursor("default"); _current_hide_popup(range); - return TRUE; + return; } _current_show_popup(range); // point the popup to the current position gint wx, wy; gtk_widget_translate_coordinates(range->band, gtk_widget_get_toplevel(range->band), 0, 0, &wx, &wy); - GdkRectangle rect = { dt_gdk_event_get_x(event), 0, 1, gtk_widget_get_allocated_height(range->band) }; + GdkRectangle rect = { x, 0, 1, gtk_widget_get_allocated_height(range->band) }; gtk_popover_set_pointing_to(GTK_POPOVER(range->cur_window), &rect); const double smin_r = (range->bounds & DT_RANGE_BOUND_MIN) ? range->min_r : range->select_min_r; @@ -1556,32 +1553,32 @@ static gboolean _event_band_motion(GtkWidget *widget, GdkEventMotion *event, gpo dt_control_change_cursor("default"); } gtk_widget_queue_draw(range->band); - return TRUE; } -static gboolean _event_band_leave(GtkWidget *w, GdkEventCrossing *e, gpointer user_data) +static void _event_band_leave_cb(GtkEventControllerMotion *controller, GtkDarktableRangeSelect *range) { - GtkDarktableRangeSelect *range = (GtkDarktableRangeSelect *)user_data; range->mouse_inside = HOVER_OUTSIDE; dt_control_change_cursor("default"); _current_hide_popup(range); gtk_widget_queue_draw(range->band); - return TRUE; } -static gboolean _event_band_press(GtkWidget *w, GdkEventButton *e, gpointer user_data) +static void _event_band_press_cb(GtkGestureSingle *gesture, int n_press, double x, double y, GtkDarktableRangeSelect *range) { - GtkDarktableRangeSelect *range = (GtkDarktableRangeSelect *)user_data; - if(e->button == GDK_BUTTON_PRIMARY && e->type == GDK_2BUTTON_PRESS) + const guint button = gtk_gesture_single_get_button(gesture); + GdkModifierType state; + gtk_get_current_event_state(&state); + + if(button == GDK_BUTTON_PRIMARY && n_press == 2) { dtgtk_range_select_set_selection(range, DT_RANGE_BOUND_MIN | DT_RANGE_BOUND_MAX, range->min_r, range->max_r, TRUE, TRUE); } - else if(e->button == GDK_BUTTON_PRIMARY) + else if(button == GDK_BUTTON_PRIMARY) { - if(!range->mouse_inside) return TRUE; - const double pos_r = _graph_value_from_pos(range, e->x - range->alloc_padding.x, TRUE); + if(!range->mouse_inside) return; + const double pos_r = _graph_value_from_pos(range, x - range->alloc_padding.x, TRUE); if(range->mouse_inside == HOVER_MAX) { range->bounds &= ~DT_RANGE_BOUND_MAX; @@ -1593,7 +1590,7 @@ static gboolean _event_band_press(GtkWidget *w, GdkEventButton *e, gpointer user range->select_min_r = range->select_max_r; range->select_max_r = pos_r; } - else if(dt_modifier_is(e->state, GDK_SHIFT_MASK)) + else if(dt_modifier_is(state, GDK_SHIFT_MASK)) { // if we have shift pressed, we only want to set the second bound which is done in release range->bounds &= ~DT_RANGE_BOUND_FIXED; @@ -1610,17 +1607,15 @@ static gboolean _event_band_press(GtkWidget *w, GdkEventButton *e, gpointer user gtk_widget_queue_draw(range->band); } - else if(e->button == GDK_BUTTON_SECONDARY) + else if(button == GDK_BUTTON_SECONDARY) { _popup_show(range, range->band); } - return TRUE; } -static gboolean _event_band_release(GtkWidget *w, GdkEventButton *e, gpointer user_data) +static void _event_band_release_cb(GtkGestureSingle *gesture, int n_press, double x, double y, GtkDarktableRangeSelect *range) { - GtkDarktableRangeSelect *range = (GtkDarktableRangeSelect *)user_data; - if(!range->set_selection) return TRUE; - range->select_max_r = _graph_value_from_pos(range, e->x - range->alloc_padding.x, TRUE); + if(!range->set_selection) return; + range->select_max_r = _graph_value_from_pos(range, x - range->alloc_padding.x, TRUE); const double min_pos_px = _graph_value_to_pos(range, range->select_min_r); // we verify that the values are in the right order @@ -1632,7 +1627,7 @@ static gboolean _event_band_release(GtkWidget *w, GdkEventButton *e, gpointer us } // we also set the bounds - if(fabs(e->x - range->alloc_padding.x - min_pos_px) < 2) + if(fabs(x - range->alloc_padding.x - min_pos_px) < 2) range->bounds = DT_RANGE_BOUND_FIXED; else { @@ -1652,8 +1647,6 @@ static gboolean _event_band_release(GtkWidget *w, GdkEventButton *e, gpointer us range->set_selection = FALSE; dtgtk_range_select_set_selection(range, range->bounds, range->select_min_r, range->select_max_r, TRUE, FALSE); - - return TRUE; } // Public functions @@ -1686,14 +1679,11 @@ GtkWidget *dtgtk_range_select_new(const gchar *property, const gboolean show_ent // the graph band range->band = gtk_drawing_area_new(); - gtk_widget_set_events(range->band, GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_STRUCTURE_MASK - | GDK_LEAVE_NOTIFY_MASK | GDK_POINTER_MOTION_MASK); + gtk_widget_set_events(range->band, GDK_STRUCTURE_MASK); g_signal_connect(G_OBJECT(range->band), "draw", G_CALLBACK(_event_band_draw), range); - g_signal_connect(G_OBJECT(range->band), "button-press-event", G_CALLBACK(_event_band_press), range); - g_signal_connect(G_OBJECT(range->band), "button-release-event", G_CALLBACK(_event_band_release), range); - g_signal_connect(G_OBJECT(range->band), "motion-notify-event", G_CALLBACK(_event_band_motion), range); - g_signal_connect(G_OBJECT(range->band), "leave-notify-event", G_CALLBACK(_event_band_leave), range); g_signal_connect(G_OBJECT(range->band), "style-updated", G_CALLBACK(_dt_pref_changed), range); + dt_gui_connect_click_all(range->band, _event_band_press_cb, _event_band_release_cb, range); + dt_gui_connect_motion(range->band, _event_band_motion_cb, NULL, _event_band_leave_cb, range); gtk_widget_set_name(GTK_WIDGET(range->band), "dt-range-band"); gtk_widget_set_can_default(range->band, TRUE); @@ -1726,7 +1716,7 @@ GtkWidget *dtgtk_range_select_new(const gchar *property, const gboolean show_ent _entry_set_tooltip(range->entry_min, BOUND_MIN, range->type); g_signal_connect(G_OBJECT(range->entry_min), "activate", G_CALLBACK(_event_entry_activated), range); g_signal_connect(G_OBJECT(range->entry_min), "focus-out-event", G_CALLBACK(_event_entry_focus_out), range); - g_signal_connect(G_OBJECT(range->entry_min), "button-press-event", G_CALLBACK(_event_entry_press), range); + dt_gui_connect_click_all(range->entry_min, _event_entry_press_cb, NULL, range); range->entry_max = dt_ui_entry_new(0); gtk_widget_set_can_default(range->entry_max, TRUE); @@ -1734,7 +1724,7 @@ GtkWidget *dtgtk_range_select_new(const gchar *property, const gboolean show_ent _entry_set_tooltip(range->entry_max, BOUND_MAX, range->type); g_signal_connect(G_OBJECT(range->entry_max), "activate", G_CALLBACK(_event_entry_activated), range); g_signal_connect(G_OBJECT(range->entry_max), "focus-out-event", G_CALLBACK(_event_entry_focus_out), range); - g_signal_connect(G_OBJECT(range->entry_max), "button-press-event", G_CALLBACK(_event_entry_press), range); + dt_gui_connect_click_all(range->entry_max, _event_entry_press_cb, NULL, range); dt_gui_box_add(vbox, dt_gui_hbox(dt_gui_expand(range->entry_min), dt_gui_expand(range->entry_max))); } From bf8b9d91d1139b656ec98134c9d5ebf374f4eb3c Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 01:33:34 -0300 Subject: [PATCH 24/95] gtk4-prep: convert masks event signals to event controllers --- src/libs/masks.c | 55 ++++++++++++++++++++---------------------------- 1 file changed, 23 insertions(+), 32 deletions(-) diff --git a/src/libs/masks.c b/src/libs/masks.c index f1031e86cec..d211306c7dd 100644 --- a/src/libs/masks.c +++ b/src/libs/masks.c @@ -664,22 +664,23 @@ static void _tree_add_shape(GtkButton *button, gpointer shape) dt_control_queue_redraw_center(); } -static gboolean _bt_add_shape(GtkWidget *widget, GdkEventButton *event, gpointer shape) +static void _bt_add_shape_cb(GtkGestureSingle *gesture, int n_press, double x, double y, gpointer shape) { - DT_GUARD_GUI_UPDATE(FALSE); - if(dt_gdk_event_get_button(event) == GDK_BUTTON_PRIMARY) + if(gtk_gesture_single_get_button(gesture) == GDK_BUTTON_PRIMARY) { #ifdef HAVE_AI if(GPOINTER_TO_INT(shape) == DT_MASKS_OBJECT && !dt_masks_object_available()) { dt_control_log(_("AI model is not available. Check preferences > AI")); - return TRUE; + return; } #endif _tree_add_shape(NULL, shape); - if(dt_modifier_is(dt_gdk_event_get_state(event), GDK_CONTROL_MASK)) + GdkModifierType state; + gtk_get_current_event_state(&state); + if(dt_modifier_is(state, GDK_CONTROL_MASK)) { darktable.develop->form_gui->creation_continuous = TRUE; darktable.develop->form_gui->creation_continuous_module = @@ -688,7 +689,6 @@ static gboolean _bt_add_shape(GtkWidget *widget, GdkEventButton *event, gpointer _lib_masks_inactivate_icons(darktable.develop->proxy.masks.module); } - return TRUE; } static void _tree_add_exist(GtkButton *button, dt_masks_form_t *grp) @@ -1222,10 +1222,9 @@ static void _tree_selection_change(GtkTreeSelection *selection, dt_lib_masks_t * _update_all_properties(self); } -static int _tree_button_pressed(GtkWidget *treeview, - GdkEventButton *event, - dt_lib_module_t *self) +static void _tree_button_pressed_cb(GtkGestureSingle *gesture, int n_press, double x, double y, dt_lib_module_t *self) { + GtkWidget *treeview = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); // we first need to adjust selection GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)); GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(treeview)); @@ -1235,7 +1234,7 @@ static int _tree_button_pressed(GtkWidget *treeview, dt_iop_module_t *module = NULL; gboolean on_row = FALSE; if(gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(treeview), - (gint)dt_gdk_event_get_x(event), (gint)dt_gdk_event_get_y(event), &mouse_path, NULL, + (gint)x, (gint)y, &mouse_path, NULL, NULL, NULL)) { on_row = TRUE; @@ -1246,7 +1245,8 @@ static int _tree_button_pressed(GtkWidget *treeview, } } /* single click with the right mouse button? */ - if(dt_gdk_event_get_type(event) == GDK_BUTTON_PRESS && dt_gdk_event_get_button(event) == GDK_BUTTON_PRIMARY) + const guint button = gtk_gesture_single_get_button(gesture); + if(button == GDK_BUTTON_PRIMARY) { // if click on a blank space, then deselect all if(!on_row) @@ -1254,13 +1254,15 @@ static int _tree_button_pressed(GtkWidget *treeview, gtk_tree_selection_unselect_all(selection); } } - else if(dt_gdk_event_get_type(event) == GDK_BUTTON_PRESS && dt_gdk_event_get_button(event) == GDK_BUTTON_SECONDARY) + else if(button == GDK_BUTTON_SECONDARY) { + GdkModifierType state; + gtk_get_current_event_state(&state); // if we are already inside the selection, no change if(on_row && !gtk_tree_selection_path_is_selected(selection, mouse_path)) { - if(!dt_modifier_is(dt_gdk_event_get_state(event), GDK_CONTROL_MASK)) + if(!dt_modifier_is(state, GDK_CONTROL_MASK)) gtk_tree_selection_unselect_all(selection); gtk_tree_selection_select_path(selection, mouse_path); @@ -1516,12 +1518,8 @@ static int _tree_button_pressed(GtkWidget *treeview, gtk_widget_show_all(GTK_WIDGET(menu)); - gtk_menu_popup_at_pointer(GTK_MENU(menu), (GdkEvent *)event); - - return 1; + gtk_menu_popup_at_pointer(GTK_MENU(menu), gtk_get_current_event()); } - - return 0; } static gboolean _tree_restrict_select(GtkTreeSelection *selection, @@ -2276,40 +2274,35 @@ void gui_init(dt_lib_module_t *self) d->bt_gradient = dtgtk_togglebutton_new(dtgtk_cairo_paint_masks_gradient, 0, NULL); dt_action_define(DT_ACTION(self), N_("shapes"), N_("add gradient"), d->bt_gradient, &dt_action_def_toggle); - g_signal_connect(G_OBJECT(d->bt_gradient), "button-press-event", - G_CALLBACK(_bt_add_shape), GINT_TO_POINTER(DT_MASKS_GRADIENT)); + dt_gui_connect_click(d->bt_gradient, _bt_add_shape_cb, NULL, GINT_TO_POINTER(DT_MASKS_GRADIENT)); gtk_widget_set_tooltip_text(d->bt_gradient, _("add gradient")); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(d->bt_gradient), FALSE); d->bt_path = dtgtk_togglebutton_new(dtgtk_cairo_paint_masks_path, 0, NULL); dt_action_define(DT_ACTION(self), N_("shapes"), N_("add path"), d->bt_path, &dt_action_def_toggle); - g_signal_connect(G_OBJECT(d->bt_path), "button-press-event", - G_CALLBACK(_bt_add_shape), GINT_TO_POINTER(DT_MASKS_PATH)); + dt_gui_connect_click(d->bt_path, _bt_add_shape_cb, NULL, GINT_TO_POINTER(DT_MASKS_PATH)); gtk_widget_set_tooltip_text(d->bt_path, _("add path")); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(d->bt_path), FALSE); d->bt_ellipse = dtgtk_togglebutton_new(dtgtk_cairo_paint_masks_ellipse, 0, NULL); dt_action_define(DT_ACTION(self), N_("shapes"), N_("add ellipse"), d->bt_ellipse, &dt_action_def_toggle); - g_signal_connect(G_OBJECT(d->bt_ellipse), "button-press-event", - G_CALLBACK(_bt_add_shape), GINT_TO_POINTER(DT_MASKS_ELLIPSE)); + dt_gui_connect_click(d->bt_ellipse, _bt_add_shape_cb, NULL, GINT_TO_POINTER(DT_MASKS_ELLIPSE)); gtk_widget_set_tooltip_text(d->bt_ellipse, _("add ellipse")); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(d->bt_ellipse), FALSE); d->bt_circle = dtgtk_togglebutton_new(dtgtk_cairo_paint_masks_circle, 0, NULL); dt_action_define(DT_ACTION(self), N_("shapes"), N_("add circle"), d->bt_circle, &dt_action_def_toggle); - g_signal_connect(G_OBJECT(d->bt_circle), "button-press-event", - G_CALLBACK(_bt_add_shape), GINT_TO_POINTER(DT_MASKS_CIRCLE)); + dt_gui_connect_click(d->bt_circle, _bt_add_shape_cb, NULL, GINT_TO_POINTER(DT_MASKS_CIRCLE)); gtk_widget_set_tooltip_text(d->bt_circle, _("add circle")); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(d->bt_circle), FALSE); d->bt_brush = dtgtk_togglebutton_new(dtgtk_cairo_paint_masks_brush, 0, NULL); dt_action_define(DT_ACTION(self), N_("shapes"), N_("add brush"), d->bt_brush, &dt_action_def_toggle); - g_signal_connect(G_OBJECT(d->bt_brush), "button-press-event", - G_CALLBACK(_bt_add_shape), GINT_TO_POINTER(DT_MASKS_BRUSH)); + dt_gui_connect_click(d->bt_brush, _bt_add_shape_cb, NULL, GINT_TO_POINTER(DT_MASKS_BRUSH)); gtk_widget_set_tooltip_text(d->bt_brush, _("add brush")); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(d->bt_brush), FALSE); @@ -2317,8 +2310,7 @@ void gui_init(dt_lib_module_t *self) d->bt_object = dtgtk_togglebutton_new(dtgtk_cairo_paint_masks_object, 0, NULL); dt_action_define(DT_ACTION(self), N_("shapes"), N_("add object"), d->bt_object, &dt_action_def_toggle); - g_signal_connect(G_OBJECT(d->bt_object), "button-press-event", - G_CALLBACK(_bt_add_shape), GINT_TO_POINTER(DT_MASKS_OBJECT)); + dt_gui_connect_click(d->bt_object, _bt_add_shape_cb, NULL, GINT_TO_POINTER(DT_MASKS_OBJECT)); gtk_widget_set_tooltip_text(d->bt_object, _("add AI object")); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(d->bt_object), FALSE); #endif @@ -2355,8 +2347,7 @@ void gui_init(dt_lib_module_t *self) gtk_widget_set_has_tooltip(d->treeview, TRUE); g_signal_connect(d->treeview, "query-tooltip", G_CALLBACK(_tree_query_tooltip), NULL); g_signal_connect(selection, "changed", G_CALLBACK(_tree_selection_change), d); - g_signal_connect(d->treeview, "button-press-event", - G_CALLBACK(_tree_button_pressed), self); + dt_gui_connect_click_all(d->treeview, _tree_button_pressed_cb, NULL, self); GtkWidget *shape_buttons = dt_gui_hbox (dt_gui_expand(dt_ui_label_new(_("created shapes"))), From 66524fb560a2e73a540a5bc90927934b187c4c94 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 01:33:42 -0300 Subject: [PATCH 25/95] gtk4-prep: convert bauhaus event signals to event controllers --- src/bauhaus/bauhaus.c | 81 +++++++++++++++++++------------------------ 1 file changed, 36 insertions(+), 45 deletions(-) diff --git a/src/bauhaus/bauhaus.c b/src/bauhaus/bauhaus.c index bef22e724f5..4b215da1554 100644 --- a/src/bauhaus/bauhaus.c +++ b/src/bauhaus/bauhaus.c @@ -517,28 +517,23 @@ static void _slider_zoom_toast(dt_bauhaus_widget_t *w) g_free(max_text); } -static gboolean _popup_scroll(GtkWidget *widget, - GdkEventScroll *event, +static void _popup_scroll_cb(GtkEventControllerScroll *controller, + gdouble dx, + gdouble dy, gpointer user_data) { dt_bauhaus_widget_t *w = darktable.bauhaus->current; if(w->type == DT_BAUHAUS_COMBOBOX) { // match keyboard: right & down -> next - int delta_x = 0, delta_y = 0; - if(dt_gui_get_scroll_unit_deltas(event, &delta_x, &delta_y)) - { - int delta = abs(delta_x) > abs(delta_y) ? delta_x : delta_y; + const int delta = fabs(dx) > fabs(dy) ? (int)dx : (int)dy; + if(delta != 0) _combobox_next_sensitive(w, delta, 0, w->combobox.mute_scrolling); - } } else { - int delta = 0; - if(dt_gui_get_scroll_unit_delta(event, &delta)) - _slider_zoom_range(w, delta); + _slider_zoom_range(w, -(int)dy); } - return TRUE; } static void _window_moved_to_rect(GdkWindow *window, @@ -685,63 +680,61 @@ static gboolean _window_motion_notify(GtkWidget *widget, return TRUE; } -static gboolean _popup_leave_notify(GtkWidget *widget, - GdkEventCrossing *event, +static void _popup_leave_notify_cb(GtkEventControllerMotion *controller, gpointer user_data) { + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); gtk_widget_set_state_flags(widget, GTK_STATE_FLAG_NORMAL, TRUE); - return TRUE; } -static gboolean _popup_button_release(GtkWidget *widget, - GdkEventButton *event, - gpointer user_data) +static void _popup_button_release_cb(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, + gpointer user_data) { - if(darktable.bauhaus->change_active && dt_gdk_event_get_button(event) != GDK_BUTTON_MIDDLE) + if(darktable.bauhaus->change_active && gtk_gesture_single_get_button(gesture) != GDK_BUTTON_MIDDLE) _popup_hide(); - - return TRUE; } -static gboolean _popup_button_press(GtkWidget *widget, - GdkEventButton *event, - gpointer user_data) +static void _popup_button_press_cb(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, + gpointer user_data) { - if(dt_gdk_event_get_window(event) != gtk_widget_get_window(widget)) - { - _popup_reject(); - return TRUE; - } - dt_bauhaus_t *bh = darktable.bauhaus; dt_bauhaus_widget_t *w = bh->current; + const guint button = gtk_gesture_single_get_button(gesture); - if(dt_gdk_event_get_button(event) == GDK_BUTTON_PRIMARY) + if(button == GDK_BUTTON_PRIMARY) { // only accept left mouse click gtk_widget_set_state_flags(GTK_WIDGET(w), GTK_STATE_FLAG_FOCUSED, FALSE); if(w->type == DT_BAUHAUS_COMBOBOX - && !dt_gui_long_click(dt_gdk_event_get_time(event), bh->opentime)) + && !dt_gui_long_click(gdk_event_get_time(gtk_gesture_get_last_event(GTK_GESTURE(gesture), NULL)), bh->opentime)) { // counts as double click, reset: - if(!(dt_modifier_is(dt_gdk_event_get_state(event), GDK_CONTROL_MASK) && w->field + GdkModifierType state; + gtk_get_current_event_state(&state); + if(!(dt_modifier_is(state, GDK_CONTROL_MASK) && w->field && dt_gui_presets_autoapply_for_module((dt_iop_module_t *)w->module, GTK_WIDGET(w)))) dt_bauhaus_widget_reset(GTK_WIDGET(w)); } bh->change_active = TRUE; - event->state |= GDK_BUTTON1_MASK; - _window_motion_notify(widget, (GdkEventMotion*)event, user_data); + GtkWidget *w_current = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + const GdkEvent *current_event = gtk_get_current_event(); + _window_motion_notify(w_current, + (GdkEventMotion *)current_event, user_data); } - else if(dt_gdk_event_get_button(event) == GDK_BUTTON_MIDDLE && w->type == DT_BAUHAUS_SLIDER) + else if(button == GDK_BUTTON_MIDDLE && w->type == DT_BAUHAUS_SLIDER) _slider_zoom_range(w, 0); else _popup_reject(); - - return TRUE; } static void _window_show(GtkWidget *w, gpointer user_data) @@ -982,10 +975,7 @@ void dt_bauhaus_init() gtk_container_add(GTK_CONTAINER(pop->window), pop->area); gtk_widget_set_can_focus(pop->area, TRUE); gtk_widget_add_events(pop->area, - GDK_POINTER_MOTION_MASK - | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - | GDK_KEY_PRESS_MASK | GDK_LEAVE_NOTIFY_MASK - | darktable.gui->scroll_mask); + darktable.gui->scroll_mask); GObject *window = G_OBJECT(pop->window); GObject *area = G_OBJECT(pop->area); @@ -996,11 +986,12 @@ void dt_bauhaus_init() g_signal_connect(window, "show", G_CALLBACK(_window_show), area); g_signal_connect(window, "motion-notify-event", G_CALLBACK(_window_motion_notify), NULL); g_signal_connect(area, "draw", G_CALLBACK(_popup_draw), NULL); - g_signal_connect(area, "leave-notify-event", G_CALLBACK(_popup_leave_notify), NULL); - g_signal_connect(area, "button-press-event", G_CALLBACK(_popup_button_press), NULL); - g_signal_connect(area, "button-release-event", G_CALLBACK (_popup_button_release), NULL); g_signal_connect(area, "key-press-event", G_CALLBACK(_popup_key_press), NULL); - g_signal_connect(area, "scroll-event", G_CALLBACK(_popup_scroll), NULL); + dt_gui_connect_motion(area, NULL, NULL, _popup_leave_notify_cb, NULL); + dt_gui_connect_click_all(area, _popup_button_press_cb, _popup_button_release_cb, NULL); + dt_gui_connect_scroll(area, GTK_EVENT_CONTROLLER_SCROLL_BOTH_AXES + | GTK_EVENT_CONTROLLER_SCROLL_DISCRETE, + _popup_scroll_cb, NULL); dt_action_define(&darktable.control->actions_focus, NULL, N_("sliders"), NULL, &_action_def_focus_slider); From ad9c8eccdc245c98f3a60929274d054d50322a71 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 01:33:46 -0300 Subject: [PATCH 26/95] gtk4-prep: convert timeline event signals to event controllers --- src/libs/tools/timeline.c | 161 +++++++++++++++++++------------------- 1 file changed, 81 insertions(+), 80 deletions(-) diff --git a/src/libs/tools/timeline.c b/src/libs/tools/timeline.c index aa2ec475ad2..8ac47879fc7 100644 --- a/src/libs/tools/timeline.c +++ b/src/libs/tools/timeline.c @@ -1072,44 +1072,47 @@ static gboolean _lib_timeline_draw_callback(GtkWidget *widget, cairo_t *wcr, dt_ return TRUE; } -static gboolean _lib_timeline_button_press_callback(GtkWidget *w, GdkEventButton *e, dt_lib_module_t *self) +static void _lib_timeline_button_press_callback(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, + dt_lib_module_t *self) { dt_lib_timeline_t *strip = self->data; - if(e->button == GDK_BUTTON_PRIMARY) + const guint button = gtk_gesture_single_get_button(gesture); + + if(button == GDK_BUTTON_PRIMARY && n_press == 1) { - if(e->type == GDK_BUTTON_PRESS) + if(x - strip->start_x < 2 && x - strip->start_x > -2) { - if(e->x - strip->start_x < 2 && e->x - strip->start_x > -2) - { - strip->start_x = strip->stop_x; - strip->start_t = strip->stop_t; - strip->stop_x = e->x; - strip->stop_t = _time_get_from_pos(e->x, strip); - strip->move_edge = TRUE; - } - else if(e->x - strip->stop_x < 2 && e->x - strip->stop_x > -2) - { - strip->stop_x = e->x; - strip->stop_t = _time_get_from_pos(e->x, strip); - strip->move_edge = TRUE; - } + strip->start_x = strip->stop_x; + strip->start_t = strip->stop_t; + strip->stop_x = x; + strip->stop_t = _time_get_from_pos(x, strip); + strip->move_edge = TRUE; + } + else if(x - strip->stop_x < 2 && x - strip->stop_x > -2) + { + strip->stop_x = x; + strip->stop_t = _time_get_from_pos(x, strip); + strip->move_edge = TRUE; + } + else + { + strip->start_x = strip->stop_x = x; + dt_datetime_t tt = _time_get_from_pos(x, strip); + if(_time_compare(tt, _time_init()) == 0) + strip->start_t = strip->stop_t = strip->time_maxi; //we are past the end so selection extends until the end else - { - strip->start_x = strip->stop_x = e->x; - dt_datetime_t tt = _time_get_from_pos(e->x, strip); - if(_time_compare(tt, _time_init()) == 0) - strip->start_t = strip->stop_t = strip->time_maxi; //we are past the end so selection extends until the end - else - strip->start_t = strip->stop_t = tt; - strip->move_edge = FALSE; - } - strip->selecting = TRUE; - strip->has_selection = TRUE; - gtk_widget_queue_draw(strip->timeline); + strip->start_t = strip->stop_t = tt; + strip->move_edge = FALSE; } + strip->selecting = TRUE; + strip->has_selection = TRUE; + gtk_widget_queue_draw(strip->timeline); } - else if(e->button == GDK_BUTTON_SECONDARY) + else if(button == GDK_BUTTON_SECONDARY) { // we remove the last rule if it's a datetime one const int nb_rules = dt_conf_get_int("plugins/lighttable/collect/num_rules"); @@ -1127,18 +1130,20 @@ static gboolean _lib_timeline_button_press_callback(GtkWidget *w, GdkEventButton } } } - - return FALSE; } -static gboolean _lib_timeline_button_release_callback(GtkWidget *w, GdkEventButton *e, dt_lib_module_t *self) +static void _lib_timeline_button_release_callback(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, + dt_lib_module_t *self) { dt_lib_timeline_t *strip = self->data; if(strip->selecting) { - strip->stop_x = e->x; - dt_datetime_t tt = _time_get_from_pos(e->x, strip); + strip->stop_x = x; + dt_datetime_t tt = _time_get_from_pos(x, strip); if(_time_compare(tt, _time_init()) == 0) strip->stop_t = strip->time_maxi; //we are past the end so selection extends until the end else @@ -1160,14 +1165,14 @@ static gboolean _lib_timeline_button_release_callback(GtkWidget *w, GdkEventButt } strip->selecting = FALSE; - if(!strip->move_edge && dt_modifier_is(e->state, GDK_SHIFT_MASK)) + GdkModifierType state; + gtk_get_current_event_state(&state); + if(!strip->move_edge && dt_modifier_is(state, GDK_SHIFT_MASK)) _selection_collect(strip, DT_LIB_TIMELINE_MODE_RESET); else _selection_collect(strip, DT_LIB_TIMELINE_MODE_AND); gtk_widget_queue_draw(strip->timeline); } - - return TRUE; } static void _selection_start(dt_action_t *action) @@ -1258,14 +1263,17 @@ static gboolean _block_autoscroll(dt_lib_module_t *self) return TRUE; } -static gboolean _lib_timeline_motion_notify_callback(GtkWidget *w, GdkEventMotion *e, dt_lib_module_t *self) +static void _lib_timeline_motion_notify_cb(GtkEventControllerMotion *controller, + gdouble x, + gdouble y, + dt_lib_module_t *self) { dt_lib_timeline_t *strip = self->data; strip->in = TRUE; // auto-scroll if cursor is at one end of the panel - if((e->x < 10 || e->x > strip->panel_width - 10) && !strip->autoscroll) + if((x < 10 || x > strip->panel_width - 10) && !strip->autoscroll) { // first scroll immediately and then every 400ms until cursor quit the "auto-zone" if(_block_autoscroll(self)) @@ -1275,22 +1283,22 @@ static gboolean _lib_timeline_motion_notify_callback(GtkWidget *w, GdkEventMotio } } - strip->current_x = e->x; + strip->current_x = x; if(strip->selecting) { - strip->stop_x = e->x; - strip->stop_t = _time_get_from_pos(e->x, strip); + strip->stop_x = x; + strip->stop_t = _time_get_from_pos(x, strip); dt_control_change_cursor("default"); } else { // we change the cursor if we are close enough of a selection limit - if(e->x - strip->start_x < 2 && e->x - strip->start_x > -2) + if(x - strip->start_x < 2 && x - strip->start_x > -2) { dt_control_change_cursor("w-resize"); } - else if(e->x - strip->stop_x < 2 && e->x - strip->stop_x > -2) + else if(x - strip->stop_x < 2 && x - strip->stop_x > -2) { dt_control_change_cursor("e-resize"); } @@ -1300,25 +1308,29 @@ static gboolean _lib_timeline_motion_notify_callback(GtkWidget *w, GdkEventMotio } } gtk_widget_queue_draw(strip->timeline); - return TRUE; } -static gboolean _lib_timeline_scroll_callback(GtkWidget *w, GdkEventScroll *e, dt_lib_module_t *self) +static void _lib_timeline_scroll_cb(GtkEventControllerScroll *controller, + gdouble dx, + gdouble dy, + dt_lib_module_t *self) { dt_lib_timeline_t *strip = self->data; + GdkModifierType state; + gtk_get_current_event_state(&state); + // zoom change (with Ctrl key) - if(dt_modifier_is(e->state, GDK_CONTROL_MASK)) + if(dt_modifier_is(state, GDK_CONTROL_MASK)) { int z = strip->zoom; - int delta_y = 0; - if(dt_gui_get_scroll_unit_delta(e, &delta_y)) + if(dy != 0.0) { - if(delta_y < 0) + if(dy < 0) { if(z != DT_LIB_TIMELINE_ZOOM_HOUR) z++; } - else if(delta_y > 0) + else if(dy > 0) { if(z != DT_LIB_TIMELINE_ZOOM_YEAR) z--; } @@ -1338,37 +1350,32 @@ static gboolean _lib_timeline_scroll_callback(GtkWidget *w, GdkEventScroll *e, d strip->surface = NULL; gtk_widget_queue_draw(strip->timeline); } - return TRUE; + return; } else { // timeline panning: right==down==forward - int delta_x = 0, delta_y = 0; - if(dt_gui_get_scroll_unit_deltas(e, &delta_x, &delta_y)) - { - int move = abs(delta_x) > abs(delta_y) ? delta_x : delta_y; - if(dt_modifier_is(e->state, GDK_SHIFT_MASK)) move *= 2; + int move = fabs(dx) > fabs(dy) ? (int)dx : (int)dy; + if(dt_modifier_is(state, GDK_SHIFT_MASK)) move *= 2; - _time_add(&(strip->time_pos), move, strip->zoom); - // we ensure that the fimlstrip stay in the bounds - strip->time_pos = _selection_scroll_to(strip->time_pos, strip); + _time_add(&(strip->time_pos), move, strip->zoom); + // we ensure that the fimlstrip stay in the bounds + strip->time_pos = _selection_scroll_to(strip->time_pos, strip); - cairo_surface_destroy(strip->surface); - strip->surface = NULL; - gtk_widget_queue_draw(strip->timeline); - } + cairo_surface_destroy(strip->surface); + strip->surface = NULL; + gtk_widget_queue_draw(strip->timeline); } - return FALSE; } -static gboolean _lib_timeline_mouse_leave_callback(GtkWidget *w, GdkEventCrossing *e, dt_lib_module_t *self) +static void _lib_timeline_mouse_leave_cb(GtkEventControllerMotion *controller, + dt_lib_module_t *self) { dt_lib_timeline_t *strip = self->data; strip->in = FALSE; gtk_widget_queue_draw(strip->timeline); - return TRUE; } void gui_init(dt_lib_module_t *self) @@ -1396,20 +1403,14 @@ void gui_init(dt_lib_module_t *self) /* creating timeline box*/ d->timeline = gtk_event_box_new(); - gtk_widget_add_events(d->timeline, GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK - | GDK_BUTTON_RELEASE_MASK | darktable.gui->scroll_mask - | GDK_LEAVE_NOTIFY_MASK); + gtk_widget_add_events(d->timeline, 0); g_signal_connect(G_OBJECT(d->timeline), "draw", G_CALLBACK(_lib_timeline_draw_callback), self); - g_signal_connect(G_OBJECT(d->timeline), "button-press-event", G_CALLBACK(_lib_timeline_button_press_callback), - self); - g_signal_connect(G_OBJECT(d->timeline), "button-release-event", - G_CALLBACK(_lib_timeline_button_release_callback), self); - g_signal_connect(G_OBJECT(d->timeline), "scroll-event", G_CALLBACK(_lib_timeline_scroll_callback), self); - g_signal_connect(G_OBJECT(d->timeline), "motion-notify-event", G_CALLBACK(_lib_timeline_motion_notify_callback), - self); - g_signal_connect(G_OBJECT(d->timeline), "leave-notify-event", G_CALLBACK(_lib_timeline_mouse_leave_callback), - self); + dt_gui_connect_click_all(d->timeline, _lib_timeline_button_press_callback, _lib_timeline_button_release_callback, self); + dt_gui_connect_motion(d->timeline, _lib_timeline_motion_notify_cb, NULL, _lib_timeline_mouse_leave_cb, self); + dt_gui_connect_scroll(d->timeline, GTK_EVENT_CONTROLLER_SCROLL_BOTH_AXES + | GTK_EVENT_CONTROLLER_SCROLL_DISCRETE, + _lib_timeline_scroll_cb, self); gtk_box_pack_start(GTK_BOX(self->widget), d->timeline, TRUE, TRUE, 0); From 5c449136fc42f23a57a97f6ba4560c755bac79ad Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 01:33:58 -0300 Subject: [PATCH 27/95] gtk4-prep: convert culling event signals to event controllers --- src/dtgtk/culling.c | 170 ++++++++++++++++++-------------------------- 1 file changed, 71 insertions(+), 99 deletions(-) diff --git a/src/dtgtk/culling.c b/src/dtgtk/culling.c index 2fff76a66d4..649c201dded 100644 --- a/src/dtgtk/culling.c +++ b/src/dtgtk/culling.c @@ -809,118 +809,106 @@ static gboolean _event_draw(GtkWidget *widget, return FALSE; // let's propagate this event } -static gboolean _event_leave_notify(GtkWidget *widget, - GdkEventCrossing *event, - gpointer user_data) +static void _event_leave_cb(GtkEventControllerMotion *controller, + dt_culling_t *table) { - dt_culling_t *table = (dt_culling_t *)user_data; + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); // if the leaving cause is the hide of the widget, no mouseover change if(!gtk_widget_is_visible(widget)) { table->mouse_inside = FALSE; - return FALSE; + return; } - // if we leave thumbtable in favour of an inferior (a thumbnail) - // it's not a real leave ! same if this is not a mouse move action - // (shortcut that activate a button for example) - if(event->detail == GDK_NOTIFY_INFERIOR - || event->mode == GDK_CROSSING_GTK_GRAB - || event->mode == GDK_CROSSING_GRAB) - return FALSE; - table->mouse_inside = FALSE; dt_control_set_mouse_over_id(NO_IMGID); - return TRUE; } -static gboolean _event_enter_notify(GtkWidget *widget, - GdkEventCrossing *event, - gpointer user_data) +static void _event_enter_cb(GtkEventControllerMotion *controller, + gdouble x, + gdouble y, + dt_culling_t *table) { - // we only handle the case where we enter thumbtable from an - // inferior (a thumbnail) this is when the mouse enter an "empty" - // area of thumbtable - if(event->detail != GDK_NOTIFY_INFERIOR) return FALSE; - + // when entering the culling area, clear the mouse-over id dt_control_set_mouse_over_id(NO_IMGID); - return TRUE; } -static gboolean _event_button_press(GtkWidget *widget, - GdkEventButton *event, - gpointer user_data) +static void _event_button_press_cb(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, + dt_culling_t *table) { - dt_culling_t *table = (dt_culling_t *)user_data; + const guint button = gtk_gesture_single_get_button(gesture); - if(dt_gdk_event_get_button(event) == GDK_BUTTON_PRIMARY - && dt_gdk_event_get_type(event) == GDK_BUTTON_PRESS) + if(button == GDK_BUTTON_PRIMARY && n_press == 1) { // make sure any edition field loses the focus gtk_widget_grab_focus(dt_ui_center(darktable.gui->ui)); } - if(dt_gdk_event_get_button(event) == GDK_BUTTON_MIDDLE) + if(button == GDK_BUTTON_MIDDLE) { - // convert screen coordinates to culling coordinates - int ox = 0, oy = 0; - GdkWindow *win = gtk_widget_get_window(table->widget); - if(win) - gdk_window_get_origin(win, &ox, &oy); - const float x_culling = dt_gdk_event_get_root_x(event) - ox; - const float y_culling = dt_gdk_event_get_root_y(event) - oy; - // if shift is pressed, we work only with image hovered - if(dt_modifier_is(dt_gdk_event_get_state(event), GDK_SHIFT_MASK)) - _toggle_zoom_current(table, x_culling, y_culling); + GdkModifierType state; + gtk_get_current_event_state(&state); + if(dt_modifier_is(state, GDK_SHIFT_MASK)) + _toggle_zoom_current(table, x, y); else - _toggle_zoom_all(table, x_culling, y_culling); - return TRUE; + _toggle_zoom_all(table, x, y); + return; } - const dt_imgid_t id = dt_control_get_mouse_over_id(); - if(dt_is_valid_imgid(id) - && dt_gdk_event_get_button(event) == GDK_BUTTON_PRIMARY - && dt_gdk_event_get_type(event) == GDK_2BUTTON_PRESS) - { - // we have to set again the selected image, because it was deselected - // during the previous GDK_BUTTON_PRESS event - const dt_imgid_t old_selection = table->selection; - table->selection = id; - dt_view_manager_switch(darktable.view_manager, "darkroom"); - if (id != old_selection) + if(button == GDK_BUTTON_PRIMARY && n_press == 2) + { + const dt_imgid_t id = dt_control_get_mouse_over_id(); + if(dt_is_valid_imgid(id)) { - _update_selected_thumbnail(table, old_selection); - dt_act_on_reset_cache(TRUE); - dt_act_on_reset_cache(FALSE); + // we have to set again the selected image, because it was deselected + // during the previous GDK_BUTTON_PRESS event + const dt_imgid_t old_selection = table->selection; + table->selection = id; + dt_view_manager_switch(darktable.view_manager, "darkroom"); + if(id != old_selection) + { + _update_selected_thumbnail(table, old_selection); + dt_act_on_reset_cache(TRUE); + dt_act_on_reset_cache(FALSE); + } } - return TRUE; + return; } - table->pan_x = dt_gdk_event_get_root_x(event); - table->pan_y = dt_gdk_event_get_root_y(event); + // start panning — need root coordinates for pan tracking + const GdkEvent *current = gtk_get_current_event(); + if(current) + gdk_event_get_root_coords(current, &table->pan_x, &table->pan_y); table->panning = TRUE; - return TRUE; } -static gboolean _event_motion_notify(GtkWidget *widget, - GdkEventMotion *event, - gpointer user_data) +static void _event_motion_notify_cb(GtkEventControllerMotion *controller, + gdouble x, + gdouble y, + dt_culling_t *table) { - dt_culling_t *table = (dt_culling_t *)user_data; + // get root coordinates for pan tracking + const GdkEvent *current = gtk_get_current_event(); + gdouble root_x = 0, root_y = 0; + if(current) gdk_event_get_root_coords(current, &root_x, &root_y); + table->mouse_inside = TRUE; if(!table->panning) { - table->pan_x = dt_gdk_event_get_root_x(event); - table->pan_y = dt_gdk_event_get_root_y(event); - return FALSE; + table->pan_x = root_x; + table->pan_y = root_y; + return; } // get the max zoom of all images const int max_in_memory_images = _get_max_in_memory_images(); if(table->mode == DT_CULLING_MODE_CULLING && table->thumbs_count > max_in_memory_images) - return FALSE; + return; float fz = 1.0f; for(GList *l = table->list; l; l = g_list_next(l)) @@ -931,14 +919,14 @@ static gboolean _event_motion_notify(GtkWidget *widget, if(table->panning && fz > 1.0f) { - const double x = dt_gdk_event_get_root_x(event); - const double y = dt_gdk_event_get_root_y(event); // we want the images to stay in the screen const float scale = darktable.gui->ppd_thb / darktable.gui->ppd; - const float valx = (x - table->pan_x) * scale; - const float valy = (y - table->pan_y) * scale; + const float valx = (root_x - table->pan_x) * scale; + const float valy = (root_y - table->pan_y) * scale; - if(dt_modifier_is(dt_gdk_event_get_state(event), GDK_SHIFT_MASK)) + GdkModifierType state; + gtk_get_current_event_state(&state); + if(dt_modifier_is(state, GDK_SHIFT_MASK)) { const dt_imgid_t mouseid = dt_control_get_mouse_over_id(); for(GList *l = table->list; l; l = g_list_next(l)) @@ -983,8 +971,8 @@ static gboolean _event_motion_notify(GtkWidget *widget, th->zoomy = mindy; } - table->pan_x = x; - table->pan_y = y; + table->pan_x = root_x; + table->pan_y = root_y; } for(GList *l = table->list; l; l = g_list_next(l)) @@ -992,22 +980,21 @@ static gboolean _event_motion_notify(GtkWidget *widget, dt_thumbnail_t *th = l->data; dt_thumbnail_image_refresh_position(th); } - return TRUE; } -static gboolean _event_button_release(GtkWidget *widget, - GdkEventButton *event, - gpointer user_data) +static void _event_button_release_cb(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, + dt_culling_t *table) { - dt_culling_t *table = (dt_culling_t *)user_data; table->panning = FALSE; const dt_imgid_t overid = dt_control_get_mouse_over_id(); // if the act_on algorithm need a specific culling "selection", // we use a very simple culling-specific selection if(dt_act_on_use_culling_selection() - && dt_is_valid_imgid(overid) - && dt_gdk_event_get_button(event) == GDK_BUTTON_PRIMARY) + && dt_is_valid_imgid(overid)) { const dt_imgid_t old_sel = table->selection; if(table->selection == overid) @@ -1026,8 +1013,6 @@ static gboolean _event_button_release(GtkWidget *widget, dt_act_on_reset_cache(TRUE); dt_act_on_reset_cache(FALSE); } - - return TRUE; } // called each time the preference change, to update specific parts @@ -1215,12 +1200,7 @@ dt_culling_t *dt_culling_new(const dt_culling_mode_t mode) // set widget signals gtk_widget_set_events(table->widget, GDK_EXPOSURE_MASK - | GDK_POINTER_MOTION_MASK - | GDK_BUTTON_PRESS_MASK - | GDK_BUTTON_RELEASE_MASK | GDK_STRUCTURE_MASK - | GDK_ENTER_NOTIFY_MASK - | GDK_LEAVE_NOTIFY_MASK | GDK_TOUCHPAD_GESTURE_MASK); dt_gui_add_class(table->widget, "dt_transparent_background"); @@ -1232,16 +1212,8 @@ dt_culling_t *dt_culling_new(const dt_culling_mode_t mode) G_CALLBACK(_event_scroll), table); g_signal_connect(G_OBJECT(table->widget), "draw", G_CALLBACK(_event_draw), table); - g_signal_connect(G_OBJECT(table->widget), "leave-notify-event", - G_CALLBACK(_event_leave_notify), table); - g_signal_connect(G_OBJECT(table->widget), "enter-notify-event", - G_CALLBACK(_event_enter_notify), table); - g_signal_connect(G_OBJECT(table->widget), "button-press-event", - G_CALLBACK(_event_button_press), table); - g_signal_connect(G_OBJECT(table->widget), "motion-notify-event", - G_CALLBACK(_event_motion_notify), table); - g_signal_connect(G_OBJECT(table->widget), "button-release-event", - G_CALLBACK(_event_button_release), table); + dt_gui_connect_motion(table->widget, _event_motion_notify_cb, _event_enter_cb, _event_leave_cb, table); + dt_gui_connect_click_all(table->widget, _event_button_press_cb, _event_button_release_cb, table); // we register globals signals DT_CONTROL_SIGNAL_CONNECT(DT_SIGNAL_MOUSE_OVER_IMAGE_CHANGE, From b99fa585cb9b580b0a3b0ba3a173d5ba88a5de8a Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 01:34:00 -0300 Subject: [PATCH 28/95] gtk4-prep: convert thumbtable event signals to event controllers --- src/dtgtk/thumbtable.c | 152 ++++++++++++++++++----------------------- 1 file changed, 68 insertions(+), 84 deletions(-) diff --git a/src/dtgtk/thumbtable.c b/src/dtgtk/thumbtable.c index d2d717f1cbe..d926eddc423 100644 --- a/src/dtgtk/thumbtable.c +++ b/src/dtgtk/thumbtable.c @@ -1375,43 +1375,30 @@ static gboolean _event_draw(GtkWidget *widget, return FALSE; // let's propagate this event } -static gboolean _event_leave_notify(GtkWidget *widget, - GdkEventCrossing *event, - dt_thumbtable_t *table) +static void _event_leave_cb(GtkEventControllerMotion *controller, + dt_thumbtable_t *table) { + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); // if the leaving cause is the hide of the widget, no mouseover change if(!gtk_widget_is_visible(widget)) { table->mouse_inside = FALSE; - return FALSE; + return; } - // if we leave thumbtable in favour of an inferior (a thumbnail) - // it's not a real leave ! same if this is not a mouse move action - // (shortcut that activate a button for example) - if(event->detail == GDK_NOTIFY_INFERIOR - || event->mode == GDK_CROSSING_GTK_GRAB - || event->mode == GDK_CROSSING_GRAB) - return FALSE; - table->mouse_inside = FALSE; dt_control_set_mouse_over_id(NO_IMGID); - return TRUE; } -static gboolean _event_enter_notify(GtkWidget *widget, - GdkEventCrossing *event, - dt_thumbtable_t *table) +static void _event_enter_cb(GtkEventControllerMotion *controller, + gdouble x, + gdouble y, + dt_thumbtable_t *table) { dt_set_backthumb_time(0.0); - // we only handle the case where we enter thumbtable from an inferior (a thumbnail) - // this is when the mouse enter an "empty" area of thumbtable - if(event->detail != GDK_NOTIFY_INFERIOR) - return FALSE; - + // when entering the thumbtable area, clear the mouse-over id dt_control_set_mouse_over_id(NO_IMGID); - return TRUE; } static gboolean _do_select_single(gpointer user_data) @@ -1427,25 +1414,28 @@ static gboolean _do_select_single(gpointer user_data) return FALSE; } -static gboolean _event_button_press(GtkWidget *widget, - GdkEventButton *event, - dt_thumbtable_t *table) +static void _event_button_press_cb(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, + dt_thumbtable_t *table) { dt_set_backthumb_time(0.0); + const guint button = gtk_gesture_single_get_button(gesture); const dt_imgid_t id = dt_control_get_mouse_over_id(); - if(dt_is_valid_imgid(id) && dt_gdk_event_get_button(event) == GDK_BUTTON_PRIMARY) + if(button == GDK_BUTTON_PRIMARY && n_press == 2) { - // double-click - if(dt_gdk_event_get_type(event) == GDK_2BUTTON_PRESS) + // double-click + if(dt_is_valid_imgid(id)) { switch(table->mode) { case DT_THUMBTABLE_MODE_FILEMANAGER: case DT_THUMBTABLE_MODE_ZOOM: dt_view_manager_switch(darktable.view_manager, "darkroom"); - break; + return; case DT_THUMBTABLE_MODE_FILMSTRIP: if(dt_view_get_current() == DT_VIEW_DARKROOM) @@ -1455,35 +1445,34 @@ static gboolean _event_button_press(GtkWidget *widget, g_source_remove(table->sel_single_cb); table->sel_single_cb = 0; } - // disable next BUTTON_RELEASE event (see _event_motion_release) + // disable next BUTTON_RELEASE event table->to_selid = -1; // unselect currently edited picture, select new one dt_selection_deselect(darktable.selection, darktable.develop->image_storage.id); dt_selection_select(darktable.selection, id); DT_CONTROL_SIGNAL_RAISE(DT_SIGNAL_VIEWMANAGER_THUMBTABLE_ACTIVATE, id); - return FALSE; + return; } default: break; } } - - if(dt_gdk_event_get_type(event) == GDK_BUTTON_PRESS - && table->mode == DT_THUMBTABLE_MODE_FILMSTRIP) - return FALSE; } - if(dt_gdk_event_get_button(event) == GDK_BUTTON_PRIMARY && dt_gdk_event_get_type(event) == GDK_BUTTON_PRESS) + if(button == GDK_BUTTON_PRIMARY && n_press == 1 + && table->mode == DT_THUMBTABLE_MODE_FILMSTRIP) + return; + + if(button == GDK_BUTTON_PRIMARY && n_press == 1) { // make sure any edition field loses the focus gtk_widget_grab_focus(dt_ui_center(darktable.gui->ui)); } - if(table->mode != DT_THUMBTABLE_MODE_ZOOM - && !dt_is_valid_imgid(id) - && dt_gdk_event_get_button(event) == GDK_BUTTON_PRIMARY - && dt_gdk_event_get_type(event) == GDK_BUTTON_PRESS) + if(button == GDK_BUTTON_PRIMARY && n_press == 1 + && table->mode != DT_THUMBTABLE_MODE_ZOOM + && !dt_is_valid_imgid(id)) { const dt_view_type_flags_t cv = dt_view_get_current(); @@ -1499,20 +1488,20 @@ static gboolean _event_button_press(GtkWidget *widget, darktable.develop->image_storage.id); } - PangoRectangle *button = &table->manual_button; - if(dt_gdk_event_get_x(event) < button->x && dt_gdk_event_get_x(event) > button->x - button->width - && dt_gdk_event_get_y(event) < button->y && dt_gdk_event_get_y(event) > button->y - button->height) + PangoRectangle *button_rect = &table->manual_button; + if(x < button_rect->x && x > button_rect->x - button_rect->width + && y < button_rect->y && y > button_rect->y - button_rect->height) { dt_gui_show_help(NULL); } - return TRUE; + return; } if(table->mode != DT_THUMBTABLE_MODE_ZOOM) - return TRUE; + return; - if(dt_gdk_event_get_button(event) == GDK_BUTTON_PRIMARY && dt_gdk_event_get_type(event) == GDK_BUTTON_PRESS) + if(button == GDK_BUTTON_PRIMARY && n_press == 1) { table->dragging = TRUE; table->drag_dx = table->drag_dy = 0; @@ -1521,22 +1510,26 @@ static gboolean _event_button_press(GtkWidget *widget, if(table->drag_thumb) table->drag_thumb->moved = FALSE; } - return TRUE; } -static gboolean _event_motion_notify(GtkWidget *widget, - GdkEventMotion *event, - dt_thumbtable_t *table) +static void _event_motion_notify_cb(GtkEventControllerMotion *controller, + gdouble x, + gdouble y, + dt_thumbtable_t *table) { dt_set_backthumb_time(0.0); table->mouse_inside = TRUE; - gboolean ret = FALSE; + // get root coordinates for drag tracking + const GdkEvent *current = gtk_get_current_event(); + gdouble root_x = 0, root_y = 0; + if(current) gdk_event_get_root_coords(current, &root_x, &root_y); + if(table->dragging && table->mode == DT_THUMBTABLE_MODE_ZOOM) { - const int dx = ceil(dt_gdk_event_get_root_x(event)) - table->last_x; - const int dy = ceil(dt_gdk_event_get_root_y(event)) - table->last_y; + const int dx = ceil(root_x) - table->last_x; + const int dy = ceil(root_y) - table->last_y; _move(table, dx, dy, TRUE); table->drag_dx += dx; table->drag_dy += dy; @@ -1547,17 +1540,17 @@ static gboolean _event_motion_notify(GtkWidget *widget, table->drag_thumb->moved = ((abs(table->drag_dx) + abs(table->drag_dy)) > DT_PIXEL_APPLY_DPI(8)); } - ret = TRUE; } - table->last_x = ceil(dt_gdk_event_get_root_x(event)); - table->last_y = ceil(dt_gdk_event_get_root_y(event)); - return ret; + table->last_x = ceil(root_x); + table->last_y = ceil(root_y); } -static gboolean _event_button_release(GtkWidget *widget, - GdkEventButton *event, - dt_thumbtable_t *table) +static void _event_button_release_cb(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, + dt_thumbtable_t *table) { // we select only in LIGHTTABLE, DARKROOM & MAP mode const dt_view_type_flags_t cv = dt_view_get_current(); @@ -1566,21 +1559,22 @@ static gboolean _event_button_release(GtkWidget *widget, && cv != DT_VIEW_LIGHTTABLE && cv != DT_VIEW_MAP && cv != DT_VIEW_PRINT) - return FALSE; + return; dt_set_backthumb_time(0.0); const dt_imgid_t id = dt_control_get_mouse_over_id(); - if(dt_is_valid_imgid(id) - && dt_gdk_event_get_button(event) == GDK_BUTTON_PRIMARY - && dt_gdk_event_get_type(event) == GDK_BUTTON_RELEASE) + GdkModifierType state; + gtk_get_current_event_state(&state); + + if(dt_is_valid_imgid(id)) { - if(dt_modifier_is(dt_gdk_event_get_state(event), GDK_CONTROL_MASK) - || dt_modifier_is(dt_gdk_event_get_state(event), GDK_MOD2_MASK)) // CMD key on macOS + if(dt_modifier_is(state, GDK_CONTROL_MASK) + || dt_modifier_is(state, GDK_MOD2_MASK)) // CMD key on macOS { dt_selection_toggle(darktable.selection, id); } - else if(dt_modifier_is(dt_gdk_event_get_state(event), GDK_SHIFT_MASK)) + else if(dt_modifier_is(state, GDK_SHIFT_MASK)) { dt_selection_select_range(darktable.selection, id); } @@ -1602,7 +1596,8 @@ static gboolean _event_button_release(GtkWidget *widget, } else { - GtkSettings *settings = gtk_widget_get_settings(GTK_WIDGET (widget)); + GtkWidget *w = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + GtkSettings *settings = gtk_widget_get_settings(GTK_WIDGET(w)); guint double_click_time = 400; if(settings) @@ -1631,7 +1626,7 @@ static gboolean _event_button_release(GtkWidget *widget, // Left now if not in zoom mode if(table->mode != DT_THUMBTABLE_MODE_ZOOM) - return TRUE; + return; // in some case, image_over_id can get out of sync at the end of dragging // this happen esp. if the pointer as been out of the center area during drag @@ -1662,7 +1657,6 @@ static gboolean _event_button_release(GtkWidget *widget, // we register the position dt_conf_set_int("lighttable/zoomable/last_pos_x", table->thumbs_area.x); dt_conf_set_int("lighttable/zoomable/last_pos_y", table->thumbs_area.y); - return TRUE; } // set scrollbars visibility @@ -2572,10 +2566,8 @@ dt_thumbtable_t *dt_thumbtable_new() // set widget signals gtk_widget_set_events(table->widget, - GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK - | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - | GDK_STRUCTURE_MASK - | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK); + GDK_EXPOSURE_MASK + | GDK_STRUCTURE_MASK); dt_gui_add_class(table->widget, "dt_transparent_background"); gtk_widget_set_can_focus(table->widget, TRUE); @@ -2598,16 +2590,8 @@ dt_thumbtable_t *dt_thumbtable_new() G_CALLBACK(_event_scroll), table); g_signal_connect(G_OBJECT(table->widget), "draw", G_CALLBACK(_event_draw), table); - g_signal_connect(G_OBJECT(table->widget), "leave-notify-event", - G_CALLBACK(_event_leave_notify), table); - g_signal_connect(G_OBJECT(table->widget), "enter-notify-event", - G_CALLBACK(_event_enter_notify), table); - g_signal_connect(G_OBJECT(table->widget), "button-press-event", - G_CALLBACK(_event_button_press), table); - g_signal_connect(G_OBJECT(table->widget), "motion-notify-event", - G_CALLBACK(_event_motion_notify), table); - g_signal_connect(G_OBJECT(table->widget), "button-release-event", - G_CALLBACK(_event_button_release), table); + dt_gui_connect_motion(table->widget, _event_motion_notify_cb, _event_enter_cb, _event_leave_cb, table); + dt_gui_connect_click_all(table->widget, _event_button_press_cb, _event_button_release_cb, table); // we register globals signals DT_CONTROL_SIGNAL_CONNECT(DT_SIGNAL_COLLECTION_CHANGED, From 9202e18c40c4fc35aa9f1a7a7ed874ff8ad68baa Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 01:34:02 -0300 Subject: [PATCH 29/95] gtk4-prep: convert accelerators event signals to event controllers --- src/gui/accelerators.c | 50 +++++++++++++++++++----------------------- 1 file changed, 22 insertions(+), 28 deletions(-) diff --git a/src/gui/accelerators.c b/src/gui/accelerators.c index 5267e9fdaee..621b259a119 100644 --- a/src/gui/accelerators.c +++ b/src/gui/accelerators.c @@ -1988,10 +1988,13 @@ static void _shortcut_row_activated(GtkTreeView *tree_view, _grab_in_tree_view(tree_view); } -static gboolean _view_key_pressed(GtkWidget *widget, - GdkEventKey *event, - gpointer user_data) +static gboolean _view_key_pressed_cb(GtkEventControllerKey *controller, + guint keyval, + guint keycode, + GdkModifierType state, + GtkWidget *search_entry) { + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); GtkTreeView *view = GTK_TREE_VIEW(widget); GtkTreeSelection *selection = gtk_tree_view_get_selection(view); @@ -2002,7 +2005,7 @@ static gboolean _view_key_pressed(GtkWidget *widget, if(!strcmp(gtk_widget_get_name(widget), "actions_view")) { // if control key pressed, copy lua command to clipboard (CTRL+C will work) - if(dt_modifier_is(dt_gdk_event_get_state(event), GDK_CONTROL_MASK)) + if(dt_modifier_is(state, GDK_CONTROL_MASK)) { dt_shortcut_t shortcut = { .speed = 1.0 }; gtk_tree_model_get(model, &iter, 0, &shortcut.action, -1); @@ -2020,13 +2023,13 @@ static gboolean _view_key_pressed(GtkWidget *widget, dt_shortcut_t *s = g_sequence_get(shortcut_iter); // if control key pressed, copy lua command to clipboard (CTRL+C will work) - if(dt_modifier_is(dt_gdk_event_get_state(event), GDK_CONTROL_MASK) && s->views) + if(dt_modifier_is(state, GDK_CONTROL_MASK) && s->views) { _shortcut_copy_lua(NULL, s, NULL); } // GDK_KEY_BackSpace moves to parent in tree - if(dt_gdk_event_get_keyval(event) == GDK_KEY_Delete || dt_gdk_event_get_keyval(event) == GDK_KEY_KP_Delete) + if(keyval == GDK_KEY_Delete || keyval == GDK_KEY_KP_Delete) { if(dt_gui_show_yes_no_dialog(_("removing shortcut"), "", s->is_default ? s->views ? @@ -2045,7 +2048,7 @@ static gboolean _view_key_pressed(GtkWidget *widget, } } - return dt_gui_search_start(widget, event, user_data); + return dt_gui_search_start(widget, (GdkEventKey *)gtk_get_current_event(), GTK_SEARCH_ENTRY(search_entry)); } static void _add_shortcuts_to_tree() @@ -2260,22 +2263,22 @@ static gboolean _action_find_and_expand(GtkTreeModel *model, return FALSE; } -static gboolean _action_view_click(GtkWidget *widget, - GdkEventButton *event, - gpointer data) +static void _action_view_click_cb(GtkGestureSingle *gesture, int n_press, double x, double y, GtkTreeStore *model_data) { + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); GtkTreeView *view = GTK_TREE_VIEW(widget); GtkTreeModel *model = gtk_tree_view_get_model(view); + const guint button = gtk_gesture_single_get_button(gesture); - if(dt_gdk_event_get_button(event) == GDK_BUTTON_PRIMARY) + if(button == GDK_BUTTON_PRIMARY) { GtkTreeSelection *selection = gtk_tree_view_get_selection(view); GtkTreePath *path = NULL; - if(gtk_tree_view_get_path_at_pos(view, (gint)dt_gdk_event_get_x(event), (gint)dt_gdk_event_get_y(event), + if(gtk_tree_view_get_path_at_pos(view, (gint)x, (gint)y, &path, NULL, NULL, NULL)) { - if(dt_gdk_event_get_type(event) == GDK_DOUBLE_BUTTON_PRESS) + if(n_press == 2) { gtk_tree_selection_select_path(selection, path); _action_row_activated(view, path, NULL, model); @@ -2296,15 +2299,13 @@ static gboolean _action_view_click(GtkWidget *widget, else gtk_tree_selection_unselect_all(selection); } - else if(dt_gdk_event_get_button(event) == GDK_BUTTON_SECONDARY) + else if(button == GDK_BUTTON_SECONDARY) { GtkTreeIter iter; gtk_tree_model_get_iter_first(model, &iter); _action_find_and_expand(model, &iter, view); } - - return TRUE; } static gboolean _action_view_show(GtkTreeView *view, @@ -2910,8 +2911,7 @@ GtkWidget *dt_shortcuts_prefs(GtkWidget *widget) gtk_widget_set_name(GTK_WIDGET(shortcuts_view), "shortcuts_view"); g_signal_connect(G_OBJECT(shortcuts_view), "row-activated", G_CALLBACK(_shortcut_row_activated), filtered_shortcuts); - g_signal_connect(G_OBJECT(shortcuts_view), "key-press-event", - G_CALLBACK(_view_key_pressed), search_shortcuts); + dt_gui_connect_key(shortcuts_view, _view_key_pressed_cb, search_shortcuts); g_signal_connect(G_OBJECT(_shortcuts_store), "row-inserted", G_CALLBACK(_shortcut_row_inserted), shortcuts_view); @@ -3009,10 +3009,8 @@ GtkWidget *dt_shortcuts_prefs(GtkWidget *widget) gtk_widget_set_name(GTK_WIDGET(actions_view), "actions_view"); g_signal_connect(G_OBJECT(actions_view), "row-activated", G_CALLBACK(_action_row_activated), _actions_store); - g_signal_connect(G_OBJECT(actions_view), "button-press-event", - G_CALLBACK(_action_view_click), _actions_store); - g_signal_connect(G_OBJECT(actions_view), "key-press-event", - G_CALLBACK(_view_key_pressed), search_actions); + dt_gui_connect_click_all(actions_view, _action_view_click_cb, NULL, _actions_store); + dt_gui_connect_key(actions_view, _view_key_pressed_cb, search_actions); g_signal_connect(G_OBJECT(gtk_tree_view_get_selection(actions_view)), "changed", G_CALLBACK(_action_selection_changed), shortcuts_view); @@ -4853,12 +4851,9 @@ dt_action_t *dt_action_locate(dt_action_t *owner, return owner; } -static gboolean _reset_element_on_leave(GtkWidget *widget, - GdkEvent *event, - gpointer user_data) +static void _reset_element_on_leave_cb(GtkEventControllerMotion *controller, gpointer user_data) { darktable.control->element = -1; - return FALSE; } dt_action_t *dt_action_define(dt_action_t *owner, @@ -4917,8 +4912,7 @@ dt_action_t *dt_action_define(dt_action_t *owner, } gtk_widget_set_has_tooltip(widget, TRUE); - g_signal_connect(G_OBJECT(widget), "leave-notify-event", - G_CALLBACK(_reset_element_on_leave), NULL); + dt_gui_connect_motion(widget, NULL, NULL, _reset_element_on_leave_cb, NULL); } } From 1ff2acbd58c31a16688bc366f366933f63c2c089 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 01:35:08 -0300 Subject: [PATCH 30/95] gtk4-prep: convert ratings event signals to event controllers --- src/libs/tools/ratings.c | 60 ++++++++++++++++++---------------------- 1 file changed, 27 insertions(+), 33 deletions(-) diff --git a/src/libs/tools/ratings.c b/src/libs/tools/ratings.c index 148c83ca362..ce08f042b71 100644 --- a/src/libs/tools/ratings.c +++ b/src/libs/tools/ratings.c @@ -15,8 +15,6 @@ You should have received a copy of the GNU General Public License along with darktable. If not, see . */ -#include "common/gdk_event_utils.h" - #include "common/ratings.h" #include "common/collection.h" #include "common/debug.h" @@ -40,17 +38,20 @@ typedef struct dt_lib_ratings_t /* redraw the ratings */ static gboolean _lib_ratings_draw_callback(GtkWidget *widget, cairo_t *cr, dt_lib_module_t *self); /* motion notify handler*/ -static gboolean _lib_ratings_motion_notify_callback(GtkWidget *widget, GdkEventMotion *event, - dt_lib_module_t *self); +static void _lib_ratings_motion_notify_callback(GtkEventControllerMotion *controller, + double x, double y, + dt_lib_module_t *self); /* motion leavel handler */ -static gboolean _lib_ratings_leave_notify_callback(GtkWidget *widget, GdkEventCrossing *event, - dt_lib_module_t *self); +static void _lib_ratings_leave_notify_callback(GtkEventControllerMotion *controller, + dt_lib_module_t *self); /* button press handler */ -static gboolean _lib_ratings_button_press_callback(GtkWidget *widget, GdkEventButton *event, - dt_lib_module_t *self); +static void _lib_ratings_button_press_callback(GtkGestureSingle *gesture, int n_press, + double x, double y, + dt_lib_module_t *self); /* button release handler */ -static gboolean _lib_ratings_button_release_callback(GtkWidget *widget, GdkEventButton *event, - dt_lib_module_t *self); +static void _lib_ratings_button_release_callback(GtkGestureSingle *gesture, int n_press, + double x, double y, + dt_lib_module_t *self); const char *name(dt_lib_module_t *self) { @@ -89,20 +90,14 @@ void gui_init(dt_lib_module_t *self) GtkWidget *drawing = gtk_drawing_area_new(); - gtk_widget_set_events(drawing, GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK - | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK - | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - | GDK_STRUCTURE_MASK); + gtk_widget_set_events(drawing, GDK_EXPOSURE_MASK | GDK_STRUCTURE_MASK); /* connect callbacks */ gtk_widget_set_tooltip_text(drawing, _("set star rating for selected images")); dt_gui_add_class(drawing, "dt_transparent_background"); g_signal_connect(G_OBJECT(drawing), "draw", G_CALLBACK(_lib_ratings_draw_callback), self); - g_signal_connect(G_OBJECT(drawing), "button-press-event", G_CALLBACK(_lib_ratings_button_press_callback), self); - g_signal_connect(G_OBJECT(drawing), "button-release-event", G_CALLBACK(_lib_ratings_button_release_callback), - self); - g_signal_connect(G_OBJECT(drawing), "motion-notify-event", G_CALLBACK(_lib_ratings_motion_notify_callback), self); - g_signal_connect(G_OBJECT(drawing), "leave-notify-event", G_CALLBACK(_lib_ratings_leave_notify_callback), self); + dt_gui_connect_click(drawing, _lib_ratings_button_press_callback, _lib_ratings_button_release_callback, self); + dt_gui_connect_motion(drawing, _lib_ratings_motion_notify_callback, NULL, _lib_ratings_leave_notify_callback, self); gtk_box_pack_start(GTK_BOX(self->widget), drawing, TRUE, TRUE, 0); @@ -180,19 +175,20 @@ static gboolean _lib_ratings_draw_callback(GtkWidget *widget, cairo_t *crf, dt_l return TRUE; } -static gboolean _lib_ratings_motion_notify_callback(GtkWidget *widget, GdkEventMotion *event, - dt_lib_module_t *self) +static void _lib_ratings_motion_notify_callback(GtkEventControllerMotion *controller, + double x, double y, + dt_lib_module_t *self) { dt_lib_ratings_t *d = self->data; - d->pointerx = dt_gdk_event_get_x(event); - d->pointery = dt_gdk_event_get_y(event); + d->pointerx = x; + d->pointery = y; gtk_widget_queue_draw(self->widget); - return TRUE; } -static gboolean _lib_ratings_button_press_callback(GtkWidget *widget, GdkEventButton *event, - dt_lib_module_t *self) +static void _lib_ratings_button_press_callback(GtkGestureSingle *gesture, int n_press, + double x, double y, + dt_lib_module_t *self) { dt_lib_ratings_t *d = self->data; if(d->current > 0) @@ -203,22 +199,20 @@ static gboolean _lib_ratings_button_press_callback(GtkWidget *widget, GdkEventBu dt_control_queue_redraw_center(); } - return TRUE; } -static gboolean _lib_ratings_button_release_callback(GtkWidget *widget, GdkEventButton *event, - dt_lib_module_t *self) +static void _lib_ratings_button_release_callback(GtkGestureSingle *gesture, int n_press, + double x, double y, + dt_lib_module_t *self) { - return TRUE; } -static gboolean _lib_ratings_leave_notify_callback(GtkWidget *widget, GdkEventCrossing *event, - dt_lib_module_t *self) +static void _lib_ratings_leave_notify_callback(GtkEventControllerMotion *controller, + dt_lib_module_t *self) { dt_lib_ratings_t *d = self->data; d->pointery = d->pointerx = 0; gtk_widget_queue_draw(self->widget); - return TRUE; } From 6b23561a179b53de240aca929720412b33173fd4 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 01:36:28 -0300 Subject: [PATCH 31/95] gtk4-prep: convert navigation event signals to event controllers --- src/libs/navigation.c | 88 +++++++++++++++++++++---------------------- 1 file changed, 43 insertions(+), 45 deletions(-) diff --git a/src/libs/navigation.c b/src/libs/navigation.c index ba61f4baa5f..f67d52e12e6 100644 --- a/src/libs/navigation.c +++ b/src/libs/navigation.c @@ -49,9 +49,9 @@ static gboolean _lib_navigation_draw_callback(GtkWidget *widget, cairo_t *crf, gpointer user_data); /* motion notify callback handler*/ -static gboolean _lib_navigation_motion_notify_callback(GtkWidget *widget, - GdkEventMotion *event, - dt_lib_module_t *self); +static void _lib_navigation_motion_notify_callback(GtkEventControllerMotion *controller, + double x, double y, + dt_lib_module_t *self); /* scroll callback */ static void _lib_navigation_scroll_callback(GtkEventControllerScroll *controller, double dx, double dy, @@ -65,17 +65,16 @@ static void _lib_navigation_pinch_scale_callback(GtkGesture *gesture, gdouble scale, dt_lib_module_t *self); /* button press callback */ -static gboolean _lib_navigation_button_press_callback(GtkWidget *widget, - GdkEvent *event, - dt_lib_module_t *self); +static void _lib_navigation_button_press_callback(GtkGestureSingle *gesture, int n_press, + double x, double y, + dt_lib_module_t *self); /* button release callback */ -static gboolean _lib_navigation_button_release_callback(GtkWidget *widget, - GdkEventButton *event, - dt_lib_module_t *self); +static void _lib_navigation_button_release_callback(GtkGestureSingle *gesture, int n_press, + double x, double y, + dt_lib_module_t *self); /* leave notify callback */ -static gboolean _lib_navigation_leave_notify_callback(GtkWidget *widget, - GdkEventCrossing *event, - dt_lib_module_t *self); +static void _lib_navigation_leave_notify_callback(GtkEventControllerMotion *controller, + dt_lib_module_t *self); /* helper function for position set */ static void _lib_navigation_set_position(struct dt_lib_module_t *self, @@ -229,10 +228,7 @@ void gui_init(dt_lib_module_t *self) dt_gui_add_class(thumbnail, "dt_transparent_background"); g_signal_connect(G_OBJECT(thumbnail), "draw", G_CALLBACK(_lib_navigation_draw_callback), self); - g_signal_connect(G_OBJECT(thumbnail), "button-press-event", - G_CALLBACK(_lib_navigation_button_press_callback), self); - g_signal_connect(G_OBJECT(thumbnail), "button-release-event", - G_CALLBACK(_lib_navigation_button_release_callback), self); + dt_gui_connect_click_all(thumbnail, _lib_navigation_button_press_callback, _lib_navigation_button_release_callback, self); dt_gui_connect_scroll(thumbnail, GTK_EVENT_CONTROLLER_SCROLL_BOTH_AXES, _lib_navigation_scroll_callback, self); // FIXME: Make helper function for zoom gesture. If discrete zooming @@ -242,10 +238,7 @@ void gui_init(dt_lib_module_t *self) g_object_weak_ref(G_OBJECT(thumbnail), (GWeakNotify) g_object_unref, zoom_gesture); g_signal_connect(zoom_gesture, "begin", G_CALLBACK(_lib_navigation_pinch_begin_callback), self); g_signal_connect(zoom_gesture, "scale-changed", G_CALLBACK(_lib_navigation_pinch_scale_callback), self); - g_signal_connect(G_OBJECT(thumbnail), "motion-notify-event", - G_CALLBACK(_lib_navigation_motion_notify_callback), self); - g_signal_connect(G_OBJECT(thumbnail), "leave-notify-event", - G_CALLBACK(_lib_navigation_leave_notify_callback), self); + dt_gui_connect_motion(thumbnail, _lib_navigation_motion_notify_callback, NULL, _lib_navigation_leave_notify_callback, self); /* set size of navigation draw area */ // gtk_widget_set_size_request(thumbnail, -1, DT_PIXEL_APPLY_DPI(175)); @@ -422,15 +415,15 @@ void _lib_navigation_set_position(dt_lib_module_t *self, } } -static gboolean _lib_navigation_motion_notify_callback(GtkWidget *widget, - GdkEventMotion *event, - dt_lib_module_t *self) +static void _lib_navigation_motion_notify_callback(GtkEventControllerMotion *controller, + double x, double y, + dt_lib_module_t *self) { + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); GtkAllocation allocation; gtk_widget_get_allocation(widget, &allocation); - _lib_navigation_set_position(self, dt_gdk_event_get_x(event), dt_gdk_event_get_y(event), + _lib_navigation_set_position(self, x, y, allocation.width, allocation.height); - return TRUE; } static void _zoom_changed(GtkWidget *widget, gpointer user_data) @@ -592,48 +585,53 @@ static void _lib_navigation_pinch_scale_callback(GtkGesture *gesture, } } -static gboolean _lib_navigation_button_press_callback(GtkWidget *widget, - GdkEvent *event, - dt_lib_module_t *self) +static void _lib_navigation_button_press_callback(GtkGestureSingle *gesture, int n_press, + double x, double y, + dt_lib_module_t *self) { dt_lib_navigation_t *d = self->data; + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); GtkAllocation allocation; gtk_widget_get_allocation(widget, &allocation); - if(dt_gdk_event_get_type(event) == GDK_BUTTON_PRESS && dt_gdk_event_get_button(event) != 2) + const guint button = gtk_gesture_single_get_button(gesture); + + if(button == GDK_BUTTON_PRIMARY || button == GDK_BUTTON_SECONDARY) { d->dragging = 1; - _lib_navigation_set_position(self, dt_gdk_event_get_x(event), dt_gdk_event_get_y(event), + _lib_navigation_set_position(self, x, y, allocation.width, allocation.height); - - return TRUE; } - else + else if(button == GDK_BUTTON_MIDDLE) { GtkWidget *center = dt_ui_center(darktable.gui->ui); GtkAllocation center_alloc; gtk_widget_get_allocation(center, ¢er_alloc); - event->scroll.x *= (gdouble)center_alloc.width / allocation.width; - event->scroll.y *= (gdouble)center_alloc.height / allocation.height; - return gtk_widget_event(center, event); + GdkEvent *ev = gdk_event_new(GDK_BUTTON_PRESS); + gdk_event_set_screen(ev, gtk_widget_get_screen(center)); + ev->button.window = gtk_widget_get_window(center); + ev->button.button = GDK_BUTTON_MIDDLE; + ev->button.x = x * (gdouble)center_alloc.width / allocation.width; + ev->button.y = y * (gdouble)center_alloc.height / allocation.height; + ev->button.type = GDK_BUTTON_PRESS; + ev->button.time = GDK_CURRENT_TIME; + if(ev->button.window) g_object_ref(ev->button.window); + gtk_widget_event(center, ev); + gdk_event_free(ev); } } -static gboolean _lib_navigation_button_release_callback(GtkWidget *widget, - GdkEventButton *event, - dt_lib_module_t *self) +static void _lib_navigation_button_release_callback(GtkGestureSingle *gesture, int n_press, + double x, double y, + dt_lib_module_t *self) { dt_lib_navigation_t *d = self->data; d->dragging = 0; - - return TRUE; } -static gboolean _lib_navigation_leave_notify_callback(GtkWidget *widget, - GdkEventCrossing *event, - dt_lib_module_t *self) +static void _lib_navigation_leave_notify_callback(GtkEventControllerMotion *controller, + dt_lib_module_t *self) { - return TRUE; } // clang-format off From de141dd10b71549641f47314db95d23310860cc7 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 01:37:19 -0300 Subject: [PATCH 32/95] gtk4-prep: convert log history event signals to event controllers --- src/libs/tools/log_history.c | 57 ++++++++++++------------------------ 1 file changed, 18 insertions(+), 39 deletions(-) diff --git a/src/libs/tools/log_history.c b/src/libs/tools/log_history.c index b4ba8dfc472..b92c3d0a160 100644 --- a/src/libs/tools/log_history.c +++ b/src/libs/tools/log_history.c @@ -15,8 +15,6 @@ You should have received a copy of the GNU General Public License along with darktable. If not, see . */ -#include "common/gdk_event_utils.h" - #include "control/signal.h" #include "control/control.h" #include "dtgtk/button.h" @@ -37,14 +35,14 @@ typedef struct dt_lib_log_history_t static void _populate_list_box(dt_lib_module_t *self); static void _log_redraw_callback(gpointer instance, dt_lib_module_t *self); -static gboolean _button_press_release(GtkWidget *button, - GdkEventButton *event, - dt_lib_module_t *self); +static void _button_press_cb(GtkGestureSingle *gesture, int n_press, + double x, double y, + dt_lib_module_t *self); static gboolean _suppress_popup(GtkWidget *widget, gpointer user_data); -static gboolean _label_button_press(GtkWidget *widget, - GdkEventButton *event, - gpointer user_data); +static void _label_button_press_cb(GtkGestureSingle *gesture, int n_press, + double x, double y, + gpointer user_data); const char *name(dt_lib_module_t *self) { @@ -97,8 +95,7 @@ static void _populate_list_box(dt_lib_module_t *self) gtk_label_set_xalign(GTK_LABEL(label), 0.0f); gtk_label_set_selectable(GTK_LABEL(label), TRUE); dt_gui_add_class(label, "dt_monospace"); - g_signal_connect(G_OBJECT(label), "button-press-event", - G_CALLBACK(_label_button_press), NULL); + dt_gui_connect_click_all(label, _label_button_press_cb, NULL, NULL); g_signal_connect(G_OBJECT(label), "popup-menu", G_CALLBACK(_suppress_popup), NULL); gtk_list_box_insert(GTK_LIST_BOX(d->list_box), label, -1); @@ -137,29 +134,20 @@ static gboolean _suppress_popup(GtkWidget *widget, return TRUE; } -static gboolean _label_button_press(GtkWidget *widget, - GdkEventButton *event, - gpointer user_data) +static void _label_button_press_cb(GtkGestureSingle *gesture, int n_press, + double x, double y, + gpointer user_data) { - if(dt_gdk_event_get_button(event) == GDK_BUTTON_SECONDARY) - return TRUE; - return FALSE; + if(gtk_gesture_single_get_button(gesture) == GDK_BUTTON_SECONDARY) + dt_gui_claim(gesture); } -static gboolean _button_press_release(GtkWidget *button, - GdkEventButton *event, - dt_lib_module_t *self) +static void _button_press_cb(GtkGestureSingle *gesture, int n_press, + double x, double y, + dt_lib_module_t *self) { - static guint start_time = 0; - - int delay = 0; - g_object_get(gtk_settings_get_default(), "gtk-long-press-time", &delay, NULL); - - if((dt_gdk_event_get_type(event) == GDK_BUTTON_PRESS - && (dt_gdk_event_get_button(event) == GDK_BUTTON_PRIMARY - || dt_gdk_event_get_button(event) == GDK_BUTTON_SECONDARY)) - || (dt_gdk_event_get_type(event) == GDK_BUTTON_RELEASE - && dt_gdk_event_get_time(event) - start_time > delay)) + const guint button = gtk_gesture_single_get_button(gesture); + if(button == GDK_BUTTON_PRIMARY || button == GDK_BUTTON_SECONDARY) { dt_lib_log_history_t *d = self->data; if(gtk_widget_is_visible(d->popover)) @@ -171,12 +159,6 @@ static gboolean _button_press_release(GtkWidget *button, // hide unread indicator now that the user sees the log gtk_widget_hide(d->badge); } - return TRUE; - } - else - { - start_time = dt_gdk_event_get_time(event); - return FALSE; } } @@ -223,10 +205,7 @@ void gui_init(dt_lib_module_t *self) gtk_container_add(GTK_CONTAINER(d->scrolled), d->list_box); gtk_container_add(GTK_CONTAINER(d->popover), d->scrolled); - g_signal_connect(G_OBJECT(d->button), "button-press-event", - G_CALLBACK(_button_press_release), self); - g_signal_connect(G_OBJECT(d->button), "button-release-event", - G_CALLBACK(_button_press_release), self); + dt_gui_connect_click_all(d->button, _button_press_cb, NULL, self); self->widget = dt_gui_hbox(overlay); From 4a47bc3b30fa0f7a3c6af62cc1352baac9b4e882 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 01:38:35 -0300 Subject: [PATCH 33/95] gtk4-prep: convert viewswitcher event signals to event controllers --- src/libs/tools/viewswitcher.c | 45 ++++++++++++++++++++++------------- 1 file changed, 28 insertions(+), 17 deletions(-) diff --git a/src/libs/tools/viewswitcher.c b/src/libs/tools/viewswitcher.c index 766911f3acd..3232f2b98cd 100644 --- a/src/libs/tools/viewswitcher.c +++ b/src/libs/tools/viewswitcher.c @@ -1,6 +1,6 @@ /* This file is part of darktable, - Copyright (C) 2011-2024 darktable developers. + Copyright (C) 2011-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 @@ -45,12 +45,19 @@ typedef struct dt_lib_viewswitcher_t } dt_lib_viewswitcher_t; /* callback when a view label is pressed */ -static gboolean _lib_viewswitcher_button_press_callback(GtkWidget *w, GdkEventButton *ev, const dt_view_t *view); +static void _lib_viewswitcher_button_press_callback(GtkGestureSingle *gesture, int n_press, + double x, double y, + dt_view_t *view); /* helper function to create a label */ static GtkWidget *_lib_viewswitcher_create_label(dt_view_t *view); /* callback when view changed signal happens */ static void _lib_viewswitcher_view_changed_callback(gpointer instance, dt_view_t *old_view, dt_view_t *new_view, dt_lib_module_t *self); +static void _lib_viewswitcher_enter_callback(GtkEventControllerMotion *controller, + double x, double y, + GtkWidget *label); +static void _lib_viewswitcher_leave_callback(GtkEventControllerMotion *controller, + GtkWidget *label); static void _lib_viewswitcher_view_cannot_change_callback(gpointer instance, dt_view_t *old_view, dt_view_t *new_view, dt_lib_module_t *self); static void _switch_view(const dt_view_t *view); @@ -171,15 +178,22 @@ void gui_cleanup(dt_lib_module_t *self) self->data = NULL; } -static gboolean _lib_viewswitcher_enter_leave_notify_callback(GtkWidget *w, GdkEventCrossing *e, GtkLabel *l) +static void _lib_viewswitcher_enter_callback(GtkEventControllerMotion *controller, + double x, double y, + GtkWidget *label) { + GtkWidget *w = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); /* if not active view lets highlight */ - if(e->type == GDK_ENTER_NOTIFY && - strcmp(g_object_get_data(G_OBJECT(w), "view-label"), dt_view_manager_name(darktable.view_manager))) - gtk_widget_set_state_flags(GTK_WIDGET(l), GTK_STATE_FLAG_PRELIGHT, FALSE); + if(strcmp(g_object_get_data(G_OBJECT(w), "view-label"), dt_view_manager_name(darktable.view_manager))) + gtk_widget_set_state_flags(label, GTK_STATE_FLAG_PRELIGHT, FALSE); else - gtk_widget_unset_state_flags(GTK_WIDGET(l), GTK_STATE_FLAG_PRELIGHT); - return FALSE; + gtk_widget_unset_state_flags(label, GTK_STATE_FLAG_PRELIGHT); +} + +static void _lib_viewswitcher_leave_callback(GtkEventControllerMotion *controller, + GtkWidget *label) +{ + gtk_widget_unset_state_flags(label, GTK_STATE_FLAG_PRELIGHT); } static void _lib_viewswitcher_view_cannot_change_callback(gpointer instance, dt_view_t *old_view, @@ -259,13 +273,10 @@ static GtkWidget *_lib_viewswitcher_create_label(dt_view_t *view) gtk_widget_set_state_flags(b, GTK_STATE_FLAG_NORMAL, TRUE); /* connect button press handler */ - g_signal_connect(G_OBJECT(eb), "button-press-event", G_CALLBACK(_lib_viewswitcher_button_press_callback), view); + dt_gui_connect_click(eb, _lib_viewswitcher_button_press_callback, NULL, view); /* set enter/leave notify events and connect signals */ - gtk_widget_add_events(GTK_WIDGET(eb), GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK); - - g_signal_connect(G_OBJECT(eb), "enter-notify-event", G_CALLBACK(_lib_viewswitcher_enter_leave_notify_callback), b); - g_signal_connect(G_OBJECT(eb), "leave-notify-event", G_CALLBACK(_lib_viewswitcher_enter_leave_notify_callback), b); + dt_gui_connect_motion(eb, NULL, _lib_viewswitcher_enter_callback, _lib_viewswitcher_leave_callback, b); return eb; } @@ -275,14 +286,14 @@ static void _switch_view(const dt_view_t *view) dt_ctl_switch_mode_to_by_view(view); } -static gboolean _lib_viewswitcher_button_press_callback(GtkWidget *w, GdkEventButton *ev, const dt_view_t *view) +static void _lib_viewswitcher_button_press_callback(GtkGestureSingle *gesture, int n_press, + double x, double y, + dt_view_t *view) { - if(ev->button == GDK_BUTTON_PRIMARY) + if(gtk_gesture_single_get_button(gesture) == GDK_BUTTON_PRIMARY) { _switch_view(view); - return TRUE; } - return FALSE; } From e89fd14d54ba6250f9aeadf189cc8bd5fe53cbe7 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 01:40:23 -0300 Subject: [PATCH 34/95] gtk4-prep: convert colorlabels event signals to event controllers --- src/libs/tools/colorlabels.c | 64 ++++++++++++++++++++---------------- 1 file changed, 35 insertions(+), 29 deletions(-) diff --git a/src/libs/tools/colorlabels.c b/src/libs/tools/colorlabels.c index 8e125a56091..d6aed035a19 100644 --- a/src/libs/tools/colorlabels.c +++ b/src/libs/tools/colorlabels.c @@ -15,8 +15,6 @@ You should have received a copy of the GNU General Public License along with darktable. If not, see . */ -#include "common/gdk_event_utils.h" - #include "bauhaus/bauhaus.h" #include "common/colorlabels.h" #include "common/collection.h" @@ -45,9 +43,12 @@ typedef struct dt_lib_colorlabels_t } dt_lib_colorlabels_t; /* callback when a colorlabel button is clicked */ -static gboolean _lib_colorlabels_button_clicked_callback(GtkWidget *w, - GdkEventButton *event, - dt_lib_module_t *self); +static void _lib_colorlabels_button_press_callback(GtkGestureSingle *gesture, int n_press, + double x, double y, + dt_lib_module_t *self); +static void _lib_colorlabels_enter_notify_callback(GtkEventControllerMotion *controller, + double x, double y, + dt_lib_module_t *self); gint _get_colorlabel(dt_lib_module_t *self, GtkWidget *w) { @@ -85,14 +86,14 @@ int position(const dt_lib_module_t *self) return 1001; } -static gboolean _lib_colorlabels_enter_notify_callback(GtkWidget *widget, - GdkEventCrossing *event, +static void _lib_colorlabels_enter_notify_callback(GtkEventControllerMotion *controller, + double x, double y, dt_lib_module_t *self) { + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); const gint colorlabel = _get_colorlabel(self, widget); darktable.control->element = (colorlabel + 1) % 6; - return FALSE; } static char *_get_tooltip_for(const int coloridx) @@ -137,12 +138,8 @@ void gui_init(dt_lib_module_t *self) gtk_widget_set_tooltip_markup(button, tooltip); g_free(tooltip); gtk_box_pack_start(GTK_BOX(self->widget), button, TRUE, TRUE, 0); - g_signal_connect(G_OBJECT(button), "button-press-event", - G_CALLBACK(_lib_colorlabels_button_clicked_callback), - self); - g_signal_connect(G_OBJECT(button), "enter-notify-event", - G_CALLBACK(_lib_colorlabels_enter_notify_callback), - self); + dt_gui_connect_click_all(button, _lib_colorlabels_button_press_callback, NULL, self); + dt_gui_connect_motion(button, NULL, _lib_colorlabels_enter_notify_callback, NULL, self); ac = dt_action_define(&darktable.control->actions_thumb, NULL, N_("color label"), button, &dt_action_def_color_label); } @@ -164,13 +161,15 @@ void gui_cleanup(dt_lib_module_t *self) #define FLOATING_ENTRY_WIDTH DT_PIXEL_APPLY_DPI(150) -static gboolean _lib_colorlabels_key_press(GtkWidget *entry, - GdkEventKey *event, - dt_lib_module_t *self) +static gboolean _lib_colorlabels_key_press_cb(GtkEventControllerKey *controller, + guint keyval, + guint keycode, + GdkModifierType state, + dt_lib_module_t *self) { dt_lib_colorlabels_t *d = self->data; - switch(dt_gdk_event_get_keyval(event)) + switch(keyval) { case GDK_KEY_Escape: gtk_widget_destroy(d->floating_window); @@ -181,6 +180,7 @@ static gboolean _lib_colorlabels_key_press(GtkWidget *entry, case GDK_KEY_Return: case GDK_KEY_KP_Enter: { + GtkWidget *entry = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); char confname[128]; const gchar *label = gtk_entry_get_text(GTK_ENTRY(entry)); snprintf(confname, sizeof(confname), "colorlabel/%s", @@ -210,7 +210,8 @@ static gboolean _lib_colorlabels_destroy(GtkWidget *widget, } static void _lib_colorlabels_edit(dt_lib_module_t *self, - GdkEventButton *event) + const gdouble root_x, + const gdouble root_y) { dt_lib_colorlabels_t *d = self->data; @@ -225,7 +226,7 @@ static void _lib_colorlabels_edit(dt_lib_module_t *self, gtk_widget_add_events(entry, GDK_FOCUS_CHANGE_MASK); gtk_editable_select_region(GTK_EDITABLE(entry), 0, -1); g_signal_connect(entry, "focus-out-event", G_CALLBACK(_lib_colorlabels_destroy), self); - g_signal_connect(entry, "key-press-event", G_CALLBACK(_lib_colorlabels_key_press), self); + dt_gui_connect_key(entry, _lib_colorlabels_key_press_cb, self); gtk_widget_set_tooltip_text(entry, _("enter a description of how you use this color label")); if(use_popover) @@ -248,8 +249,8 @@ static void _lib_colorlabels_edit(dt_lib_module_t *self, else { // Legacy/X11 path: keep undecorated popup GtkWindow - const gint x = dt_gdk_event_get_root_x(event); - const gint y = dt_gdk_event_get_root_y(event) - DT_PIXEL_APPLY_DPI(50); + const gint x = root_x; + const gint y = root_y - DT_PIXEL_APPLY_DPI(50); d->floating_window = gtk_window_new(GTK_WINDOW_TOPLEVEL); #ifdef GDK_WINDOWING_QUARTZ @@ -268,20 +269,26 @@ static void _lib_colorlabels_edit(dt_lib_module_t *self, } } -static gboolean _lib_colorlabels_button_clicked_callback(GtkWidget *w, - GdkEventButton *event, - dt_lib_module_t *self) +static void _lib_colorlabels_button_press_callback(GtkGestureSingle *gesture, int n_press, + double x, double y, + dt_lib_module_t *self) { + GtkWidget *w = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); dt_lib_colorlabels_t *d = self->data; const gint colorlabel = _get_colorlabel(self, w); - if(dt_gdk_event_get_type(event) == GDK_BUTTON_PRESS - && dt_gdk_event_get_button(event) == GDK_BUTTON_SECONDARY + if(gtk_gesture_single_get_button(gesture) == GDK_BUTTON_SECONDARY && colorlabel != 5) // The button to reset colorlabels needs no description { d->colorlabel = colorlabel; - _lib_colorlabels_edit(self, event); + GdkEvent *ev = gtk_get_current_event(); + if(ev) + { + gdouble root_x, root_y; + gdk_event_get_root_coords(ev, &root_x, &root_y); + _lib_colorlabels_edit(self, root_x, root_y); + } } else { @@ -291,7 +298,6 @@ static gboolean _lib_colorlabels_button_clicked_callback(GtkWidget *w, DT_COLLECTION_CHANGE_RELOAD, DT_COLLECTION_PROP_COLORLABEL, imgs); } - return TRUE; } // clang-format off From 24ef633fa21945bf575d6c0b9a808508c401c74c Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 01:41:39 -0300 Subject: [PATCH 35/95] gtk4-prep: convert colors filter enter-notify event to event controller --- src/libs/filters/colors.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/libs/filters/colors.c b/src/libs/filters/colors.c index e366fe4a0cc..41a557ec4c1 100644 --- a/src/libs/filters/colors.c +++ b/src/libs/filters/colors.c @@ -265,10 +265,11 @@ static gboolean _colors_update(dt_lib_filtering_rule_t *rule) return TRUE; } -static gboolean _colors_enter_notify(GtkWidget *widget, GdkEventCrossing *event, gpointer user_data) +static void _colors_enter_cb(GtkEventControllerMotion *controller, + double x, double y, + gpointer user_data) { darktable.control->element = GPOINTER_TO_INT(user_data) + 1; - return FALSE; } static float _action_process_colors(gpointer target, dt_action_element_t element, dt_action_effect_t effect, float move_size) @@ -349,8 +350,7 @@ static void _colors_widget_init(dt_lib_filtering_rule_t *rule, const dt_collecti "\nctrl+click to exclude the color label" "\nthe gray button affects all color labels")); dt_gui_connect_click(colors->colors[k], _colors_clicked_gesture, NULL, colors); - g_signal_connect(G_OBJECT(colors->colors[k]), "enter-notify-event", G_CALLBACK(_colors_enter_notify), - GINT_TO_POINTER(k)); + dt_gui_connect_motion(colors->colors[k], NULL, _colors_enter_cb, NULL, GINT_TO_POINTER(k)); dt_action_define(DT_ACTION(self), N_("rules"), N_("color label"), colors->colors[k], &dt_action_def_colors_rule); } colors->operator= dtgtk_button_new(dtgtk_cairo_paint_intersection, 0, NULL); @@ -360,8 +360,7 @@ static void _colors_widget_init(dt_lib_filtering_rule_t *rule, const dt_collecti "\nintersection: images having all selected color labels" "\nunion: images with at least one of the selected color labels")); g_signal_connect(G_OBJECT(colors->operator), "clicked", G_CALLBACK(_colors_operator_clicked), colors); - g_signal_connect(G_OBJECT(colors->operator), "enter-notify-event", G_CALLBACK(_colors_enter_notify), - GINT_TO_POINTER(-1)); + dt_gui_connect_motion(colors->operator, NULL, _colors_enter_cb, NULL, GINT_TO_POINTER(-1)); dt_action_t *ac = dt_action_define(DT_ACTION(self), N_("rules"), N_("color label"), colors->operator, &dt_action_def_colors_rule); dt_shortcut_register(ac, DT_COLORLABELS_RED + 1, DT_ACTION_EFFECT_TOGGLE, GDK_KEY_F1, GDK_SHIFT_MASK); From 40066f2c8b2963786514efcd2bd3289668f152a5 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 01:42:37 -0300 Subject: [PATCH 36/95] gtk4-prep: convert location result button-press event to event controller --- src/libs/location.c | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/src/libs/location.c b/src/libs/location.c index c09fdc888c6..312325936e9 100644 --- a/src/libs/location.c +++ b/src/libs/location.c @@ -15,8 +15,6 @@ You should have received a copy of the GNU General Public License along with darktable. If not, see . */ -#include "common/gdk_event_utils.h" - #include "common/darktable.h" #include "common/geo.h" #include "common/curl_tools.h" @@ -89,9 +87,9 @@ typedef struct _callback_param_t static void _lib_location_entry_activated(GtkButton *button, dt_lib_module_t *self); -static gboolean _lib_location_result_item_activated(GtkButton *button, - GdkEventButton *ev, - gpointer user_data); +static void _lib_location_result_item_activated(GtkGestureSingle *gesture, int n_press, + double x, double y, + gpointer user_data); static void _lib_location_parser_start_element(GMarkupParseContext *cxt, const char *element_name, @@ -209,9 +207,7 @@ static GtkWidget *_lib_location_place_widget_new(dt_lib_location_t *lib, lib->callback_params = g_list_append(lib->callback_params, param); param->lib = lib; param->result = place; - g_signal_connect(G_OBJECT(eb), "button-press-event", - G_CALLBACK(_lib_location_result_item_activated), - (gpointer)param); + dt_gui_connect_click(eb, _lib_location_result_item_activated, NULL, param); } return eb; } @@ -440,15 +436,14 @@ static gboolean _lib_location_search(dt_lib_module_t *self) return FALSE; } -gboolean _lib_location_result_item_activated(GtkButton *button, - GdkEventButton *ev, - gpointer user_data) +static void _lib_location_result_item_activated(GtkGestureSingle *gesture, int n_press, + double x, double y, + gpointer user_data) { _callback_param_t *param = (_callback_param_t *)user_data; dt_lib_location_t *lib = param->lib; _lib_location_result_t *result = param->result; _show_location(lib, result); - return TRUE; } void _lib_location_entry_activated(GtkButton *button, From 7c2fc896f540748860f33b12357046201e0b51d5 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 01:44:00 -0300 Subject: [PATCH 37/95] gtk4-prep: convert blend gui event signals to event controllers --- src/develop/blend_gui.c | 66 ++++++++++++++++++++--------------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/src/develop/blend_gui.c b/src/develop/blend_gui.c index b9289771678..dfd1219567d 100644 --- a/src/develop/blend_gui.c +++ b/src/develop/blend_gui.c @@ -2192,28 +2192,33 @@ static void _blendop_blendif_channel_mask_view_toggle // magic mode: if mouse cursor enters a gradient slider with shift // and/or control pressed we enter channel display and/or mask display // mode -static gboolean _blendop_blendif_enter(GtkWidget *widget, - GdkEventCrossing *event, - dt_iop_module_t *module) +static void _blendop_blendif_enter_cb(GtkEventControllerMotion *controller, + double x, double y, + dt_iop_module_t *module) { - DT_GUARD_GUI_UPDATE(FALSE); + if(dt_atomic_get_int(&darktable.gui->reset) != 0) return; + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); dt_iop_gui_blend_data_t *data = module->blend_data; dt_dev_pixelpipe_display_mask_t mode = DT_DEV_PIXELPIPE_DISPLAY_NONE; - // depending on shift modifiers we activate channel and/or mask display - if(dt_modifier_is(dt_gdk_event_get_state(event), GDK_SHIFT_MASK | GDK_CONTROL_MASK)) - { - mode = (DT_DEV_PIXELPIPE_DISPLAY_MASK | DT_DEV_PIXELPIPE_DISPLAY_CHANNEL); - } - else if(dt_modifier_is(dt_gdk_event_get_state(event), GDK_SHIFT_MASK)) - { - mode = DT_DEV_PIXELPIPE_DISPLAY_CHANNEL; - } - else if(dt_modifier_is(dt_gdk_event_get_state(event), GDK_CONTROL_MASK)) + GdkModifierType state; + if(gtk_get_current_event_state(&state)) { - mode = DT_DEV_PIXELPIPE_DISPLAY_MASK; + // depending on shift modifiers we activate channel and/or mask display + if(dt_modifier_is(state, GDK_SHIFT_MASK | GDK_CONTROL_MASK)) + { + mode = (DT_DEV_PIXELPIPE_DISPLAY_MASK | DT_DEV_PIXELPIPE_DISPLAY_CHANNEL); + } + else if(dt_modifier_is(state, GDK_SHIFT_MASK)) + { + mode = DT_DEV_PIXELPIPE_DISPLAY_CHANNEL; + } + else if(dt_modifier_is(state, GDK_CONTROL_MASK)) + { + mode = DT_DEV_PIXELPIPE_DISPLAY_MASK; + } } dt_pthread_mutex_lock(&data->lock); @@ -2235,7 +2240,6 @@ static gboolean _blendop_blendif_enter(GtkWidget *widget, _blendop_blendif_channel_mask_view(widget, module, mode); gtk_widget_grab_focus(widget); - return FALSE; } @@ -2265,11 +2269,10 @@ static gboolean _blendop_blendif_leave_delayed(gpointer data) } // de-activate magic mode when leaving the gradient slider -static gboolean _blendop_blendif_leave(GtkWidget *widget, - GdkEventCrossing *event, - dt_iop_module_t *module) +static void _blendop_blendif_leave_cb(GtkEventControllerMotion *controller, + dt_iop_module_t *module) { - DT_GUARD_GUI_UPDATE(FALSE); + if(dt_atomic_get_int(&darktable.gui->reset) != 0) return; dt_iop_gui_blend_data_t *data = module->blend_data; @@ -2283,24 +2286,25 @@ static gboolean _blendop_blendif_leave(GtkWidget *widget, != (data->save_for_leave & ~DT_DEV_PIXELPIPE_DISPLAY_STICKY))) data->timeout_handle = g_timeout_add(1000, _blendop_blendif_leave_delayed, module); dt_pthread_mutex_unlock(&data->lock); - - return FALSE; } -static gboolean _blendop_blendif_key_press(GtkWidget *widget, - GdkEventKey *event, - dt_iop_module_t *module) +static gboolean _blendop_blendif_key_press_cb(GtkEventControllerKey *controller, + guint keyval, + guint keycode, + GdkModifierType state, + dt_iop_module_t *module) { - DT_GUARD_GUI_UPDATE(FALSE); + if(dt_atomic_get_int(&darktable.gui->reset) != 0) return FALSE; + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); dt_iop_gui_blend_data_t *data = module->blend_data; gboolean handled = FALSE; const int tab = data->tab; const int in_out = (widget == GTK_WIDGET(data->filter[1].slider)) ? 1 : 0; - switch(dt_gdk_event_get_keyval(event)) + switch(keyval) { case GDK_KEY_a: case GDK_KEY_A: @@ -2656,12 +2660,8 @@ void dt_iop_gui_init_blendif(GtkWidget *blendw, dt_iop_module_t *module) G_CALLBACK(_blendop_blendif_sliders_callback), bd); g_signal_connect(G_OBJECT(sl->slider), "value-reset", G_CALLBACK(_blendop_blendif_sliders_reset_callback), bd); - g_signal_connect(G_OBJECT(sl->slider), "leave-notify-event", - G_CALLBACK(_blendop_blendif_leave), module); - g_signal_connect(G_OBJECT(sl->slider), "enter-notify-event", - G_CALLBACK(_blendop_blendif_enter), module); - g_signal_connect(G_OBJECT(sl->slider), "key-press-event", - G_CALLBACK(_blendop_blendif_key_press), module); + dt_gui_connect_motion(sl->slider, NULL, _blendop_blendif_enter_cb, _blendop_blendif_leave_cb, module); + dt_gui_connect_key(sl->slider, _blendop_blendif_key_press_cb, module); g_signal_connect(G_OBJECT(sl->polarity), "toggled", G_CALLBACK(_blendop_blendif_polarity_callback), bd); From b55676795e14293bcd0681480f6f7f58096ea9af Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 01:47:12 -0300 Subject: [PATCH 38/95] gtk4-prep: convert export spinbutton button-press events to event controllers --- src/libs/export.c | 66 +++++++++++++++++++---------------------------- 1 file changed, 27 insertions(+), 39 deletions(-) diff --git a/src/libs/export.c b/src/libs/export.c index 3e4558e5224..6cf6263685c 100644 --- a/src/libs/export.c +++ b/src/libs/export.c @@ -567,11 +567,12 @@ static void _scale_changed(GtkEntry *spin, static void _width_changed(GtkEditable *entry, gpointer user_data); static void _height_changed(GtkEditable *entry, gpointer user_data); -static gboolean _scale_mdlclick(GtkEntry *spin, - GdkEventButton *event, - dt_lib_export_t *d) +static void _scale_mdlclick_cb(GtkGestureSingle *gesture, int n_press, + double x, double y, + dt_lib_export_t *d) { - if(dt_gdk_event_get_button(event) == GDK_BUTTON_MIDDLE) + GtkWidget *spin = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + if(gtk_gesture_single_get_button(gesture) == GDK_BUTTON_MIDDLE) { dt_conf_set_string(CONFIG_PREFIX "resizing_factor", "1"); g_signal_handlers_block_by_func(spin, _scale_changed, d); @@ -580,46 +581,44 @@ static gboolean _scale_mdlclick(GtkEntry *spin, } else { - _scale_changed(spin, d); + _scale_changed(GTK_ENTRY(spin), d); } - return FALSE; } -static gboolean _widht_mdlclick(GtkEntry *spin, - GdkEventButton *event, - gpointer user_data) +static void _widht_mdlclick_cb(GtkGestureSingle *gesture, int n_press, + double x, double y, + dt_lib_export_t *d) { - if(dt_gdk_event_get_button(event) == GDK_BUTTON_MIDDLE) + GtkWidget *spin = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + if(gtk_gesture_single_get_button(gesture) == GDK_BUTTON_MIDDLE) { dt_conf_set_int(CONFIG_PREFIX "width", 0); - g_signal_handlers_block_by_func(spin, _width_changed, user_data); + g_signal_handlers_block_by_func(spin, _width_changed, d); gtk_entry_set_text(GTK_ENTRY(spin), "0"); - g_signal_handlers_unblock_by_func(spin, _width_changed, user_data); + g_signal_handlers_unblock_by_func(spin, _width_changed, d); } else { - _width_changed(GTK_EDITABLE(spin), user_data); + _width_changed(GTK_EDITABLE(spin), d); } - - return FALSE; } -static gboolean _height_mdlclick(GtkEntry *spin, - GdkEventButton *event, - gpointer user_data) +static void _height_mdlclick_cb(GtkGestureSingle *gesture, int n_press, + double x, double y, + dt_lib_export_t *d) { - if(dt_gdk_event_get_button(event) == GDK_BUTTON_MIDDLE) + GtkWidget *spin = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + if(gtk_gesture_single_get_button(gesture) == GDK_BUTTON_MIDDLE) { dt_conf_set_int(CONFIG_PREFIX "height", 0); - g_signal_handlers_block_by_func(spin, _height_changed, user_data); + g_signal_handlers_block_by_func(spin, _height_changed, d); gtk_entry_set_text(GTK_ENTRY(spin), "0"); - g_signal_handlers_unblock_by_func(spin, _height_changed, user_data); + g_signal_handlers_unblock_by_func(spin, _height_changed, d); } else { - _height_changed(GTK_EDITABLE(spin), user_data); + _height_changed(GTK_EDITABLE(spin), d); } - return FALSE; } static void _size_in_px_update(dt_lib_export_t *d) @@ -1737,22 +1736,11 @@ void gui_init(dt_lib_module_t *self) dt_gui_box_add(d->cs.container, view, d->batch_export_button); - gtk_widget_add_events(d->width, GDK_BUTTON_PRESS_MASK); - gtk_widget_add_events(d->height, GDK_BUTTON_PRESS_MASK); - gtk_widget_add_events(d->print_width, GDK_BUTTON_PRESS_MASK); - gtk_widget_add_events(d->print_height, GDK_BUTTON_PRESS_MASK); - gtk_widget_add_events(d->scale, GDK_BUTTON_PRESS_MASK); - - g_signal_connect(G_OBJECT(d->width), "button-press-event", - G_CALLBACK(_widht_mdlclick), (gpointer)d); - g_signal_connect(G_OBJECT(d->height), "button-press-event", - G_CALLBACK(_height_mdlclick), (gpointer)d); - g_signal_connect(G_OBJECT(d->print_width), "button-press-event", - G_CALLBACK(_widht_mdlclick), (gpointer)d); - g_signal_connect(G_OBJECT(d->print_height), "button-press-event", - G_CALLBACK(_height_mdlclick), (gpointer)d); - g_signal_connect(G_OBJECT(d->scale), "button-press-event", - G_CALLBACK(_scale_mdlclick), (gpointer)d); + dt_gui_connect_click_all(d->width, _widht_mdlclick_cb, NULL, d); + dt_gui_connect_click_all(d->height, _height_mdlclick_cb, NULL, d); + dt_gui_connect_click_all(d->print_width, _widht_mdlclick_cb, NULL, d); + dt_gui_connect_click_all(d->print_height, _height_mdlclick_cb, NULL, d); + dt_gui_connect_click_all(d->scale, _scale_mdlclick_cb, NULL, d); // this takes care of keeping hidden widgets hidden gtk_widget_show_all(self->widget); From 6cc03558cee404a1d2be627851eb1b22f5e5950e Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 01:48:58 -0300 Subject: [PATCH 39/95] gtk4-prep: convert neural restore event signals to event controllers --- src/libs/neural_restore.c | 92 ++++++++++++++------------------------- 1 file changed, 32 insertions(+), 60 deletions(-) diff --git a/src/libs/neural_restore.c b/src/libs/neural_restore.c index 915dd398f19..64ab4b4d3a8 100644 --- a/src/libs/neural_restore.c +++ b/src/libs/neural_restore.c @@ -15,8 +15,6 @@ You should have received a copy of the GNU General Public License along with darktable. If not, see . */ -#include "common/gdk_event_utils.h" - // neural restore — lighttable module for AI-based image restoration // // overview @@ -3501,11 +3499,11 @@ static void _pick_toggled(GtkToggleButton *btn, gtk_widget_queue_draw(d->preview_area); } -static gboolean _pick_double_click(GtkWidget *widget, - GdkEventButton *event, - dt_lib_module_t *self) +static void _pick_double_click_cb(GtkGestureSingle *gesture, int n_press, + double x, double y, + dt_lib_module_t *self) { - if(dt_gdk_event_get_type(event) != GDK_2BUTTON_PRESS) return FALSE; + if(n_press < 2) return; dt_lib_neural_restore_t *d = self->data; d->patch_center[0] = 0.5f; d->patch_center[1] = 0.5f; @@ -3517,7 +3515,6 @@ static gboolean _pick_double_click(GtkWidget *widget, gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(d->pick_button), FALSE); d->preview_requested = TRUE; _trigger_preview(self); - return TRUE; } // upper bound on tooltip pixel dimensions so we never overflow the @@ -3927,18 +3924,14 @@ static gboolean _preview_draw(GtkWidget *widget, // clicks within this distance grip the divider without snapping it #define PREVIEW_DIVIDER_NEAR_PX 3.0 -static gboolean _preview_button_press(GtkWidget *widget, - GdkEventButton *event, - dt_lib_module_t *self) +static void _preview_button_press_cb(GtkGestureSingle *gesture, int n_press, + double ex, double ey, + dt_lib_module_t *self) { + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); dt_lib_neural_restore_t *d = (dt_lib_neural_restore_t *)self->data; - guint button = 0; - gdk_event_get_button((GdkEvent *)event, &button); - if(button != 1) return FALSE; - - double ex = 0.0, ey = 0.0; - gdk_event_get_coords((GdkEvent *)event, &ex, &ey); + if(gtk_gesture_single_get_button(gesture) != 1) return; // thumbnail picking mode: click to select area and trigger preview if(d->picking_thumbnail && d->export_cairo) @@ -3949,17 +3942,10 @@ static gboolean _preview_button_press(GtkWidget *widget, _picking_geometry(d, w, h, &img_w, &img_h, &ox, &oy); // convert click to normalized image coords. - // * RGB denoise / upscale: clamp so the crop rectangle stays - // within the image (master behaviour — the export-based preview - // needs this because the worker and draw share a single - // export_w-based scale). - // * raw denoise: no inner-margin clamp — user can pick corners. - // the raw worker CLAMPs crop_x/y, and _preview_draw pushes the - // rectangle inward to match. const float nx = (float)((ex - ox) / img_w); const float ny = (float)((ey - oy) / img_h); if(nx < 0.0f || nx > 1.0f || ny < 0.0f || ny > 1.0f) - return TRUE; + return; if(d->task == NEURAL_TASK_RAW_DENOISE) { @@ -3987,7 +3973,7 @@ static gboolean _preview_button_press(GtkWidget *widget, d->preview_requested = TRUE; dt_control_log(_("generating preview...")); _trigger_preview(self); - return TRUE; + return; } // click to start preview generation @@ -3995,56 +3981,51 @@ static gboolean _preview_button_press(GtkWidget *widget, { d->preview_requested = TRUE; _trigger_preview(self); - return TRUE; + return; } - if(!d->preview_ready) return FALSE; + if(!d->preview_ready) return; const int w = gtk_widget_get_allocated_width(widget); const int h = gtk_widget_get_allocated_height(widget); const int pw = d->preview_w; const int ph = d->preview_h; - if(pw <= 0 || ph <= 0) return FALSE; + if(pw <= 0 || ph <= 0) return; const double scale = fmax(1.0, fmin((double)w / pw, (double)h / ph)); - const double ox = (w - pw * scale) / 2.0; - const double div_x = ox + d->split_pos * pw * scale; + const double div_ox = (w - pw * scale) / 2.0; + const double div_x = div_ox + d->split_pos * pw * scale; if(fabs(ex - div_x) < PREVIEW_DIVIDER_NEAR_PX) { // precision grip on the divider — drag without snapping d->dragging_split = TRUE; - return TRUE; + return; } // click anywhere else snaps the divider then enters drag - d->split_pos = CLAMP((ex - ox) / (pw * scale), 0.0, 1.0); + d->split_pos = CLAMP((ex - div_ox) / (pw * scale), 0.0, 1.0); d->dragging_split = TRUE; gtk_widget_queue_draw(widget); - return TRUE; } -static gboolean _preview_button_release(GtkWidget *widget, - GdkEventButton *event, - dt_lib_module_t *self) +static void _preview_button_release_cb(GtkGestureSingle *gesture, int n_press, + double x, double y, + dt_lib_module_t *self) { dt_lib_neural_restore_t *d = (dt_lib_neural_restore_t *)self->data; if(d->dragging_split) { d->dragging_split = FALSE; - return TRUE; } - return FALSE; } -static gboolean _preview_motion(GtkWidget *widget, - GdkEventMotion *event, - dt_lib_module_t *self) +static void _preview_motion_cb(GtkEventControllerMotion *controller, + double ex, double ey, + dt_lib_module_t *self) { + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); dt_lib_neural_restore_t *d = (dt_lib_neural_restore_t *)self->data; - double ex = 0.0, ey = 0.0; - gdk_event_get_coords((GdkEvent *)event, &ex, &ey); - // move crop rectangle while hovering in picking mode if(d->picking_thumbnail && d->export_cairo) { @@ -4072,7 +4053,7 @@ static gboolean _preview_motion(GtkWidget *widget, d->patch_center[1] = CLAMP(ry, half_h, 1.0f - half_h); } gtk_widget_queue_draw(widget); - return TRUE; + return; } if(d->dragging_split) @@ -4080,7 +4061,7 @@ static gboolean _preview_motion(GtkWidget *widget, const int w = gtk_widget_get_allocated_width(widget); const int pw = d->preview_w; const int ph = d->preview_h; - if(pw <= 0 || ph <= 0) return FALSE; + if(pw <= 0 || ph <= 0) return; const int ah = gtk_widget_get_allocated_height(widget); const double scale = fmax(1.0, fmin((double)w / pw, (double)ah / ph)); @@ -4089,7 +4070,7 @@ static gboolean _preview_motion(GtkWidget *widget, d->split_pos = CLAMP((ex - ox) / img_w, 0.0, 1.0); gtk_widget_queue_draw(widget); - return TRUE; + return; } // change cursor near divider @@ -4123,7 +4104,7 @@ static gboolean _preview_motion(GtkWidget *widget, } } - return FALSE; + return; } static void _selection_changed_callback(gpointer instance, @@ -4342,23 +4323,14 @@ void gui_init(dt_lib_module_t *self) "double-click to reset to center")); g_signal_connect(d->pick_button, "toggled", G_CALLBACK(_pick_toggled), self); - g_signal_connect(d->pick_button, "button-press-event", - G_CALLBACK(_pick_double_click), self); + dt_gui_connect_click_all(d->pick_button, _pick_double_click_cb, NULL, self); // preview area (resizable via dt_ui_resize_wrap) d->preview_area = GTK_WIDGET(dt_ui_resize_wrap(NULL, 200, CONF_PREVIEW_HEIGHT)); - gtk_widget_add_events(d->preview_area, - GDK_BUTTON_PRESS_MASK - | GDK_BUTTON_RELEASE_MASK - | GDK_POINTER_MOTION_MASK); g_signal_connect(d->preview_area, "draw", G_CALLBACK(_preview_draw), self); - g_signal_connect(d->preview_area, "button-press-event", - G_CALLBACK(_preview_button_press), self); - g_signal_connect(d->preview_area, "button-release-event", - G_CALLBACK(_preview_button_release), self); - g_signal_connect(d->preview_area, "motion-notify-event", - G_CALLBACK(_preview_motion), self); + dt_gui_connect_click(d->preview_area, _preview_button_press_cb, _preview_button_release_cb, self); + dt_gui_connect_motion(d->preview_area, _preview_motion_cb, NULL, NULL, self); // hover-zoom tooltip: shows the same preview at 2x so the user can // see individual pixels. only fires when there's a valid preview; // suppressed during inference / picking / dragging From e720434cdda3d83948893e7b1defa071bce55958 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 01:50:28 -0300 Subject: [PATCH 40/95] gtk4-prep: convert preferences_ai event signals to event controllers --- src/gui/preferences_ai.c | 110 +++++++++++++++------------------------ 1 file changed, 42 insertions(+), 68 deletions(-) diff --git a/src/gui/preferences_ai.c b/src/gui/preferences_ai.c index ec27e2eb7ac..5e1b2e4511a 100644 --- a/src/gui/preferences_ai.c +++ b/src/gui/preferences_ai.c @@ -15,8 +15,6 @@ You should have received a copy of the GNU General Public License along with darktable. If not, see . */ -#include "common/gdk_event_utils.h" - #include "gui/preferences_ai.h" #include "bauhaus/bauhaus.h" #include "dtgtk/button.h" @@ -611,32 +609,28 @@ static void _on_provider_changed(GtkWidget *widget, gpointer user_data) // double-click on label resets the enable toggle to default static gboolean -_reset_enable_click(GtkWidget *label, GdkEventButton *event, GtkWidget *widget) +static void _reset_enable_click_cb(GtkGestureSingle *gesture, int n_press, + double x, double y, + GtkWidget *widget) { - if(dt_gdk_event_get_type(event) == GDK_2BUTTON_PRESS) - { - const gboolean def = dt_confgen_get_bool("plugins/ai/enabled", DT_DEFAULT); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), def); - return TRUE; - } - return FALSE; + if(n_press < 2) return; + const gboolean def = dt_confgen_get_bool("plugins/ai/enabled", DT_DEFAULT); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), def); } // double-click on label resets the provider combo to default -static gboolean -_reset_provider_click(GtkWidget *label, GdkEventButton *event, gpointer user_data) +static void +_reset_provider_click_cb(GtkGestureSingle *gesture, int n_press, + double x, double y, + gpointer user_data) { - if(dt_gdk_event_get_type(event) == GDK_2BUTTON_PRESS) - { - dt_prefs_ai_data_t *data = (dt_prefs_ai_data_t *)user_data; - const char *def = dt_confgen_get(DT_AI_CONF_PROVIDER, DT_DEFAULT); - dt_ai_provider_t provider = dt_ai_provider_from_string(def); - dt_bauhaus_combobox_set(data->provider_combo, - _provider_to_combo_idx(provider, - data->supported_providers)); - return TRUE; - } - return FALSE; + if(n_press < 2) return; + dt_prefs_ai_data_t *data = (dt_prefs_ai_data_t *)user_data; + const char *def = dt_confgen_get(DT_AI_CONF_PROVIDER, DT_DEFAULT); + dt_ai_provider_t provider = dt_ai_provider_from_string(def); + dt_bauhaus_combobox_set(data->provider_combo, + _provider_to_combo_idx(provider, + data->supported_providers)); } static void _on_model_selection_toggled(GtkCellRendererToggle *cell, @@ -1260,24 +1254,16 @@ static gboolean _on_query_tooltip(GtkWidget *widget, } // hand cursor on info column for downloaded rows -static gboolean _on_tree_motion(GtkWidget *widget, - GdkEventMotion *event, - gpointer user_data) +static void _on_tree_motion_cb(GtkEventControllerMotion *controller, + double x, double y, + gpointer user_data) { + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); GtkTreeView *tv = GTK_TREE_VIEW(widget); GdkWindow *bin = gtk_tree_view_get_bin_window(tv); - if(!bin) return FALSE; + if(!bin) return; gint bx, by; - if(dt_gdk_event_get_window(event) == bin) - { - bx = (gint)dt_gdk_event_get_x(event); - by = (gint)dt_gdk_event_get_y(event); - } - else - { - gtk_tree_view_convert_widget_to_bin_window_coords( - tv, (gint)dt_gdk_event_get_x(event), (gint)dt_gdk_event_get_y(event), &bx, &by); - } + gtk_tree_view_convert_widget_to_bin_window_coords(tv, (gint)x, (gint)y, &bx, &by); if(_info_active_at_bin(user_data, tv, bx, by)) { GdkCursor *cursor = gdk_cursor_new_from_name(gdk_window_get_display(bin), "pointer"); @@ -1288,32 +1274,30 @@ static gboolean _on_tree_motion(GtkWidget *widget, { gdk_window_set_cursor(bin, NULL); } - return FALSE; } // click on the ⓘ info column opens the model card -static gboolean _on_info_button_press(GtkWidget *widget, - GdkEventButton *event, - gpointer user_data) +static void _on_info_button_press_cb(GtkGestureSingle *gesture, int n_press, + double x, double y, + gpointer user_data) { - if(dt_gdk_event_get_type(event) != GDK_BUTTON_PRESS - || dt_gdk_event_get_button(event) != 1) - return FALSE; + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + if(gtk_gesture_single_get_button(gesture) != 1) return; dt_prefs_ai_data_t *data = (dt_prefs_ai_data_t *)user_data; GtkTreeView *tv = GTK_TREE_VIEW(widget); GtkTreePath *path = NULL; GtkTreeViewColumn *column = NULL; - if(!gtk_tree_view_get_path_at_pos(tv, (gint)dt_gdk_event_get_x(event), (gint)dt_gdk_event_get_y(event), + if(!gtk_tree_view_get_path_at_pos(tv, (gint)x, (gint)y, &path, &column, NULL, NULL)) - return FALSE; + return; // only react to clicks on the info column if(column != data->info_col) { gtk_tree_path_free(path); - return FALSE; + return; } GtkTreeIter iter; @@ -1328,7 +1312,6 @@ static gboolean _on_info_button_press(GtkWidget *widget, g_free(model_id); } gtk_tree_path_free(path); - return TRUE; } #if !defined(__APPLE__) @@ -1439,13 +1422,14 @@ static void _on_detect_system_ort(GtkButton *button, gpointer user_data) g_list_free_full(found, (GDestroyNotify)dt_ai_ort_found_free); } -static gboolean _reset_ort_path_click(GtkWidget *w, GdkEventButton *e, gpointer user_data) +static void _reset_ort_path_click_cb(GtkGestureSingle *gesture, int n_press, + double x, double y, + gpointer user_data) { - if(e->type != GDK_2BUTTON_PRESS) return FALSE; + if(n_press < 2) return; dt_prefs_ai_data_t *data = (dt_prefs_ai_data_t *)user_data; gtk_entry_set_text(GTK_ENTRY(data->ort_path_entry), ""); _set_ort_path(data, ""); - return TRUE; } static void _on_ort_path_changed(GtkEntry *entry, gpointer user_data) { @@ -1546,7 +1530,7 @@ void init_tab_ai(GtkWidget *dialog, GtkWidget *stack) GtkWidget *enable_label = gtk_label_new(_("enable AI features")); gtk_widget_set_halign(enable_label, GTK_ALIGN_START); GtkWidget *enable_labelev = gtk_event_box_new(); - gtk_widget_add_events(enable_labelev, GDK_BUTTON_PRESS_MASK); + gtk_container_add(GTK_CONTAINER(enable_labelev), enable_label); gtk_event_box_set_visible_window(GTK_EVENT_BOX(enable_labelev), FALSE); @@ -1560,11 +1544,7 @@ void init_tab_ai(GtkWidget *dialog, GtkWidget *stack) "toggled", G_CALLBACK(_on_enable_toggled), data); - g_signal_connect( - enable_labelev, - "button-press-event", - G_CALLBACK(_reset_enable_click), - data->enable_toggle); + dt_gui_connect_click_all(enable_labelev, _reset_enable_click_cb, NULL, data->enable_toggle); // single grid for enable, provider, and ORT path (column alignment) GtkWidget *settings_grid = gtk_grid_new(); gtk_grid_set_row_spacing(GTK_GRID(settings_grid), DT_PIXEL_APPLY_DPI(3)); @@ -1591,7 +1571,7 @@ void init_tab_ai(GtkWidget *dialog, GtkWidget *stack) GtkWidget *provider_label = gtk_label_new(_("AI acceleration")); gtk_widget_set_halign(provider_label, GTK_ALIGN_START); GtkWidget *provider_labelev = gtk_event_box_new(); - gtk_widget_add_events(provider_labelev, GDK_BUTTON_PRESS_MASK); + gtk_container_add(GTK_CONTAINER(provider_labelev), provider_label); gtk_event_box_set_visible_window(GTK_EVENT_BOX(provider_labelev), FALSE); @@ -1608,10 +1588,7 @@ void init_tab_ai(GtkWidget *dialog, GtkWidget *stack) "value-changed", G_CALLBACK(_on_provider_changed), data); - g_signal_connect(provider_labelev, - "button-press-event", - G_CALLBACK(_reset_provider_click), - data); + dt_gui_connect_click_all(provider_labelev, _reset_provider_click_cb, NULL, data); g_signal_connect(data->gpu_combo, "value-changed", G_CALLBACK(_on_gpu_changed), data); @@ -1691,7 +1668,7 @@ void init_tab_ai(GtkWidget *dialog, GtkWidget *stack) g_signal_connect(browse_btn, "clicked", G_CALLBACK(_on_ort_browse_clicked), data); g_signal_connect(detect_btn, "clicked", G_CALLBACK(_on_detect_system_ort), data); g_signal_connect(data->ort_path_entry, "activate", G_CALLBACK(_on_ort_path_changed), data); - g_signal_connect(path_labelev, "button-press-event", G_CALLBACK(_reset_ort_path_click), data); + dt_gui_connect_click_all(path_labelev, _reset_ort_path_click_cb, NULL, data); } #endif // !__APPLE__ @@ -1860,11 +1837,8 @@ void init_tab_ai(GtkWidget *dialog, GtkWidget *stack) gtk_widget_set_has_tooltip(data->model_list, TRUE); g_signal_connect(data->model_list, "query-tooltip", G_CALLBACK(_on_query_tooltip), data); - gtk_widget_add_events(data->model_list, GDK_POINTER_MOTION_MASK); - g_signal_connect(data->model_list, "motion-notify-event", - G_CALLBACK(_on_tree_motion), data); - g_signal_connect(data->model_list, "button-press-event", - G_CALLBACK(_on_info_button_press), data); + dt_gui_connect_motion(data->model_list, _on_tree_motion_cb, NULL, NULL, data); + dt_gui_connect_click(data->model_list, _on_info_button_press_cb, NULL, data); // scrolled window for the list GtkWidget *scroll = gtk_scrolled_window_new(NULL, NULL); From f1288f3c4bd0a6e5ff3ef995accca36b7a0f2ed3 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 01:51:47 -0300 Subject: [PATCH 41/95] gtk4-prep: convert lighttable profile button button-press event to event controller --- src/views/lighttable.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/views/lighttable.c b/src/views/lighttable.c index 662d3ca4653..6d4826315ca 100644 --- a/src/views/lighttable.c +++ b/src/views/lighttable.c @@ -635,6 +635,13 @@ static void _preview_set_state(dt_view_t *self, _preview_quit(self); } +static void _profile_popup_show_cb(GtkGestureSingle *gesture, int n_press, + double x, double y, + GtkWidget *popover) +{ + gtk_widget_show_all(popover); +} + void init(dt_view_t *self) { self->data = calloc(1, sizeof(dt_library_t)); @@ -1475,8 +1482,7 @@ void gui_init(dt_view_t *self) lib->profile_floating_window = gtk_popover_new(profile_button); g_object_set(G_OBJECT(lib->profile_floating_window), "transitions-enabled", FALSE, NULL); - g_signal_connect_swapped(G_OBJECT(profile_button), "button-press-event", - G_CALLBACK(gtk_widget_show_all), lib->profile_floating_window); + dt_gui_connect_click_all(profile_button, _profile_popup_show_cb, NULL, lib->profile_floating_window); GtkWidget *vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); From f3c47842349d086ef2a07c7dedfc4df5e934c5fe Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 01:52:47 -0300 Subject: [PATCH 42/95] gtk4-prep: convert import metadata button-press events to event controllers --- src/gui/import_metadata.c | 29 +++++++++++------------------ 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/src/gui/import_metadata.c b/src/gui/import_metadata.c index 482018f26f1..7ead2465b15 100644 --- a/src/gui/import_metadata.c +++ b/src/gui/import_metadata.c @@ -15,8 +15,6 @@ You should have received a copy of the GNU General Public License along with darktable. If not, see . */ -#include "common/gdk_event_utils.h" - #include "common/debug.h" #include "common/metadata.h" #include "control/conf.h" @@ -67,15 +65,14 @@ static void _import_metadata_changed(GtkWidget *widget, gtk_combo_box_set_active(GTK_COMBO_BOX(w), -1); } -static gboolean _import_metadata_reset(GtkWidget *label, - GdkEventButton *event, - GtkWidget *widget) +static void _import_metadata_reset_cb(GtkGestureSingle *gesture, int n_press, + double x, double y, + GtkWidget *widget) { - if(dt_gdk_event_get_type(event) == GDK_2BUTTON_PRESS) + if(n_press >= 2) { gtk_entry_set_text(GTK_ENTRY(widget), ""); } - return FALSE; } static void _metadata_reset_all(dt_import_metadata_t *metadata, @@ -105,15 +102,14 @@ static void _metadata_reset_all(dt_import_metadata_t *metadata, } } -static gboolean _import_metadata_reset_all(GtkWidget *label, - GdkEventButton *event, - dt_import_metadata_t *metadata) +static void _import_metadata_reset_all_cb(GtkGestureSingle *gesture, int n_press, + double x, double y, + dt_import_metadata_t *metadata) { - if(dt_gdk_event_get_type(event) == GDK_2BUTTON_PRESS) + if(n_press >= 2) { _metadata_reset_all(metadata, FALSE); } - return FALSE; } static void _import_metadata_toggled(GtkWidget *widget, @@ -452,8 +448,7 @@ static void _fill_metadata_grid(dt_import_metadata_t *metadata) g_free(setting); g_signal_connect(GTK_ENTRY(metadata_entry), "changed", G_CALLBACK(_import_metadata_changed), metadata); - g_signal_connect(GTK_EVENT_BOX(labelev), "button-press-event", - G_CALLBACK(_import_metadata_reset), metadata_entry); + dt_gui_connect_click_all(labelev, _import_metadata_reset_cb, NULL, metadata_entry); GtkWidget *metadata_imported = gtk_check_button_new(); g_object_set_data(G_OBJECT(metadata_imported), "tagname", md->tagname); @@ -489,8 +484,7 @@ void dt_import_metadata_init(dt_import_metadata_t *metadata) gtk_widget_set_tooltip_text(GTK_WIDGET(label), _("metadata to be applied per default" "\ndouble-click on a label to clear the corresponding entry" "\ndouble-click on 'preset' to clear all entries")); - g_signal_connect(GTK_EVENT_BOX(labelev), "button-press-event", - G_CALLBACK(_import_metadata_reset_all), metadata); + dt_gui_connect_click_all(labelev, _import_metadata_reset_all_cb, NULL, metadata); GtkWidget *presets = _set_up_combobox(metadata->m_model, DT_META_META_HEADER, metadata); @@ -527,8 +521,7 @@ void dt_import_metadata_init(dt_import_metadata_t *metadata) gtk_widget_set_tooltip_text(entry, _("comma separated list of tags")); g_signal_connect(GTK_ENTRY(entry), "changed", G_CALLBACK(_import_tags_changed), metadata); - g_signal_connect(GTK_EVENT_BOX(labelev), "button-press-event", - G_CALLBACK(_import_metadata_reset), entry); + dt_gui_connect_click_all(labelev, _import_metadata_reset_cb, NULL, entry); GtkWidget *tags_imported = gtk_check_button_new(); _set_up_toggle_button(tags_imported, dt_conf_get_bool("ui_last/import_last_tags_imported"), From 9595e57a981c396fd761ef860d7a7c2905c27e91 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 01:57:35 -0300 Subject: [PATCH 43/95] gtk4-prep: convert filtering event signals to event controllers --- src/libs/filtering.c | 100 +++++++++++++++++++++++++++++-------------- 1 file changed, 69 insertions(+), 31 deletions(-) diff --git a/src/libs/filtering.c b/src/libs/filtering.c index 978a4d869d0..a55f9a19cb6 100644 --- a/src/libs/filtering.c +++ b/src/libs/filtering.c @@ -1033,27 +1033,24 @@ static void _topbar_reset(dt_lib_module_t *self) dt_collection_update_query(darktable.collection, DT_COLLECTION_CHANGE_RELOAD, DT_COLLECTION_PROP_UNDEF, NULL); } -static gboolean _topbar_reset_press(GtkWidget *w, - GdkEventButton *e, - dt_lib_module_t *self) +static void _topbar_reset_press_cb(GtkGestureSingle *gesture, int n_press, + double x, double y, + dt_lib_module_t *self) { //reset the filters _topbar_reset(self); //close the popup dt_lib_filtering_t *d = self->data; gtk_widget_destroy(d->topbar_popup); - - return FALSE; } -static gboolean _topbar_label_press(GtkWidget *w, - GdkEventButton *e, - dt_lib_module_t *self) +static void _topbar_label_press_cb(GtkGestureSingle *gesture, int n_press, + double x, double y, + dt_lib_module_t *self) { //reset on double-click - if(e->button == GDK_BUTTON_PRIMARY && e->type == GDK_2BUTTON_PRESS) + if(gtk_gesture_single_get_button(gesture) == GDK_BUTTON_PRIMARY && n_press >= 2) _topbar_reset(self); - return FALSE; } static void _topbar_update(dt_lib_module_t *self) @@ -1088,7 +1085,7 @@ static void _topbar_update(dt_lib_module_t *self) GtkWidget *evtb = gtk_event_box_new(); GtkWidget *label = gtk_label_new(C_("quickfilter", "filter")); gtk_container_add(GTK_CONTAINER(evtb), label); - g_signal_connect(G_OBJECT(evtb), "button-press-event", G_CALLBACK(_topbar_label_press), self); + dt_gui_connect_click_all(evtb, _topbar_label_press_cb, NULL, self); gtk_box_pack_start(GTK_BOX(fbox), evtb, TRUE, TRUE, 0); gtk_widget_show_all(evtb); } @@ -1163,16 +1160,19 @@ static void _event_rule_disable(GtkWidget *widget, dt_lib_filtering_rule_t *rule _widget_header_update(rule); } -static gboolean _event_rule_close(GtkWidget *widget, GdkEventButton *event, dt_lib_module_t *self) +static void _event_rule_close_cb(GtkGestureSingle *gesture, int n_press, + double x, double y, + dt_lib_module_t *self) { + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); dt_lib_filtering_rule_t *rule = (dt_lib_filtering_rule_t *)g_object_get_data(G_OBJECT(widget), "rule"); - if(rule->manual_widget_set) return TRUE; + if(rule->manual_widget_set) return; if(!rule->topbar) { // decrease the nb of active rules dt_lib_filtering_t *d = rule->lib; - if(d->nb_rules <= 0) return FALSE; + if(d->nb_rules <= 0) return; d->nb_rules--; dt_conf_set_int("plugins/lighttable/filtering/num_rules", d->nb_rules); @@ -1210,9 +1210,7 @@ static gboolean _event_rule_close(GtkWidget *widget, GdkEventButton *event, dt_l dt_collection_update_query(darktable.collection, DT_COLLECTION_CHANGE_RELOAD, rule->prop, NULL); } else - return FALSE; - - return TRUE; + return; } static gboolean _rule_available_for_topbar(const dt_collection_properties_t prop) @@ -1308,7 +1306,7 @@ static gboolean _widget_init(dt_lib_filtering_rule_t *rule, const dt_collection_ // remove button rule->w_close = dtgtk_button_new(dtgtk_cairo_paint_remove, 0, NULL); g_object_set_data(G_OBJECT(rule->w_close), "rule", rule); - g_signal_connect(G_OBJECT(rule->w_close), "button-press-event", G_CALLBACK(_event_rule_close), self); + dt_gui_connect_click_all(rule->w_close, _event_rule_close_cb, NULL, self); gtk_box_pack_end(GTK_BOX(rule->w_btn_box), rule->w_close, FALSE, FALSE, 0); } @@ -1665,10 +1663,13 @@ static void _topbar_populate_rules_combo(GtkWidget *w, dt_lib_filtering_t *d) #undef ADD_COLLECT_ENTRY } -static gboolean _topbar_rule_remove(GtkWidget *widget, GdkEventButton *event, dt_lib_module_t *self) +static void _topbar_rule_remove_cb(GtkGestureSingle *gesture, int n_press, + double x, double y, + dt_lib_module_t *self) { + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); dt_lib_filtering_rule_t *rule = (dt_lib_filtering_rule_t *)g_object_get_data(G_OBJECT(widget), "rule"); - if(rule->manual_widget_set) return TRUE; + if(rule->manual_widget_set) return; dt_lib_filtering_t *d = self->data; // unpin the rule @@ -1676,7 +1677,45 @@ static gboolean _topbar_rule_remove(GtkWidget *widget, GdkEventButton *event, dt _topbar_update(self); // remove the rule - _event_rule_close(widget, NULL, self); + dt_lib_filtering_rule_t *r = (dt_lib_filtering_rule_t *)g_object_get_data(G_OBJECT(widget), "rule"); + if(!r->manual_widget_set && !r->topbar) + { + if(d->nb_rules > 0) + { + d->nb_rules--; + dt_conf_set_int("plugins/lighttable/filtering/num_rules", d->nb_rules); + for(int i = r->num; i < DT_COLLECTION_MAX_RULES - 1; i++) + { + char confname[200] = { 0 }; + snprintf(confname, sizeof(confname), "plugins/lighttable/filtering/mode%1d", i + 1); + const int mode = dt_conf_get_int(confname); + snprintf(confname, sizeof(confname), "plugins/lighttable/filtering/item%1d", i + 1); + const int item = dt_conf_get_int(confname); + snprintf(confname, sizeof(confname), "plugins/lighttable/filtering/off%1d", i + 1); + const int off = dt_conf_get_int(confname); + snprintf(confname, sizeof(confname), "plugins/lighttable/filtering/top%1d", i + 1); + const int top = dt_conf_get_int(confname); + snprintf(confname, sizeof(confname), "plugins/lighttable/filtering/string%1d", i + 1); + gchar *string = dt_conf_get_string(confname); + if(string) + { + snprintf(confname, sizeof(confname), "plugins/lighttable/filtering/mode%1d", i); + dt_conf_set_int(confname, mode); + snprintf(confname, sizeof(confname), "plugins/lighttable/filtering/item%1d", i); + dt_conf_set_int(confname, item); + snprintf(confname, sizeof(confname), "plugins/lighttable/filtering/off%1d", i); + dt_conf_set_int(confname, off); + snprintf(confname, sizeof(confname), "plugins/lighttable/filtering/top%1d", i); + dt_conf_set_int(confname, top); + snprintf(confname, sizeof(confname), "plugins/lighttable/filtering/string%1d", i); + dt_conf_set_string(confname, string); + g_free(string); + } + } + _filters_gui_update(self); + dt_collection_update_query(darktable.collection, DT_COLLECTION_CHANGE_RELOAD, r->prop, NULL); + } + } // reconstruct the combobox GtkWidget *hb = gtk_widget_get_parent(widget); @@ -1687,8 +1726,6 @@ static gboolean _topbar_rule_remove(GtkWidget *widget, GdkEventButton *event, dt // remove the entry from the popover gtk_container_remove(GTK_CONTAINER(gtk_widget_get_parent(hb)), hb); - - return TRUE; } static GtkWidget *_topbar_menu_new_rule(dt_lib_filtering_rule_t *rule, dt_lib_module_t *self) @@ -1698,7 +1735,7 @@ static GtkWidget *_topbar_menu_new_rule(dt_lib_filtering_rule_t *rule, dt_lib_mo gtk_box_pack_start(GTK_BOX(hb), lb, TRUE, TRUE, 0); GtkWidget *btr = dtgtk_button_new(dtgtk_cairo_paint_remove, 0, NULL); g_object_set_data(G_OBJECT(btr), "rule", rule); - g_signal_connect(G_OBJECT(btr), "button-press-event", G_CALLBACK(_topbar_rule_remove), self); + dt_gui_connect_click_all(btr, _topbar_rule_remove_cb, NULL, self); gtk_box_pack_start(GTK_BOX(hb), btr, FALSE, TRUE, 0); return hb; } @@ -1774,7 +1811,7 @@ static void _topbar_show_pref_menu(dt_lib_module_t *self, GtkWidget *bt) gtk_box_pack_start(GTK_BOX(vbox), lb, TRUE, TRUE, 0); GtkWidget *btr = gtk_button_new_with_label(_("reset quickfilters")); dt_gui_add_class(btr, "dt_transparent_background"); - g_signal_connect(G_OBJECT(btr), "button-press-event", G_CALLBACK(_topbar_reset_press), self); + dt_gui_connect_click_all(btr, _topbar_reset_press_cb, NULL, self); gtk_box_pack_start(GTK_BOX(vbox), btr, TRUE, TRUE, 0); // show the popover @@ -1891,14 +1928,17 @@ static void _proxy_reset_filter(dt_lib_module_t *self, gboolean smart_filter) } } -static gboolean _sort_close(GtkWidget *widget, GdkEventButton *event, dt_lib_module_t *self) +static void _sort_close_cb(GtkGestureSingle *gesture, int n_press, + double x, double y, + dt_lib_module_t *self) { + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); _widgets_sort_t *sort = (_widgets_sort_t *)g_object_get_data(G_OBJECT(widget), "sort"); - if(sort->lib->manual_sort_set) return TRUE; + if(sort->lib->manual_sort_set) return; // decrease the nb of active rules dt_lib_filtering_t *d = sort->lib; - if(d->nb_sort <= 1) return FALSE; + if(d->nb_sort <= 1) return; d->nb_sort--; dt_conf_set_int("plugins/lighttable/filtering/num_sort", d->nb_sort); @@ -1920,8 +1960,6 @@ static gboolean _sort_close(GtkWidget *widget, GdkEventButton *event, dt_lib_mod _history_save(d, TRUE); _sort_gui_update(self); dt_collection_update_query(darktable.collection, DT_COLLECTION_CHANGE_RELOAD, DT_COLLECTION_PROP_SORT, NULL); - - return TRUE; } static gboolean _sort_init(_widgets_sort_t *sort, const dt_collection_sort_t sortid, const int sortorder, @@ -1974,7 +2012,7 @@ static gboolean _sort_init(_widgets_sort_t *sort, const dt_collection_sort_t sor gtk_widget_set_no_show_all(sort->close, TRUE); g_object_set_data(G_OBJECT(sort->close), "sort", sort); gtk_widget_set_tooltip_text(sort->close, _("remove this sort order")); - g_signal_connect(G_OBJECT(sort->close), "button-press-event", G_CALLBACK(_sort_close), self); + dt_gui_connect_click_all(sort->close, _sort_close_cb, NULL, self); gtk_box_pack_start(GTK_BOX(sort->box), sort->close, FALSE, FALSE, 0); } From 4664694e70d5768b484b82a2dbbc24eb59acce81 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 01:58:28 -0300 Subject: [PATCH 44/95] gtk4-prep: convert lighttable layout button-release events to event controllers --- src/libs/tools/lighttable.c | 51 ++++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/src/libs/tools/lighttable.c b/src/libs/tools/lighttable.c index 39c77e5d414..c79188a4214 100644 --- a/src/libs/tools/lighttable.c +++ b/src/libs/tools/lighttable.c @@ -15,8 +15,6 @@ You should have received a copy of the GNU General Public License along with darktable. If not, see . */ -#include "common/gdk_event_utils.h" - #include #include "common/collection.h" @@ -211,24 +209,31 @@ static void _lib_lighttable_set_layout(dt_lib_module_t *self, _lib_lighttable_update_btn(self); } -static gboolean _lib_lighttable_layout_btn_release(GtkWidget *w, GdkEventButton *event, dt_lib_module_t *self) +static void _lib_lighttable_layout_btn_release_cb(GtkGestureSingle *gesture, int n_press, + double x, double y, + dt_lib_module_t *self) { + GtkWidget *w = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); dt_lib_tool_lighttable_t *d = self->data; const gboolean active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w)); // note : this is the state before the change dt_lighttable_layout_t new_layout = DT_LIGHTTABLE_LAYOUT_FILEMANAGER; + + GdkModifierType state; + gtk_get_current_event_state(&state); + if(!active) { // that means we want to activate the button if(w == d->layout_preview) { - d->fullpreview_focus = dt_modifier_is(dt_gdk_event_get_state(event), GDK_CONTROL_MASK); + d->fullpreview_focus = dt_modifier_is(state, GDK_CONTROL_MASK); new_layout = DT_LIGHTTABLE_LAYOUT_PREVIEW; } else if(w == d->layout_culling_fix) { - if(dt_modifier_is(dt_gdk_event_get_state(event), GDK_CONTROL_MASK)) + if(dt_modifier_is(state, GDK_CONTROL_MASK)) d->culling_init_restriction = DT_LIGHTTABLE_CULLING_RESTRICTION_COLLECTION; else d->culling_init_restriction = DT_LIGHTTABLE_CULLING_RESTRICTION_AUTO; @@ -249,23 +254,29 @@ static gboolean _lib_lighttable_layout_btn_release(GtkWidget *w, GdkEventButton else { // we can't exit from filemanager or zoomable - return TRUE; + return; } } _lib_lighttable_set_layout(self, new_layout); - return TRUE; } -static gboolean _lib_lighttable_restricted_btn_release(GtkWidget *w, GdkEventButton *event, dt_lib_module_t *self) +static void _lib_lighttable_do_restricted_btn(dt_lib_module_t *self, GtkWidget *w) { dt_lighttable_culling_restriction_t restriction = DT_LIGHTTABLE_CULLING_RESTRICTION_SELECTION; if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))) - restriction = DT_LIGHTTABLE_CULLING_RESTRICTION_COLLECTION; // note : this is the state before the change + restriction = DT_LIGHTTABLE_CULLING_RESTRICTION_COLLECTION; dt_view_lighttable_set_culling_restricted_state(darktable.view_manager, restriction); _lib_lighttable_update_btn(self); - return TRUE; +} + +static void _lib_lighttable_restricted_btn_release_cb(GtkGestureSingle *gesture, int n_press, + double x, double y, + dt_lib_module_t *self) +{ + _lib_lighttable_do_restricted_btn(self, + gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture))); } static void _lib_lighttable_key_accel_toggle_filemanager(dt_action_t *action) @@ -318,7 +329,7 @@ static void _lib_lighttable_key_accel_toggle_restricted_mode(dt_action_t *action if(d->layout == DT_LIGHTTABLE_LAYOUT_CULLING || dt_view_lighttable_preview_state(darktable.view_manager)) { // if we are already in culling layout or fullpreview, we switch between restricted and unrestricted - _lib_lighttable_restricted_btn_release(d->layout_culling_restricted, NULL, self); + _lib_lighttable_do_restricted_btn(self, d->layout_culling_restricted); } } @@ -462,31 +473,27 @@ void gui_init(dt_lib_module_t *self) dt_action_register(ac, NULL, _lib_lighttable_key_accel_toggle_filemanager, 0, 0); dt_gui_add_help_link(d->layout_filemanager, "layout_filemanager"); gtk_widget_set_tooltip_text(d->layout_filemanager, _("click to enter filemanager layout.")); - g_signal_connect(G_OBJECT(d->layout_filemanager), "button-release-event", - G_CALLBACK(_lib_lighttable_layout_btn_release), self); + dt_gui_connect_click(d->layout_filemanager, NULL, _lib_lighttable_layout_btn_release_cb, self); d->layout_zoomable = dtgtk_togglebutton_new(dtgtk_cairo_paint_lt_mode_zoom, 0, NULL); ac = dt_action_define(ltv, NULL, N_("toggle zoomable lighttable layout"), d->layout_zoomable, NULL); dt_action_register(ac, NULL, _lib_lighttable_key_accel_toggle_zoomable, 0, 0); dt_gui_add_help_link(d->layout_zoomable, "layout_zoomable"); gtk_widget_set_tooltip_text(d->layout_zoomable, _("click to enter zoomable lighttable layout.")); - g_signal_connect(G_OBJECT(d->layout_zoomable), "button-release-event", - G_CALLBACK(_lib_lighttable_layout_btn_release), self); + dt_gui_connect_click(d->layout_zoomable, NULL, _lib_lighttable_layout_btn_release_cb, self); d->layout_culling_fix = dtgtk_togglebutton_new(dtgtk_cairo_paint_lt_mode_culling_fixed, 0, NULL); ac = dt_action_define(ltv, NULL, N_("toggle culling mode"), d->layout_culling_fix, &_action_def_culling); dt_shortcut_register(ac, DT_ACTION_ELEMENT_DEFAULT, DT_ACTION_EFFECT_HOLD_TOGGLE, GDK_KEY_x, 0); dt_shortcut_register(ac, DT_ACTION_ELEMENT_CULLING_NO_RESTRICTION, DT_ACTION_EFFECT_HOLD_TOGGLE, GDK_KEY_x, GDK_SHIFT_MASK); dt_gui_add_help_link(d->layout_culling_fix, "layout_culling"); - g_signal_connect(G_OBJECT(d->layout_culling_fix), "button-release-event", - G_CALLBACK(_lib_lighttable_layout_btn_release), self); + dt_gui_connect_click(d->layout_culling_fix, NULL, _lib_lighttable_layout_btn_release_cb, self); d->layout_culling_dynamic = dtgtk_togglebutton_new(dtgtk_cairo_paint_lt_mode_culling_dynamic, 0, NULL); ac = dt_action_define(ltv, NULL, N_("toggle culling dynamic mode"), d->layout_culling_dynamic, NULL); dt_action_register(ac, NULL, _lib_lighttable_key_accel_toggle_culling_dynamic_mode, GDK_KEY_x, GDK_CONTROL_MASK); dt_gui_add_help_link(d->layout_culling_dynamic, "layout_culling"); - g_signal_connect(G_OBJECT(d->layout_culling_dynamic), "button-release-event", - G_CALLBACK(_lib_lighttable_layout_btn_release), self); + dt_gui_connect_click(d->layout_culling_dynamic, NULL, _lib_lighttable_layout_btn_release_cb, self); d->layout_preview = dtgtk_togglebutton_new(dtgtk_cairo_paint_lt_mode_fullpreview, 0, NULL); ac = dt_action_define(ltv, NULL, N_("preview"), d->layout_preview, &_action_def_preview); @@ -495,8 +502,7 @@ void gui_init(dt_lib_module_t *self) dt_shortcut_register(ac, DT_ACTION_ELEMENT_DEFAULT, DT_ACTION_EFFECT_HOLD, GDK_KEY_w, 0); dt_shortcut_register(ac, DT_ACTION_ELEMENT_PREVIEW_FOCUS_DETECT, DT_ACTION_EFFECT_HOLD, GDK_KEY_w, GDK_CONTROL_MASK); dt_gui_add_help_link(d->layout_preview, "layout_preview"); - g_signal_connect(G_OBJECT(d->layout_preview), "button-release-event", - G_CALLBACK(_lib_lighttable_layout_btn_release), self); + dt_gui_connect_click(d->layout_preview, NULL, _lib_lighttable_layout_btn_release_cb, self); d->layout_box = dt_gui_hbox(d->layout_filemanager, d->layout_zoomable, d->layout_culling_fix, d->layout_culling_dynamic, @@ -517,8 +523,7 @@ void gui_init(dt_lib_module_t *self) dt_action_register(ac, NULL, _lib_lighttable_key_accel_toggle_restricted_mode, GDK_KEY_r, GDK_CONTROL_MASK); dt_gui_add_help_link(d->layout_culling_restricted, "layout_culling"); gtk_widget_set_no_show_all(d->layout_culling_restricted, TRUE); - g_signal_connect(G_OBJECT(d->layout_culling_restricted), "button-release-event", - G_CALLBACK(_lib_lighttable_restricted_btn_release), self); + dt_gui_connect_click(d->layout_culling_restricted, NULL, _lib_lighttable_restricted_btn_release_cb, self); self->widget = dt_gui_hbox(d->layout_box, d->zoom, d->layout_culling_restricted); From f294dbe359838faedf49df5c2ea7774eefd70801 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 02:00:35 -0300 Subject: [PATCH 45/95] gtk4-prep: convert import event signals to event controllers --- src/libs/import.c | 92 ++++++++++++++++++++++------------------------- 1 file changed, 43 insertions(+), 49 deletions(-) diff --git a/src/libs/import.c b/src/libs/import.c index 4979ff44841..6cb99cfeef5 100644 --- a/src/libs/import.c +++ b/src/libs/import.c @@ -15,8 +15,6 @@ You should have received a copy of the GNU General Public License along with darktable. If not, see . */ -#include "common/gdk_event_utils.h" - #include "common/collection.h" #include "common/darktable.h" #include "common/file_location.h" @@ -558,18 +556,19 @@ static void _thumb_set_in_listview(GtkTreeModel *model, g_free(fullname); } -static gboolean _files_button_press(GtkWidget *view, - GdkEventButton *event, - dt_lib_module_t *self) +static void _files_button_press_cb(GtkGestureSingle *gesture, int n_press, + double x, double y, + dt_lib_module_t *self) { + GtkWidget *view = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); dt_lib_import_t *d = self->data; - if((dt_gdk_event_get_type(event) == GDK_BUTTON_PRESS && dt_gdk_event_get_button(event) == GDK_BUTTON_PRIMARY)) + if(n_press == 1) { GtkTreePath *path = NULL; GtkTreeViewColumn *column = NULL; // Get tree path for row that was clicked if(gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(view), - (gint)dt_gdk_event_get_x(event), (gint)dt_gdk_event_get_y(event), + (gint)x, (gint)y, &path, &column, NULL, NULL)) { if(column == d->from.pixcol) @@ -581,17 +580,17 @@ static gboolean _files_button_press(GtkWidget *view, gtk_tree_model_get(model, &iter, DT_IMPORT_SEL_THUMB, &thumb_sel, -1); _thumb_set_in_listview(model, &iter, !thumb_sel, self); gtk_tree_path_free(path); - return TRUE; + return; } } gtk_tree_path_free(path); } - else if((dt_gdk_event_get_type(event) == GDK_2BUTTON_PRESS && dt_gdk_event_get_button(event) == GDK_BUTTON_PRIMARY)) + else if(n_press >= 2) { GtkTreePath *path = NULL; // Get tree path for row that was clicked if(gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(view), - (gint)dt_gdk_event_get_x(event), (gint)dt_gdk_event_get_y(event), + (gint)x, (gint)y, &path, NULL, NULL, NULL)) { GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(view)); @@ -599,10 +598,9 @@ static gboolean _files_button_press(GtkWidget *view, gtk_tree_selection_select_path(selection, path); gtk_dialog_response(GTK_DIALOG(d->from.dialog), GTK_RESPONSE_ACCEPT); gtk_tree_path_free(path); - return TRUE; + return; } } - return FALSE; } static gboolean _thumb_set(dt_lib_module_t *self) @@ -1264,14 +1262,14 @@ static void _remove_selected_place(GtkWidget *widget, dt_lib_module_t *self) _update_files_list(self); } -static gboolean _places_button_press(GtkWidget *view, - GdkEventButton *event, - dt_lib_module_t *self) +static void _places_button_press_cb(GtkGestureSingle *gesture, int n_press, + double x, double y, + dt_lib_module_t *self) { - gboolean res = FALSE; + GtkWidget *view = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); GtkTreePath *path = NULL; if(gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(view), - (gint)dt_gdk_event_get_x(event), (gint)dt_gdk_event_get_y(event), &path, NULL, NULL, NULL)) + (gint)x, (gint)y, &path, NULL, NULL, NULL)) { GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(view)); GtkTreeIter iter; @@ -1280,10 +1278,8 @@ static gboolean _places_button_press(GtkWidget *view, char *folder_name, *folder_path; gtk_tree_model_get(model, &iter, 0, &folder_name, 1, &folder_path, -1); - const int button_pressed = (dt_gdk_event_get_type(event) == GDK_BUTTON_PRESS) ? dt_gdk_event_get_button(event) : 0; - // left-click: set as new root - if(button_pressed == GDK_BUTTON_PRIMARY) + if(gtk_gesture_single_get_button(gesture) == GDK_BUTTON_PRIMARY) { GtkTreeSelection *place_selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(view)); gtk_tree_selection_select_path(place_selection, path); @@ -1296,35 +1292,36 @@ static gboolean _places_button_press(GtkWidget *view, g_free(folder_name); g_free(folder_path); - - res = TRUE; } gtk_tree_path_free(path); - return res; } -static gboolean _folders_button_press(GtkWidget *view, - GdkEventButton *event, - dt_lib_module_t *self) +static void _folders_button_press_cb(GtkGestureSingle *gesture, int n_press, + double x, double y, + dt_lib_module_t *self) { + GtkWidget *view = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); dt_lib_import_t *d = self->data; - gboolean res = FALSE; - const int button_pressed = (dt_gdk_event_get_type(event) == GDK_BUTTON_PRESS) ? dt_gdk_event_get_button(event) : 0; - const gboolean modifier = dt_modifier_is(dt_gdk_event_get_state(event), GDK_SHIFT_MASK | GDK_CONTROL_MASK); - if((button_pressed == GDK_BUTTON_PRIMARY) && !modifier) + + GdkModifierType state; + gtk_get_current_event_state(&state); + + if(n_press == 1 + && gtk_gesture_single_get_button(gesture) == GDK_BUTTON_PRIMARY + && !dt_modifier_is(state, GDK_SHIFT_MASK | GDK_CONTROL_MASK)) { GtkTreePath *path = NULL; if(gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(view), - dt_gdk_event_get_x(event), dt_gdk_event_get_y(event), &path, NULL, NULL, NULL)) + x, y, &path, NULL, NULL, NULL)) { GdkRectangle rect; gtk_tree_view_get_cell_area(GTK_TREE_VIEW(view), path, d->from.foldercol, &rect); const gboolean blank = gtk_tree_view_is_blank_at_pos(GTK_TREE_VIEW(view), - dt_gdk_event_get_x(event), dt_gdk_event_get_y(event), + x, y, NULL, NULL, NULL, NULL); // select and save new folder only if not click on expander - if(blank || (dt_gdk_event_get_x(event) > rect.x)) + if(blank || (x > rect.x)) { GtkTreeSelection *selection = gtk_tree_view_get_selection(d->from.folderview); gtk_tree_selection_select_path(selection, path); @@ -1337,26 +1334,26 @@ static gboolean _folders_button_press(GtkWidget *view, g_free(folder); _update_files_list(self); _show_all_thumbs(self); - res = TRUE; } } gtk_tree_path_free(path); } - - if(dt_gdk_event_get_type(event) == GDK_DOUBLE_BUTTON_PRESS) + else if(n_press >= 2 && gtk_gesture_single_get_button(gesture) == GDK_BUTTON_PRIMARY) { GtkTreePath *path = NULL; gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(view), - dt_gdk_event_get_x(event), dt_gdk_event_get_y(event), &path, NULL, NULL, NULL); - if(gtk_tree_view_row_expanded(d->from.folderview, path)) - gtk_tree_view_collapse_row (d->from.folderview, path); - else - gtk_tree_view_expand_row (d->from.folderview, path, FALSE); - gtk_tree_path_free(path); + x, y, &path, NULL, NULL, NULL); + if(path) + { + if(gtk_tree_view_row_expanded(d->from.folderview, path)) + gtk_tree_view_collapse_row(d->from.folderview, path); + else + gtk_tree_view_expand_row(d->from.folderview, path, FALSE); + gtk_tree_path_free(path); + } } g_timeout_add_full(G_PRIORITY_DEFAULT_IDLE, 100, (GSourceFunc)_clear_parasitic_selection, self, NULL); - return res; } static void _folder_order_clicked(GtkTreeViewColumn *column, @@ -1465,8 +1462,7 @@ static void _set_places_list(GtkWidget *places_paned, gtk_paned_pack1(GTK_PANED(places_paned), places_top_box, TRUE, TRUE); - g_signal_connect(G_OBJECT(d->placesView), "button-press-event", - G_CALLBACK(_places_button_press), self); + dt_gui_connect_click(d->placesView, _places_button_press_cb, NULL, self); } static void _set_folders_list(GtkWidget *places_paned, dt_lib_module_t* self) @@ -1490,8 +1486,7 @@ static void _set_folders_list(GtkWidget *places_paned, dt_lib_module_t* self) gtk_tree_view_column_set_resizable(column, TRUE); gtk_tree_view_set_expander_column(d->from.folderview, column); g_signal_connect(d->from.folderview, "row-expanded", G_CALLBACK(_row_expanded), self); - g_signal_connect(G_OBJECT(d->from.folderview), "button-press-event", - G_CALLBACK(_folders_button_press), self); + dt_gui_connect_click(d->from.folderview, _folders_button_press_cb, NULL, self); gtk_tree_view_column_set_sort_column_id(column, DT_FOLDER_PATH); gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(store), DT_FOLDER_PATH, dt_conf_get_bool("ui_last/import_last_folder_descending") @@ -1901,8 +1896,7 @@ static void _set_files_list(GtkWidget *rbox, dt_lib_module_t* self) gtk_tree_view_column_set_clickable(column, TRUE); gtk_tree_view_column_set_min_width(column, DT_PIXEL_APPLY_DPI(128)); d->from.pixcol = column; - g_signal_connect(G_OBJECT(d->from.treeview), "button-press-event", - G_CALLBACK(_files_button_press), self); + dt_gui_connect_click(d->from.treeview, _files_button_press_cb, NULL, self); GtkTreeSelection *selection = gtk_tree_view_get_selection(d->from.treeview); gtk_tree_selection_set_mode(selection, GTK_SELECTION_MULTIPLE); From 0091aec78d5bb852e879f2e51a87704990980332 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 02:02:03 -0300 Subject: [PATCH 46/95] gtk4-prep: convert metadata event signals to event controllers --- src/libs/metadata.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/libs/metadata.c b/src/libs/metadata.c index 5c22763252f..ecb6f6beb81 100644 --- a/src/libs/metadata.c +++ b/src/libs/metadata.c @@ -15,8 +15,6 @@ You should have received a copy of the GNU General Public License along with darktable. If not, see . */ -#include "common/gdk_event_utils.h" - #include "common/metadata.h" #include "common/collection.h" #include "common/darktable.h" @@ -420,24 +418,27 @@ static void _cancel_button_clicked(GtkButton *button, gtk_window_set_focus(GTK_WINDOW(dt_ui_main_window(darktable.gui->ui)), NULL); } -static gboolean _key_pressed(GtkWidget *textview, - GdkEventKey *event, - dt_lib_module_t *self) +static gboolean _key_pressed_cb(GtkEventControllerKey *controller, + guint keyval, + guint keycode, + GdkModifierType state, + dt_lib_module_t *self) { + GtkWidget *textview = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); dt_lib_metadata_t *d = self->data; - switch(dt_gdk_event_get_keyval(event)) + switch(keyval) { case GDK_KEY_Return: case GDK_KEY_KP_Enter: - if(!dt_modifier_is(dt_gdk_event_get_state(event), GDK_CONTROL_MASK)) + if(!dt_modifier_is(state, GDK_CONTROL_MASK)) { gtk_button_clicked(GTK_BUTTON(d->apply_button)); return TRUE; } break; case GDK_KEY_Escape: - if(dt_modifier_is(dt_gdk_event_get_state(event), 0)) + if(dt_modifier_is(state, 0)) { gtk_button_clicked(GTK_BUTTON(d->cancel_button)); return TRUE; @@ -447,7 +448,7 @@ static gboolean _key_pressed(GtkWidget *textview, break; } - return gtk_text_view_im_context_filter_keypress(GTK_TEXT_VIEW(textview), event); + return gtk_text_view_im_context_filter_keypress(GTK_TEXT_VIEW(textview), (GdkEventKey *)gtk_get_current_event()); } static gboolean _textview_focus(GtkWidget *widget, @@ -569,11 +570,11 @@ static void _populate_popup_multi(GtkTextView *textview, gtk_widget_show_all(popup); } -static gboolean _metadata_reset(GtkWidget *label, - GdkEventButton *event, - GtkWidget *widget) +static void _metadata_reset_cb(GtkGestureSingle *gesture, int n_press, + double x, double y, + GtkWidget *widget) { - if(dt_gdk_event_get_type(event) == GDK_2BUTTON_PRESS) + if(n_press >= 2) { g_object_set_data(G_OBJECT(widget), "tv_multiple", GINT_TO_POINTER(FALSE)); GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(widget)); @@ -582,7 +583,6 @@ static gboolean _metadata_reset(GtkWidget *label, else g_signal_emit_by_name(G_OBJECT(buffer), "changed"); // even if unchanged } - return TRUE; } static void _add_grid_row(dt_metadata_t *metadata, int row, dt_lib_module_t *self) @@ -640,10 +640,10 @@ static void _add_grid_row(dt_metadata_t *metadata, int row, dt_lib_module_t *sel gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(textview), GTK_WRAP_WORD_CHAR); gtk_text_view_set_accepts_tab(GTK_TEXT_VIEW(textview), FALSE); gtk_widget_add_events(textview, GDK_FOCUS_CHANGE_MASK | GDK_ENTER_NOTIFY_MASK); - g_signal_connect(textview, "key-press-event", G_CALLBACK(_key_pressed), self); + dt_gui_connect_key(textview, _key_pressed_cb, self); g_signal_connect(textview, "focus", G_CALLBACK(_textview_focus), self); g_signal_connect(textview, "populate-popup", G_CALLBACK(_populate_popup_multi), self); - g_signal_connect(labelev, "button-press-event", G_CALLBACK(_metadata_reset), textview); + dt_gui_connect_click_all(labelev, _metadata_reset_cb, NULL, textview); g_signal_connect(buffer, "changed", G_CALLBACK(_textbuffer_changed), self); gtk_widget_set_hexpand(textview, TRUE); gtk_widget_set_vexpand(textview, TRUE); From a982b2c13a7fcd3ff9375e0e7d0201854916e6e4 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 02:06:52 -0300 Subject: [PATCH 47/95] gtk4-prep: convert collect event signals to event controllers --- src/libs/collect.c | 81 ++++++++++++++++++++++++---------------------- 1 file changed, 43 insertions(+), 38 deletions(-) diff --git a/src/libs/collect.c b/src/libs/collect.c index e0306005bd8..a71d176b038 100644 --- a/src/libs/collect.c +++ b/src/libs/collect.c @@ -632,31 +632,39 @@ static void view_popup_menu(GtkWidget *treeview, gtk_menu_popup_at_pointer(GTK_MENU(menu), (GdkEvent *)event); } -static gboolean view_onButtonPressed(GtkWidget *treeview, - GdkEventButton *event, - dt_lib_collect_t *d) +static void view_onButtonPressed_cb(GtkGestureSingle *gesture, int n_press, + double x, double y, + dt_lib_collect_t *d) { + GtkWidget *treeview = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + static GdkModifierType last_mod_state = 0; + + GdkEvent *event = gtk_get_current_event(); + /* Get tree path for row that was clicked */ GtkTreePath *path = NULL; const gboolean get_path = gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(treeview), - (gint)dt_gdk_event_get_x(event), (gint)dt_gdk_event_get_y(event), + (gint)x, (gint)y, &path, NULL, NULL, NULL); - if(dt_gdk_event_get_type(event) == GDK_DOUBLE_BUTTON_PRESS || d->singleclick) + GdkModifierType mod_state; + gtk_get_current_event_state(&mod_state); + + if((n_press >= 2 || d->singleclick) && path) { - if(dt_gdk_event_get_state(event) == last_state && path) + if(mod_state == last_mod_state) { if(gtk_tree_view_row_expanded(GTK_TREE_VIEW(treeview), path)) gtk_tree_view_collapse_row(GTK_TREE_VIEW(treeview), path); else gtk_tree_view_expand_row(GTK_TREE_VIEW(treeview), path, FALSE); } - last_state = dt_gdk_event_get_state(event); + last_mod_state = mod_state; } // case of a range selection GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)); - if(get_path && dt_modifier_is(dt_gdk_event_get_state(event), GDK_SHIFT_MASK) + if(get_path && dt_modifier_is(mod_state, GDK_SHIFT_MASK) && gtk_tree_selection_count_selected_rows(selection) > 0 && (d->view_rule == DT_COLLECTION_PROP_DAY || d->view_rule == DT_COLLECTION_PROP_MONTH @@ -678,10 +686,10 @@ static gboolean view_onButtonPressed(GtkWidget *treeview, gtk_tree_selection_select_range(selection, path2, path); g_list_free_full(sels, (GDestroyNotify)gtk_tree_path_free); - row_activated_with_event(GTK_TREE_VIEW(treeview), path, NULL, event, d); + row_activated_with_event(GTK_TREE_VIEW(treeview), path, NULL, (GdkEventButton *)event, d); gtk_tree_path_free(path); - return TRUE; + return; } if(path) @@ -690,37 +698,38 @@ static gboolean view_onButtonPressed(GtkWidget *treeview, gtk_tree_selection_select_path(selection, path); } + const guint button = gtk_gesture_single_get_button(gesture); + // case of a context-menu (folder/filmroll) if(((d->view_rule == DT_COLLECTION_PROP_FOLDERS) || (d->view_rule == DT_COLLECTION_PROP_FILMROLL)) - && (dt_gdk_event_get_type(event) == GDK_BUTTON_PRESS && dt_gdk_event_get_button(event) == GDK_BUTTON_SECONDARY) - && !(dt_modifier_is(dt_gdk_event_get_state(event), GDK_SHIFT_MASK) - || dt_modifier_is(dt_gdk_event_get_state(event), GDK_CONTROL_MASK))) + && (n_press == 1 && button == GDK_BUTTON_SECONDARY) + && !(dt_modifier_is(mod_state, GDK_SHIFT_MASK) + || dt_modifier_is(mod_state, GDK_CONTROL_MASK))) { - row_activated_with_event(GTK_TREE_VIEW(treeview), path, NULL, event, d); - view_popup_menu(treeview, event, d); + row_activated_with_event(GTK_TREE_VIEW(treeview), path, NULL, (GdkEventButton *)event, d); + view_popup_menu(treeview, (GdkEventButton *)event, d); if(path) gtk_tree_path_free(path); - return TRUE; + return; } // case of a activation - if((!d->singleclick && dt_gdk_event_get_type(event) == GDK_2BUTTON_PRESS && dt_gdk_event_get_button(event) == GDK_BUTTON_PRIMARY) - || (d->singleclick && dt_gdk_event_get_type(event) == GDK_BUTTON_PRESS && dt_gdk_event_get_button(event) == GDK_BUTTON_PRIMARY) - || (!d->singleclick && dt_gdk_event_get_type(event) == GDK_BUTTON_PRESS && dt_gdk_event_get_button(event) == GDK_BUTTON_PRIMARY - && (dt_modifier_is(dt_gdk_event_get_state(event), GDK_SHIFT_MASK) - || dt_modifier_is(dt_gdk_event_get_state(event), GDK_CONTROL_MASK))) + if((!d->singleclick && n_press >= 2 && button == GDK_BUTTON_PRIMARY) + || (d->singleclick && n_press == 1 && button == GDK_BUTTON_PRIMARY) + || (!d->singleclick && n_press == 1 && button == GDK_BUTTON_PRIMARY + && (dt_modifier_is(mod_state, GDK_SHIFT_MASK) + || dt_modifier_is(mod_state, GDK_CONTROL_MASK))) || (d->view_rule == DT_COLLECTION_PROP_MONTH - && dt_gdk_event_get_type(event) == GDK_BUTTON_PRESS && dt_gdk_event_get_button(event) == GDK_BUTTON_PRIMARY)) + && n_press == 1 && button == GDK_BUTTON_PRIMARY)) { - row_activated_with_event(GTK_TREE_VIEW(treeview), path, NULL, event, d); + row_activated_with_event(GTK_TREE_VIEW(treeview), path, NULL, (GdkEventButton *)event, d); if(path) gtk_tree_path_free(path); - return TRUE; + return; } if(path) gtk_tree_path_free(path); - return FALSE; } static gboolean view_onPopupMenu(GtkWidget *treeview, dt_lib_collect_t *d) @@ -3590,12 +3599,12 @@ static void menuitem_clear(GtkMenuItem *menuitem, DT_COLLECTION_PROP_UNDEF, NULL); } -static gboolean popup_button_callback(GtkWidget *widget, - GdkEventButton *event, - dt_lib_collect_rule_t *d) +static void popup_button_callback_cb(GtkGestureSingle *gesture, int n_press, + double x, double y, + dt_lib_collect_rule_t *d) { - if(dt_gdk_event_get_button(event) != 1) - return FALSE; + if(gtk_gesture_single_get_button(gesture) != 1) + return; GtkWidget *menu = gtk_menu_new(); GtkWidget *mi; @@ -3655,9 +3664,8 @@ static gboolean popup_button_callback(GtkWidget *widget, gtk_widget_show_all(GTK_WIDGET(menu)); - gtk_menu_popup_at_pointer(GTK_MENU(menu), (GdkEvent *)event); - - return TRUE; + gtk_menu_popup_at_pointer(GTK_MENU(menu), gtk_get_current_event()); + return; } static void view_set_click(gpointer instance, @@ -4045,9 +4053,7 @@ void gui_init(dt_lib_module_t *self) d->rule[i].button = w = dtgtk_button_new(dtgtk_cairo_paint_presets, 0, NULL); dt_gui_add_class(GTK_WIDGET(w), "dt_big_btn_canvas"); - gtk_widget_set_events(w, GDK_BUTTON_PRESS_MASK); - g_signal_connect(G_OBJECT(w), "button-press-event", - G_CALLBACK(popup_button_callback), d->rule + i); + dt_gui_connect_click(w, popup_button_callback_cb, NULL, d->rule + i); d->rule[i].hbox = dt_gui_hbox(d->rule[i].combo, dt_gui_expand(d->rule[i].text), d->rule[i].button); gtk_widget_set_name(d->rule[i].hbox, "lib-dtbutton"); @@ -4058,8 +4064,7 @@ void gui_init(dt_lib_module_t *self) d->view_rule = -1; d->view = view; gtk_tree_view_set_headers_visible(view, FALSE); - g_signal_connect(G_OBJECT(view), "button-press-event", - G_CALLBACK(view_onButtonPressed), d); + dt_gui_connect_click_all(view, view_onButtonPressed_cb, NULL, d); g_signal_connect(G_OBJECT(view), "popup-menu", G_CALLBACK(view_onPopupMenu), d); GtkTreeViewColumn *col = gtk_tree_view_column_new(); From 739cdbe49ea14adae0e07d7b73a5f312a8aa18b9 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 02:56:00 -0300 Subject: [PATCH 48/95] gtk4-prep: replace scroll-event signals with event controllers in culling and thumbtable --- src/dtgtk/culling.c | 89 ++++++++++++++++++++++++------------------ src/dtgtk/thumbtable.c | 43 +++++++++++--------- 2 files changed, 74 insertions(+), 58 deletions(-) diff --git a/src/dtgtk/culling.c b/src/dtgtk/culling.c index 649c201dded..79204d9714e 100644 --- a/src/dtgtk/culling.c +++ b/src/dtgtk/culling.c @@ -651,26 +651,33 @@ static gboolean _event_gesture(GtkWidget *widget, return TRUE; } -static gboolean _event_scroll(GtkWidget *widget, - GdkEvent *event, - gpointer user_data) +static void _event_scroll(GtkEventControllerScroll *controller, + gdouble dx, + gdouble dy, + dt_culling_t *table) { - GdkEventScroll *e = (GdkEventScroll *)event; - dt_culling_t *table = (dt_culling_t *)user_data; + GdkEvent *event = gtk_get_current_event(); + if(!event) return; + + GdkDevice *device = dt_gdk_event_get_source_device(event); + const GdkScrollDirection direction = dt_gdk_event_get_scroll_direction(event); + const gboolean is_stop = gdk_event_is_scroll_stop_event(event); + const GdkModifierType state = dt_gdk_event_get_state(event); + const gdouble x_root = dt_gdk_event_get_root_x(event); + const gdouble y_root = dt_gdk_event_get_root_y(event); - GdkDevice *device = gdk_event_get_source_device(event); dt_print(DT_DEBUG_INPUT, "[culling scroll] direction=%d smooth=%s stop=%s ctrl=%s" " device='%s' source-type=%d x_root=%.1f y_root=%.1f" " delta_x=%.3f delta_y=%.3f state=0x%x", - e->direction, - e->direction == GDK_SCROLL_SMOOTH ? "yes" : "no", - e->is_stop ? "yes" : "no", - dt_modifier_is(e->state, GDK_CONTROL_MASK) ? "yes" : "no", + direction, + direction == GDK_SCROLL_SMOOTH ? "yes" : "no", + is_stop ? "yes" : "no", + dt_modifier_is(state, GDK_CONTROL_MASK) ? "yes" : "no", device ? gdk_device_get_name(device) : "", device ? (int)gdk_device_get_source(device) : -1, - e->x_root, e->y_root, - e->delta_x, e->delta_y, e->state); + x_root, y_root, + dx, dy, state); // ctrl + smooth scroll: apply fractional zoom on every event so the zoom // feels seamless rather than stepped. This must come before the integer- @@ -683,19 +690,19 @@ static gboolean _event_scroll(GtkWidget *widget, // must be finalised regardless. (If no zoom was pending this is a no-op, and // the safety-net timer in _thumbs_zoom_add covers devices that never emit a // stop event at all.) - if(e->direction == GDK_SCROLL_SMOOTH && e->is_stop) + if(direction == GDK_SCROLL_SMOOTH && is_stop) { + gdk_event_free(event); dt_culling_zoom_end(table); - return TRUE; + return; } - if(e->direction == GDK_SCROLL_SMOOTH && !e->is_stop - && dt_modifiers_include(e->state, GDK_CONTROL_MASK)) + if(direction == GDK_SCROLL_SMOOTH && !is_stop + && dt_modifiers_include(state, GDK_CONTROL_MASK)) { - gdouble dx = 0.0, dy = 0.0; - if(dt_gui_get_scroll_deltas(e, &dx, &dy) && (dx != 0.0 || dy != 0.0)) + if(dx != 0.0 || dy != 0.0) { - // dt_gui_get_scroll_deltas gives the raw fractional platform delta. + // controller dx/dy gives the raw fractional platform delta. // Scale so that one full unit of scroll (delta_y == 1.0) matches the // 0.5 zoom_delta of a discrete mouse-wheel click. right==up==zoom-in const gdouble delta = fabs(dx) > fabs(dy) ? -dx : dy; @@ -705,22 +712,23 @@ static gboolean _event_scroll(GtkWidget *widget, GdkWindow *win = gtk_widget_get_window(table->widget); if(win) gdk_window_get_origin(win, &ox, &oy); - const float x_culling = e->x_root - ox; - const float y_culling = e->y_root - oy; + const float x_culling = x_root - ox; + const float y_culling = y_root - oy; dt_print(DT_DEBUG_INPUT, "[culling scroll] ctrl+smooth zoom_delta=%.4f x_culling=%.1f y_culling=%.1f", zoom_delta, x_culling, y_culling); if(fabsf(zoom_delta) > 0.001f) - _thumbs_zoom_add(table, zoom_delta, x_culling, y_culling, e->state, TRUE); + _thumbs_zoom_add(table, zoom_delta, x_culling, y_culling, state, TRUE); } - return TRUE; + gdk_event_free(event); + return; } // Smooth scroll (touchpad two-finger swipe): pan zoomed images or navigate images. // We check before the unit-delta path so fractional smooth scroll is used for panning // with full fidelity rather than being accumulated into integer steps. - if(e->direction == GDK_SCROLL_SMOOTH && !e->is_stop - && !dt_modifiers_include(e->state, GDK_CONTROL_MASK)) + if(direction == GDK_SCROLL_SMOOTH && !is_stop + && !dt_modifiers_include(state, GDK_CONTROL_MASK)) { // Check if any thumbnail is zoomed in; if so, pan instead of navigate. float fz = 1.0f; @@ -734,29 +742,31 @@ static gboolean _event_scroll(GtkWidget *widget, fz, fz > 1.0f ? "pan path" : "navigate path"); if(fz > 1.0f) { - gdouble dx = 0.0, dy = 0.0; - if(dt_gui_get_scroll_deltas(e, &dx, &dy) && (dx != 0.0 || dy != 0.0)) + if(dx != 0.0 || dy != 0.0) { - // dt_gui_get_scroll_deltas returns platform-normalised fractional units; + // controller dx/dy is platform-normalised fractional units; // scale to pixel-scale (matches the factor used by the center-widget pan path). dt_print(DT_DEBUG_INPUT, "[culling scroll] panning dx=%.3f dy=%.3f (scaled: dx=%.1f dy=%.1f)", dx, dy, dx * 50.0, dy * 50.0); - dt_culling_pan_move(table, (float)(-dx * 50.0), (float)(-dy * 50.0), e->state); + dt_culling_pan_move(table, (float)(-dx * 50.0), (float)(-dy * 50.0), state); } else { - dt_print(DT_DEBUG_INPUT, "[culling scroll] smooth pan: no delta from dt_gui_get_scroll_deltas"); + dt_print(DT_DEBUG_INPUT, "[culling scroll] smooth pan: no delta from controller"); } - return TRUE; + gdk_event_free(event); + return; } } + // discrete scroll: use unit deltas for zoom/navigation + const GdkEventScroll *scroll_event = (const GdkEventScroll *)event; int delta_x = 0, delta_y = 0; - if(dt_gui_get_scroll_unit_deltas(e, &delta_x, &delta_y)) + if(dt_gui_get_scroll_unit_deltas(scroll_event, &delta_x, &delta_y)) { const gboolean is_horizontal = abs(delta_x) > abs(delta_y); - if(dt_modifiers_include(e->state, GDK_CONTROL_MASK)) + if(dt_modifiers_include(state, GDK_CONTROL_MASK)) { // zooming: right==up==zoom-in const int delta = is_horizontal ? -delta_x : delta_y; @@ -766,8 +776,8 @@ static gboolean _event_scroll(GtkWidget *widget, GdkWindow *win = gtk_widget_get_window(table->widget); if(win) gdk_window_get_origin(win, &ox, &oy); - const float x_culling = e->x_root - ox; - const float y_culling = e->y_root - oy; + const float x_culling = x_root - ox; + const float y_culling = y_root - oy; dt_print(DT_DEBUG_INPUT, "[culling scroll] ctrl+scroll zoom_delta=%.2f x_culling=%.1f y_culling=%.1f", zoom_delta, x_culling, y_culling); @@ -775,7 +785,7 @@ static gboolean _event_scroll(GtkWidget *widget, // smooth is_stop event to finalise it, so reload the surface immediately // (still cheap — the native mipmap surface cache is reused). Leaving it // deferred would freeze the image at a stale, scaled-up resolution. - _thumbs_zoom_add(table, zoom_delta, x_culling, y_culling, e->state, FALSE); + _thumbs_zoom_add(table, zoom_delta, x_culling, y_culling, state, FALSE); } else { @@ -786,7 +796,7 @@ static gboolean _event_scroll(GtkWidget *widget, _thumbs_move(table, move); } } - return TRUE; + gdk_event_free(event); } static gboolean _event_draw(GtkWidget *widget, @@ -1208,8 +1218,9 @@ dt_culling_t *dt_culling_new(const dt_culling_mode_t mode) g_signal_connect(G_OBJECT(table->widget), "event", G_CALLBACK(_event_gesture), table); - g_signal_connect(G_OBJECT(table->widget), "scroll-event", - G_CALLBACK(_event_scroll), table); + dt_gui_connect_scroll(table->widget, GTK_EVENT_CONTROLLER_SCROLL_BOTH_AXES + | GTK_EVENT_CONTROLLER_SCROLL_DISCRETE, + _event_scroll, table); g_signal_connect(G_OBJECT(table->widget), "draw", G_CALLBACK(_event_draw), table); dt_gui_connect_motion(table->widget, _event_motion_notify_cb, _event_enter_cb, _event_leave_cb, table); diff --git a/src/dtgtk/thumbtable.c b/src/dtgtk/thumbtable.c index d926eddc423..cf7305b7b45 100644 --- a/src/dtgtk/thumbtable.c +++ b/src/dtgtk/thumbtable.c @@ -1117,34 +1117,39 @@ static gboolean _event_scroll_compressed(gpointer user_data) return FALSE; } -static gboolean _event_scroll(GtkWidget *widget, - GdkEvent *event, - dt_thumbtable_t *table) +static void _event_scroll(GtkEventControllerScroll *controller, + gdouble dx, + gdouble dy, + dt_thumbtable_t *table) { - GdkEventScroll *e = (GdkEventScroll *)event; + GdkEvent *event = gtk_get_current_event(); + if(!event) return; + const GdkEventScroll *e = (const GdkEventScroll *)event; + const GdkModifierType state = dt_gdk_event_get_state(event); // file manager can either scroll fractionally and smoothly for precision // touch pads, or in one-thumbnail increments for clicky scroll wheels, // except while control is held, as that indicates zooming if(table->mode == DT_THUMBTABLE_MODE_FILEMANAGER - && !dt_modifier_is(e->state, GDK_CONTROL_MASK)) + && !dt_modifier_is(state, GDK_CONTROL_MASK)) { gdouble deltaf = 0.f; gboolean did_scroll; if(dt_conf_get_bool("thumbtable_fractional_scrolling")) { - gdouble deltaf_x, deltaf_y; - did_scroll = dt_gui_get_scroll_deltas(e, &deltaf_x, &deltaf_y); - if (did_scroll) { - // file manager scroll: tilt right (delta_x >) 0 or scroll down (delta_y > 0) -> down (towards the last image) - deltaf = fabs(deltaf_x) > fabs(deltaf_y) ? deltaf_x : deltaf_y; + // use controller dx/dy directly for fractional scrolling + did_scroll = (dx != 0.0 || dy != 0.0); + if(did_scroll) + { + // file manager scroll: tilt right (dx > 0) or scroll down (dy > 0) -> down + deltaf = fabs(dx) > fabs(dy) ? dx : dy; } } else { int delta_x, delta_y; did_scroll = dt_gui_get_scroll_unit_deltas(e, &delta_x, &delta_y); - if (did_scroll) + if(did_scroll) { deltaf = abs(delta_x) > abs(delta_y) ? delta_x : delta_y; } @@ -1159,8 +1164,8 @@ static gboolean _event_scroll(GtkWidget *widget, } table->scroll_value += deltaf; } - // we stop here to avoid scrolledwindow to move - return TRUE; + gdk_event_free(event); + return; } // filmstrip and zoom mode always use clicky scroll: @@ -1170,7 +1175,7 @@ static gboolean _event_scroll(GtkWidget *widget, { // for zoomable, scroll = zoom if(table->mode == DT_THUMBTABLE_MODE_ZOOM - || dt_modifier_is(e->state, GDK_CONTROL_MASK)) + || dt_modifier_is(state, GDK_CONTROL_MASK)) { // up==right==zoom in const int delta = abs(delta_x) > abs(delta_y) ? -delta_x : delta_y; @@ -1192,7 +1197,7 @@ static gboolean _event_scroll(GtkWidget *widget, { // filmstrip scroll: tilt right (delta_x >) 0 or scroll down (delta_y > 0) -> down (towards the last image) const int delta = abs(delta_x) > abs(delta_y) ? delta_x : delta_y; - _move(table, -delta * (dt_modifier_is(e->state, GDK_SHIFT_MASK) + _move(table, -delta * (dt_modifier_is(state, GDK_SHIFT_MASK) ? table->view_width - table->thumb_size : table->thumb_size), 0, TRUE); @@ -1202,8 +1207,7 @@ static gboolean _event_scroll(GtkWidget *widget, dt_control_set_mouse_over_id(th->imgid); } } - // we stop here to avoid scrolled window to move - return TRUE; + gdk_event_free(event); } static void _line_to(cairo_t *cr, @@ -2586,8 +2590,9 @@ dt_thumbtable_t *dt_thumbtable_new() g_signal_connect(table->widget, "drag-data-received", G_CALLBACK(dt_thumbtable_event_dnd_received), table); - g_signal_connect(G_OBJECT(table->widget), "scroll-event", - G_CALLBACK(_event_scroll), table); + dt_gui_connect_scroll(table->widget, GTK_EVENT_CONTROLLER_SCROLL_BOTH_AXES + | GTK_EVENT_CONTROLLER_SCROLL_DISCRETE, + _event_scroll, table); g_signal_connect(G_OBJECT(table->widget), "draw", G_CALLBACK(_event_draw), table); dt_gui_connect_motion(table->widget, _event_motion_notify_cb, _event_enter_cb, _event_leave_cb, table); From 5e13858f301a29673a1b28dc001af7bd017934b3 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 02:56:03 -0300 Subject: [PATCH 49/95] gtk4-prep: replace motion-notify and key-press signals with event controllers in bauhaus --- src/bauhaus/bauhaus.c | 94 +++++++++++++++++++++++++++++++------------ 1 file changed, 68 insertions(+), 26 deletions(-) diff --git a/src/bauhaus/bauhaus.c b/src/bauhaus/bauhaus.c index 4b215da1554..c91ef1d2447 100644 --- a/src/bauhaus/bauhaus.c +++ b/src/bauhaus/bauhaus.c @@ -171,7 +171,15 @@ static double INNER_PADDING = 4.0; static void _popup_reject(void); static void _popup_hide(void); static gboolean _popup_draw(GtkWidget *widget, cairo_t *cr, gpointer user_data); -static gboolean _popup_key_press(GtkWidget *widget, GdkEventKey *event, gpointer user_data); +static void _window_motion_handle(GtkWidget *widget, + gdouble root_x, + gdouble root_y, + GdkModifierType state); +static gboolean _popup_key_press(GtkEventControllerKey *controller, + guint keyval, + guint keycode, + GdkModifierType state, + gpointer user_data); static void _combobox_set(dt_bauhaus_widget_t *w, const int pos, const gboolean mute); @@ -591,9 +599,10 @@ static void _window_position(const int offset) 0, - pop->offset + pop->offcut); } -static gboolean _window_motion_notify(GtkWidget *widget, - GdkEventMotion *event, - gpointer user_data) +static void _window_motion_handle(GtkWidget *widget, + gdouble root_x, + gdouble root_y, + GdkModifierType state) { dt_bauhaus_t *bh = darktable.bauhaus; dt_bauhaus_popup_t *pop = &bh->popup; @@ -607,16 +616,16 @@ static gboolean _window_motion_notify(GtkWidget *widget, // recalculate event coords so we get useful values outside window GdkWindow *window = gtk_widget_get_window(pop->area); gdk_window_get_origin(window, &allocation.x, &allocation.y); - const gint ex = dt_gdk_event_get_root_x(event) - allocation.x; - const gint ey = dt_gdk_event_get_root_y(event) - allocation.y; + const gint ex = root_x - allocation.x; + const gint ey = root_y - allocation.y; - const int tol = DT_PIXEL_APPLY_DPI(dt_gdk_event_get_state(event) & GDK_BUTTON1_MASK ? 400 : 50); + const int tol = DT_PIXEL_APPLY_DPI(state & GDK_BUTTON1_MASK ? 400 : 50); if(ex < - tol || ex > allocation.width + tol || ey + pop->offcut < - tol || ey + pop->offcut > pop->position.height + tol) { _popup_reject(); - return TRUE; + return; } if(bh->keys_cnt == 0) _stop_cursor(); @@ -653,7 +662,7 @@ static gboolean _window_motion_notify(GtkWidget *widget, : _slider_get_line_offset (pop->oldpos, 5.0 * powf(10.0f, -d->digits) / (d->max - d->min) / fabsf(d->factor), bh->mouse_x / (width - _widget_get_quad_width(w)), bh->mouse_y / width, ht / width); - if(dt_gdk_event_get_state(event) & GDK_BUTTON1_MASK + if(state & GDK_BUTTON1_MASK || (bh->mouse_line_distance && ((bh->mouse_line_distance * mouse_off <= 0) ^ (fabsf(bh->mouse_line_distance - mouse_off) > .5f)))) @@ -668,7 +677,7 @@ static gboolean _window_motion_notify(GtkWidget *widget, const int active = (bh->mouse_y - w->top_gap) / bh->line_height; if(active >= 0 && active < d->entries->len) { - if(_combobox_entry(d, active)->sensitive && dt_gdk_event_get_state(event) & GDK_BUTTON1_MASK) + if(_combobox_entry(d, active)->sensitive && state & GDK_BUTTON1_MASK) { if(active != d->active) _combobox_set(w, active, w->combobox.mute_scrolling); @@ -677,7 +686,21 @@ static gboolean _window_motion_notify(GtkWidget *widget, } gtk_widget_queue_draw(pop->area); - return TRUE; +} + +static void _window_motion_cb(GtkEventControllerMotion *controller, + gdouble x, + gdouble y, + gpointer user_data) +{ + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); + GdkEvent *event = gtk_get_current_event(); + if(!event) return; + const gdouble root_x = dt_gdk_event_get_root_x(event); + const gdouble root_y = dt_gdk_event_get_root_y(event); + const GdkModifierType state = dt_gdk_event_get_state(event); + gdk_event_free(event); + _window_motion_handle(widget, root_x, root_y, state); } static void _popup_leave_notify_cb(GtkEventControllerMotion *controller, @@ -728,8 +751,10 @@ static void _popup_button_press_cb(GtkGestureSingle *gesture, bh->change_active = TRUE; GtkWidget *w_current = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); const GdkEvent *current_event = gtk_get_current_event(); - _window_motion_notify(w_current, - (GdkEventMotion *)current_event, user_data); + _window_motion_handle(w_current, + dt_gdk_event_get_root_x(current_event), + dt_gdk_event_get_root_y(current_event), + dt_gdk_event_get_state(current_event)); } else if(button == GDK_BUTTON_MIDDLE && w->type == DT_BAUHAUS_SLIDER) _slider_zoom_range(w, 0); @@ -984,10 +1009,10 @@ void dt_bauhaus_init() g_signal_connect(gtk_widget_get_window(pop->window), "moved-to-rect", G_CALLBACK(_window_moved_to_rect), NULL); g_signal_connect(window, "show", G_CALLBACK(_window_show), area); - g_signal_connect(window, "motion-notify-event", G_CALLBACK(_window_motion_notify), NULL); g_signal_connect(area, "draw", G_CALLBACK(_popup_draw), NULL); - g_signal_connect(area, "key-press-event", G_CALLBACK(_popup_key_press), NULL); + dt_gui_connect_key(area, _popup_key_press, NULL); dt_gui_connect_motion(area, NULL, NULL, _popup_leave_notify_cb, NULL); + dt_gui_connect_motion(window, _window_motion_cb, NULL, NULL, NULL); dt_gui_connect_click_all(area, _popup_button_press_cb, _popup_button_release_cb, NULL); dt_gui_connect_scroll(area, GTK_EVENT_CONTROLLER_SCROLL_BOTH_AXES | GTK_EVENT_CONTROLLER_SCROLL_DISCRETE, @@ -3756,16 +3781,18 @@ static void _slider_set_normalized(dt_bauhaus_widget_t *w, float pos) } } -static gboolean _popup_key_press(GtkWidget *widget, - GdkEventKey *event, - gpointer user_data) +static gboolean _popup_key_press(GtkEventControllerKey *controller, + guint keyval, + guint keycode, + GdkModifierType state, + gpointer user_data) { dt_bauhaus_t *bh = darktable.bauhaus; dt_bauhaus_widget_t *w = bh->current; const gboolean is_combo = w->type == DT_BAUHAUS_COMBOBOX; int delta = -1; - switch(dt_gdk_event_get_keyval(event)) + switch(keyval) { case GDK_KEY_BackSpace: case GDK_KEY_Delete: @@ -3831,22 +3858,37 @@ static gboolean _popup_key_press(GtkWidget *widget, if(is_combo) _combobox_next_sensitive(w, delta, 0, w->combobox.mute_scrolling); else - _slider_add_step(GTK_WIDGET(w), delta, dt_gdk_event_get_state(event), FALSE); + _slider_add_step(GTK_WIDGET(w), delta, state, FALSE); break; default: - if(!event->string || !g_utf8_validate(event->string, -1, NULL)) return FALSE; - const gunichar c = g_utf8_get_char(event->string); - if(!g_unichar_isprint(c)) return FALSE; - const long int char_width = g_utf8_next_char(event->string) - event->string; + { + GdkEvent *event = gtk_get_current_event(); + if(!event) return FALSE; + const gchar *str = ((GdkEventKey *)event)->string; + if(!str || !g_utf8_validate(str, -1, NULL)) + { + gdk_event_free(event); + return FALSE; + } + const gunichar c = g_utf8_get_char(str); + if(!g_unichar_isprint(c)) + { + gdk_event_free(event); + return FALSE; + } + const long int char_width = g_utf8_next_char(str) - str; if(bh->keys_cnt + 1 + char_width < DT_BAUHAUS_MAX_TEXT - && (is_combo || strchr("0123456789.,%%+-*Xx/:^~ ()", event->string[0]))) + && (is_combo || strchr("0123456789.,%%+-*Xx/:^~ ()", str[0]))) { // only accept valid keys for slider; combo is checked in _popup_draw - strncpy(bh->keys + bh->keys_cnt, event->string, char_width); + strncpy(bh->keys + bh->keys_cnt, str, char_width); bh->keys_cnt += char_width; if(!is_combo) _start_cursor(-1); } + gdk_event_free(event); + break; + } } gtk_widget_queue_draw(bh->popup.area); return TRUE; From d44fc6951437209bd65543fe2fb2562c93fff6c3 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 02:56:07 -0300 Subject: [PATCH 50/95] gtk4-prep: replace event signals with event controllers in tagging module --- src/libs/tagging.c | 165 ++++++++++++++++++++++++++------------------- 1 file changed, 94 insertions(+), 71 deletions(-) diff --git a/src/libs/tagging.c b/src/libs/tagging.c index 55b56393ef2..c13c444285f 100644 --- a/src/libs/tagging.c +++ b/src/libs/tagging.c @@ -1469,22 +1469,26 @@ static void _pop_menu_attached(GtkWidget *treeview, gtk_menu_popup_at_pointer(GTK_MENU(menu), (GdkEvent *)event); } -static gboolean _click_on_view_attached(GtkWidget *view, - GdkEventButton *event, - dt_lib_module_t *self) +static void _click_on_view_attached(GtkGestureSingle *gesture, + int n_press, + double x, + double y, + dt_lib_module_t *self) { dt_lib_tagging_t *d = self->data; + GtkWidget *view = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); _unselect_all_in_view(d->dictionary_view); - if((dt_gdk_event_get_type(event) == GDK_BUTTON_PRESS && dt_gdk_event_get_button(event) == GDK_BUTTON_SECONDARY) - || (dt_gdk_event_get_type(event) == GDK_2BUTTON_PRESS && dt_gdk_event_get_button(event) == GDK_BUTTON_PRIMARY) - || (dt_gdk_event_get_type(event) == GDK_BUTTON_PRESS && dt_gdk_event_get_button(event) == GDK_BUTTON_PRIMARY)) + const guint button = gtk_gesture_single_get_button(gesture); + if((n_press == 1 && button == GDK_BUTTON_SECONDARY) + || (n_press == 2 && button == GDK_BUTTON_PRIMARY) + || (n_press == 1 && button == GDK_BUTTON_PRIMARY)) { GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(view)); GtkTreePath *path = NULL; // Get tree path for row that was clicked if(gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(view), - (gint)dt_gdk_event_get_x(event), (gint)dt_gdk_event_get_y(event), + (gint)x, (gint)y, &path, NULL, NULL, NULL)) { gboolean valid_tag = FALSE; @@ -1497,46 +1501,51 @@ static gboolean _click_on_view_attached(GtkWidget *view, { gtk_tree_selection_select_path(selection, path); dt_lib_gui_queue_update(self); - if(dt_gdk_event_get_type(event) == GDK_BUTTON_PRESS - && dt_gdk_event_get_button(event) == GDK_BUTTON_SECONDARY) + if(n_press == 1 && button == GDK_BUTTON_SECONDARY) { - _pop_menu_attached(view, event, self); + dt_gui_claim(gesture); + GdkEvent *event = gtk_get_current_event(); + _pop_menu_attached(view, (GdkEventButton *)event, self); + if(event) gdk_event_free(event); gtk_tree_path_free(path); - return TRUE; + return; } - else if(dt_gdk_event_get_type(event) == GDK_2BUTTON_PRESS - && dt_gdk_event_get_button(event) == GDK_BUTTON_PRIMARY) + else if(n_press == 2 && button == GDK_BUTTON_PRIMARY) { + dt_gui_claim(gesture); _detach_selected_tag(d->attached_view, self); gtk_tree_path_free(path); - return TRUE; + return; } } else { // prevent to select a darktable tag + dt_gui_claim(gesture); gtk_tree_path_free(path); - return TRUE; + return; } } gtk_tree_path_free(path); } - return FALSE; } -static gboolean _attached_key_pressed(GtkWidget *view, - GdkEventKey *event, - dt_lib_module_t *self) +static gboolean _attached_key_pressed(GtkEventControllerKey *controller, + guint keyval, + guint keycode, + GdkModifierType state, + dt_lib_module_t *self) { dt_lib_tagging_t *d = self->data; _unselect_all_in_view(d->dictionary_view); + GtkWidget *view = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); GtkTreeIter iter; GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(d->attached_view)); GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(view)); if(gtk_tree_selection_get_selected(selection, &model, &iter)) { GtkTreePath *path = gtk_tree_model_get_path(model, &iter); - switch(dt_gdk_event_get_keyval(event)) + switch(keyval) { case GDK_KEY_Delete: case GDK_KEY_KP_Delete: @@ -1548,13 +1557,13 @@ static gboolean _attached_key_pressed(GtkWidget *view, } gtk_tree_path_free(path); } - if(dt_gdk_event_get_keyval(event) == GDK_KEY_Tab) + if(keyval == GDK_KEY_Tab) { gtk_tree_selection_unselect_all(selection); gtk_widget_grab_focus(GTK_WIDGET(d->entry)); return TRUE; } - else if(dt_gdk_event_get_keyval(event) == GDK_KEY_ISO_Left_Tab) + else if(keyval == GDK_KEY_ISO_Left_Tab) { gtk_tree_selection_unselect_all(selection); return TRUE; @@ -1603,12 +1612,15 @@ static void _new_button_clicked(GtkButton *button, dt_lib_module_t *self) tagname ? tagname + 1 : d->last_tag, FALSE, TRUE); } -static gboolean _enter_key_pressed(GtkWidget *entry, - GdkEventKey *event, - dt_lib_module_t *self) +static gboolean _enter_key_pressed(GtkEventControllerKey *controller, + guint keyval, + guint keycode, + GdkModifierType state, + dt_lib_module_t *self) { dt_lib_tagging_t *d = self->data; - switch(dt_gdk_event_get_keyval(event)) + GtkWidget *entry = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); + switch(keyval) { case GDK_KEY_Return: case GDK_KEY_KP_Enter: @@ -2635,28 +2647,33 @@ static void _pop_menu_dictionary(GtkWidget *treeview, } } -static gboolean _click_on_view_dictionary(GtkWidget *view, - GdkEventButton *event, - dt_lib_module_t *self) +static void _click_on_view_dictionary(GtkGestureSingle *gesture, + int n_press, + double x, + double y, + dt_lib_module_t *self) { dt_lib_tagging_t *d = self->data; + GtkWidget *view = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); _unselect_all_in_view(d->attached_view); - const int button_pressed = (dt_gdk_event_get_type(event) == GDK_BUTTON_PRESS) ? dt_gdk_event_get_button(event) : 0; - const gboolean shift_pressed = dt_modifier_is(dt_gdk_event_get_state(event), GDK_SHIFT_MASK); - if((button_pressed == GDK_BUTTON_SECONDARY) // contextual menu - || (d->tree_flag && button_pressed == GDK_BUTTON_PRIMARY) // expand & drag - || (dt_gdk_event_get_type(event) == GDK_2BUTTON_PRESS && dt_gdk_event_get_button(event) == GDK_BUTTON_PRIMARY)) // attach + GdkEvent *event = gtk_get_current_event(); + const GdkModifierType state = event ? dt_gdk_event_get_state(event) : 0; + const guint button = gtk_gesture_single_get_button(gesture); + const gboolean shift_pressed = dt_modifier_is(state, GDK_SHIFT_MASK); + if((button == GDK_BUTTON_SECONDARY && n_press == 1) // contextual menu + || (d->tree_flag && button == GDK_BUTTON_PRIMARY && n_press == 1) // expand & drag + || (n_press == 2 && button == GDK_BUTTON_PRIMARY)) // attach { GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(view)); GtkTreePath *path = NULL; // Get tree path for row that was clicked if(gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(view), - (gint)dt_gdk_event_get_x(event), (gint)dt_gdk_event_get_y(event), + (gint)x, (gint)y, &path, NULL, NULL, NULL)) { if(d->tree_flag - && button_pressed == GDK_BUTTON_PRIMARY + && button == GDK_BUTTON_PRIMARY && n_press == 1 && !shift_pressed) { GtkTreeModel *model = gtk_tree_view_get_model(d->dictionary_view); @@ -2671,60 +2688,69 @@ static gboolean _click_on_view_dictionary(GtkWidget *view, d->drag.path = path; if(d->drag.lastpath) gtk_tree_path_free(d->drag.lastpath); d->drag.lastpath = NULL; - return FALSE; + if(event) gdk_event_free(event); + return; } else { gtk_tree_selection_select_path(selection, path); dt_lib_gui_queue_update(self); - if(button_pressed == GDK_BUTTON_SECONDARY) + if(button == GDK_BUTTON_SECONDARY && n_press == 1) { - _pop_menu_dictionary(view, event, self); + dt_gui_claim(gesture); + _pop_menu_dictionary(view, (GdkEventButton *)event, self); gtk_tree_path_free(path); - return TRUE; + if(event) gdk_event_free(event); + return; } else if(d->tree_flag - && button_pressed == GDK_BUTTON_PRIMARY + && button == GDK_BUTTON_PRIMARY && n_press == 1 && shift_pressed) { + dt_gui_claim(gesture); gtk_tree_view_expand_row(GTK_TREE_VIEW(view), path, TRUE); gtk_tree_path_free(path); - return TRUE; + if(event) gdk_event_free(event); + return; } - else if(dt_gdk_event_get_type(event) == GDK_2BUTTON_PRESS - && dt_gdk_event_get_button(event) == GDK_BUTTON_PRIMARY) + else if(n_press == 2 && button == GDK_BUTTON_PRIMARY) { + dt_gui_claim(gesture); _attach_selected_tag(self, d); gtk_tree_path_free(path); - return TRUE; + if(event) gdk_event_free(event); + return; } } } gtk_tree_path_free(path); } - return FALSE; + if(event) gdk_event_free(event); } -static gboolean _dictionary_key_pressed(GtkWidget *view, - GdkEventKey *event, - dt_lib_module_t *self) +static gboolean _dictionary_key_pressed(GtkEventControllerKey *controller, + guint keyval, + guint keycode, + GdkModifierType state, + dt_lib_module_t *self) { dt_lib_tagging_t *d = self->data; _unselect_all_in_view(d->attached_view); GtkTreeIter iter; GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(d->dictionary_view)); + GtkWidget *view = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(view)); gboolean res = FALSE; if(gtk_tree_selection_get_selected(selection, &model, &iter)) { GtkTreePath *path = gtk_tree_model_get_path(model, &iter); - switch(dt_gdk_event_get_keyval(event)) + switch(keyval) { case GDK_KEY_Return: case GDK_KEY_KP_Enter: { _attach_selected_tag(self, d); - if(dt_modifier_is(dt_gdk_event_get_state(event), GDK_SHIFT_MASK)) + if(dt_modifier_is(state, GDK_SHIFT_MASK)) { gtk_tree_selection_unselect_all(selection); gtk_entry_set_text(GTK_ENTRY(d->entry), ""); @@ -2736,7 +2762,7 @@ static gboolean _dictionary_key_pressed(GtkWidget *view, case GDK_KEY_Left: if(path) { - if(dt_modifier_is(dt_gdk_event_get_state(event), GDK_SHIFT_MASK)) + if(dt_modifier_is(state, GDK_SHIFT_MASK)) gtk_tree_view_collapse_all(GTK_TREE_VIEW(view)); else gtk_tree_view_collapse_row(GTK_TREE_VIEW(view), path); @@ -2747,7 +2773,7 @@ static gboolean _dictionary_key_pressed(GtkWidget *view, if(path) { gtk_tree_view_expand_row(GTK_TREE_VIEW(view), path, - dt_modifier_is(dt_gdk_event_get_state(event), GDK_SHIFT_MASK)); + dt_modifier_is(state, GDK_SHIFT_MASK)); res = TRUE; } break; @@ -2756,12 +2782,12 @@ static gboolean _dictionary_key_pressed(GtkWidget *view, } gtk_tree_path_free(path); } - if(dt_gdk_event_get_keyval(event) == GDK_KEY_Tab) + if(keyval == GDK_KEY_Tab) { gtk_tree_selection_unselect_all(selection); res = TRUE; } - else if(dt_gdk_event_get_keyval(event) == GDK_KEY_ISO_Left_Tab) + else if(keyval == GDK_KEY_ISO_Left_Tab) { gtk_tree_selection_unselect_all(selection); gtk_widget_grab_focus(GTK_WIDGET(d->entry)); @@ -3529,10 +3555,8 @@ void gui_init(dt_lib_module_t *self) "\npress Delete or double-click to detach" "\nright-click for other actions on attached tag," "\nTab to give the focus to entry")); - g_signal_connect(G_OBJECT(view), "button-press-event", - G_CALLBACK(_click_on_view_attached), (gpointer)self); - g_signal_connect(G_OBJECT(view), "key-press-event", - G_CALLBACK(_attached_key_pressed), (gpointer)self); + dt_gui_connect_click_all(view, _click_on_view_attached, NULL, self); + dt_gui_connect_key(view, _attached_key_pressed, self); g_signal_connect(gtk_tree_view_get_selection(view), "changed", G_CALLBACK(_tree_selection_changed), self); @@ -3591,8 +3615,7 @@ void gui_init(dt_lib_module_t *self) gtk_widget_add_events(GTK_WIDGET(w), GDK_KEY_RELEASE_MASK); g_signal_connect(G_OBJECT(w), "changed", G_CALLBACK(_tag_name_changed), (gpointer)self); - g_signal_connect(G_OBJECT(w), "key-press-event", - G_CALLBACK(_enter_key_pressed), (gpointer)self); + dt_gui_connect_key(w, _enter_key_pressed, self); d->entry = GTK_ENTRY(w); button = dtgtk_button_new(dtgtk_cairo_paint_multiply_small, 0, NULL); @@ -3669,10 +3692,8 @@ void gui_init(dt_lib_module_t *self) "\nright-click for other actions on selected tag" "\nshift+Tab to give the focus to entry")); - g_signal_connect(G_OBJECT(view), "button-press-event", - G_CALLBACK(_click_on_view_dictionary), (gpointer)self); - g_signal_connect(G_OBJECT(view), "key-press-event", - G_CALLBACK(_dictionary_key_pressed), (gpointer)self); + dt_gui_connect_click_all(view, _click_on_view_dictionary, NULL, self); + dt_gui_connect_key(view, _dictionary_key_pressed, self); gtk_tree_view_set_model(view, GTK_TREE_MODEL(d->dictionary_listfilter)); g_object_unref(d->dictionary_listfilter); g_object_set(G_OBJECT(view), "has-tooltip", TRUE, NULL); @@ -3767,12 +3788,14 @@ void gui_cleanup(dt_lib_module_t *self) } // http://stackoverflow.com/questions/4631388/transparent-floating-gtkentry -static gboolean _lib_tagging_tag_key_press(GtkWidget *entry, - GdkEventKey *event, - dt_lib_module_t *self) +static gboolean _lib_tagging_tag_key_press(GtkEventControllerKey *controller, + guint keyval, + guint keycode, + GdkModifierType state, + dt_lib_module_t *self) { dt_lib_tagging_t *d = self->data; - switch(dt_gdk_event_get_keyval(event)) + switch(keyval) { case GDK_KEY_Escape: g_list_free(d->floating_tag_imgs); @@ -3784,6 +3807,7 @@ static gboolean _lib_tagging_tag_key_press(GtkWidget *entry, case GDK_KEY_Return: case GDK_KEY_KP_Enter: { + GtkWidget *entry = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); dt_gui_cursor_set_busy(); const gchar *tag = gtk_entry_get_text(GTK_ENTRY(entry)); const gboolean res = dt_tag_attach_string_list(tag, d->floating_tag_imgs, TRUE); @@ -3895,8 +3919,7 @@ static void _lib_tagging_tag_show(dt_action_t *action) gtk_container_add(GTK_CONTAINER(d->floating_tag_window), entry); g_signal_connect(entry, "focus-out-event", G_CALLBACK(_lib_tagging_tag_destroy), d->floating_tag_window); - g_signal_connect(entry, "key-press-event", - G_CALLBACK(_lib_tagging_tag_key_press), self); + dt_gui_connect_key(entry, _lib_tagging_tag_key_press, self); gtk_widget_show_all(d->floating_tag_window); gtk_widget_grab_focus(entry); From 17953ee67db627e69891455172716d5354d5bd69 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 02:56:10 -0300 Subject: [PATCH 51/95] gtk4-prep: replace scroll-event with event controller in colorequal --- src/iop/colorequal.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/iop/colorequal.c b/src/iop/colorequal.c index 96b2c40320e..028e6a2e299 100644 --- a/src/iop/colorequal.c +++ b/src/iop/colorequal.c @@ -2697,16 +2697,20 @@ static void _area_reset_nodes(dt_iop_colorequal_gui_data_t *g) } } -static gboolean _area_scrolled_callback(GtkWidget *widget, - GdkEventScroll *event, - const dt_iop_module_t *self) +static void _area_scrolled_callback(GtkEventControllerScroll *controller, + gdouble dx, + gdouble dy, + dt_iop_module_t *self) { const dt_iop_colorequal_gui_data_t *g = self->gui_data; + GdkEvent *event = gtk_get_current_event(); + if(!event) return; + GtkWidget *w = dt_modifier_is(dt_gdk_event_get_state(event), GDK_MOD1_MASK) ? GTK_WIDGET(g->notebook) : _get_slider(g, g->selected); - return gtk_widget_event(w, (GdkEvent*)event); + gtk_widget_event(w, event); } static void _area_motion_notify_callback(GtkEventControllerMotion *controller, @@ -2977,8 +2981,9 @@ void gui_init(dt_iop_module_t *self) dt_gui_connect_click_all(g->area, _area_button_press_callback, _area_button_release_callback, self); dt_gui_connect_motion(g->area, _area_motion_notify_callback, NULL, NULL, self); gtk_widget_add_events(GTK_WIDGET(g->area), darktable.gui->scroll_mask); - g_signal_connect(G_OBJECT(g->area), "scroll-event", - G_CALLBACK(_area_scrolled_callback), self); + dt_gui_connect_scroll(g->area, GTK_EVENT_CONTROLLER_SCROLL_BOTH_AXES + | GTK_EVENT_CONTROLLER_SCROLL_DISCRETE, + _area_scrolled_callback, self); g_signal_connect(G_OBJECT(g->area), "size-allocate", G_CALLBACK(_area_size_callback), self); From efb2f3ae3d553a64a8372ce97f570a4c832de86e Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 02:56:12 -0300 Subject: [PATCH 52/95] gtk4-prep: replace scroll-event and togglebutton callback in tonequal --- src/iop/toneequal.c | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/src/iop/toneequal.c b/src/iop/toneequal.c index 8d5ec7734de..5d5b89a58bf 100644 --- a/src/iop/toneequal.c +++ b/src/iop/toneequal.c @@ -1926,9 +1926,11 @@ static void auto_adjust_contrast_boost(GtkWidget *quad, dt_iop_module_t *self) } -static void show_luminance_mask_callback(GtkWidget *togglebutton, - GdkEventButton *event, - dt_iop_module_t *self) +static void show_luminance_mask_callback(GtkGestureSingle *gesture, + int n_press, + double x, + double y, + dt_iop_module_t *self) { DT_GUARD_GUI_UPDATE(); dt_iop_request_focus(self); @@ -3107,12 +3109,17 @@ static void area_button_release(GtkGestureSingle *gesture, } } -static gboolean area_scroll(GtkWidget *widget, - GdkEventScroll *event, - gpointer user_data) +static void area_scroll(GtkEventControllerScroll *controller, + gdouble dx, + gdouble dy, + dt_iop_module_t *self) { // do not propagate to tab bar unless scrolling sidebar - return !dt_gui_ignore_scroll(event); + GdkEvent *event = gtk_get_current_event(); + if(!event) return; + if(!dt_gui_ignore_scroll((GdkEventScroll *)event)) + dt_gui_claim(controller); + gdk_event_free(event); } static void notebook_button_press(GtkGestureSingle *gesture, @@ -3276,8 +3283,9 @@ void gui_init(dt_iop_module_t *self) dt_gui_connect_click(g->area, area_button_press, area_button_release, self); dt_gui_connect_motion(g->area, area_motion_notify, NULL, area_leave_notify, self); gtk_widget_add_events(GTK_WIDGET(g->area), darktable.gui->scroll_mask); - g_signal_connect(G_OBJECT(g->area), "scroll-event", - G_CALLBACK(area_scroll), self); + dt_gui_connect_scroll(g->area, GTK_EVENT_CONTROLLER_SCROLL_BOTH_AXES + | GTK_EVENT_CONTROLLER_SCROLL_DISCRETE, + area_scroll, self); gtk_widget_set_tooltip_text(GTK_WIDGET(g->area), _("double-click to reset the curve")); g->smoothing = dt_bauhaus_slider_new_with_range(self, -2.33f, +1.67f, 0, 0.0f, 2); From 890fc18ac862d5b19f1470c5e516bbdcc4c49b8f Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 02:56:18 -0300 Subject: [PATCH 53/95] gtk4-prep: migrate dt_iop_togglebutton_new from button-press-event to gesture controller Replace the g_signal_connect_data("button-press-event") inside dt_iop_togglebutton_new with a GtkGestureMultiPress that captures clicks via the "pressed" signal. Update all callers' callbacks to match the gesture controller's pressed signal signature: void callback(GtkGestureSingle *gesture, int n_press, double x, double y, user_data_type) Files updated: - src/develop/imageop_gui.c (function definition) - src/iop/filmicrgb.c (show_mask_callback) - src/iop/temperature.c (_btn_toggled, 4 call sites) - src/iop/liquify.c (btn_make_radio_callback refactored) - src/iop/spots.c (_add_shape_callback, _edit_masks) - src/iop/retouch.c (rt_edit_masks_callback, rt_add_shape_callback) --- src/develop/imageop_gui.c | 7 +++++- src/iop/filmicrgb.c | 6 ++++- src/iop/liquify.c | 52 +++++++++++++++++++++++++++------------ src/iop/retouch.c | 46 +++++++++++++++++++++------------- src/iop/spots.c | 36 ++++++++++++++++----------- src/iop/temperature.c | 12 +++++---- 6 files changed, 105 insertions(+), 54 deletions(-) diff --git a/src/develop/imageop_gui.c b/src/develop/imageop_gui.c index 5112a3d8b75..7bd38142dbb 100644 --- a/src/develop/imageop_gui.c +++ b/src/develop/imageop_gui.c @@ -246,7 +246,12 @@ GtkWidget *dt_iop_togglebutton_new(dt_iop_module_t *self, const char *section, c DTGTKCairoPaintIconFunc paint, GtkWidget *box) { GtkWidget *w = dtgtk_togglebutton_new(paint, 0, NULL); - g_signal_connect_data(G_OBJECT(w), "button-press-event", callback, self, NULL, 0); + { + GtkGesture *gesture = gtk_gesture_multi_press_new(w); + g_object_weak_ref(G_OBJECT(w), (GWeakNotify)g_object_unref, gesture); + g_signal_connect_data(gesture, "pressed", callback, self, NULL, 0); + gtk_gesture_single_set_button(GTK_GESTURE_SINGLE(gesture), 0); + } if(!ctrl_label) gtk_widget_set_tooltip_text(w, _(label)); diff --git a/src/iop/filmicrgb.c b/src/iop/filmicrgb.c index 8a33c4ffd5f..621c61d722b 100644 --- a/src/iop/filmicrgb.c +++ b/src/iop/filmicrgb.c @@ -2714,7 +2714,11 @@ void color_picker_apply(dt_iop_module_t *self, GtkWidget *picker, apply_autotune(self); } -static void show_mask_callback(GtkToggleButton *button, GdkEventButton *event, const dt_iop_module_t *self) +static void show_mask_callback(GtkGestureSingle *gesture, + int n_press, + double x, + double y, + const dt_iop_module_t *self) { DT_TRY_GUI_UPDATE(); dt_iop_filmicrgb_gui_data_t *g = self->gui_data; diff --git a/src/iop/liquify.c b/src/iop/liquify.c index 15728296bd3..0243582b54d 100644 --- a/src/iop/liquify.c +++ b/src/iop/liquify.c @@ -2725,9 +2725,14 @@ void gui_post_expose(dt_iop_module_t *self, } } -static gboolean btn_make_radio_callback(GtkToggleButton *btn, - const GdkEventButton *event, - dt_iop_module_t *self); +static void _btn_make_radio_cb(GtkToggleButton *btn, + gboolean ctrl_pressed, + dt_iop_module_t *self); +static void btn_make_radio_callback(GtkGestureSingle *gesture, + int n_press, + double x, + double y, + dt_iop_module_t *self); void gui_focus(dt_iop_module_t *self, const gboolean in) @@ -2735,7 +2740,7 @@ void gui_focus(dt_iop_module_t *self, if(!in) { dt_collection_hint_message(darktable.collection); - btn_make_radio_callback(NULL, NULL, self); + _btn_make_radio_cb(NULL, FALSE, self); } } @@ -3230,7 +3235,7 @@ int button_released(dt_iop_module_t *self, if(g->creation_continuous) _start_new_shape(self); else - btn_make_radio_callback(g->btn_node_tool, NULL, self); + _btn_make_radio_cb(GTK_TOGGLE_BUTTON(g->btn_node_tool), FALSE, self); handled = 2; } else if(gtk_toggle_button_get_active(g->btn_line_tool)) @@ -3291,7 +3296,7 @@ int button_released(dt_iop_module_t *self, else { g->status &= ~DT_LIQUIFY_STATUS_PREVIEW; - btn_make_radio_callback(g->btn_node_tool, NULL, self); + _btn_make_radio_cb(GTK_TOGGLE_BUTTON(g->btn_node_tool), FALSE, self); } handled = 2; goto done; @@ -3300,7 +3305,7 @@ int button_released(dt_iop_module_t *self, // right click on background toggles node tool if(g->last_hit.layer == DT_LIQUIFY_LAYER_BACKGROUND) { - btn_make_radio_callback(g->btn_node_tool, NULL, self); + _btn_make_radio_cb(GTK_TOGGLE_BUTTON(g->btn_node_tool), FALSE, self); handled = 1; goto done; } @@ -3522,9 +3527,9 @@ static void _liquify_cairo_paint_node_tool(cairo_t *cr, // we need this only because darktable has no radiobutton support -static gboolean btn_make_radio_callback(GtkToggleButton *btn, - const GdkEventButton *event, - dt_iop_module_t *self) +static void _btn_make_radio_cb(GtkToggleButton *btn, + gboolean ctrl_pressed, + dt_iop_module_t *self) { dt_iop_liquify_gui_data_t *g = self->gui_data; dt_iop_liquify_params_t *p = self->params; @@ -3533,10 +3538,10 @@ static gboolean btn_make_radio_callback(GtkToggleButton *btn, // does nothing (expect resetting the toggle button status). if(is_dragging(g) && g->temp && node_prev(p, g->temp)) { - return TRUE; + return; } - g->creation_continuous = event != NULL && dt_modifier_is(dt_gdk_event_get_state(event), GDK_CONTROL_MASK); + g->creation_continuous = ctrl_pressed; dt_control_hinter_message(""); @@ -3551,7 +3556,7 @@ static gboolean btn_make_radio_callback(GtkToggleButton *btn, } // now, let's enable and start a new form safely - if(!btn || !gtk_toggle_button_get_active(btn)) + if(!btn || !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(btn))) { gtk_toggle_button_set_active(g->btn_point_tool, btn == g->btn_point_tool); gtk_toggle_button_set_active(g->btn_line_tool, btn == g->btn_line_tool); @@ -3585,12 +3590,27 @@ static gboolean btn_make_radio_callback(GtkToggleButton *btn, } else { - gtk_toggle_button_set_active(btn, FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(btn), FALSE); } sync_pipe(self, FALSE); +} - return TRUE; +static void btn_make_radio_callback(GtkGestureSingle *gesture, + int n_press, + double x, + double y, + dt_iop_module_t *self) +{ + GtkWidget *btn = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + gboolean ctrl_pressed = FALSE; + GdkEvent *event = gtk_get_current_event(); + if(event) + { + ctrl_pressed = dt_modifier_is(dt_gdk_event_get_state(event), GDK_CONTROL_MASK); + gdk_event_free(event); + } + _btn_make_radio_cb(GTK_TOGGLE_BUTTON(btn), ctrl_pressed, self); } void gui_update(dt_iop_module_t *self) @@ -3676,7 +3696,7 @@ void gui_reset(dt_iop_module_t *self) g->dragging = NOWHERE; g->temp = NULL; g->status = 0; - btn_make_radio_callback(NULL, NULL, self); + _btn_make_radio_cb(NULL, FALSE, self); } // defgroup Button paint functions diff --git a/src/iop/retouch.c b/src/iop/retouch.c index 9acc137fe2d..67e83e20d5c 100644 --- a/src/iop/retouch.c +++ b/src/iop/retouch.c @@ -1799,19 +1799,25 @@ void gui_post_expose(dt_iop_module_t *self, } } -static gboolean rt_edit_masks_callback(GtkWidget *widget, - GdkEventButton *event, - dt_iop_module_t *self) +static void rt_edit_masks_callback(GtkGestureSingle *gesture, + int n_press, + double x, + double y, + dt_iop_module_t *self) { - DT_GUARD_GUI_UPDATE(FALSE); + if(dt_atomic_get_int(&darktable.gui->reset) != 0) return; // if we don't have the focus, request for it and quit, gui_focus() do the rest if(darktable.develop->gui_module != self) { dt_iop_request_focus(self); - return FALSE; + return; } + GdkEvent *event = gtk_get_current_event(); + const guint button = event ? dt_gdk_event_get_button(event) : 0; + const GdkModifierType state = event ? dt_gdk_event_get_state(event) : 0; + dt_iop_gui_blend_data_t *bd = self->blend_data; dt_iop_retouch_gui_data_t *g = self->gui_data; @@ -1831,7 +1837,7 @@ static gboolean rt_edit_masks_callback(GtkWidget *widget, gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(g->bt_ellipse), FALSE); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(g->bt_brush), FALSE); - if(dt_gdk_event_get_button(event) == GDK_BUTTON_PRIMARY) + if(button == GDK_BUTTON_PRIMARY) { DT_ENTER_GUI_UPDATE(); @@ -1842,7 +1848,7 @@ static gboolean rt_edit_masks_callback(GtkWidget *widget, if(grp && (grp->type & DT_MASKS_GROUP) && grp->points) { const gboolean control_button_pressed = - dt_modifier_is(dt_gdk_event_get_state(event), GDK_CONTROL_MASK); + dt_modifier_is(state, GDK_CONTROL_MASK); switch(bd->masks_shown) { @@ -1876,24 +1882,32 @@ static gboolean rt_edit_masks_callback(GtkWidget *widget, && (darktable.develop->gui_module == self)); DT_LEAVE_GUI_UPDATE(); - - return TRUE; } - return TRUE; + if(event) gdk_event_free(event); } -static gboolean rt_add_shape_callback(GtkWidget *widget, - GdkEventButton *e, - dt_iop_module_t *self) +static void rt_add_shape_callback(GtkGestureSingle *gesture, + int n_press, + double x, + double y, + dt_iop_module_t *self) { dt_iop_retouch_gui_data_t *g = self->gui_data; - DT_GUARD_GUI_UPDATE(FALSE); + if(dt_atomic_get_int(&darktable.gui->reset) != 0) return; + + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); dt_iop_color_picker_reset(self, TRUE); - const gboolean creation_continuous = dt_modifier_is(e->state, GDK_CONTROL_MASK); + gboolean creation_continuous = FALSE; + GdkEvent *event = gtk_get_current_event(); + if(event) + { + creation_continuous = dt_modifier_is(dt_gdk_event_get_state(event), GDK_CONTROL_MASK); + gdk_event_free(event); + } rt_add_shape(widget, creation_continuous, self); @@ -1905,8 +1919,6 @@ static gboolean rt_add_shape_callback(GtkWidget *widget, rt_shape_is_being_added(self, DT_MASKS_ELLIPSE)); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(g->bt_brush), rt_shape_is_being_added(self, DT_MASKS_BRUSH)); - - return TRUE; } static gboolean rt_select_algorithm_callback(GtkToggleButton *togglebutton, diff --git a/src/iop/spots.c b/src/iop/spots.c index 03148fdd6af..5b730938dca 100644 --- a/src/iop/spots.c +++ b/src/iop/spots.c @@ -18,6 +18,7 @@ #include "control/conf.h" #include "control/control.h" +#include "common/gdk_event_utils.h" #include "common/imagebuf.h" #include "develop/blend.h" #include "develop/imageop.h" @@ -328,15 +329,24 @@ static gboolean _add_shape(GtkWidget *widget, return FALSE; } -static gboolean _add_shape_callback(GtkWidget *widget, - GdkEventButton *e, - dt_iop_module_t *self) +static void _add_shape_callback(GtkGestureSingle *gesture, + int n_press, + double x, + double y, + dt_iop_module_t *self) { - DT_GUARD_GUI_UPDATE(FALSE); + if(dt_atomic_get_int(&darktable.gui->reset) != 0) return; + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); const dt_iop_spots_gui_data_t *g = self->gui_data; - const gboolean creation_continuous = dt_modifier_is(e->state, GDK_CONTROL_MASK); + gboolean creation_continuous = FALSE; + GdkEvent *event = gtk_get_current_event(); + if(event) + { + creation_continuous = dt_modifier_is(dt_gdk_event_get_state(event), GDK_CONTROL_MASK); + gdk_event_free(event); + } _add_shape(widget, creation_continuous, self); @@ -346,21 +356,21 @@ static gboolean _add_shape_callback(GtkWidget *widget, _shape_is_being_added(self, DT_MASKS_ELLIPSE)); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(g->bt_path), _shape_is_being_added(self, DT_MASKS_PATH)); - - return TRUE; } -static gboolean _edit_masks(GtkWidget *widget, - GdkEventButton *e, - dt_iop_module_t *self) +static void _edit_masks(GtkGestureSingle *gesture, + int n_press, + double x, + double y, + dt_iop_module_t *self) { - DT_GUARD_GUI_UPDATE(FALSE); + if(dt_atomic_get_int(&darktable.gui->reset) != 0) return; // if we don't have the focus, request for it and quit, gui_focus() do the rest if(darktable.develop->gui_module != self) { dt_iop_request_focus(self); - return FALSE; + return; } dt_iop_gui_blend_data_t *bd = self->blend_data; @@ -408,8 +418,6 @@ static gboolean _edit_masks(GtkWidget *widget, DT_LEAVE_GUI_UPDATE(); dt_control_queue_redraw_center(); - - return TRUE; } static gboolean masks_form_is_in_roi(dt_iop_module_t *self, diff --git a/src/iop/temperature.c b/src/iop/temperature.c index da14913030c..cb6581af477 100644 --- a/src/iop/temperature.c +++ b/src/iop/temperature.c @@ -1730,12 +1730,15 @@ void gui_changed(dt_iop_module_t *self, GtkWidget *w, void *previous) _update_preset(self, DT_IOP_TEMP_USER); } -static gboolean _btn_toggled(GtkWidget *togglebutton, - GdkEventButton *event, - dt_iop_module_t *self) +static void _btn_toggled(GtkGestureSingle *gesture, + int n_press, + double x, + double y, + dt_iop_module_t *self) { - DT_GUARD_GUI_UPDATE(TRUE); + if(dt_atomic_get_int(&darktable.gui->reset) != 0) return; + GtkWidget *togglebutton = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); dt_iop_temperature_gui_data_t *g = (dt_iop_temperature_gui_data_t*)self->gui_data; const int preset = togglebutton == g->btn_asshot ? DT_IOP_TEMP_AS_SHOT : @@ -1761,7 +1764,6 @@ static gboolean _btn_toggled(GtkWidget *togglebutton, "preset='%s': D65 %.3f %.3f %.3f, AS-SHOT %.3f %.3f %.3f", _preset_to_str(preset), chr->D65coeffs[0], chr->D65coeffs[1], chr->D65coeffs[2], chr->as_shot[0], chr->as_shot[1], chr->as_shot[2]); - return TRUE; } static void _preset_tune_callback(GtkWidget *widget, dt_iop_module_t *self) From 51d7410f74ca0ade1f7f8990bbd2db964bac0f22 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 02:58:23 -0300 Subject: [PATCH 54/95] gtk4-prep: migrate togglebutton callbacks to gesture controller in blend_gui Convert all 15 distinct callback functions that were passed to dt_iop_togglebutton_new from button-press-event handlers to GtkGestureSingle pressed signal handlers: void callback(GtkGestureSingle *gesture, int n_press, double x, double y, user_data_type) - 11 callbacks that didn't use the event: signature-only change, get widget from gtk_event_controller_get_widget() - 4 callbacks that used button/state: get button via gtk_get_current_event() + dt_gdk_event_get_{button,state}() - Replace DT_GUARD_GUI_UPDATE(ret) with atomic guard + return - Remove gboolean return values (gesture pressed is void) --- src/develop/blend_gui.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/develop/blend_gui.c b/src/develop/blend_gui.c index dfd1219567d..51e30bec8a8 100644 --- a/src/develop/blend_gui.c +++ b/src/develop/blend_gui.c @@ -1517,12 +1517,15 @@ static gboolean _blendop_masks_modes_param_toggled(GtkToggleButton *button, DEVELOP_MASK_ENABLED | DEVELOP_MASK_CONDITIONAL); } -static gboolean _blendop_masks_modes_both_toggled(GtkToggleButton *button, - GdkEventButton *event, - dt_iop_module_t *module) +static void _blendop_masks_modes_both_toggled(GtkGestureSingle *gesture, + int n_press, + double x, + double y, + dt_iop_module_t *module) { - return _blendop_masks_modes_toggle(button, module, - DEVELOP_MASK_ENABLED | DEVELOP_MASK_MASK_CONDITIONAL); + GtkWidget *button = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + _blendop_masks_modes_toggle(GTK_TOGGLE_BUTTON(button), module, + DEVELOP_MASK_ENABLED | DEVELOP_MASK_MASK_CONDITIONAL); } static gboolean _blendop_masks_modes_raster_toggled(GtkToggleButton *button, From 635842a902eb307525fabf0b8988f33ed4b94fd9 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 02:59:06 -0300 Subject: [PATCH 55/95] gtk4-prep: replace event signals with event controllers in remaining modules - src/views/map.c: 4 signals (scroll, button-press, button-release, motion) - src/chart/main.c: 1 signal (motion-notify on drawing areas) - src/libs/geotagging.c: 3 signals (key-press, button-press) - src/gui/preferences.c: 2 signals (key-press on presets tree) - src/libs/modulegroups.c: 1 signal (button-press on presets button) --- src/chart/main.c | 49 +++--- src/gui/preferences.c | 58 +++++-- src/libs/geotagging.c | 36 +++-- src/libs/modulegroups.c | 18 ++- src/views/map.c | 348 ++++++++++++++++++++++------------------ 5 files changed, 298 insertions(+), 211 deletions(-) diff --git a/src/chart/main.c b/src/chart/main.c index 60bce19eb21..da7cebe7877 100644 --- a/src/chart/main.c +++ b/src/chart/main.c @@ -16,6 +16,7 @@ along with darktable. If not, see . */ #include "common/gdk_event_utils.h" +#include "gui/gtk.h" #include "chart/dtcairo.h" #include "chart/colorchart.h" @@ -77,7 +78,7 @@ typedef struct dt_lut_t } dt_lut_t; // boring helper functions -static void init_image(dt_lut_t *self, image_t *image, GCallback motion_cb); +static void init_image(dt_lut_t *self, image_t *image, void (*motion_cb)(GtkEventControllerMotion *, gdouble, gdouble, dt_lut_t *)); static void image_lab_to_xyz(float *image, const int width, const int height); static void map_boundingbox_to_view(image_t *image, point_t *bb); static point_t map_point_to_view(image_t *image, point_t p); @@ -98,9 +99,9 @@ static void get_pixel_region(const image_t *const image, const point_t *const co int *x_end, int *y_end); static void reset_bb(image_t *image); static void free_image(image_t *image); -static gboolean handle_motion(GtkWidget *widget, GdkEventMotion *event, dt_lut_t *self, image_t *image); +static gboolean handle_motion(GtkWidget *widget, gdouble mx, gdouble my, dt_lut_t *self, image_t *image); static int find_closest_corner(point_t *bb, float x, float y); -static void map_mouse_to_0_1(GtkWidget *widget, GdkEventMotion *event, image_t *image, float *x, float *y); +static void map_mouse_to_0_1(GtkWidget *widget, gdouble mx, gdouble my, image_t *image, float *x, float *y); static void update_corner(image_t *image, int which, float *x, float *y); static gboolean open_source_image(dt_lut_t *self, const char *filename); static gboolean open_reference_image(dt_lut_t *self, const char *filename); @@ -170,37 +171,43 @@ static point_t map_point_to_view(image_t *image, point_t p) return result; } -static gboolean motion_notify_callback_source(GtkWidget *widget, GdkEventMotion *event, gpointer user_data) +static void _motion_cb_source(GtkEventControllerMotion *controller, + gdouble x, + gdouble y, + dt_lut_t *self) { - dt_lut_t *self = (dt_lut_t *)user_data; - const gboolean res = handle_motion(widget, event, self, &self->source); + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); + const gboolean res = handle_motion(widget, x, y, self, &self->source); if(res) { collect_source_patches(self); update_table(self); } - return res; } -static gboolean motion_notify_callback_reference(GtkWidget *widget, GdkEventMotion *event, gpointer user_data) +static void _motion_cb_reference(GtkEventControllerMotion *controller, + gdouble x, + gdouble y, + dt_lut_t *self) { - dt_lut_t *self = (dt_lut_t *)user_data; - const gboolean res = handle_motion(widget, event, self, &self->reference); + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); + const gboolean res = handle_motion(widget, x, y, self, &self->reference); if(res) { collect_reference_patches(self); update_table(self); } - return res; } -static gboolean handle_motion(GtkWidget *widget, GdkEventMotion *event, dt_lut_t *self, image_t *image) +static gboolean handle_motion(GtkWidget *widget, gdouble mx, gdouble my, dt_lut_t *self, image_t *image) { - if(!(dt_gdk_event_get_state(event) & GDK_BUTTON1_MASK) || !image->image) return FALSE; + GdkModifierType state; + gtk_get_current_event_state(&state); + if(!(state & GDK_BUTTON1_MASK) || !image->image) return FALSE; // mouse -> 0..1 float x, y; - map_mouse_to_0_1(widget, event, image, &x, &y); + map_mouse_to_0_1(widget, mx, my, image, &x, &y); // dragging the crosses is hard when they are not in a cornerof the bb but sprinkled over the chart int closest_corner = find_closest_corner(image->bb, x, y); @@ -255,13 +262,13 @@ static int find_closest_corner(point_t *bb, float x, float y) return closest_corner; } -static void map_mouse_to_0_1(GtkWidget *widget, GdkEventMotion *event, image_t *image, float *x, float *y) +static void map_mouse_to_0_1(GtkWidget *widget, gdouble mx, gdouble my, image_t *image, float *x, float *y) { guint width = gtk_widget_get_allocated_width(widget); guint height = gtk_widget_get_allocated_height(widget); - *x = (dt_gdk_event_get_x(event) - image->offset_x) / (width - 2.0 * image->offset_x); - *y = (dt_gdk_event_get_y(event) - image->offset_y) / (height - 2.0 * image->offset_y); + *x = (mx - image->offset_x) / (width - 2.0 * image->offset_x); + *y = (my - image->offset_y) / (height - 2.0 * image->offset_y); } static void update_corner(image_t *image, int which, float *x, float *y) @@ -1189,7 +1196,7 @@ static GtkWidget *create_notebook_page_source(dt_lut_t *self) gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new("size:"), FALSE, TRUE, 0); gtk_box_pack_start(GTK_BOX(hbox), source_shrink, TRUE, TRUE, 0); - init_image(self, &self->source, G_CALLBACK(motion_notify_callback_source)); + init_image(self, &self->source, _motion_cb_source); self->source.draw_colored = TRUE; gtk_box_pack_start(GTK_BOX(page), self->source.drawing_area, TRUE, TRUE, 0); @@ -1242,7 +1249,7 @@ static GtkWidget *create_notebook_page_reference(dt_lut_t *self) gtk_box_pack_start(GTK_BOX(reference_image_box), reference_shrink, TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(hbox), reference_image_box, TRUE, TRUE, 0); - init_image(self, &self->reference, G_CALLBACK(motion_notify_callback_reference)); + init_image(self, &self->reference, _motion_cb_reference); self->reference.draw_colored = FALSE; gtk_box_pack_start(GTK_BOX(page), self->reference.drawing_area, TRUE, TRUE, 0); @@ -1621,7 +1628,7 @@ static void reset_bb(image_t *image) image->bb[BOTTOM_LEFT].y = 0.95; } -static void init_image(dt_lut_t *self, image_t *image, GCallback motion_cb) +static void init_image(dt_lut_t *self, image_t *image, void (*motion_cb)(GtkEventControllerMotion *, gdouble, gdouble, dt_lut_t *)) { memset(image, 0x00, sizeof(image_t)); image->chart = &self->chart; @@ -1631,7 +1638,7 @@ static void init_image(dt_lut_t *self, image_t *image, GCallback motion_cb) GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK); g_signal_connect(image->drawing_area, "size-allocate", G_CALLBACK(size_allocate_callback), image); g_signal_connect(image->drawing_area, "draw", G_CALLBACK(draw_image_callback), image); - g_signal_connect(image->drawing_area, "motion-notify-event", G_CALLBACK(motion_cb), self); + dt_gui_connect_motion(image->drawing_area, motion_cb, NULL, NULL, self); } static void free_image(image_t *image) diff --git a/src/gui/preferences.c b/src/gui/preferences.c index 19b4bb2981e..6f256b49846 100644 --- a/src/gui/preferences.c +++ b/src/gui/preferences.c @@ -98,12 +98,16 @@ static void tree_row_activated_presets(GtkTreeView *tree, gpointer data); static void tree_selection_changed(GtkTreeSelection *selection, gpointer data); -static gboolean tree_key_press(GtkWidget *widget, - GdkEventKey *event, - gpointer data); -static gboolean tree_key_press_presets(GtkWidget *widget, - GdkEventKey *event, - gpointer data); +static gboolean _search_key_pressed(GtkEventControllerKey *controller, + guint keyval, + guint keycode, + GdkModifierType state, + GtkWidget *search_entry); +static gboolean _delete_preset_key_pressed(GtkEventControllerKey *controller, + guint keyval, + guint keycode, + GdkModifierType state, + GtkTreeStore *model); static GtkWidget *_preferences_dialog; @@ -904,6 +908,24 @@ static gboolean _search_func(GtkTreeModel *model, return TRUE; } +static gboolean _search_key_pressed(GtkEventControllerKey *controller, + guint keyval, + guint keycode, + GdkModifierType state, + GtkWidget *search_entry) +{ + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); + GtkSearchEntry *entry = GTK_SEARCH_ENTRY(search_entry); + // we build a temporary GdkEventKey to reuse dt_gui_search_start + GdkEventKey event; + memset(&event, 0, sizeof(event)); + event.type = GDK_KEY_PRESS; + event.keyval = keyval; + event.state = state; + event.is_modifier = (keyval >= GDK_KEY_Shift_L && keyval <= GDK_KEY_Hyper_R); + return dt_gui_search_start(widget, &event, entry); +} + static void init_tab_presets(GtkWidget *stack) { GtkTreeView *tree = GTK_TREE_VIEW(gtk_tree_view_new()); @@ -1013,8 +1035,7 @@ static void init_tab_presets(GtkWidget *stack) G_CALLBACK(dt_gui_search_stop), tree); g_signal_connect(G_OBJECT(search_presets), "stop-search", G_CALLBACK(dt_gui_search_stop), tree); - g_signal_connect(G_OBJECT(tree), "key-press-event", - G_CALLBACK(dt_gui_search_start), search_presets); + dt_gui_connect_key(tree, _search_key_pressed, search_presets); gtk_tree_view_set_search_entry(tree, GTK_ENTRY(search_presets)); GtkWidget *button = gtk_button_new_with_label(C_("preferences", "import...")); @@ -1039,8 +1060,7 @@ static void init_tab_presets(GtkWidget *stack) G_CALLBACK(tree_row_activated_presets), NULL); // A keypress may delete preset - g_signal_connect(G_OBJECT(tree), "key-press-event", - G_CALLBACK(tree_key_press_presets), (gpointer)model); + dt_gui_connect_key(tree, _delete_preset_key_pressed, model); // Setting up the search functionality gtk_tree_view_set_search_equal_func(tree, _search_func, tree, NULL); @@ -1152,18 +1172,22 @@ static void tree_row_activated_presets(GtkTreeView *tree, } } -static gboolean tree_key_press_presets(GtkWidget *widget, - GdkEventKey *event, - gpointer data) +static gboolean _delete_preset_key_pressed(GtkEventControllerKey *controller, + guint keyval, + guint keycode, + GdkModifierType state, + GtkTreeStore *model_store) { - GtkTreeModel *model = (GtkTreeModel *)data; + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); + GtkTreeModel *model = GTK_TREE_MODEL(model_store); GtkTreeIter iter; GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget)); - // We can just ignore mod key presses outright - if(event->is_modifier) return FALSE; + // We can just ignore modifier keys outright + if((keyval >= GDK_KEY_Shift_L && keyval <= GDK_KEY_Hyper_R)) + return FALSE; - if(dt_gdk_event_get_keyval(event) == GDK_KEY_Delete || dt_gdk_event_get_keyval(event) == GDK_KEY_BackSpace) + if(keyval == GDK_KEY_Delete || keyval == GDK_KEY_BackSpace) { // If a leaf node is selected, delete that preset diff --git a/src/libs/geotagging.c b/src/libs/geotagging.c index e148be82e1c..9392eb41e85 100644 --- a/src/libs/geotagging.c +++ b/src/libs/geotagging.c @@ -563,13 +563,16 @@ static void _refresh_display_all_tracks(GtkWidget *widget, dt_lib_module_t *self _refresh_displayed_images(self); } -static gboolean _click_for_entire_track(GtkEntry *spin, GdkEventButton *event, dt_lib_module_t *self) +static void _click_for_entire_track_pressed(GtkGestureSingle *gesture, + int n_press, + double x, + double y, + dt_lib_module_t *self) { - if(dt_gdk_event_get_button(event) == GDK_BUTTON_PRIMARY && dt_gdk_event_get_type(event) == GDK_2BUTTON_PRESS) + if(n_press == 2) { _refresh_display_all_tracks(NULL, self); } - return FALSE; } static void _track_seg_toggled(GtkCellRendererToggle *cell_renderer, gchar *path_str, dt_lib_module_t *self) @@ -1565,10 +1568,14 @@ static GtkWidget *_gui_init_datetime(gchar *text, return flow; } -static gboolean _datetime_key_pressed(GtkWidget *entry, GdkEventKey *event, dt_lib_module_t *self) +static gboolean _datetime_key_pressed(GtkEventControllerKey *controller, + guint keyval, + guint keycode, + GdkModifierType state, + dt_lib_module_t *self) { dt_lib_geotagging_t *d = self->data; - switch(dt_gdk_event_get_keyval(event)) + switch(keyval) { case GDK_KEY_Escape: { @@ -1624,9 +1631,8 @@ static gboolean _datetime_key_pressed(GtkWidget *entry, GdkEventKey *event, dt_l g_signal_emit_by_name(d->dt.widget[0], "changed"); return FALSE; - default: // let shortcut system deal with everything else - g_signal_stop_emission_by_name(entry, "key-press-event"); - return FALSE; + default: + return TRUE; } } @@ -1655,9 +1661,13 @@ static void _timezone_save(dt_lib_module_t *self) #endif } -static gboolean _timezone_key_pressed(GtkWidget *entry, GdkEventKey *event, dt_lib_module_t *self) +static gboolean _timezone_key_pressed(GtkEventControllerKey *controller, + guint keyval, + guint keycode, + GdkModifierType state, + dt_lib_module_t *self) { - switch(dt_gdk_event_get_keyval(event)) + switch(keyval) { case GDK_KEY_Return: case GDK_KEY_KP_Enter: @@ -1861,7 +1871,7 @@ void gui_init(dt_lib_module_t *self) gtk_entry_completion_set_match_func(completion, _completion_match_func, NULL, NULL); gtk_entry_completion_set_minimum_key_length(completion, 0); gtk_entry_set_completion(GTK_ENTRY(d->timezone), completion); - g_signal_connect(G_OBJECT(d->timezone), "key-press-event", G_CALLBACK(_timezone_key_pressed), self); + dt_gui_connect_key(d->timezone, _timezone_key_pressed, self); g_signal_connect(G_OBJECT(d->timezone), "focus-out-event", G_CALLBACK(_timezone_focus_out), self); // gpx @@ -1928,7 +1938,7 @@ void gui_init(dt_lib_module_t *self) g_object_set(G_OBJECT(d->map.gpx_view), "has-tooltip", TRUE, NULL); g_signal_connect(G_OBJECT(d->map.gpx_view), "query-tooltip", G_CALLBACK(_row_tooltip_setup), self); - g_signal_connect(G_OBJECT(d->map.gpx_view), "button-press-event", G_CALLBACK(_click_for_entire_track), self); + dt_gui_connect_click(d->map.gpx_view, _click_for_entire_track_pressed, NULL, self); // avoid ugly console pixman messages due to headers gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(d->map.gpx_view), FALSE); @@ -1998,7 +2008,7 @@ void gui_init(dt_lib_module_t *self) for(int i = 0; i < DT_GEOTAG_PARTS_NB; i++) { g_signal_connect(d->dt.widget[i], "changed", G_CALLBACK(_datetime_entry_changed), self); - g_signal_connect(d->dt.widget[i], "key-press-event", G_CALLBACK(_datetime_key_pressed), self); + dt_gui_connect_key(d->dt.widget[i], _datetime_key_pressed, self); dt_gui_connect_scroll(d->dt.widget[i], GTK_EVENT_CONTROLLER_SCROLL_VERTICAL | GTK_EVENT_CONTROLLER_SCROLL_DISCRETE, diff --git a/src/libs/modulegroups.c b/src/libs/modulegroups.c index 57ea2085861..4db6db4a78a 100644 --- a/src/libs/modulegroups.c +++ b/src/libs/modulegroups.c @@ -2668,16 +2668,19 @@ static void _manage_editor_module_add_popup(GtkWidget *widget, G_CALLBACK(_manage_editor_module_add), self, FALSE); } -static gboolean _presets_pressed(GtkWidget *widget, - GdkEventButton *event, - dt_lib_module_t *self) +static void _presets_pressed_cb(GtkGestureSingle *gesture, + int n_press, + double x, + double y, + dt_lib_module_t *self) { - if(dt_modifier_is(dt_gdk_event_get_state(event), GDK_CONTROL_MASK)) + GdkModifierType state; + gtk_get_current_event_state(&state); + if(state & GDK_CONTROL_MASK) { manage_presets(self); - return TRUE; + dt_gui_claim(gesture); } - return FALSE; } static void _manage_direct_popup(GtkGestureSingle *gesture, @@ -3019,8 +3022,7 @@ void gui_init(dt_lib_module_t *self) self->presets_button = dtgtk_button_new(dtgtk_cairo_paint_presets, 0, NULL); gtk_widget_set_tooltip_text(self->presets_button, _("presets\nctrl+click to manage")); gtk_box_pack_start(GTK_BOX(d->hbox_buttons), self->presets_button, FALSE, FALSE, 0); - g_signal_connect(self->presets_button, "button-press-event", - G_CALLBACK(_presets_pressed), self); + dt_gui_connect_click(self->presets_button, _presets_pressed_cb, NULL, self); /* search box */ d->text_entry = gtk_search_entry_new(); diff --git a/src/views/map.c b/src/views/map.c index 047f6bd1f46..7590758d802 100644 --- a/src/views/map.c +++ b/src/views/map.c @@ -213,20 +213,26 @@ static void _view_map_dnd_get_callback(GtkWidget *widget, static void _view_map_changed_callback(OsmGpsMap *map, dt_view_t *self); /* callback that handles mouse scroll */ -static gboolean _view_map_scroll_event(GtkWidget *w, - GdkEventScroll *event, - dt_view_t *self); +static void _view_map_scroll_cb(GtkEventControllerScroll *controller, + gdouble dx, + gdouble dy, + dt_view_t *self); /* callback that handles clicks on the map */ -static gboolean _view_map_button_press_callback(GtkWidget *w, - GdkEventButton *e, - dt_view_t *self); -static gboolean _view_map_button_release_callback(GtkWidget *w, - GdkEventButton *e, - dt_view_t *self); +static void _view_map_click_pressed_cb(GtkGestureSingle *gesture, + int n_press, + double x, + double y, + dt_view_t *self); +static void _view_map_click_released_cb(GtkGestureSingle *gesture, + int n_press, + double x, + double y, + dt_view_t *self); /* callback when the mouse is moved */ -static gboolean _view_map_motion_notify_callback(GtkWidget *w, - GdkEventMotion *e, - dt_view_t *self); +static void _view_map_motion_cb(GtkEventControllerMotion *controller, + gdouble x, + gdouble y, + dt_view_t *self); static gboolean _view_map_drag_motion_callback(GtkWidget *widget, GdkDragContext *dc, const gint x, @@ -767,8 +773,10 @@ void init(dt_view_t *self) gtk_drag_dest_set(GTK_WIDGET(lib->map), GTK_DEST_DEFAULT_ALL, target_list_internal, n_targets_internal, GDK_ACTION_MOVE); - g_signal_connect(GTK_WIDGET(lib->map), "scroll-event", - G_CALLBACK(_view_map_scroll_event), self); + dt_gui_connect_scroll(GTK_WIDGET(lib->map), + GTK_EVENT_CONTROLLER_SCROLL_VERTICAL + | GTK_EVENT_CONTROLLER_SCROLL_DISCRETE, + _view_map_scroll_cb, self); g_signal_connect(GTK_WIDGET(lib->map), "drag-data-received", G_CALLBACK(_drag_and_drop_received), self); g_signal_connect(GTK_WIDGET(lib->map), "drag-data-get", @@ -778,13 +786,8 @@ void init(dt_view_t *self) g_signal_connect(GTK_WIDGET(lib->map), "changed", G_CALLBACK(_view_map_changed_callback), self); - g_signal_connect_after(G_OBJECT(lib->map), "button-press-event", - G_CALLBACK(_view_map_button_press_callback), self); - g_signal_connect_after(G_OBJECT(lib->map), "button-release-event", - G_CALLBACK(_view_map_button_release_callback), self); - g_signal_connect(G_OBJECT(lib->map), "motion-notify-event", - G_CALLBACK(_view_map_motion_notify_callback), - self); + dt_gui_connect_click(lib->map, _view_map_click_pressed_cb, _view_map_click_released_cb, self); + dt_gui_connect_motion(lib->map, _view_map_motion_cb, NULL, NULL, self); g_signal_connect(G_OBJECT(lib->map), "drag-motion", G_CALLBACK(_view_map_drag_motion_callback), self); @@ -1850,91 +1853,111 @@ static gboolean _view_map_drag_motion_callback(GtkWidget *widget, return FALSE; } -static gboolean _view_map_motion_notify_callback(GtkWidget *widget, - GdkEventMotion *e, - dt_view_t *self) +static void _view_map_motion_cb(GtkEventControllerMotion *controller, + gdouble x, + gdouble y, + dt_view_t *self) { + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); dt_map_t *lib = self->data; - OsmGpsMapPoint *p = osm_gps_map_get_event_location(lib->map, (GdkEventButton *)e); - float lat, lon; - osm_gps_map_point_get_degrees(p, &lat, &lon); - _toast_log_lat_lon(lat, lon); + GdkEvent *event = gtk_get_current_event(); - if(lib->loc.drag - && lib->loc.main.id > 0 - && (abs(lib->start_drag_x - (int)ceil(e->x_root)) + - abs(lib->start_drag_y - (int)ceil(e->y_root))) > DT_PIXEL_APPLY_DPI(8)) - { - lib->loc.drag = FALSE; - osm_gps_map_image_remove(lib->map, lib->loc.main.location); - GtkTargetList *targets = gtk_target_list_new(target_list_internal, n_targets_internal); - - GdkDragContext *context = - gtk_drag_begin_with_coordinates(GTK_WIDGET(lib->map), targets, - GDK_ACTION_MOVE, 1, - (GdkEvent *)e, -1, -1); - - int width; - int height; - GdkPixbuf *location = _draw_location(lib, &width, &height, &lib->loc.main.data, TRUE); - if(location) - { - GtkWidget *image = gtk_image_new_from_pixbuf(location); - dt_gui_add_class(image, "dt_transparent_background"); - gtk_widget_set_name(image, "map-drag-icon"); - gtk_widget_show(image); - gtk_drag_set_icon_widget(context, image, - DT_PIXEL_APPLY_DPI(width), - DT_PIXEL_APPLY_DPI(height)); - g_object_unref(location); - } - gtk_target_list_unref(targets); - return TRUE; + if(event) + { + OsmGpsMapPoint *p = osm_gps_map_point_new_degrees(0.0, 0.0); + osm_gps_map_convert_screen_to_geographic(lib->map, x, y, p); + float lat, lon; + osm_gps_map_point_get_degrees(p, &lat, &lon); + osm_gps_map_point_free(p); + _toast_log_lat_lon(lat, lon); + } + + if(event && lib->loc.drag + && lib->loc.main.id > 0) + { + gdouble root_x, root_y; + gdk_event_get_root_coords(event, &root_x, &root_y); + if((abs(lib->start_drag_x - (int)ceil(root_x)) + + abs(lib->start_drag_y - (int)ceil(root_y))) > DT_PIXEL_APPLY_DPI(8)) + { + lib->loc.drag = FALSE; + osm_gps_map_image_remove(lib->map, lib->loc.main.location); + GtkTargetList *targets = gtk_target_list_new(target_list_internal, n_targets_internal); + + GdkDragContext *context = + gtk_drag_begin_with_coordinates(GTK_WIDGET(lib->map), targets, + GDK_ACTION_MOVE, 1, + event, -1, -1); + + int width; + int height; + GdkPixbuf *location = _draw_location(lib, &width, &height, &lib->loc.main.data, TRUE); + if(location) + { + GtkWidget *image = gtk_image_new_from_pixbuf(location); + dt_gui_add_class(image, "dt_transparent_background"); + gtk_widget_set_name(image, "map-drag-icon"); + gtk_widget_show(image); + gtk_drag_set_icon_widget(context, image, + DT_PIXEL_APPLY_DPI(width), + DT_PIXEL_APPLY_DPI(height)); + g_object_unref(location); + } + gtk_target_list_unref(targets); + gdk_event_free(event); + return; + } } - if(lib->start_drag - && lib->selected_images - && (abs(lib->start_drag_x - (int)ceil(e->x_root)) + - abs(lib->start_drag_y - (int)ceil(e->y_root))) > DT_PIXEL_APPLY_DPI(8)) + if(event && lib->start_drag + && lib->selected_images) { - const int nb = g_list_length(lib->selected_images); - for(const GSList *iter = lib->images; - iter; - iter = g_slist_next(iter)) + gdouble root_x, root_y; + gdk_event_get_root_coords(event, &root_x, &root_y); + if((abs(lib->start_drag_x - (int)ceil(root_x)) + + abs(lib->start_drag_y - (int)ceil(root_y))) > DT_PIXEL_APPLY_DPI(8)) { - dt_map_image_t *entry = iter->data; - if(entry->image) + const int nb = g_list_length(lib->selected_images); + for(const GSList *iter = lib->images; + iter; + iter = g_slist_next(iter)) { - const GList *sel_img = lib->selected_images; - if(entry->imgid == GPOINTER_TO_INT(sel_img->data)) + dt_map_image_t *entry = iter->data; + if(entry->image) { - if(entry->group_count == nb) + const GList *sel_img = lib->selected_images; + if(entry->imgid == GPOINTER_TO_INT(sel_img->data)) { - osm_gps_map_image_remove(lib->map, entry->image); - entry->image = NULL; + if(entry->group_count == nb) + { + osm_gps_map_image_remove(lib->map, entry->image); + entry->image = NULL; + } + else + _display_next_image(self, entry, TRUE); + break; } - else - _display_next_image(self, entry, TRUE); - break; } } - } - const int group_count = g_list_length(lib->selected_images); + const int group_count = g_list_length(lib->selected_images); - lib->start_drag = FALSE; - GtkTargetList *targets = gtk_target_list_new(target_list_all, n_targets_all); - GdkDragContext *context = gtk_drag_begin_with_coordinates(GTK_WIDGET(lib->map), targets, - GDK_ACTION_MOVE, 1, - (GdkEvent *)e, -1, -1); - _view_map_drag_set_icon(self, context, GPOINTER_TO_INT(lib->selected_images->data), - group_count); - gtk_target_list_unref(targets); - return TRUE; + lib->start_drag = FALSE; + GtkTargetList *targets = gtk_target_list_new(target_list_all, n_targets_all); + GdkDragContext *context = gtk_drag_begin_with_coordinates(GTK_WIDGET(lib->map), targets, + GDK_ACTION_MOVE, 1, + event, -1, -1); + _view_map_drag_set_icon(self, context, GPOINTER_TO_INT(lib->selected_images->data), + group_count); + gtk_target_list_unref(targets); + gdk_event_free(event); + return; + } } + if(event) gdk_event_free(event); - dt_map_image_t *entry = _view_map_get_entry_at_pos(self, e->x, e->y); + dt_map_image_t *entry = _view_map_get_entry_at_pos(self, x, y); if(entry) { // show image information if image is hovered @@ -1944,7 +1967,7 @@ static gboolean _view_map_motion_notify_callback(GtkWidget *widget, { _view_map_draw_image(entry, TRUE, DT_MAP_THUMB_THUMB, self); lib->last_hovered_entry = entry; - return TRUE; + return; } } else @@ -1957,7 +1980,6 @@ static gboolean _view_map_motion_notify_callback(GtkWidget *widget, lib->last_hovered_entry = NULL; } } - return FALSE; } static gboolean _zoom_and_center(const gint x, @@ -2003,38 +2025,54 @@ static gboolean _zoom_and_center(const gint x, return TRUE; } -static gboolean _view_map_scroll_event(GtkWidget *w, - GdkEventScroll *event, - dt_view_t *self) +static void _view_map_scroll_cb(GtkEventControllerScroll *controller, + gdouble dx, + gdouble dy, + dt_view_t *self) { dt_map_t *lib = self->data; - // check if the click was on image(s) or just some random position - dt_map_image_t *entry = _view_map_get_entry_at_pos(self, dt_gdk_event_get_x(event), dt_gdk_event_get_y(event)); + + // get the current event for position and modifier state + GdkEvent *event = gtk_get_current_event(); + if(!event) return; + gdouble x, y; + GdkModifierType state; + gdk_event_get_coords(event, &x, &y); + gdk_event_get_state(event, &state); + gdk_event_free(event); + + // determine scroll direction from dy + const gboolean scroll_down = dy > 0; + const gboolean scroll_up = dy < 0; + + // check if the scroll was on image(s) or just some random position + dt_map_image_t *entry = _view_map_get_entry_at_pos(self, x, y); if(entry) { - if(_display_next_image(self, entry, dt_gdk_event_get_scroll_direction(event) == GDK_SCROLL_DOWN)) - return TRUE; + if(_display_next_image(self, entry, scroll_down)) + return; } - OsmGpsMapPoint *p = osm_gps_map_get_event_location(lib->map, (GdkEventButton *)event); + OsmGpsMapPoint *p = osm_gps_map_point_new_degrees(0.0, 0.0); + osm_gps_map_convert_screen_to_geographic(lib->map, x, y, p); float lat, lon; osm_gps_map_point_get_degrees(p, &lat, &lon); + osm_gps_map_point_free(p); + if(lib->loc.main.id > 0) { - const gboolean increase = dt_gdk_event_get_scroll_direction(event) == GDK_SCROLL_UP - || dt_gdk_event_get_scroll_direction(event) == GDK_SCROLL_RIGHT; - const gboolean decrease = dt_gdk_event_get_scroll_direction(event) == GDK_SCROLL_DOWN - || dt_gdk_event_get_scroll_direction(event) == GDK_SCROLL_LEFT; + const gboolean increase = scroll_up; + const gboolean decrease = scroll_down; if(dt_map_location_included(lon, lat, &lib->loc.main.data)) { - if(dt_modifier_is(dt_gdk_event_get_state(event), GDK_SHIFT_MASK)) + if(dt_modifier_is(state, GDK_SHIFT_MASK)) { if(increase) lib->loc.main.data.delta1 *= 1.1; else if(decrease) lib->loc.main.data.delta1 /= 1.1; } - else if(dt_modifier_is(dt_gdk_event_get_state(event), GDK_CONTROL_MASK)) + else if(dt_modifier_is(state, GDK_CONTROL_MASK)) { if(increase) lib->loc.main.data.delta2 *= 1.1; @@ -2048,7 +2086,7 @@ static gboolean _view_map_scroll_event(GtkWidget *w, lib->loc.main.data.delta1 *= 1.1; lib->loc.main.data.delta2 *= 1.1; } - else if (decrease) + else if(decrease) { lib->loc.main.data.delta1 /= 1.1; lib->loc.main.data.delta2 /= 1.1; @@ -2057,27 +2095,32 @@ static gboolean _view_map_scroll_event(GtkWidget *w, _view_map_draw_main_location(lib, &lib->loc.main); _view_map_update_location_geotag(self); _view_map_signal_change_wait(self, 3); // wait 3/10 sec after last scroll - return TRUE; + return; } else // scroll on the map. try to keep the map where it is { _toast_log_lat_lon(lat, lon); - return _zoom_and_center(dt_gdk_event_get_x(event), dt_gdk_event_get_y(event), dt_gdk_event_get_scroll_direction(event), self); + _zoom_and_center(x, y, scroll_up ? GDK_SCROLL_UP : GDK_SCROLL_DOWN, self); + return; } } else { _toast_log_lat_lon(lat, lon); - return _zoom_and_center(dt_gdk_event_get_x(event), dt_gdk_event_get_y(event), dt_gdk_event_get_scroll_direction(event), self); + _zoom_and_center(x, y, scroll_up ? GDK_SCROLL_UP : GDK_SCROLL_DOWN, self); } - return FALSE; } -static gboolean _view_map_button_press_callback(GtkWidget *w, - GdkEventButton *e, - dt_view_t *self) +static void _view_map_click_pressed_cb(GtkGestureSingle *gesture, + int n_press, + double x, + double y, + dt_view_t *self) { dt_map_t *lib = self->data; + GdkModifierType state; + gtk_get_current_event_state(&state); + if(lib->selected_images) { g_list_free(lib->selected_images); @@ -2087,9 +2130,7 @@ static gboolean _view_map_button_press_callback(GtkWidget *w, if(lib->osd) { // check if the OSD circle was clicked - GValue value = { - 0, - }; + GValue value = { 0 }; g_object_get_property((GObject*) lib->osd, "osd-x", &value); const gint osd_x = g_value_get_int(&value); @@ -2098,46 +2139,52 @@ static gboolean _view_map_button_press_callback(GtkWidget *w, g_object_get_property((GObject*) lib->osd, "dpad-radius", &value); const gint dpad_radius = g_value_get_int(&value); g_object_get_property((GObject*) lib->osd, "show-zoom", &value); - // g_value_get_boolean returns FALSE although the value is 1! Bug? const gint show_zoom = g_value_get_int(&value); - const gint zoom_height = show_zoom? 40:0; + const gint zoom_height = show_zoom ? 40 : 0; - if(e->x >= osd_x && e->x <= osd_x+2*dpad_radius && - e->y >= osd_y && e->y <= osd_y+2*dpad_radius+zoom_height) + if(x >= osd_x && x <= osd_x + 2 * dpad_radius + && y >= osd_y && y <= osd_y + 2 * dpad_radius + zoom_height) { - return FALSE; + return; } } - if(e->button == GDK_BUTTON_PRIMARY) + if(gtk_gesture_single_get_button(gesture) == GDK_BUTTON_PRIMARY) { - // check if the click was in a location form - crtl gives priority to images + // check if the click was in a location form - ctrl gives priority to images if(lib->loc.main.id > 0 && (lib->loc.main.data.shape != MAP_LOCATION_SHAPE_POLYGONS) - && !dt_modifier_is(e->state, GDK_CONTROL_MASK)) + && !dt_modifier_is(state, GDK_CONTROL_MASK)) { - - OsmGpsMapPoint *p = osm_gps_map_get_event_location(lib->map, e); + OsmGpsMapPoint *p = osm_gps_map_point_new_degrees(0.0, 0.0); + osm_gps_map_convert_screen_to_geographic(lib->map, x, y, p); float lat, lon; osm_gps_map_point_get_degrees(p, &lat, &lon); + osm_gps_map_point_free(p); if(dt_map_location_included(lon, lat, &lib->loc.main.data)) { - if(!dt_modifier_is(e->state, GDK_SHIFT_MASK)) + if(!dt_modifier_is(state, GDK_SHIFT_MASK)) { - lib->start_drag_x = ceil(e->x_root); - lib->start_drag_y = ceil(e->y_root); + GdkDisplay *display = gtk_widget_get_display(GTK_WIDGET(lib->map)); + GdkDevice *pointer = gdk_seat_get_pointer(gdk_display_get_default_seat(display)); + gdouble root_x, root_y; + gdk_device_get_position(pointer, NULL, &root_x, &root_y); + lib->start_drag_x = ceil(root_x); + lib->start_drag_y = ceil(root_y); lib->loc.drag = TRUE; - return TRUE; + return; } } } // check if another location is clicked - ctrl gives priority to images - if(!dt_modifier_is(e->state, GDK_CONTROL_MASK) && - dt_conf_get_bool("plugins/map/showalllocations")) + if(!dt_modifier_is(state, GDK_CONTROL_MASK) + && dt_conf_get_bool("plugins/map/showalllocations")) { - OsmGpsMapPoint *p = osm_gps_map_get_event_location(lib->map, e); + OsmGpsMapPoint *p = osm_gps_map_point_new_degrees(0.0, 0.0); + osm_gps_map_convert_screen_to_geographic(lib->map, x, y, p); float lat, lon; osm_gps_map_point_get_degrees(p, &lat, &lon); + osm_gps_map_point_free(p); for(GList *other = lib->loc.others; other; other = g_list_next(other)) @@ -2154,44 +2201,42 @@ static gboolean _view_map_button_press_callback(GtkWidget *w, G_CALLBACK(_view_map_collection_changed), self); dt_control_signal_unblock_by_func(darktable.signals, G_CALLBACK(_view_map_geotag_changed), self); - return TRUE; + return; } } } // check if the click was on image(s) or just some random position lib->selected_images = - _view_map_get_imgs_at_pos(self, e->x, e->y, + _view_map_get_imgs_at_pos(self, x, y, &lib->start_drag_offset_x, &lib->start_drag_offset_y, - !dt_modifier_is(e->state, GDK_SHIFT_MASK)); - if(e->type == GDK_BUTTON_PRESS) + !dt_modifier_is(state, GDK_SHIFT_MASK)); + if(n_press == 1) { if(lib->selected_images) { - lib->start_drag_x = ceil(e->x_root); - lib->start_drag_y = ceil(e->y_root); + GdkDisplay *display = gtk_widget_get_display(GTK_WIDGET(lib->map)); + GdkDevice *pointer = gdk_seat_get_pointer(gdk_display_get_default_seat(display)); + gdouble root_x, root_y; + gdk_device_get_position(pointer, NULL, &root_x, &root_y); + lib->start_drag_x = ceil(root_x); + lib->start_drag_y = ceil(root_y); lib->start_drag = TRUE; - return TRUE; - } - else - { - return FALSE; } } - if(e->type == GDK_2BUTTON_PRESS) + else if(n_press == 2) { if(lib->selected_images) { // open the image in darkroom dt_control_set_mouse_over_id(GPOINTER_TO_INT(lib->selected_images->data)); dt_ctl_switch_mode_to("darkroom"); - return TRUE; } else { // zoom into that position float longitude, latitude; OsmGpsMapPoint *pt = osm_gps_map_point_new_degrees(0.0, 0.0); - osm_gps_map_convert_screen_to_geographic(lib->map, e->x, e->y, pt); + osm_gps_map_convert_screen_to_geographic(lib->map, x, y, pt); osm_gps_map_point_get_degrees(pt, &latitude, &longitude); osm_gps_map_point_free(pt); int zoom, max_zoom; @@ -2199,22 +2244,21 @@ static gboolean _view_map_button_press_callback(GtkWidget *w, zoom = MIN(zoom + 1, max_zoom); _view_map_center_on_location(self, longitude, latitude, zoom); } - return TRUE; } } - return FALSE; } -static gboolean _view_map_button_release_callback(GtkWidget *w, - GdkEventButton *e, - dt_view_t *self) +static void _view_map_click_released_cb(GtkGestureSingle *gesture, + int n_press, + double x, + double y, + dt_view_t *self) { dt_map_t *lib = self->data; lib->start_drag = FALSE; lib->start_drag_offset_x = 0; lib->start_drag_offset_y = 0; lib->loc.drag = FALSE; - return FALSE; } static gboolean _view_map_display_selected(const gpointer user_data) From 8e2154a0761295b94cdf3b4804d97d1818d4791d Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 15:10:22 -0300 Subject: [PATCH 56/95] gtk4-prep: fix toggle button recursion by claiming gesture sequence --- src/develop/imageop_gui.c | 19 +++++++++++++++++++ src/iop/liquify.c | 22 +++++++++++++++++++--- 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/src/develop/imageop_gui.c b/src/develop/imageop_gui.c index 7bd38142dbb..1e74365ae62 100644 --- a/src/develop/imageop_gui.c +++ b/src/develop/imageop_gui.c @@ -241,6 +241,22 @@ GtkWidget *dt_bauhaus_toggle_from_params(dt_iop_module_t *self, const char *para return toggle; } +/* Claim the event sequence in CAPTURE phase so the togglebutton's + * internal GtkGestureMultiPress (GTK_PHASE_BUBBLE) does NOT process + * the event. This prevents GtkButton from emitting "clicked" and + * toggling the button state behind our callback, which would conflict + * with callbacks that implement radio-button behaviour by explicitly + * managing all toggle states. + * + * GTK4 migration: the pattern is the same — just rename + * GtkGestureMultiPress to GtkGestureClick. */ +static void _gesture_begin_claim(GtkGesture *gesture, + GdkEventSequence *sequence, + gpointer user_data) +{ + gtk_gesture_set_sequence_state(gesture, sequence, GTK_EVENT_SEQUENCE_CLAIMED); +} + GtkWidget *dt_iop_togglebutton_new(dt_iop_module_t *self, const char *section, const gchar *label, const gchar *ctrl_label, GCallback callback, gboolean local, guint accel_key, GdkModifierType mods, DTGTKCairoPaintIconFunc paint, GtkWidget *box) @@ -248,8 +264,11 @@ GtkWidget *dt_iop_togglebutton_new(dt_iop_module_t *self, const char *section, c GtkWidget *w = dtgtk_togglebutton_new(paint, 0, NULL); { GtkGesture *gesture = gtk_gesture_multi_press_new(w); + gtk_event_controller_set_propagation_phase(GTK_EVENT_CONTROLLER(gesture), + GTK_PHASE_CAPTURE); g_object_weak_ref(G_OBJECT(w), (GWeakNotify)g_object_unref, gesture); g_signal_connect_data(gesture, "pressed", callback, self, NULL, 0); + g_signal_connect(gesture, "begin", G_CALLBACK(_gesture_begin_claim), NULL); gtk_gesture_single_set_button(GTK_GESTURE_SINGLE(gesture), 0); } diff --git a/src/iop/liquify.c b/src/iop/liquify.c index 0243582b54d..ba035990895 100644 --- a/src/iop/liquify.c +++ b/src/iop/liquify.c @@ -3555,8 +3555,22 @@ static void _btn_make_radio_cb(GtkToggleButton *btn, g->status &= ~DT_LIQUIFY_STATUS_PREVIEW; } + /* Called from GtkGestureMultiPress::pressed (via our CAPTURE-phase + * gesture that claims the sequence). The signal fires BEFORE the + * togglebutton toggles, so we manage all toggle states explicitly. */ + if(!btn) + { + /* NULL btn from gui_focus() / gui_reset() — disable all tools. */ + gtk_toggle_button_set_active(g->btn_point_tool, FALSE); + gtk_toggle_button_set_active(g->btn_line_tool, FALSE); + gtk_toggle_button_set_active(g->btn_curve_tool, FALSE); + gtk_toggle_button_set_active(g->btn_node_tool, FALSE); + dt_control_hinter_message(""); + return; + } + // now, let's enable and start a new form safely - if(!btn || !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(btn))) + if(!gtk_toggle_button_get_active(btn)) { gtk_toggle_button_set_active(g->btn_point_tool, btn == g->btn_point_tool); gtk_toggle_button_set_active(g->btn_line_tool, btn == g->btn_line_tool); @@ -3602,14 +3616,16 @@ static void btn_make_radio_callback(GtkGestureSingle *gesture, double y, dt_iop_module_t *self) { - GtkWidget *btn = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); - gboolean ctrl_pressed = FALSE; GdkEvent *event = gtk_get_current_event(); + gboolean ctrl_pressed = FALSE; if(event) { ctrl_pressed = dt_modifier_is(dt_gdk_event_get_state(event), GDK_CONTROL_MASK); gdk_event_free(event); } + + GtkWidget *btn = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + _btn_make_radio_cb(GTK_TOGGLE_BUTTON(btn), ctrl_pressed, self); } From febc420506b533f27e6b09efefad4f8c43d7de88 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 15:10:28 -0300 Subject: [PATCH 57/95] gtk4-prep: guard double-click to lighttable in darkroom and liquify --- src/iop/liquify.c | 4 ++++ src/views/darkroom.c | 21 ++++++++++++++++++++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/iop/liquify.c b/src/iop/liquify.c index ba035990895..5b4dc153c50 100644 --- a/src/iop/liquify.c +++ b/src/iop/liquify.c @@ -3097,6 +3097,10 @@ int button_pressed(dt_iop_module_t *self, const uint32_t state, const float zoom_scale) { + // avoid unexpected back to lighttable mode on double-click + if(type == GDK_2BUTTON_PRESS && which == GDK_BUTTON_PRIMARY) + return 1; + dt_iop_liquify_gui_data_t *g = self->gui_data; dt_iop_liquify_params_t *p = self->params; diff --git a/src/views/darkroom.c b/src/views/darkroom.c index 1c3143642c2..abd64dc0674 100644 --- a/src/views/darkroom.c +++ b/src/views/darkroom.c @@ -4571,7 +4571,16 @@ int button_pressed(dt_view_t *self, if(handled) return handled; } - if(which == GDK_BUTTON_PRIMARY && type == GDK_2BUTTON_PRESS) return 0; + if(which == GDK_BUTTON_PRIMARY && type == GDK_2BUTTON_PRESS) + { + // When masks are being edited, consume the double-click to avoid + // accidentally switching to lighttable. The mask-specific handlers + // (brush, path, gradient, object, and our ellipse/circle guards) + // already return 1 for 2BUTTON_PRESS when form_visible is set; + // this is a belt-and-suspenders check for edge cases. + if(dev->form_visible) return 1; + return 0; + } if(which == GDK_BUTTON_PRIMARY) { dt_control_change_cursor("pointer"); @@ -5172,6 +5181,16 @@ static void _second_window_buttons_enter_notify_callback(GtkEventControllerMotio static void _second_window_buttons_leave_notify_callback(GtkEventControllerMotion *controller, GtkWidget *button_box) { + // GDK_NOTIFY_INFERIOR means the pointer moved into a child window (still + // within the second window); keep the buttons visible in that case. + GdkEvent *event = gtk_get_current_event(); + if(event && event->crossing.detail == GDK_NOTIFY_INFERIOR) + { + gdk_event_free(event); + return; + } + if(event) gdk_event_free(event); + gtk_widget_set_opacity(button_box, 0.0); gtk_overlay_set_overlay_pass_through(GTK_OVERLAY(gtk_widget_get_parent(button_box)), button_box, TRUE); From 94c1f5e47814c3a3b9c3957e31bf14cf439524ff Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 15:10:31 -0300 Subject: [PATCH 58/95] gtk4-prep: add GtkGestureMultiPress double-click bridge for GTK3 --- src/gui/gtk.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++- src/gui/gtk.h | 21 +++++++++++++++++ 2 files changed, 85 insertions(+), 1 deletion(-) diff --git a/src/gui/gtk.c b/src/gui/gtk.c index b0401cc676f..472c925b585 100644 --- a/src/gui/gtk.c +++ b/src/gui/gtk.c @@ -4769,6 +4769,70 @@ GtkGestureSingle *(dt_gui_connect_click)(GtkWidget *widget, return (GtkGestureSingle *)gesture; } +/* + * GTK3 bridge for double/triple-click detection. + * + * GtkGestureMultiPress in GTK3 does not process GDK_2BUTTON_PRESS or + * GDK_3BUTTON_PRESS events at all: + * - gtk_gesture_handle_event() only dispatches GDK_BUTTON_PRESS (not 2/3) + * - gtk_gesture_multi_press_begin() checks for GDK_BUTTON_PRESS only + * - GDK always delivers GDK_2BUTTON_PRESS for the second press of a + * double-click (never a second GDK_BUTTON_PRESS) + * + * As a result, GtkGestureMultiPress's "pressed" signal with n_press=2 or 3 + * is NEVER emitted in GTK3. This helper works around it by connecting a + * classic "button-press-event" signal handler that catches GDK_2BUTTON_PRESS + * and GDK_3BUTTON_PRESS and forwards them to the same pressed callback with + * the correct n_press value. + * + * GTK4 migration: DELETE this entire helper (struct, free, handler, and both + * public functions). GtkGestureClick (the GTK4 replacement for + * GtkGestureMultiPress) uses an internal timer to detect multi-press patterns + * and correctly emits "pressed" with n_press=2/3 without needing GDK_2BUTTON_PRESS. + * The callers using dt_gui_connect_double_click() should simply remove those + * calls — the gesture alone will suffice. + */ +typedef struct _DblClkData +{ + GCallback cb; + gpointer data; +} DblClkData; + +static void _dbl_clk_free(gpointer p, GClosure *cl) +{ + g_free(p); +} + +static gboolean _dbl_clk_handler(GtkWidget *w, GdkEventButton *ev, gpointer user) +{ + DblClkData *d = user; + int n; + if(ev->type == GDK_2BUTTON_PRESS) n = 2; + else if(ev->type == GDK_3BUTTON_PRESS) n = 3; + else return GDK_EVENT_PROPAGATE; + ((void (*)(GtkGestureSingle *, int, double, double, gpointer))d->cb) + (NULL, n, ev->x, ev->y, d->data); + return GDK_EVENT_STOP; +} + +unsigned long +(dt_gui_connect_double_click)(GtkWidget *widget, + GCallback pressed, + gpointer data) +{ + DblClkData *d = g_malloc(sizeof(DblClkData)); + d->cb = pressed; + d->data = data; + return g_signal_connect_data(widget, "button-press-event", + G_CALLBACK(_dbl_clk_handler), + d, _dbl_clk_free, 0); +} + +void (dt_gui_disconnect_double_click)(GtkWidget *widget, unsigned long id) +{ + g_signal_handler_disconnect(widget, id); +} + GtkGesture *(dt_gui_connect_drag)(GtkWidget *widget, GCallback drag_begin, GCallback drag_end, @@ -4779,7 +4843,6 @@ GtkGesture *(dt_gui_connect_drag)(GtkWidget *widget, g_object_weak_ref(G_OBJECT (widget), (GWeakNotify) g_object_unref, gesture); // GTK4 GtkGesture *gesture = gtk_gesture_drag_new(); // gtk_widget_add_controller(widget, GTK_EVENT_CONTROLLER(gesture)); - if(drag_begin) g_signal_connect(gesture, "drag-begin", G_CALLBACK(drag_begin), data); if(drag_end) g_signal_connect(gesture, "drag-end", G_CALLBACK(drag_end), data); if(drag_update) g_signal_connect(gesture, "drag-update", G_CALLBACK(drag_update), data); diff --git a/src/gui/gtk.h b/src/gui/gtk.h index f4a1ee89885..c7d4540cf5a 100644 --- a/src/gui/gtk.h +++ b/src/gui/gtk.h @@ -558,6 +558,27 @@ GtkGestureSingle *(dt_gui_connect_click)(GtkWidget *widget, #define dt_gui_connect_click_all(widget, pressed, released, data) \ gtk_gesture_single_set_button(dt_gui_connect_click(widget, pressed, released, data), 0) +/* + * GTK3 bridge: GtkGestureMultiPress in GTK3 does not process + * GDK_2BUTTON_PRESS / GDK_3BUTTON_PRESS. See implementation in gtk.c + * for the full explanation and GTK4 migration instructions. + * + * Connection: call alongside dt_gui_connect_click() with the same + * pressed callback and data. The callback receives (NULL, n_press, x, y, data) + * — the NULL gesture indicates the call came from this bridge, so the callback + * must handle that gracefully (see culling.c/thumbtable.c for the pattern). + * + * GTK4 migration: remove all calls to dt_gui_connect_double_click() and + * delete this declaration. GtkGestureClick handles n_press natively. + */ +unsigned long dt_gui_connect_double_click(GtkWidget *widget, + GCallback pressed, + gpointer data); +#define dt_gui_connect_double_click(widget, pressed, data) ( \ + ASSERT_FUNC_TYPE(pressed, void(*)(GtkGestureSingle *, int, double, double, __typeof__(data))), \ + dt_gui_connect_double_click(GTK_WIDGET(widget), G_CALLBACK(pressed), (data))) +void dt_gui_disconnect_double_click(GtkWidget *widget, unsigned long id); + GtkGesture *(dt_gui_connect_drag)(GtkWidget *widget, GCallback drag_begin, GCallback drag_end, From 96985dbeacff66f1252a4d38ec2bf930d003d580 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 15:10:34 -0300 Subject: [PATCH 59/95] gtk4-prep: convert culling and thumbtable event signals to event controllers --- src/dtgtk/culling.c | 48 ++++++++++++++++++++++++++++++++++++++---- src/dtgtk/thumbtable.c | 48 ++++++++++++++++++++++++++++++++++++++---- 2 files changed, 88 insertions(+), 8 deletions(-) diff --git a/src/dtgtk/culling.c b/src/dtgtk/culling.c index 79204d9714e..77a2c7d6b59 100644 --- a/src/dtgtk/culling.c +++ b/src/dtgtk/culling.c @@ -831,7 +831,18 @@ static void _event_leave_cb(GtkEventControllerMotion *controller, } table->mouse_inside = FALSE; - dt_control_set_mouse_over_id(NO_IMGID); + + // check crossing detail: don't clear mouse_over_id when leaving to + // a child widget (thumbnail) or due to a grab + GdkEvent *event = gtk_get_current_event(); + if(event) + { + if(event->crossing.detail != GDK_NOTIFY_INFERIOR + && event->crossing.mode != GDK_CROSSING_GTK_GRAB + && event->crossing.mode != GDK_CROSSING_GRAB) + dt_control_set_mouse_over_id(NO_IMGID); + gdk_event_free(event); + } } static void _event_enter_cb(GtkEventControllerMotion *controller, @@ -839,8 +850,15 @@ static void _event_enter_cb(GtkEventControllerMotion *controller, gdouble y, dt_culling_t *table) { - // when entering the culling area, clear the mouse-over id - dt_control_set_mouse_over_id(NO_IMGID); + // when entering the culling area from a child thumbnail (INFERIOR), + // clear the mouse-over id since we're now in the empty area + GdkEvent *event = gtk_get_current_event(); + if(event) + { + if(event->crossing.detail == GDK_NOTIFY_INFERIOR) + dt_control_set_mouse_over_id(NO_IMGID); + gdk_event_free(event); + } } static void _event_button_press_cb(GtkGestureSingle *gesture, @@ -849,7 +867,20 @@ static void _event_button_press_cb(GtkGestureSingle *gesture, gdouble y, dt_culling_t *table) { - const guint button = gtk_gesture_single_get_button(gesture); + /* + * GTK3 bridge for GDK_2BUTTON_PRESS (see dt_gui_connect_double_click): + * GtkGestureMultiPress doesn't process multi-press events, so when a + * double/triple-click is detected by the classic "button-press-event" + * signal handler, it calls this callback with gesture=NULL. In that + * case the button is always GDK_BUTTON_PRIMARY (GDK_2BUTTON_PRESS only + * occurs for primary button). + * + * GTK4 migration: remove the ternary and just call + * gtk_gesture_single_get_button(gesture) directly — GtkGestureClick + * will provide a valid gesture pointer for all n_press values. */ + const guint button = gesture + ? gtk_gesture_single_get_button(gesture) + : GDK_BUTTON_PRIMARY; if(button == GDK_BUTTON_PRIMARY && n_press == 1) { @@ -1225,6 +1256,15 @@ dt_culling_t *dt_culling_new(const dt_culling_mode_t mode) G_CALLBACK(_event_draw), table); dt_gui_connect_motion(table->widget, _event_motion_notify_cb, _event_enter_cb, _event_leave_cb, table); dt_gui_connect_click_all(table->widget, _event_button_press_cb, _event_button_release_cb, table); + /* GTK3 bridge: GtkGestureMultiPress does not process GDK_2BUTTON_PRESS. + * dt_gui_connect_double_click forwards double/triple clicks via a + * "button-press-event" signal handler. The callback checks for NULL + * gesture (meaning it came from this bridge) and uses GDK_BUTTON_PRIMARY. + * + * GTK4 migration: remove this call. GtkGestureClick handles n_press + * natively and the callback can use gtk_gesture_single_get_button() + * safely on the real gesture pointer. */ + dt_gui_connect_double_click(table->widget, _event_button_press_cb, table); // we register globals signals DT_CONTROL_SIGNAL_CONNECT(DT_SIGNAL_MOUSE_OVER_IMAGE_CHANGE, diff --git a/src/dtgtk/thumbtable.c b/src/dtgtk/thumbtable.c index cf7305b7b45..4323f954ff1 100644 --- a/src/dtgtk/thumbtable.c +++ b/src/dtgtk/thumbtable.c @@ -1391,7 +1391,18 @@ static void _event_leave_cb(GtkEventControllerMotion *controller, } table->mouse_inside = FALSE; - dt_control_set_mouse_over_id(NO_IMGID); + + // check crossing detail: don't clear mouse_over_id when leaving to + // a child widget (thumbnail) or due to a grab + GdkEvent *event = gtk_get_current_event(); + if(event) + { + if(event->crossing.detail != GDK_NOTIFY_INFERIOR + && event->crossing.mode != GDK_CROSSING_GTK_GRAB + && event->crossing.mode != GDK_CROSSING_GRAB) + dt_control_set_mouse_over_id(NO_IMGID); + gdk_event_free(event); + } } static void _event_enter_cb(GtkEventControllerMotion *controller, @@ -1401,8 +1412,15 @@ static void _event_enter_cb(GtkEventControllerMotion *controller, { dt_set_backthumb_time(0.0); - // when entering the thumbtable area, clear the mouse-over id - dt_control_set_mouse_over_id(NO_IMGID); + // when entering the thumbtable area from a child thumbnail (INFERIOR), + // clear the mouse-over id since we're now in the empty area + GdkEvent *event = gtk_get_current_event(); + if(event) + { + if(event->crossing.detail == GDK_NOTIFY_INFERIOR) + dt_control_set_mouse_over_id(NO_IMGID); + gdk_event_free(event); + } } static gboolean _do_select_single(gpointer user_data) @@ -1426,7 +1444,20 @@ static void _event_button_press_cb(GtkGestureSingle *gesture, { dt_set_backthumb_time(0.0); - const guint button = gtk_gesture_single_get_button(gesture); + /* + * GTK3 bridge for GDK_2BUTTON_PRESS (see dt_gui_connect_double_click): + * GtkGestureMultiPress doesn't process multi-press events, so when a + * double/triple-click is detected by the classic "button-press-event" + * signal handler, it calls this callback with gesture=NULL. In that + * case the button is always GDK_BUTTON_PRIMARY (GDK_2BUTTON_PRESS only + * occurs for primary button). + * + * GTK4 migration: remove the ternary and just call + * gtk_gesture_single_get_button(gesture) directly — GtkGestureClick + * will provide a valid gesture pointer for all n_press values. */ + const guint button = gesture + ? gtk_gesture_single_get_button(gesture) + : GDK_BUTTON_PRIMARY; const dt_imgid_t id = dt_control_get_mouse_over_id(); if(button == GDK_BUTTON_PRIMARY && n_press == 2) @@ -2597,6 +2628,15 @@ dt_thumbtable_t *dt_thumbtable_new() G_CALLBACK(_event_draw), table); dt_gui_connect_motion(table->widget, _event_motion_notify_cb, _event_enter_cb, _event_leave_cb, table); dt_gui_connect_click_all(table->widget, _event_button_press_cb, _event_button_release_cb, table); + /* GTK3 bridge: GtkGestureMultiPress does not process GDK_2BUTTON_PRESS. + * dt_gui_connect_double_click forwards double/triple clicks via a + * "button-press-event" signal handler. The callback checks for NULL + * gesture (meaning it came from this bridge) and uses GDK_BUTTON_PRIMARY. + * + * GTK4 migration: remove this call. GtkGestureClick handles n_press + * natively and the callback can use gtk_gesture_single_get_button() + * safely on the real gesture pointer. */ + dt_gui_connect_double_click(table->widget, _event_button_press_cb, table); // we register globals signals DT_CONTROL_SIGNAL_CONNECT(DT_SIGNAL_COLLECTION_CHANGED, From 18a31441b28abcf22966c5b48a8eb23db600e9d2 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 15:10:37 -0300 Subject: [PATCH 60/95] gtk4-prep: convert blend GUI event signals to event controllers --- src/develop/blend_gui.c | 323 +++++++++++++++++++++------------------- 1 file changed, 171 insertions(+), 152 deletions(-) diff --git a/src/develop/blend_gui.c b/src/develop/blend_gui.c index 51e30bec8a8..4a3410315f6 100644 --- a/src/develop/blend_gui.c +++ b/src/develop/blend_gui.c @@ -741,11 +741,15 @@ static void _blendop_blend_mode_callback(GtkWidget *combo, } } -static gboolean _blendop_blend_order_clicked(GtkWidget *button, - GdkEventButton *event, +static void _blendop_blend_order_clicked(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, dt_iop_module_t *module) { - DT_GUARD_GUI_UPDATE(TRUE); + DT_GUARD_GUI_UPDATE(); + + GtkWidget *button = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); dt_develop_blend_params_t *bp = module->blend_params; const gboolean active = !(bp->blend_mode & DEVELOP_BLEND_REVERSE); @@ -759,8 +763,6 @@ static gboolean _blendop_blend_order_clicked(GtkWidget *button, dt_dev_add_history_item(darktable.develop, module, TRUE); dt_control_queue_redraw_widget(GTK_WIDGET(button)); - - return TRUE; } static void _blendop_masks_combine_callback(GtkWidget *combo, @@ -1348,66 +1350,71 @@ static void _blendop_blendif_feathering_callback(GtkWidget *slider, } } -static gboolean _blendop_blendif_showmask_clicked(GtkToggleButton *button, - GdkEventButton *event, +static void _blendop_blendif_showmask_clicked(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, dt_iop_module_t *module) { - DT_GUARD_GUI_UPDATE(TRUE); + DT_GUARD_GUI_UPDATE(); - if(dt_gdk_event_get_button(event) == GDK_BUTTON_PRIMARY) - { - const gboolean has_mask_display = - module->request_mask_display - & (DT_DEV_PIXELPIPE_DISPLAY_MASK - | DT_DEV_PIXELPIPE_DISPLAY_CHANNEL); + GtkWidget *button = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); - module->request_mask_display &= - ~(DT_DEV_PIXELPIPE_DISPLAY_MASK - | DT_DEV_PIXELPIPE_DISPLAY_CHANNEL - | DT_DEV_PIXELPIPE_DISPLAY_ANY); + const gboolean has_mask_display = + module->request_mask_display + & (DT_DEV_PIXELPIPE_DISPLAY_MASK + | DT_DEV_PIXELPIPE_DISPLAY_CHANNEL); - if(dt_modifier_is(dt_gdk_event_get_state(event), GDK_CONTROL_MASK | GDK_SHIFT_MASK)) - module->request_mask_display |= - (DT_DEV_PIXELPIPE_DISPLAY_MASK | DT_DEV_PIXELPIPE_DISPLAY_CHANNEL); - else if(dt_modifier_is(dt_gdk_event_get_state(event), GDK_SHIFT_MASK)) - module->request_mask_display |= DT_DEV_PIXELPIPE_DISPLAY_CHANNEL; - else if(dt_modifier_is(dt_gdk_event_get_state(event), GDK_CONTROL_MASK)) - module->request_mask_display |= DT_DEV_PIXELPIPE_DISPLAY_MASK; - else - module->request_mask_display |= - (has_mask_display ? DT_DEV_PIXELPIPE_DISPLAY_NONE : DT_DEV_PIXELPIPE_DISPLAY_MASK); + module->request_mask_display &= + ~(DT_DEV_PIXELPIPE_DISPLAY_MASK + | DT_DEV_PIXELPIPE_DISPLAY_CHANNEL + | DT_DEV_PIXELPIPE_DISPLAY_ANY); - gtk_toggle_button_set_active - (button, - module->request_mask_display != DT_DEV_PIXELPIPE_DISPLAY_NONE); + GdkModifierType state; + gtk_get_current_event_state(&state); + + if(dt_modifier_is(state, GDK_CONTROL_MASK | GDK_SHIFT_MASK)) + module->request_mask_display |= + (DT_DEV_PIXELPIPE_DISPLAY_MASK | DT_DEV_PIXELPIPE_DISPLAY_CHANNEL); + else if(dt_modifier_is(state, GDK_SHIFT_MASK)) + module->request_mask_display |= DT_DEV_PIXELPIPE_DISPLAY_CHANNEL; + else if(dt_modifier_is(state, GDK_CONTROL_MASK)) + module->request_mask_display |= DT_DEV_PIXELPIPE_DISPLAY_MASK; + else + module->request_mask_display |= + (has_mask_display ? DT_DEV_PIXELPIPE_DISPLAY_NONE : DT_DEV_PIXELPIPE_DISPLAY_MASK); - if(module->off) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(module->off), TRUE); + gtk_toggle_button_set_active + (GTK_TOGGLE_BUTTON(button), + module->request_mask_display != DT_DEV_PIXELPIPE_DISPLAY_NONE); - DT_ENTER_GUI_UPDATE(); + if(module->off) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(module->off), TRUE); - // (re)set the header mask indicator too - if(module->mask_indicator) - gtk_toggle_button_set_active - (GTK_TOGGLE_BUTTON(module->mask_indicator), - module->request_mask_display != DT_DEV_PIXELPIPE_DISPLAY_NONE); + DT_ENTER_GUI_UPDATE(); - DT_LEAVE_GUI_UPDATE(); + // (re)set the header mask indicator too + if(module->mask_indicator) + gtk_toggle_button_set_active + (GTK_TOGGLE_BUTTON(module->mask_indicator), + module->request_mask_display != DT_DEV_PIXELPIPE_DISPLAY_NONE); - dt_iop_request_focus(module); - dt_iop_refresh_center(module); - } + DT_LEAVE_GUI_UPDATE(); - return TRUE; + dt_iop_request_focus(module); + dt_iop_refresh_center(module); } -static gboolean _blendop_masks_modes_none_clicked(GtkWidget *button, - GdkEventButton *event, +static void _blendop_masks_modes_none_clicked(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, dt_iop_module_t *module) { - DT_GUARD_GUI_UPDATE(TRUE); + DT_GUARD_GUI_UPDATE(); + GtkWidget *button = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); dt_iop_gui_blend_data_t *data = module->blend_data; - if(dt_gdk_event_get_button(event) == GDK_BUTTON_PRIMARY && data->selected_mask_mode != button) + if(data->selected_mask_mode != button) { gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data->selected_mask_mode), FALSE); // unsets currently toggled if any @@ -1421,8 +1428,6 @@ static gboolean _blendop_masks_modes_none_clicked(GtkWidget *button, /* and finally remove hinter messages */ dt_control_hinter_message(""); } - - return TRUE; } static gboolean _blendop_masks_modes_toggle(GtkToggleButton *button, @@ -1494,27 +1499,36 @@ static gboolean _blendop_masks_modes_toggle(GtkToggleButton *button, return TRUE; } -static gboolean _blendop_masks_modes_uni_toggled(GtkToggleButton *button, - GdkEventButton *event, +static void _blendop_masks_modes_uni_toggled(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, dt_iop_module_t *module) { - return _blendop_masks_modes_toggle(button, module, DEVELOP_MASK_ENABLED); + GtkWidget *button = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + _blendop_masks_modes_toggle(GTK_TOGGLE_BUTTON(button), module, DEVELOP_MASK_ENABLED); } -static gboolean _blendop_masks_modes_drawn_toggled(GtkToggleButton *button, - GdkEventButton *event, +static void _blendop_masks_modes_drawn_toggled(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, dt_iop_module_t *module) { - return _blendop_masks_modes_toggle(button, module, - DEVELOP_MASK_ENABLED | DEVELOP_MASK_MASK); + GtkWidget *button = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + _blendop_masks_modes_toggle(GTK_TOGGLE_BUTTON(button), module, + DEVELOP_MASK_ENABLED | DEVELOP_MASK_MASK); } -static gboolean _blendop_masks_modes_param_toggled(GtkToggleButton *button, - GdkEventButton *event, +static void _blendop_masks_modes_param_toggled(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, dt_iop_module_t *module) { - return _blendop_masks_modes_toggle(button, module, - DEVELOP_MASK_ENABLED | DEVELOP_MASK_CONDITIONAL); + GtkWidget *button = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + _blendop_masks_modes_toggle(GTK_TOGGLE_BUTTON(button), module, + DEVELOP_MASK_ENABLED | DEVELOP_MASK_CONDITIONAL); } static void _blendop_masks_modes_both_toggled(GtkGestureSingle *gesture, @@ -1528,20 +1542,27 @@ static void _blendop_masks_modes_both_toggled(GtkGestureSingle *gesture, DEVELOP_MASK_ENABLED | DEVELOP_MASK_MASK_CONDITIONAL); } -static gboolean _blendop_masks_modes_raster_toggled(GtkToggleButton *button, - GdkEventButton *event, +static void _blendop_masks_modes_raster_toggled(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, dt_iop_module_t *module) { - return _blendop_masks_modes_toggle(button, module, - DEVELOP_MASK_ENABLED | DEVELOP_MASK_RASTER); + GtkWidget *button = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + _blendop_masks_modes_toggle(GTK_TOGGLE_BUTTON(button), module, + DEVELOP_MASK_ENABLED | DEVELOP_MASK_RASTER); } -static gboolean _blendop_blendif_suppress_toggled(GtkToggleButton *togglebutton, - GdkEventButton *event, +static void _blendop_blendif_suppress_toggled(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, dt_iop_module_t *module) { + GtkWidget *togglebutton_w = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + GtkToggleButton *togglebutton = GTK_TOGGLE_BUTTON(togglebutton_w); module->suppress_mask = !gtk_toggle_button_get_active(togglebutton); - DT_GUARD_GUI_UPDATE(FALSE); + DT_GUARD_GUI_UPDATE(); if(module->off) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(module->off), TRUE); dt_iop_request_focus(module); @@ -1550,12 +1571,12 @@ static gboolean _blendop_blendif_suppress_toggled(GtkToggleButton *togglebutton, dt_control_queue_redraw_widget(GTK_WIDGET(togglebutton)); dt_iop_refresh_center(module); - - return TRUE; } -static gboolean _blendop_blendif_reset(GtkButton *button, - GdkEventButton *event, +static void _blendop_blendif_reset(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, dt_iop_module_t *module) { module->blend_params->blendif = module->default_blendop_params->blendif; @@ -1567,15 +1588,15 @@ static gboolean _blendop_blendif_reset(GtkButton *button, dt_iop_color_picker_reset(module, FALSE); dt_iop_gui_update_blendif(module); dt_dev_add_history_item(darktable.develop, module, TRUE); - - return TRUE; } -static gboolean _blendop_blendif_invert(GtkButton *button, - GdkEventButton *event, +static void _blendop_blendif_invert(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, dt_iop_module_t *module) { - DT_GUARD_GUI_UPDATE(TRUE); + DT_GUARD_GUI_UPDATE(); const dt_iop_gui_blend_data_t *data = module->blend_data; @@ -1601,21 +1622,21 @@ static gboolean _blendop_blendif_invert(GtkButton *button, module->blend_params->mask_combine ^= DEVELOP_COMBINE_INCL; dt_iop_gui_update_blending(module); dt_dev_add_history_item(darktable.develop, module, TRUE); - - return TRUE; } -static gboolean _blendop_masks_add_shape(GtkWidget *widget, - GdkEventButton *event, +static void _blendop_masks_add_shape(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, dt_iop_module_t *self) { - if(DT_IN_GUI_UPDATE() - || dt_gdk_event_get_button(event) != GDK_BUTTON_PRIMARY) - return TRUE; + GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); dt_iop_gui_blend_data_t *bd = self->blend_data; - const gboolean continuous = dt_modifier_is(dt_gdk_event_get_state(event), GDK_CONTROL_MASK); + GdkModifierType state; + gtk_get_current_event_state(&state); + const gboolean continuous = dt_modifier_is(state, GDK_CONTROL_MASK); // find out who we are int this = -1; @@ -1628,13 +1649,13 @@ static gboolean _blendop_masks_add_shape(GtkWidget *widget, } } - if(this < 0) return FALSE; + if(this < 0) return; #ifdef HAVE_AI if(bd->masks_type[this] == DT_MASKS_OBJECT && !dt_masks_object_available()) { dt_control_log(_("AI model is not available. Check preferences > AI")); - return TRUE; + return; } #endif @@ -1662,88 +1683,86 @@ static gboolean _blendop_masks_add_shape(GtkWidget *widget, } dt_control_queue_redraw_center(); - - return TRUE; } -static gboolean _blendop_masks_show_and_edit(GtkWidget *widget, - GdkEventButton *event, +static void _blendop_masks_show_and_edit(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, dt_iop_module_t *self) { - DT_GUARD_GUI_UPDATE(FALSE); - darktable.develop->form_gui->creation_continuous = FALSE; darktable.develop->form_gui->creation_continuous_module = NULL; dt_iop_gui_blend_data_t *bd = self->blend_data; - if(dt_gdk_event_get_button(event) == GDK_BUTTON_PRIMARY) - { - dt_iop_request_focus(self); - - DT_ENTER_GUI_UPDATE(); + dt_iop_request_focus(self); - dt_iop_color_picker_reset(self, FALSE); + DT_ENTER_GUI_UPDATE(); - dt_masks_form_t *grp = dt_masks_get_from_id(darktable.develop, - self->blend_params->mask_id); - if(grp && (grp->type & DT_MASKS_GROUP) && grp->points) - { - const gboolean control_button_pressed = - dt_modifier_is(dt_gdk_event_get_state(event), GDK_CONTROL_MASK); + dt_iop_color_picker_reset(self, FALSE); - switch(bd->masks_shown) - { - case DT_MASKS_EDIT_FULL: - bd->masks_shown = control_button_pressed - ? DT_MASKS_EDIT_RESTRICTED - : DT_MASKS_EDIT_OFF; - break; + GdkModifierType state; + gtk_get_current_event_state(&state); - case DT_MASKS_EDIT_RESTRICTED: - bd->masks_shown = !control_button_pressed - ? DT_MASKS_EDIT_FULL - : DT_MASKS_EDIT_OFF; - break; + dt_masks_form_t *grp = dt_masks_get_from_id(darktable.develop, + self->blend_params->mask_id); + if(grp && (grp->type & DT_MASKS_GROUP) && grp->points) + { + const gboolean control_button_pressed = + dt_modifier_is(state, GDK_CONTROL_MASK); - default: - case DT_MASKS_EDIT_OFF: - bd->masks_shown = control_button_pressed - ? DT_MASKS_EDIT_RESTRICTED - : DT_MASKS_EDIT_FULL; - } - } - else + switch(bd->masks_shown) { - bd->masks_shown = DT_MASKS_EDIT_OFF; - /* remove hinter messages */ - dt_control_hinter_message(""); - } + case DT_MASKS_EDIT_FULL: + bd->masks_shown = control_button_pressed + ? DT_MASKS_EDIT_RESTRICTED + : DT_MASKS_EDIT_OFF; + break; - gtk_toggle_button_set_active - (GTK_TOGGLE_BUTTON(bd->masks_edit), bd->masks_shown != DT_MASKS_EDIT_OFF); - dt_masks_set_edit_mode(self, bd->masks_shown); + case DT_MASKS_EDIT_RESTRICTED: + bd->masks_shown = !control_button_pressed + ? DT_MASKS_EDIT_FULL + : DT_MASKS_EDIT_OFF; + break; - // set all add shape buttons to inactive - for(int n = 0; n < DEVELOP_MASKS_NB_SHAPES; n++) - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(bd->masks_shapes[n]), FALSE); + default: + case DT_MASKS_EDIT_OFF: + bd->masks_shown = control_button_pressed + ? DT_MASKS_EDIT_RESTRICTED + : DT_MASKS_EDIT_FULL; + } + } + else + { + bd->masks_shown = DT_MASKS_EDIT_OFF; + /* remove hinter messages */ + dt_control_hinter_message(""); + } - DT_LEAVE_GUI_UPDATE(); + gtk_toggle_button_set_active + (GTK_TOGGLE_BUTTON(bd->masks_edit), bd->masks_shown != DT_MASKS_EDIT_OFF); + dt_masks_set_edit_mode(self, bd->masks_shown); - return TRUE; - } + // set all add shape buttons to inactive + for(int n = 0; n < DEVELOP_MASKS_NB_SHAPES; n++) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(bd->masks_shapes[n]), FALSE); - return FALSE; + DT_LEAVE_GUI_UPDATE(); } -static gboolean _blendop_masks_polarity_callback(GtkToggleButton *togglebutton, - GdkEventButton *event, +static void _blendop_masks_polarity_callback(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, dt_iop_module_t *self) { - DT_GUARD_GUI_UPDATE(TRUE); + DT_GUARD_GUI_UPDATE(); + + GtkWidget *togglebutton = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); - const int active = !gtk_toggle_button_get_active(togglebutton); - gtk_toggle_button_set_active(togglebutton, active); + const int active = !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(togglebutton)); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(togglebutton), active); dt_develop_blend_params_t *bp = self->blend_params; @@ -1753,9 +1772,7 @@ static gboolean _blendop_masks_polarity_callback(GtkToggleButton *togglebutton, bp->mask_combine &= ~DEVELOP_COMBINE_MASKS_POS; dt_dev_add_history_item(darktable.develop, self, TRUE); - dt_control_queue_redraw_widget(GTK_WIDGET(togglebutton)); - - return TRUE; + dt_control_queue_redraw_widget(togglebutton); } gboolean blend_color_picker_apply(dt_iop_module_t *module, @@ -2960,20 +2977,22 @@ void dt_iop_gui_update_raster(dt_iop_module_t *module) _raster_combo_populate(bd->raster_combo, &module); } -static gboolean _raster_polarity_callback(GtkToggleButton *togglebutton, - GdkEventButton *event, +static void _raster_polarity_callback(GtkGestureSingle *gesture, + gint n_press, + gdouble x, + gdouble y, dt_iop_module_t *self) { - DT_GUARD_GUI_UPDATE(TRUE); + DT_GUARD_GUI_UPDATE(); + + GtkWidget *togglebutton = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); dt_develop_blend_params_t *bp = self->blend_params; bp->raster_mask_invert ^= TRUE; - gtk_toggle_button_set_active(togglebutton, bp->raster_mask_invert); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(togglebutton), bp->raster_mask_invert); dt_dev_add_history_item(darktable.develop, self, TRUE); - - return TRUE; } void dt_iop_gui_init_raster(GtkWidget *blendw, dt_iop_module_t *module) From 7281bc0383674a474ea813677894d035832ff3e6 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 15:10:39 -0300 Subject: [PATCH 61/95] gtk4-prep: fix event memory leak in bauhaus popup button press --- src/bauhaus/bauhaus.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/bauhaus/bauhaus.c b/src/bauhaus/bauhaus.c index c91ef1d2447..b6ba9bdc7fc 100644 --- a/src/bauhaus/bauhaus.c +++ b/src/bauhaus/bauhaus.c @@ -750,11 +750,15 @@ static void _popup_button_press_cb(GtkGestureSingle *gesture, bh->change_active = TRUE; GtkWidget *w_current = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); - const GdkEvent *current_event = gtk_get_current_event(); - _window_motion_handle(w_current, - dt_gdk_event_get_root_x(current_event), - dt_gdk_event_get_root_y(current_event), - dt_gdk_event_get_state(current_event)); + GdkEvent *current_event = gtk_get_current_event(); + if(current_event) + { + _window_motion_handle(w_current, + dt_gdk_event_get_root_x(current_event), + dt_gdk_event_get_root_y(current_event), + dt_gdk_event_get_state(current_event)); + gdk_event_free(current_event); + } } else if(button == GDK_BUTTON_MIDDLE && w->type == DT_BAUHAUS_SLIDER) _slider_zoom_range(w, 0); From 2bb4950e063ab472ca801eb36e5913f7da46a82e Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 15:10:42 -0300 Subject: [PATCH 62/95] gtk4-prep: convert toneequal event signals to event controllers --- src/iop/toneequal.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/iop/toneequal.c b/src/iop/toneequal.c index 5d5b89a58bf..f67109b7ee6 100644 --- a/src/iop/toneequal.c +++ b/src/iop/toneequal.c @@ -2946,6 +2946,7 @@ static gboolean area_draw(GtkWidget *widget, static void area_leave_notify(GtkEventControllerMotion *controller, dt_iop_module_t *self) { + DT_GUARD_GUI_UPDATE(); if(!self->enabled) return; dt_iop_toneequalizer_gui_data_t *g = self->gui_data; @@ -2977,6 +2978,8 @@ static void area_button_press(GtkGestureSingle *gesture, gdouble y, dt_iop_module_t *self) { + DT_GUARD_GUI_UPDATE(); + dt_iop_toneequalizer_gui_data_t *g = self->gui_data; dt_iop_request_focus(self); @@ -3030,6 +3033,7 @@ static void area_motion_notify(GtkEventControllerMotion *controller, gdouble y, dt_iop_module_t *self) { + DT_GUARD_GUI_UPDATE(); if(!self->enabled) return; dt_iop_toneequalizer_gui_data_t *g = self->gui_data; @@ -3084,6 +3088,7 @@ static void area_button_release(GtkGestureSingle *gesture, gdouble y, dt_iop_module_t *self) { + DT_GUARD_GUI_UPDATE(); if(!self->enabled) return; if(gtk_gesture_single_get_current_button(gesture) != GDK_BUTTON_PRIMARY) @@ -3114,12 +3119,8 @@ static void area_scroll(GtkEventControllerScroll *controller, gdouble dy, dt_iop_module_t *self) { - // do not propagate to tab bar unless scrolling sidebar - GdkEvent *event = gtk_get_current_event(); - if(!event) return; - if(!dt_gui_ignore_scroll((GdkEventScroll *)event)) - dt_gui_claim(controller); - gdk_event_free(event); + // scroll is already filtered by _scroll_sidebar in the proxy, + // so only valid scroll events on the area widget reach here. } static void notebook_button_press(GtkGestureSingle *gesture, From be163eed3a2d20357bafd47465e3d23b43a8369f Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 15:10:45 -0300 Subject: [PATCH 63/95] gtk4-prep: convert lib body enter callback to event controller --- src/libs/lib.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/libs/lib.c b/src/libs/lib.c index 1734132c0e9..24f51c6aaf8 100644 --- a/src/libs/lib.c +++ b/src/libs/lib.c @@ -1163,14 +1163,30 @@ static void _body_enter_callback(GtkEventControllerMotion *controller, dt_lib_module_t *module) { // set focused module when entering (not when opening popup) - darktable.lib->gui_module = module; + // only act on non-inferior (not from child) normal crossings + GdkEvent *event = gtk_get_current_event(); + if(event) + { + if(event->crossing.detail != GDK_NOTIFY_INFERIOR + && event->crossing.mode == GDK_CROSSING_NORMAL) + darktable.lib->gui_module = module; + gdk_event_free(event); + } } static void _body_leave_callback(GtkEventControllerMotion *controller, dt_lib_module_t *module) { // clear focused module when leaving - darktable.lib->gui_module = NULL; + // only act on non-inferior (not to child) normal crossings + GdkEvent *event = gtk_get_current_event(); + if(event) + { + if(event->crossing.detail != GDK_NOTIFY_INFERIOR + && event->crossing.mode == GDK_CROSSING_NORMAL) + darktable.lib->gui_module = NULL; + gdk_event_free(event); + } } static gboolean _on_drag_motion(GtkWidget *widget, From 3fa26a1c7c69fb53a2754ac4db4b08874232c94a Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 15:19:38 -0300 Subject: [PATCH 64/95] gtk4-prep: fix build errors in map, location, and lut3d after event controller conversion --- src/iop/lut3d.c | 5 ++--- src/libs/location.c | 2 +- src/views/map.c | 13 ++++++------- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/iop/lut3d.c b/src/iop/lut3d.c index 30fef567fb4..f26dcd9bd7c 100644 --- a/src/iop/lut3d.c +++ b/src/iop/lut3d.c @@ -1475,7 +1475,7 @@ static void _lutname_callback(GtkTreeSelection *selection, dt_iop_module_t *self static void _mouse_scroll(GtkEventControllerScroll *controller, gdouble dx, gdouble dy, - dt_lib_module_t *self) + dt_iop_module_t *self) { GtkWidget *view = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(view)); @@ -1494,10 +1494,9 @@ static void _mouse_scroll(GtkEventControllerScroll *controller, GtkTreePath *path = gtk_tree_model_get_path(model, &iter); gtk_tree_view_set_cursor((GtkTreeView *)view, path, NULL, FALSE); gtk_tree_path_free(path); - return TRUE; + return; } } - return FALSE; } #endif // HAVE_GMIC diff --git a/src/libs/location.c b/src/libs/location.c index 312325936e9..d5ad2cde2e6 100644 --- a/src/libs/location.c +++ b/src/libs/location.c @@ -207,7 +207,7 @@ static GtkWidget *_lib_location_place_widget_new(dt_lib_location_t *lib, lib->callback_params = g_list_append(lib->callback_params, param); param->lib = lib; param->result = place; - dt_gui_connect_click(eb, _lib_location_result_item_activated, NULL, param); + dt_gui_connect_click(eb, _lib_location_result_item_activated, NULL, (gpointer)param); } return eb; } diff --git a/src/views/map.c b/src/views/map.c index 7590758d802..65d27918654 100644 --- a/src/views/map.c +++ b/src/views/map.c @@ -1858,7 +1858,6 @@ static void _view_map_motion_cb(GtkEventControllerMotion *controller, gdouble y, dt_view_t *self) { - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); dt_map_t *lib = self->data; GdkEvent *event = gtk_get_current_event(); @@ -2167,10 +2166,10 @@ static void _view_map_click_pressed_cb(GtkGestureSingle *gesture, { GdkDisplay *display = gtk_widget_get_display(GTK_WIDGET(lib->map)); GdkDevice *pointer = gdk_seat_get_pointer(gdk_display_get_default_seat(display)); - gdouble root_x, root_y; + gint root_x, root_y; gdk_device_get_position(pointer, NULL, &root_x, &root_y); - lib->start_drag_x = ceil(root_x); - lib->start_drag_y = ceil(root_y); + lib->start_drag_x = root_x; + lib->start_drag_y = root_y; lib->loc.drag = TRUE; return; } @@ -2216,10 +2215,10 @@ static void _view_map_click_pressed_cb(GtkGestureSingle *gesture, { GdkDisplay *display = gtk_widget_get_display(GTK_WIDGET(lib->map)); GdkDevice *pointer = gdk_seat_get_pointer(gdk_display_get_default_seat(display)); - gdouble root_x, root_y; + gint root_x, root_y; gdk_device_get_position(pointer, NULL, &root_x, &root_y); - lib->start_drag_x = ceil(root_x); - lib->start_drag_y = ceil(root_y); + lib->start_drag_x = root_x; + lib->start_drag_y = root_y; lib->start_drag = TRUE; } } From 48904489e1babc88f02f1fbb8a6777e40b2be6cb Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 15:28:16 -0300 Subject: [PATCH 65/95] gtk4-prep: revert map view to signal-based event handling (OsmGpsMap incompatible with gesture controllers) --- src/views/map.c | 347 +++++++++++++++++++++--------------------------- 1 file changed, 152 insertions(+), 195 deletions(-) diff --git a/src/views/map.c b/src/views/map.c index 65d27918654..047f6bd1f46 100644 --- a/src/views/map.c +++ b/src/views/map.c @@ -213,26 +213,20 @@ static void _view_map_dnd_get_callback(GtkWidget *widget, static void _view_map_changed_callback(OsmGpsMap *map, dt_view_t *self); /* callback that handles mouse scroll */ -static void _view_map_scroll_cb(GtkEventControllerScroll *controller, - gdouble dx, - gdouble dy, - dt_view_t *self); +static gboolean _view_map_scroll_event(GtkWidget *w, + GdkEventScroll *event, + dt_view_t *self); /* callback that handles clicks on the map */ -static void _view_map_click_pressed_cb(GtkGestureSingle *gesture, - int n_press, - double x, - double y, - dt_view_t *self); -static void _view_map_click_released_cb(GtkGestureSingle *gesture, - int n_press, - double x, - double y, - dt_view_t *self); +static gboolean _view_map_button_press_callback(GtkWidget *w, + GdkEventButton *e, + dt_view_t *self); +static gboolean _view_map_button_release_callback(GtkWidget *w, + GdkEventButton *e, + dt_view_t *self); /* callback when the mouse is moved */ -static void _view_map_motion_cb(GtkEventControllerMotion *controller, - gdouble x, - gdouble y, - dt_view_t *self); +static gboolean _view_map_motion_notify_callback(GtkWidget *w, + GdkEventMotion *e, + dt_view_t *self); static gboolean _view_map_drag_motion_callback(GtkWidget *widget, GdkDragContext *dc, const gint x, @@ -773,10 +767,8 @@ void init(dt_view_t *self) gtk_drag_dest_set(GTK_WIDGET(lib->map), GTK_DEST_DEFAULT_ALL, target_list_internal, n_targets_internal, GDK_ACTION_MOVE); - dt_gui_connect_scroll(GTK_WIDGET(lib->map), - GTK_EVENT_CONTROLLER_SCROLL_VERTICAL - | GTK_EVENT_CONTROLLER_SCROLL_DISCRETE, - _view_map_scroll_cb, self); + g_signal_connect(GTK_WIDGET(lib->map), "scroll-event", + G_CALLBACK(_view_map_scroll_event), self); g_signal_connect(GTK_WIDGET(lib->map), "drag-data-received", G_CALLBACK(_drag_and_drop_received), self); g_signal_connect(GTK_WIDGET(lib->map), "drag-data-get", @@ -786,8 +778,13 @@ void init(dt_view_t *self) g_signal_connect(GTK_WIDGET(lib->map), "changed", G_CALLBACK(_view_map_changed_callback), self); - dt_gui_connect_click(lib->map, _view_map_click_pressed_cb, _view_map_click_released_cb, self); - dt_gui_connect_motion(lib->map, _view_map_motion_cb, NULL, NULL, self); + g_signal_connect_after(G_OBJECT(lib->map), "button-press-event", + G_CALLBACK(_view_map_button_press_callback), self); + g_signal_connect_after(G_OBJECT(lib->map), "button-release-event", + G_CALLBACK(_view_map_button_release_callback), self); + g_signal_connect(G_OBJECT(lib->map), "motion-notify-event", + G_CALLBACK(_view_map_motion_notify_callback), + self); g_signal_connect(G_OBJECT(lib->map), "drag-motion", G_CALLBACK(_view_map_drag_motion_callback), self); @@ -1853,110 +1850,91 @@ static gboolean _view_map_drag_motion_callback(GtkWidget *widget, return FALSE; } -static void _view_map_motion_cb(GtkEventControllerMotion *controller, - gdouble x, - gdouble y, - dt_view_t *self) +static gboolean _view_map_motion_notify_callback(GtkWidget *widget, + GdkEventMotion *e, + dt_view_t *self) { dt_map_t *lib = self->data; - GdkEvent *event = gtk_get_current_event(); - - if(event) - { - OsmGpsMapPoint *p = osm_gps_map_point_new_degrees(0.0, 0.0); - osm_gps_map_convert_screen_to_geographic(lib->map, x, y, p); - float lat, lon; - osm_gps_map_point_get_degrees(p, &lat, &lon); - osm_gps_map_point_free(p); - _toast_log_lat_lon(lat, lon); - } - - if(event && lib->loc.drag - && lib->loc.main.id > 0) - { - gdouble root_x, root_y; - gdk_event_get_root_coords(event, &root_x, &root_y); - if((abs(lib->start_drag_x - (int)ceil(root_x)) + - abs(lib->start_drag_y - (int)ceil(root_y))) > DT_PIXEL_APPLY_DPI(8)) - { - lib->loc.drag = FALSE; - osm_gps_map_image_remove(lib->map, lib->loc.main.location); - GtkTargetList *targets = gtk_target_list_new(target_list_internal, n_targets_internal); - - GdkDragContext *context = - gtk_drag_begin_with_coordinates(GTK_WIDGET(lib->map), targets, - GDK_ACTION_MOVE, 1, - event, -1, -1); + OsmGpsMapPoint *p = osm_gps_map_get_event_location(lib->map, (GdkEventButton *)e); + float lat, lon; + osm_gps_map_point_get_degrees(p, &lat, &lon); + _toast_log_lat_lon(lat, lon); - int width; - int height; - GdkPixbuf *location = _draw_location(lib, &width, &height, &lib->loc.main.data, TRUE); - if(location) - { - GtkWidget *image = gtk_image_new_from_pixbuf(location); - dt_gui_add_class(image, "dt_transparent_background"); - gtk_widget_set_name(image, "map-drag-icon"); - gtk_widget_show(image); - gtk_drag_set_icon_widget(context, image, - DT_PIXEL_APPLY_DPI(width), - DT_PIXEL_APPLY_DPI(height)); - g_object_unref(location); - } - gtk_target_list_unref(targets); - gdk_event_free(event); - return; - } + if(lib->loc.drag + && lib->loc.main.id > 0 + && (abs(lib->start_drag_x - (int)ceil(e->x_root)) + + abs(lib->start_drag_y - (int)ceil(e->y_root))) > DT_PIXEL_APPLY_DPI(8)) + { + lib->loc.drag = FALSE; + osm_gps_map_image_remove(lib->map, lib->loc.main.location); + GtkTargetList *targets = gtk_target_list_new(target_list_internal, n_targets_internal); + + GdkDragContext *context = + gtk_drag_begin_with_coordinates(GTK_WIDGET(lib->map), targets, + GDK_ACTION_MOVE, 1, + (GdkEvent *)e, -1, -1); + + int width; + int height; + GdkPixbuf *location = _draw_location(lib, &width, &height, &lib->loc.main.data, TRUE); + if(location) + { + GtkWidget *image = gtk_image_new_from_pixbuf(location); + dt_gui_add_class(image, "dt_transparent_background"); + gtk_widget_set_name(image, "map-drag-icon"); + gtk_widget_show(image); + gtk_drag_set_icon_widget(context, image, + DT_PIXEL_APPLY_DPI(width), + DT_PIXEL_APPLY_DPI(height)); + g_object_unref(location); + } + gtk_target_list_unref(targets); + return TRUE; } - if(event && lib->start_drag - && lib->selected_images) + if(lib->start_drag + && lib->selected_images + && (abs(lib->start_drag_x - (int)ceil(e->x_root)) + + abs(lib->start_drag_y - (int)ceil(e->y_root))) > DT_PIXEL_APPLY_DPI(8)) { - gdouble root_x, root_y; - gdk_event_get_root_coords(event, &root_x, &root_y); - if((abs(lib->start_drag_x - (int)ceil(root_x)) + - abs(lib->start_drag_y - (int)ceil(root_y))) > DT_PIXEL_APPLY_DPI(8)) + const int nb = g_list_length(lib->selected_images); + for(const GSList *iter = lib->images; + iter; + iter = g_slist_next(iter)) { - const int nb = g_list_length(lib->selected_images); - for(const GSList *iter = lib->images; - iter; - iter = g_slist_next(iter)) + dt_map_image_t *entry = iter->data; + if(entry->image) { - dt_map_image_t *entry = iter->data; - if(entry->image) + const GList *sel_img = lib->selected_images; + if(entry->imgid == GPOINTER_TO_INT(sel_img->data)) { - const GList *sel_img = lib->selected_images; - if(entry->imgid == GPOINTER_TO_INT(sel_img->data)) + if(entry->group_count == nb) { - if(entry->group_count == nb) - { - osm_gps_map_image_remove(lib->map, entry->image); - entry->image = NULL; - } - else - _display_next_image(self, entry, TRUE); - break; + osm_gps_map_image_remove(lib->map, entry->image); + entry->image = NULL; } + else + _display_next_image(self, entry, TRUE); + break; } } + } - const int group_count = g_list_length(lib->selected_images); + const int group_count = g_list_length(lib->selected_images); - lib->start_drag = FALSE; - GtkTargetList *targets = gtk_target_list_new(target_list_all, n_targets_all); - GdkDragContext *context = gtk_drag_begin_with_coordinates(GTK_WIDGET(lib->map), targets, - GDK_ACTION_MOVE, 1, - event, -1, -1); - _view_map_drag_set_icon(self, context, GPOINTER_TO_INT(lib->selected_images->data), - group_count); - gtk_target_list_unref(targets); - gdk_event_free(event); - return; - } + lib->start_drag = FALSE; + GtkTargetList *targets = gtk_target_list_new(target_list_all, n_targets_all); + GdkDragContext *context = gtk_drag_begin_with_coordinates(GTK_WIDGET(lib->map), targets, + GDK_ACTION_MOVE, 1, + (GdkEvent *)e, -1, -1); + _view_map_drag_set_icon(self, context, GPOINTER_TO_INT(lib->selected_images->data), + group_count); + gtk_target_list_unref(targets); + return TRUE; } - if(event) gdk_event_free(event); - dt_map_image_t *entry = _view_map_get_entry_at_pos(self, x, y); + dt_map_image_t *entry = _view_map_get_entry_at_pos(self, e->x, e->y); if(entry) { // show image information if image is hovered @@ -1966,7 +1944,7 @@ static void _view_map_motion_cb(GtkEventControllerMotion *controller, { _view_map_draw_image(entry, TRUE, DT_MAP_THUMB_THUMB, self); lib->last_hovered_entry = entry; - return; + return TRUE; } } else @@ -1979,6 +1957,7 @@ static void _view_map_motion_cb(GtkEventControllerMotion *controller, lib->last_hovered_entry = NULL; } } + return FALSE; } static gboolean _zoom_and_center(const gint x, @@ -2024,54 +2003,38 @@ static gboolean _zoom_and_center(const gint x, return TRUE; } -static void _view_map_scroll_cb(GtkEventControllerScroll *controller, - gdouble dx, - gdouble dy, - dt_view_t *self) +static gboolean _view_map_scroll_event(GtkWidget *w, + GdkEventScroll *event, + dt_view_t *self) { dt_map_t *lib = self->data; - - // get the current event for position and modifier state - GdkEvent *event = gtk_get_current_event(); - if(!event) return; - gdouble x, y; - GdkModifierType state; - gdk_event_get_coords(event, &x, &y); - gdk_event_get_state(event, &state); - gdk_event_free(event); - - // determine scroll direction from dy - const gboolean scroll_down = dy > 0; - const gboolean scroll_up = dy < 0; - - // check if the scroll was on image(s) or just some random position - dt_map_image_t *entry = _view_map_get_entry_at_pos(self, x, y); + // check if the click was on image(s) or just some random position + dt_map_image_t *entry = _view_map_get_entry_at_pos(self, dt_gdk_event_get_x(event), dt_gdk_event_get_y(event)); if(entry) { - if(_display_next_image(self, entry, scroll_down)) - return; + if(_display_next_image(self, entry, dt_gdk_event_get_scroll_direction(event) == GDK_SCROLL_DOWN)) + return TRUE; } - OsmGpsMapPoint *p = osm_gps_map_point_new_degrees(0.0, 0.0); - osm_gps_map_convert_screen_to_geographic(lib->map, x, y, p); + OsmGpsMapPoint *p = osm_gps_map_get_event_location(lib->map, (GdkEventButton *)event); float lat, lon; osm_gps_map_point_get_degrees(p, &lat, &lon); - osm_gps_map_point_free(p); - if(lib->loc.main.id > 0) { - const gboolean increase = scroll_up; - const gboolean decrease = scroll_down; + const gboolean increase = dt_gdk_event_get_scroll_direction(event) == GDK_SCROLL_UP + || dt_gdk_event_get_scroll_direction(event) == GDK_SCROLL_RIGHT; + const gboolean decrease = dt_gdk_event_get_scroll_direction(event) == GDK_SCROLL_DOWN + || dt_gdk_event_get_scroll_direction(event) == GDK_SCROLL_LEFT; if(dt_map_location_included(lon, lat, &lib->loc.main.data)) { - if(dt_modifier_is(state, GDK_SHIFT_MASK)) + if(dt_modifier_is(dt_gdk_event_get_state(event), GDK_SHIFT_MASK)) { if(increase) lib->loc.main.data.delta1 *= 1.1; else if(decrease) lib->loc.main.data.delta1 /= 1.1; } - else if(dt_modifier_is(state, GDK_CONTROL_MASK)) + else if(dt_modifier_is(dt_gdk_event_get_state(event), GDK_CONTROL_MASK)) { if(increase) lib->loc.main.data.delta2 *= 1.1; @@ -2085,7 +2048,7 @@ static void _view_map_scroll_cb(GtkEventControllerScroll *controller, lib->loc.main.data.delta1 *= 1.1; lib->loc.main.data.delta2 *= 1.1; } - else if(decrease) + else if (decrease) { lib->loc.main.data.delta1 /= 1.1; lib->loc.main.data.delta2 /= 1.1; @@ -2094,32 +2057,27 @@ static void _view_map_scroll_cb(GtkEventControllerScroll *controller, _view_map_draw_main_location(lib, &lib->loc.main); _view_map_update_location_geotag(self); _view_map_signal_change_wait(self, 3); // wait 3/10 sec after last scroll - return; + return TRUE; } else // scroll on the map. try to keep the map where it is { _toast_log_lat_lon(lat, lon); - _zoom_and_center(x, y, scroll_up ? GDK_SCROLL_UP : GDK_SCROLL_DOWN, self); - return; + return _zoom_and_center(dt_gdk_event_get_x(event), dt_gdk_event_get_y(event), dt_gdk_event_get_scroll_direction(event), self); } } else { _toast_log_lat_lon(lat, lon); - _zoom_and_center(x, y, scroll_up ? GDK_SCROLL_UP : GDK_SCROLL_DOWN, self); + return _zoom_and_center(dt_gdk_event_get_x(event), dt_gdk_event_get_y(event), dt_gdk_event_get_scroll_direction(event), self); } + return FALSE; } -static void _view_map_click_pressed_cb(GtkGestureSingle *gesture, - int n_press, - double x, - double y, - dt_view_t *self) +static gboolean _view_map_button_press_callback(GtkWidget *w, + GdkEventButton *e, + dt_view_t *self) { dt_map_t *lib = self->data; - GdkModifierType state; - gtk_get_current_event_state(&state); - if(lib->selected_images) { g_list_free(lib->selected_images); @@ -2129,7 +2087,9 @@ static void _view_map_click_pressed_cb(GtkGestureSingle *gesture, if(lib->osd) { // check if the OSD circle was clicked - GValue value = { 0 }; + GValue value = { + 0, + }; g_object_get_property((GObject*) lib->osd, "osd-x", &value); const gint osd_x = g_value_get_int(&value); @@ -2138,52 +2098,46 @@ static void _view_map_click_pressed_cb(GtkGestureSingle *gesture, g_object_get_property((GObject*) lib->osd, "dpad-radius", &value); const gint dpad_radius = g_value_get_int(&value); g_object_get_property((GObject*) lib->osd, "show-zoom", &value); + // g_value_get_boolean returns FALSE although the value is 1! Bug? const gint show_zoom = g_value_get_int(&value); - const gint zoom_height = show_zoom ? 40 : 0; + const gint zoom_height = show_zoom? 40:0; - if(x >= osd_x && x <= osd_x + 2 * dpad_radius - && y >= osd_y && y <= osd_y + 2 * dpad_radius + zoom_height) + if(e->x >= osd_x && e->x <= osd_x+2*dpad_radius && + e->y >= osd_y && e->y <= osd_y+2*dpad_radius+zoom_height) { - return; + return FALSE; } } - if(gtk_gesture_single_get_button(gesture) == GDK_BUTTON_PRIMARY) + if(e->button == GDK_BUTTON_PRIMARY) { - // check if the click was in a location form - ctrl gives priority to images + // check if the click was in a location form - crtl gives priority to images if(lib->loc.main.id > 0 && (lib->loc.main.data.shape != MAP_LOCATION_SHAPE_POLYGONS) - && !dt_modifier_is(state, GDK_CONTROL_MASK)) + && !dt_modifier_is(e->state, GDK_CONTROL_MASK)) { - OsmGpsMapPoint *p = osm_gps_map_point_new_degrees(0.0, 0.0); - osm_gps_map_convert_screen_to_geographic(lib->map, x, y, p); + + OsmGpsMapPoint *p = osm_gps_map_get_event_location(lib->map, e); float lat, lon; osm_gps_map_point_get_degrees(p, &lat, &lon); - osm_gps_map_point_free(p); if(dt_map_location_included(lon, lat, &lib->loc.main.data)) { - if(!dt_modifier_is(state, GDK_SHIFT_MASK)) + if(!dt_modifier_is(e->state, GDK_SHIFT_MASK)) { - GdkDisplay *display = gtk_widget_get_display(GTK_WIDGET(lib->map)); - GdkDevice *pointer = gdk_seat_get_pointer(gdk_display_get_default_seat(display)); - gint root_x, root_y; - gdk_device_get_position(pointer, NULL, &root_x, &root_y); - lib->start_drag_x = root_x; - lib->start_drag_y = root_y; + lib->start_drag_x = ceil(e->x_root); + lib->start_drag_y = ceil(e->y_root); lib->loc.drag = TRUE; - return; + return TRUE; } } } // check if another location is clicked - ctrl gives priority to images - if(!dt_modifier_is(state, GDK_CONTROL_MASK) - && dt_conf_get_bool("plugins/map/showalllocations")) + if(!dt_modifier_is(e->state, GDK_CONTROL_MASK) && + dt_conf_get_bool("plugins/map/showalllocations")) { - OsmGpsMapPoint *p = osm_gps_map_point_new_degrees(0.0, 0.0); - osm_gps_map_convert_screen_to_geographic(lib->map, x, y, p); + OsmGpsMapPoint *p = osm_gps_map_get_event_location(lib->map, e); float lat, lon; osm_gps_map_point_get_degrees(p, &lat, &lon); - osm_gps_map_point_free(p); for(GList *other = lib->loc.others; other; other = g_list_next(other)) @@ -2200,42 +2154,44 @@ static void _view_map_click_pressed_cb(GtkGestureSingle *gesture, G_CALLBACK(_view_map_collection_changed), self); dt_control_signal_unblock_by_func(darktable.signals, G_CALLBACK(_view_map_geotag_changed), self); - return; + return TRUE; } } } // check if the click was on image(s) or just some random position lib->selected_images = - _view_map_get_imgs_at_pos(self, x, y, + _view_map_get_imgs_at_pos(self, e->x, e->y, &lib->start_drag_offset_x, &lib->start_drag_offset_y, - !dt_modifier_is(state, GDK_SHIFT_MASK)); - if(n_press == 1) + !dt_modifier_is(e->state, GDK_SHIFT_MASK)); + if(e->type == GDK_BUTTON_PRESS) { if(lib->selected_images) { - GdkDisplay *display = gtk_widget_get_display(GTK_WIDGET(lib->map)); - GdkDevice *pointer = gdk_seat_get_pointer(gdk_display_get_default_seat(display)); - gint root_x, root_y; - gdk_device_get_position(pointer, NULL, &root_x, &root_y); - lib->start_drag_x = root_x; - lib->start_drag_y = root_y; + lib->start_drag_x = ceil(e->x_root); + lib->start_drag_y = ceil(e->y_root); lib->start_drag = TRUE; + return TRUE; + } + else + { + return FALSE; } } - else if(n_press == 2) + if(e->type == GDK_2BUTTON_PRESS) { if(lib->selected_images) { // open the image in darkroom dt_control_set_mouse_over_id(GPOINTER_TO_INT(lib->selected_images->data)); dt_ctl_switch_mode_to("darkroom"); + return TRUE; } else { // zoom into that position float longitude, latitude; OsmGpsMapPoint *pt = osm_gps_map_point_new_degrees(0.0, 0.0); - osm_gps_map_convert_screen_to_geographic(lib->map, x, y, pt); + osm_gps_map_convert_screen_to_geographic(lib->map, e->x, e->y, pt); osm_gps_map_point_get_degrees(pt, &latitude, &longitude); osm_gps_map_point_free(pt); int zoom, max_zoom; @@ -2243,21 +2199,22 @@ static void _view_map_click_pressed_cb(GtkGestureSingle *gesture, zoom = MIN(zoom + 1, max_zoom); _view_map_center_on_location(self, longitude, latitude, zoom); } + return TRUE; } } + return FALSE; } -static void _view_map_click_released_cb(GtkGestureSingle *gesture, - int n_press, - double x, - double y, - dt_view_t *self) +static gboolean _view_map_button_release_callback(GtkWidget *w, + GdkEventButton *e, + dt_view_t *self) { dt_map_t *lib = self->data; lib->start_drag = FALSE; lib->start_drag_offset_x = 0; lib->start_drag_offset_y = 0; lib->loc.drag = FALSE; + return FALSE; } static gboolean _view_map_display_selected(const gpointer user_data) From d5fcd1bfb989a9b63cbd35e11e80f391f3f5e073 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 15:31:49 -0300 Subject: [PATCH 66/95] Revert "gtk4-prep: revert map view to signal-based event handling (OsmGpsMap incompatible with gesture controllers)" This reverts commit 4f60af58506deb51054cd1e1826b88759ef56905. --- src/views/map.c | 347 +++++++++++++++++++++++++++--------------------- 1 file changed, 195 insertions(+), 152 deletions(-) diff --git a/src/views/map.c b/src/views/map.c index 047f6bd1f46..65d27918654 100644 --- a/src/views/map.c +++ b/src/views/map.c @@ -213,20 +213,26 @@ static void _view_map_dnd_get_callback(GtkWidget *widget, static void _view_map_changed_callback(OsmGpsMap *map, dt_view_t *self); /* callback that handles mouse scroll */ -static gboolean _view_map_scroll_event(GtkWidget *w, - GdkEventScroll *event, - dt_view_t *self); +static void _view_map_scroll_cb(GtkEventControllerScroll *controller, + gdouble dx, + gdouble dy, + dt_view_t *self); /* callback that handles clicks on the map */ -static gboolean _view_map_button_press_callback(GtkWidget *w, - GdkEventButton *e, - dt_view_t *self); -static gboolean _view_map_button_release_callback(GtkWidget *w, - GdkEventButton *e, - dt_view_t *self); +static void _view_map_click_pressed_cb(GtkGestureSingle *gesture, + int n_press, + double x, + double y, + dt_view_t *self); +static void _view_map_click_released_cb(GtkGestureSingle *gesture, + int n_press, + double x, + double y, + dt_view_t *self); /* callback when the mouse is moved */ -static gboolean _view_map_motion_notify_callback(GtkWidget *w, - GdkEventMotion *e, - dt_view_t *self); +static void _view_map_motion_cb(GtkEventControllerMotion *controller, + gdouble x, + gdouble y, + dt_view_t *self); static gboolean _view_map_drag_motion_callback(GtkWidget *widget, GdkDragContext *dc, const gint x, @@ -767,8 +773,10 @@ void init(dt_view_t *self) gtk_drag_dest_set(GTK_WIDGET(lib->map), GTK_DEST_DEFAULT_ALL, target_list_internal, n_targets_internal, GDK_ACTION_MOVE); - g_signal_connect(GTK_WIDGET(lib->map), "scroll-event", - G_CALLBACK(_view_map_scroll_event), self); + dt_gui_connect_scroll(GTK_WIDGET(lib->map), + GTK_EVENT_CONTROLLER_SCROLL_VERTICAL + | GTK_EVENT_CONTROLLER_SCROLL_DISCRETE, + _view_map_scroll_cb, self); g_signal_connect(GTK_WIDGET(lib->map), "drag-data-received", G_CALLBACK(_drag_and_drop_received), self); g_signal_connect(GTK_WIDGET(lib->map), "drag-data-get", @@ -778,13 +786,8 @@ void init(dt_view_t *self) g_signal_connect(GTK_WIDGET(lib->map), "changed", G_CALLBACK(_view_map_changed_callback), self); - g_signal_connect_after(G_OBJECT(lib->map), "button-press-event", - G_CALLBACK(_view_map_button_press_callback), self); - g_signal_connect_after(G_OBJECT(lib->map), "button-release-event", - G_CALLBACK(_view_map_button_release_callback), self); - g_signal_connect(G_OBJECT(lib->map), "motion-notify-event", - G_CALLBACK(_view_map_motion_notify_callback), - self); + dt_gui_connect_click(lib->map, _view_map_click_pressed_cb, _view_map_click_released_cb, self); + dt_gui_connect_motion(lib->map, _view_map_motion_cb, NULL, NULL, self); g_signal_connect(G_OBJECT(lib->map), "drag-motion", G_CALLBACK(_view_map_drag_motion_callback), self); @@ -1850,91 +1853,110 @@ static gboolean _view_map_drag_motion_callback(GtkWidget *widget, return FALSE; } -static gboolean _view_map_motion_notify_callback(GtkWidget *widget, - GdkEventMotion *e, - dt_view_t *self) +static void _view_map_motion_cb(GtkEventControllerMotion *controller, + gdouble x, + gdouble y, + dt_view_t *self) { dt_map_t *lib = self->data; - OsmGpsMapPoint *p = osm_gps_map_get_event_location(lib->map, (GdkEventButton *)e); - float lat, lon; - osm_gps_map_point_get_degrees(p, &lat, &lon); - _toast_log_lat_lon(lat, lon); + GdkEvent *event = gtk_get_current_event(); - if(lib->loc.drag - && lib->loc.main.id > 0 - && (abs(lib->start_drag_x - (int)ceil(e->x_root)) + - abs(lib->start_drag_y - (int)ceil(e->y_root))) > DT_PIXEL_APPLY_DPI(8)) - { - lib->loc.drag = FALSE; - osm_gps_map_image_remove(lib->map, lib->loc.main.location); - GtkTargetList *targets = gtk_target_list_new(target_list_internal, n_targets_internal); - - GdkDragContext *context = - gtk_drag_begin_with_coordinates(GTK_WIDGET(lib->map), targets, - GDK_ACTION_MOVE, 1, - (GdkEvent *)e, -1, -1); - - int width; - int height; - GdkPixbuf *location = _draw_location(lib, &width, &height, &lib->loc.main.data, TRUE); - if(location) - { - GtkWidget *image = gtk_image_new_from_pixbuf(location); - dt_gui_add_class(image, "dt_transparent_background"); - gtk_widget_set_name(image, "map-drag-icon"); - gtk_widget_show(image); - gtk_drag_set_icon_widget(context, image, - DT_PIXEL_APPLY_DPI(width), - DT_PIXEL_APPLY_DPI(height)); - g_object_unref(location); - } - gtk_target_list_unref(targets); - return TRUE; + if(event) + { + OsmGpsMapPoint *p = osm_gps_map_point_new_degrees(0.0, 0.0); + osm_gps_map_convert_screen_to_geographic(lib->map, x, y, p); + float lat, lon; + osm_gps_map_point_get_degrees(p, &lat, &lon); + osm_gps_map_point_free(p); + _toast_log_lat_lon(lat, lon); + } + + if(event && lib->loc.drag + && lib->loc.main.id > 0) + { + gdouble root_x, root_y; + gdk_event_get_root_coords(event, &root_x, &root_y); + if((abs(lib->start_drag_x - (int)ceil(root_x)) + + abs(lib->start_drag_y - (int)ceil(root_y))) > DT_PIXEL_APPLY_DPI(8)) + { + lib->loc.drag = FALSE; + osm_gps_map_image_remove(lib->map, lib->loc.main.location); + GtkTargetList *targets = gtk_target_list_new(target_list_internal, n_targets_internal); + + GdkDragContext *context = + gtk_drag_begin_with_coordinates(GTK_WIDGET(lib->map), targets, + GDK_ACTION_MOVE, 1, + event, -1, -1); + + int width; + int height; + GdkPixbuf *location = _draw_location(lib, &width, &height, &lib->loc.main.data, TRUE); + if(location) + { + GtkWidget *image = gtk_image_new_from_pixbuf(location); + dt_gui_add_class(image, "dt_transparent_background"); + gtk_widget_set_name(image, "map-drag-icon"); + gtk_widget_show(image); + gtk_drag_set_icon_widget(context, image, + DT_PIXEL_APPLY_DPI(width), + DT_PIXEL_APPLY_DPI(height)); + g_object_unref(location); + } + gtk_target_list_unref(targets); + gdk_event_free(event); + return; + } } - if(lib->start_drag - && lib->selected_images - && (abs(lib->start_drag_x - (int)ceil(e->x_root)) + - abs(lib->start_drag_y - (int)ceil(e->y_root))) > DT_PIXEL_APPLY_DPI(8)) + if(event && lib->start_drag + && lib->selected_images) { - const int nb = g_list_length(lib->selected_images); - for(const GSList *iter = lib->images; - iter; - iter = g_slist_next(iter)) + gdouble root_x, root_y; + gdk_event_get_root_coords(event, &root_x, &root_y); + if((abs(lib->start_drag_x - (int)ceil(root_x)) + + abs(lib->start_drag_y - (int)ceil(root_y))) > DT_PIXEL_APPLY_DPI(8)) { - dt_map_image_t *entry = iter->data; - if(entry->image) + const int nb = g_list_length(lib->selected_images); + for(const GSList *iter = lib->images; + iter; + iter = g_slist_next(iter)) { - const GList *sel_img = lib->selected_images; - if(entry->imgid == GPOINTER_TO_INT(sel_img->data)) + dt_map_image_t *entry = iter->data; + if(entry->image) { - if(entry->group_count == nb) + const GList *sel_img = lib->selected_images; + if(entry->imgid == GPOINTER_TO_INT(sel_img->data)) { - osm_gps_map_image_remove(lib->map, entry->image); - entry->image = NULL; + if(entry->group_count == nb) + { + osm_gps_map_image_remove(lib->map, entry->image); + entry->image = NULL; + } + else + _display_next_image(self, entry, TRUE); + break; } - else - _display_next_image(self, entry, TRUE); - break; } } - } - const int group_count = g_list_length(lib->selected_images); + const int group_count = g_list_length(lib->selected_images); - lib->start_drag = FALSE; - GtkTargetList *targets = gtk_target_list_new(target_list_all, n_targets_all); - GdkDragContext *context = gtk_drag_begin_with_coordinates(GTK_WIDGET(lib->map), targets, - GDK_ACTION_MOVE, 1, - (GdkEvent *)e, -1, -1); - _view_map_drag_set_icon(self, context, GPOINTER_TO_INT(lib->selected_images->data), - group_count); - gtk_target_list_unref(targets); - return TRUE; + lib->start_drag = FALSE; + GtkTargetList *targets = gtk_target_list_new(target_list_all, n_targets_all); + GdkDragContext *context = gtk_drag_begin_with_coordinates(GTK_WIDGET(lib->map), targets, + GDK_ACTION_MOVE, 1, + event, -1, -1); + _view_map_drag_set_icon(self, context, GPOINTER_TO_INT(lib->selected_images->data), + group_count); + gtk_target_list_unref(targets); + gdk_event_free(event); + return; + } } + if(event) gdk_event_free(event); - dt_map_image_t *entry = _view_map_get_entry_at_pos(self, e->x, e->y); + dt_map_image_t *entry = _view_map_get_entry_at_pos(self, x, y); if(entry) { // show image information if image is hovered @@ -1944,7 +1966,7 @@ static gboolean _view_map_motion_notify_callback(GtkWidget *widget, { _view_map_draw_image(entry, TRUE, DT_MAP_THUMB_THUMB, self); lib->last_hovered_entry = entry; - return TRUE; + return; } } else @@ -1957,7 +1979,6 @@ static gboolean _view_map_motion_notify_callback(GtkWidget *widget, lib->last_hovered_entry = NULL; } } - return FALSE; } static gboolean _zoom_and_center(const gint x, @@ -2003,38 +2024,54 @@ static gboolean _zoom_and_center(const gint x, return TRUE; } -static gboolean _view_map_scroll_event(GtkWidget *w, - GdkEventScroll *event, - dt_view_t *self) +static void _view_map_scroll_cb(GtkEventControllerScroll *controller, + gdouble dx, + gdouble dy, + dt_view_t *self) { dt_map_t *lib = self->data; - // check if the click was on image(s) or just some random position - dt_map_image_t *entry = _view_map_get_entry_at_pos(self, dt_gdk_event_get_x(event), dt_gdk_event_get_y(event)); + + // get the current event for position and modifier state + GdkEvent *event = gtk_get_current_event(); + if(!event) return; + gdouble x, y; + GdkModifierType state; + gdk_event_get_coords(event, &x, &y); + gdk_event_get_state(event, &state); + gdk_event_free(event); + + // determine scroll direction from dy + const gboolean scroll_down = dy > 0; + const gboolean scroll_up = dy < 0; + + // check if the scroll was on image(s) or just some random position + dt_map_image_t *entry = _view_map_get_entry_at_pos(self, x, y); if(entry) { - if(_display_next_image(self, entry, dt_gdk_event_get_scroll_direction(event) == GDK_SCROLL_DOWN)) - return TRUE; + if(_display_next_image(self, entry, scroll_down)) + return; } - OsmGpsMapPoint *p = osm_gps_map_get_event_location(lib->map, (GdkEventButton *)event); + OsmGpsMapPoint *p = osm_gps_map_point_new_degrees(0.0, 0.0); + osm_gps_map_convert_screen_to_geographic(lib->map, x, y, p); float lat, lon; osm_gps_map_point_get_degrees(p, &lat, &lon); + osm_gps_map_point_free(p); + if(lib->loc.main.id > 0) { - const gboolean increase = dt_gdk_event_get_scroll_direction(event) == GDK_SCROLL_UP - || dt_gdk_event_get_scroll_direction(event) == GDK_SCROLL_RIGHT; - const gboolean decrease = dt_gdk_event_get_scroll_direction(event) == GDK_SCROLL_DOWN - || dt_gdk_event_get_scroll_direction(event) == GDK_SCROLL_LEFT; + const gboolean increase = scroll_up; + const gboolean decrease = scroll_down; if(dt_map_location_included(lon, lat, &lib->loc.main.data)) { - if(dt_modifier_is(dt_gdk_event_get_state(event), GDK_SHIFT_MASK)) + if(dt_modifier_is(state, GDK_SHIFT_MASK)) { if(increase) lib->loc.main.data.delta1 *= 1.1; else if(decrease) lib->loc.main.data.delta1 /= 1.1; } - else if(dt_modifier_is(dt_gdk_event_get_state(event), GDK_CONTROL_MASK)) + else if(dt_modifier_is(state, GDK_CONTROL_MASK)) { if(increase) lib->loc.main.data.delta2 *= 1.1; @@ -2048,7 +2085,7 @@ static gboolean _view_map_scroll_event(GtkWidget *w, lib->loc.main.data.delta1 *= 1.1; lib->loc.main.data.delta2 *= 1.1; } - else if (decrease) + else if(decrease) { lib->loc.main.data.delta1 /= 1.1; lib->loc.main.data.delta2 /= 1.1; @@ -2057,27 +2094,32 @@ static gboolean _view_map_scroll_event(GtkWidget *w, _view_map_draw_main_location(lib, &lib->loc.main); _view_map_update_location_geotag(self); _view_map_signal_change_wait(self, 3); // wait 3/10 sec after last scroll - return TRUE; + return; } else // scroll on the map. try to keep the map where it is { _toast_log_lat_lon(lat, lon); - return _zoom_and_center(dt_gdk_event_get_x(event), dt_gdk_event_get_y(event), dt_gdk_event_get_scroll_direction(event), self); + _zoom_and_center(x, y, scroll_up ? GDK_SCROLL_UP : GDK_SCROLL_DOWN, self); + return; } } else { _toast_log_lat_lon(lat, lon); - return _zoom_and_center(dt_gdk_event_get_x(event), dt_gdk_event_get_y(event), dt_gdk_event_get_scroll_direction(event), self); + _zoom_and_center(x, y, scroll_up ? GDK_SCROLL_UP : GDK_SCROLL_DOWN, self); } - return FALSE; } -static gboolean _view_map_button_press_callback(GtkWidget *w, - GdkEventButton *e, - dt_view_t *self) +static void _view_map_click_pressed_cb(GtkGestureSingle *gesture, + int n_press, + double x, + double y, + dt_view_t *self) { dt_map_t *lib = self->data; + GdkModifierType state; + gtk_get_current_event_state(&state); + if(lib->selected_images) { g_list_free(lib->selected_images); @@ -2087,9 +2129,7 @@ static gboolean _view_map_button_press_callback(GtkWidget *w, if(lib->osd) { // check if the OSD circle was clicked - GValue value = { - 0, - }; + GValue value = { 0 }; g_object_get_property((GObject*) lib->osd, "osd-x", &value); const gint osd_x = g_value_get_int(&value); @@ -2098,46 +2138,52 @@ static gboolean _view_map_button_press_callback(GtkWidget *w, g_object_get_property((GObject*) lib->osd, "dpad-radius", &value); const gint dpad_radius = g_value_get_int(&value); g_object_get_property((GObject*) lib->osd, "show-zoom", &value); - // g_value_get_boolean returns FALSE although the value is 1! Bug? const gint show_zoom = g_value_get_int(&value); - const gint zoom_height = show_zoom? 40:0; + const gint zoom_height = show_zoom ? 40 : 0; - if(e->x >= osd_x && e->x <= osd_x+2*dpad_radius && - e->y >= osd_y && e->y <= osd_y+2*dpad_radius+zoom_height) + if(x >= osd_x && x <= osd_x + 2 * dpad_radius + && y >= osd_y && y <= osd_y + 2 * dpad_radius + zoom_height) { - return FALSE; + return; } } - if(e->button == GDK_BUTTON_PRIMARY) + if(gtk_gesture_single_get_button(gesture) == GDK_BUTTON_PRIMARY) { - // check if the click was in a location form - crtl gives priority to images + // check if the click was in a location form - ctrl gives priority to images if(lib->loc.main.id > 0 && (lib->loc.main.data.shape != MAP_LOCATION_SHAPE_POLYGONS) - && !dt_modifier_is(e->state, GDK_CONTROL_MASK)) + && !dt_modifier_is(state, GDK_CONTROL_MASK)) { - - OsmGpsMapPoint *p = osm_gps_map_get_event_location(lib->map, e); + OsmGpsMapPoint *p = osm_gps_map_point_new_degrees(0.0, 0.0); + osm_gps_map_convert_screen_to_geographic(lib->map, x, y, p); float lat, lon; osm_gps_map_point_get_degrees(p, &lat, &lon); + osm_gps_map_point_free(p); if(dt_map_location_included(lon, lat, &lib->loc.main.data)) { - if(!dt_modifier_is(e->state, GDK_SHIFT_MASK)) + if(!dt_modifier_is(state, GDK_SHIFT_MASK)) { - lib->start_drag_x = ceil(e->x_root); - lib->start_drag_y = ceil(e->y_root); + GdkDisplay *display = gtk_widget_get_display(GTK_WIDGET(lib->map)); + GdkDevice *pointer = gdk_seat_get_pointer(gdk_display_get_default_seat(display)); + gint root_x, root_y; + gdk_device_get_position(pointer, NULL, &root_x, &root_y); + lib->start_drag_x = root_x; + lib->start_drag_y = root_y; lib->loc.drag = TRUE; - return TRUE; + return; } } } // check if another location is clicked - ctrl gives priority to images - if(!dt_modifier_is(e->state, GDK_CONTROL_MASK) && - dt_conf_get_bool("plugins/map/showalllocations")) + if(!dt_modifier_is(state, GDK_CONTROL_MASK) + && dt_conf_get_bool("plugins/map/showalllocations")) { - OsmGpsMapPoint *p = osm_gps_map_get_event_location(lib->map, e); + OsmGpsMapPoint *p = osm_gps_map_point_new_degrees(0.0, 0.0); + osm_gps_map_convert_screen_to_geographic(lib->map, x, y, p); float lat, lon; osm_gps_map_point_get_degrees(p, &lat, &lon); + osm_gps_map_point_free(p); for(GList *other = lib->loc.others; other; other = g_list_next(other)) @@ -2154,44 +2200,42 @@ static gboolean _view_map_button_press_callback(GtkWidget *w, G_CALLBACK(_view_map_collection_changed), self); dt_control_signal_unblock_by_func(darktable.signals, G_CALLBACK(_view_map_geotag_changed), self); - return TRUE; + return; } } } // check if the click was on image(s) or just some random position lib->selected_images = - _view_map_get_imgs_at_pos(self, e->x, e->y, + _view_map_get_imgs_at_pos(self, x, y, &lib->start_drag_offset_x, &lib->start_drag_offset_y, - !dt_modifier_is(e->state, GDK_SHIFT_MASK)); - if(e->type == GDK_BUTTON_PRESS) + !dt_modifier_is(state, GDK_SHIFT_MASK)); + if(n_press == 1) { if(lib->selected_images) { - lib->start_drag_x = ceil(e->x_root); - lib->start_drag_y = ceil(e->y_root); + GdkDisplay *display = gtk_widget_get_display(GTK_WIDGET(lib->map)); + GdkDevice *pointer = gdk_seat_get_pointer(gdk_display_get_default_seat(display)); + gint root_x, root_y; + gdk_device_get_position(pointer, NULL, &root_x, &root_y); + lib->start_drag_x = root_x; + lib->start_drag_y = root_y; lib->start_drag = TRUE; - return TRUE; - } - else - { - return FALSE; } } - if(e->type == GDK_2BUTTON_PRESS) + else if(n_press == 2) { if(lib->selected_images) { // open the image in darkroom dt_control_set_mouse_over_id(GPOINTER_TO_INT(lib->selected_images->data)); dt_ctl_switch_mode_to("darkroom"); - return TRUE; } else { // zoom into that position float longitude, latitude; OsmGpsMapPoint *pt = osm_gps_map_point_new_degrees(0.0, 0.0); - osm_gps_map_convert_screen_to_geographic(lib->map, e->x, e->y, pt); + osm_gps_map_convert_screen_to_geographic(lib->map, x, y, pt); osm_gps_map_point_get_degrees(pt, &latitude, &longitude); osm_gps_map_point_free(pt); int zoom, max_zoom; @@ -2199,22 +2243,21 @@ static gboolean _view_map_button_press_callback(GtkWidget *w, zoom = MIN(zoom + 1, max_zoom); _view_map_center_on_location(self, longitude, latitude, zoom); } - return TRUE; } } - return FALSE; } -static gboolean _view_map_button_release_callback(GtkWidget *w, - GdkEventButton *e, - dt_view_t *self) +static void _view_map_click_released_cb(GtkGestureSingle *gesture, + int n_press, + double x, + double y, + dt_view_t *self) { dt_map_t *lib = self->data; lib->start_drag = FALSE; lib->start_drag_offset_x = 0; lib->start_drag_offset_y = 0; lib->loc.drag = FALSE; - return FALSE; } static gboolean _view_map_display_selected(const gpointer user_data) From 0e5ab0dbb2c3ee9abe17098e9bd3ba2b36fe76a7 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 15:34:35 -0300 Subject: [PATCH 67/95] gtk4-prep: use CAPTURE phase for map view gesture controllers (OsmGpsMap uses widget class vfuncs, not GtkGesture) --- src/views/map.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/src/views/map.c b/src/views/map.c index 65d27918654..2676ee17a2a 100644 --- a/src/views/map.c +++ b/src/views/map.c @@ -786,8 +786,28 @@ void init(dt_view_t *self) g_signal_connect(GTK_WIDGET(lib->map), "changed", G_CALLBACK(_view_map_changed_callback), self); - dt_gui_connect_click(lib->map, _view_map_click_pressed_cb, _view_map_click_released_cb, self); - dt_gui_connect_motion(lib->map, _view_map_motion_cb, NULL, NULL, self); + /* OsmGpsMap uses widget class vfuncs (button_press_event, + * motion_notify_event) for its event handling — not GtkGesture. + * In GTK3, the vfunc fires AFTER CAPTURE controllers and BEFORE + * BUBBLE controllers on the same widget. If the vfunc returns + * TRUE (event consumed), BUBBLE controllers never fire, which + * is why BUBBLE phase doesn't work here. + * + * Use CAPTURE phase so our controllers run first. We don't + * claim the sequence, so the event continues to the widget class + * vfunc and the map handles it normally. */ + { + GtkGestureSingle *g + = dt_gui_connect_click(lib->map, _view_map_click_pressed_cb, + _view_map_click_released_cb, self); + gtk_event_controller_set_propagation_phase( + GTK_EVENT_CONTROLLER(g), GTK_PHASE_CAPTURE); + } + { + GtkEventController *m + = dt_gui_connect_motion(lib->map, _view_map_motion_cb, NULL, NULL, self); + gtk_event_controller_set_propagation_phase(m, GTK_PHASE_CAPTURE); + } g_signal_connect(G_OBJECT(lib->map), "drag-motion", G_CALLBACK(_view_map_drag_motion_callback), self); From 8387193eae83c2828ca6e2b2c4548a87368d0afc Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 15:51:10 -0300 Subject: [PATCH 68/95] gtk4-prep: fix event controller bugs in bauhaus popup - Replace gtk_gesture_single_get_button() with _get_current_button() in _popup_button_press_cb and _popup_button_release_cb. The gesture uses click_all (button=0), so get_button() always returns 0, making all button-type checks silently dead. - Restore window validation guard that was dropped during conversion: reject events whose GdkWindow doesn't match the popup area widget. - Restore BUTTON1_MASK injection on the forwarded motion state, needed for the correct motion tolerance calculation (400 vs 50px). - Restore dt_gui_get_scroll_unit_deltas() usage in _popup_scroll_cb to accumulate smooth-scroll events properly instead of truncating fractional deltas to zero. --- src/bauhaus/bauhaus.c | 49 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 44 insertions(+), 5 deletions(-) diff --git a/src/bauhaus/bauhaus.c b/src/bauhaus/bauhaus.c index b6ba9bdc7fc..c3d02be1865 100644 --- a/src/bauhaus/bauhaus.c +++ b/src/bauhaus/bauhaus.c @@ -534,13 +534,37 @@ static void _popup_scroll_cb(GtkEventControllerScroll *controller, if(w->type == DT_BAUHAUS_COMBOBOX) { // match keyboard: right & down -> next - const int delta = fabs(dx) > fabs(dy) ? (int)dx : (int)dy; + int delta_x = 0, delta_y = 0; + GdkEvent *event = gtk_get_current_event(); + if(event) + { + dt_gui_get_scroll_unit_deltas((const GdkEventScroll *)event, &delta_x, &delta_y); + gdk_event_free(event); + } + else + { + // fallback: use raw values if no current event + delta_x = (int)dx; + delta_y = (int)dy; + } + const int delta = abs(delta_x) > abs(delta_y) ? delta_x : delta_y; if(delta != 0) _combobox_next_sensitive(w, delta, 0, w->combobox.mute_scrolling); } else { - _slider_zoom_range(w, -(int)dy); + int delta = 0; + GdkEvent *event = gtk_get_current_event(); + if(event) + { + dt_gui_get_scroll_unit_delta((const GdkEventScroll *)event, &delta); + gdk_event_free(event); + } + else + { + delta = -(int)dy; + } + _slider_zoom_range(w, delta); } } @@ -716,7 +740,7 @@ static void _popup_button_release_cb(GtkGestureSingle *gesture, gdouble y, gpointer user_data) { - if(darktable.bauhaus->change_active && gtk_gesture_single_get_button(gesture) != GDK_BUTTON_MIDDLE) + if(darktable.bauhaus->change_active && gtk_gesture_single_get_current_button(gesture) != GDK_BUTTON_MIDDLE) _popup_hide(); } @@ -728,7 +752,20 @@ static void _popup_button_press_cb(GtkGestureSingle *gesture, { dt_bauhaus_t *bh = darktable.bauhaus; dt_bauhaus_widget_t *w = bh->current; - const guint button = gtk_gesture_single_get_button(gesture); + const guint button = gtk_gesture_single_get_current_button(gesture); + + // reject clicks that come from outside the popup area window + GdkEvent *cur_event = gtk_get_current_event(); + if(cur_event) + { + if(dt_gdk_event_get_window(cur_event) != gtk_widget_get_window(gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)))) + { + gdk_event_free(cur_event); + _popup_reject(); + return; + } + gdk_event_free(cur_event); + } if(button == GDK_BUTTON_PRIMARY) { @@ -753,10 +790,12 @@ static void _popup_button_press_cb(GtkGestureSingle *gesture, GdkEvent *current_event = gtk_get_current_event(); if(current_event) { + GdkModifierType motion_state = dt_gdk_event_get_state(current_event); + motion_state |= GDK_BUTTON1_MASK; _window_motion_handle(w_current, dt_gdk_event_get_root_x(current_event), dt_gdk_event_get_root_y(current_event), - dt_gdk_event_get_state(current_event)); + motion_state); gdk_event_free(current_event); } } From df1108b2814e2ad3608e24236960ac414b3d1445 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 15:51:13 -0300 Subject: [PATCH 69/95] gtk4-prep: fix get_button vs get_current_button in range widget Replace gtk_gesture_single_get_button() with _get_current_button() in _event_band_press_cb and _event_entry_press_cb. Both callbacks are connected via click_all (button=0), so get_button() always returns 0, making drag, double-click reset, and right-click popup all non-functional. --- src/dtgtk/range.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dtgtk/range.c b/src/dtgtk/range.c index 89f11d50a32..342f8b07b12 100644 --- a/src/dtgtk/range.c +++ b/src/dtgtk/range.c @@ -1184,7 +1184,7 @@ static void _popup_show(GtkDarktableRangeSelect *range, GtkWidget *w) static void _event_entry_press_cb(GtkGestureSingle *gesture, int n_press, double x, double y, GtkDarktableRangeSelect *range) { GtkWidget *w = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); - if(gtk_gesture_single_get_button(gesture) == GDK_BUTTON_SECONDARY) + if(gtk_gesture_single_get_current_button(gesture) == GDK_BUTTON_SECONDARY) { _popup_show(range, w); } @@ -1566,7 +1566,7 @@ static void _event_band_leave_cb(GtkEventControllerMotion *controller, GtkDarkta static void _event_band_press_cb(GtkGestureSingle *gesture, int n_press, double x, double y, GtkDarktableRangeSelect *range) { - const guint button = gtk_gesture_single_get_button(gesture); + const guint button = gtk_gesture_single_get_current_button(gesture); GdkModifierType state; gtk_get_current_event_state(&state); From 40ced199c5d1dca4530d452c6b082c1c96fd2bc0 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 15:51:17 -0300 Subject: [PATCH 70/95] gtk4-prep: fix memory leak in colorequal scroll callback _area_scrolled_callback calls gtk_get_current_event() but never frees the returned event, leaking one GdkEvent per scroll event in the colorequal graph. --- src/iop/colorequal.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/iop/colorequal.c b/src/iop/colorequal.c index 028e6a2e299..14cf8eccda3 100644 --- a/src/iop/colorequal.c +++ b/src/iop/colorequal.c @@ -2711,6 +2711,7 @@ static void _area_scrolled_callback(GtkEventControllerScroll *controller, ? GTK_WIDGET(g->notebook) : _get_slider(g, g->selected); gtk_widget_event(w, event); + gdk_event_free(event); } static void _area_motion_notify_callback(GtkEventControllerMotion *controller, From 51c71a8b75c104f4f53029bce15d7d7e13bef8ef Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 15:51:21 -0300 Subject: [PATCH 71/95] gtk4-prep: restore GDK_BUTTON_PRIMARY guards in blend GUI Both _blendop_blendif_showmask_clicked and _blendop_masks_modes_none_clicked lost their GDK_BUTTON_PRIMARY checks during the event controller conversion. These callbacks are connected via dt_iop_togglebutton_new which uses a gesture with button=0 (all buttons), so non-primary clicks would incorrectly trigger mask display toggles and mask mode changes. --- src/develop/blend_gui.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/develop/blend_gui.c b/src/develop/blend_gui.c index 4a3410315f6..ba69c65e438 100644 --- a/src/develop/blend_gui.c +++ b/src/develop/blend_gui.c @@ -1358,6 +1358,8 @@ static void _blendop_blendif_showmask_clicked(GtkGestureSingle *gesture, { DT_GUARD_GUI_UPDATE(); + if(gtk_gesture_single_get_current_button(gesture) != GDK_BUTTON_PRIMARY) return; + GtkWidget *button = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); const gboolean has_mask_display = @@ -1414,7 +1416,8 @@ static void _blendop_masks_modes_none_clicked(GtkGestureSingle *gesture, GtkWidget *button = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); dt_iop_gui_blend_data_t *data = module->blend_data; - if(data->selected_mask_mode != button) + if(gtk_gesture_single_get_current_button(gesture) == GDK_BUTTON_PRIMARY + && data->selected_mask_mode != button) { gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data->selected_mask_mode), FALSE); // unsets currently toggled if any From ea143e3581a8d84a57ed320b7f04cfe207828a6e Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 15:51:24 -0300 Subject: [PATCH 72/95] gtk4-prep: restore smooth-scroll accumulation in preset scroller _presets_scrolled was using raw dx/dy values directly, which truncates fractional smooth-scroll deltas to zero on trackpads. Restore dt_gui_get_scroll_unit_deltas() to accumulate events until a full scroll unit is reached, with a raw-value fallback. --- src/develop/imageop.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/develop/imageop.c b/src/develop/imageop.c index 35a868ae726..575e6b52a44 100644 --- a/src/develop/imageop.c +++ b/src/develop/imageop.c @@ -2541,7 +2541,19 @@ static void _presets_scrolled(GtkEventControllerScroll *controller, if(dy == 0.0 && dx == 0.0) return; // preset cycling: right==down==next - const int delta = fabs(dx) > fabs(dy) ? dx : dy; + int delta_x = 0, delta_y = 0; + GdkEvent *event = gtk_get_current_event(); + if(event) + { + dt_gui_get_scroll_unit_deltas((const GdkEventScroll *)event, &delta_x, &delta_y); + gdk_event_free(event); + } + else + { + delta_x = (int)dx; + delta_y = (int)dy; + } + const int delta = abs(delta_x) > abs(delta_y) ? delta_x : delta_y; dt_gui_presets_apply_adjacent_preset(module, delta); } From 237246ef3bf6e368fe7cd4f3cab30ffae4eb455e Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 15:51:29 -0300 Subject: [PATCH 73/95] gtk4-prep: fix get_button vs get_current_button in lib modules Replace gtk_gesture_single_get_button() with _get_current_button() in 6 lib module callbacks that are connected via click_all (button=0): - collect: view_onButtonPressed_cb - colorpicker: _live_sample_button_cb - export: _widht_mdlclick_cb, _height_mdlclick_cb, _scale_mdlclick_cb - tagging: _click_on_view_dictionary, _click_on_view_attached - colorlabels: _lib_colorlabels_button_press_callback - masks: _tree_button_pressed_cb get_button() returns the configured button (always 0 for click_all), not the actual event button, making all button-type checks unconditionally false. --- src/libs/collect.c | 2 +- src/libs/colorpicker.c | 2 +- src/libs/export.c | 6 +++--- src/libs/masks.c | 2 +- src/libs/tagging.c | 4 ++-- src/libs/tools/colorlabels.c | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/libs/collect.c b/src/libs/collect.c index a71d176b038..924a739ac38 100644 --- a/src/libs/collect.c +++ b/src/libs/collect.c @@ -698,7 +698,7 @@ static void view_onButtonPressed_cb(GtkGestureSingle *gesture, int n_press, gtk_tree_selection_select_path(selection, path); } - const guint button = gtk_gesture_single_get_button(gesture); + const guint button = gtk_gesture_single_get_current_button(gesture); // case of a context-menu (folder/filmroll) if(((d->view_rule == DT_COLLECTION_PROP_FOLDERS) diff --git a/src/libs/colorpicker.c b/src/libs/colorpicker.c index a06f19b2b45..6aad6cd00c3 100644 --- a/src/libs/colorpicker.c +++ b/src/libs/colorpicker.c @@ -522,7 +522,7 @@ static void _live_sample_button_cb(GtkGestureSingle *gesture, dt_colorpicker_sample_t *sample) { GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); - const guint button = gtk_gesture_single_get_button(gesture); + const guint button = gtk_gesture_single_get_current_button(gesture); if(button == GDK_BUTTON_PRIMARY) { sample->locked = !sample->locked; diff --git a/src/libs/export.c b/src/libs/export.c index 6cf6263685c..980ad7e1238 100644 --- a/src/libs/export.c +++ b/src/libs/export.c @@ -572,7 +572,7 @@ static void _scale_mdlclick_cb(GtkGestureSingle *gesture, int n_press, dt_lib_export_t *d) { GtkWidget *spin = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); - if(gtk_gesture_single_get_button(gesture) == GDK_BUTTON_MIDDLE) + if(gtk_gesture_single_get_current_button(gesture) == GDK_BUTTON_MIDDLE) { dt_conf_set_string(CONFIG_PREFIX "resizing_factor", "1"); g_signal_handlers_block_by_func(spin, _scale_changed, d); @@ -590,7 +590,7 @@ static void _widht_mdlclick_cb(GtkGestureSingle *gesture, int n_press, dt_lib_export_t *d) { GtkWidget *spin = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); - if(gtk_gesture_single_get_button(gesture) == GDK_BUTTON_MIDDLE) + if(gtk_gesture_single_get_current_button(gesture) == GDK_BUTTON_MIDDLE) { dt_conf_set_int(CONFIG_PREFIX "width", 0); g_signal_handlers_block_by_func(spin, _width_changed, d); @@ -608,7 +608,7 @@ static void _height_mdlclick_cb(GtkGestureSingle *gesture, int n_press, dt_lib_export_t *d) { GtkWidget *spin = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); - if(gtk_gesture_single_get_button(gesture) == GDK_BUTTON_MIDDLE) + if(gtk_gesture_single_get_current_button(gesture) == GDK_BUTTON_MIDDLE) { dt_conf_set_int(CONFIG_PREFIX "height", 0); g_signal_handlers_block_by_func(spin, _height_changed, d); diff --git a/src/libs/masks.c b/src/libs/masks.c index d211306c7dd..10d21f3aa4c 100644 --- a/src/libs/masks.c +++ b/src/libs/masks.c @@ -1245,7 +1245,7 @@ static void _tree_button_pressed_cb(GtkGestureSingle *gesture, int n_press, doub } } /* single click with the right mouse button? */ - const guint button = gtk_gesture_single_get_button(gesture); + const guint button = gtk_gesture_single_get_current_button(gesture); if(button == GDK_BUTTON_PRIMARY) { // if click on a blank space, then deselect all diff --git a/src/libs/tagging.c b/src/libs/tagging.c index c13c444285f..b7db3796a83 100644 --- a/src/libs/tagging.c +++ b/src/libs/tagging.c @@ -1479,7 +1479,7 @@ static void _click_on_view_attached(GtkGestureSingle *gesture, GtkWidget *view = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); _unselect_all_in_view(d->dictionary_view); - const guint button = gtk_gesture_single_get_button(gesture); + const guint button = gtk_gesture_single_get_current_button(gesture); if((n_press == 1 && button == GDK_BUTTON_SECONDARY) || (n_press == 2 && button == GDK_BUTTON_PRIMARY) || (n_press == 1 && button == GDK_BUTTON_PRIMARY)) @@ -2659,7 +2659,7 @@ static void _click_on_view_dictionary(GtkGestureSingle *gesture, GdkEvent *event = gtk_get_current_event(); const GdkModifierType state = event ? dt_gdk_event_get_state(event) : 0; - const guint button = gtk_gesture_single_get_button(gesture); + const guint button = gtk_gesture_single_get_current_button(gesture); const gboolean shift_pressed = dt_modifier_is(state, GDK_SHIFT_MASK); if((button == GDK_BUTTON_SECONDARY && n_press == 1) // contextual menu || (d->tree_flag && button == GDK_BUTTON_PRIMARY && n_press == 1) // expand & drag diff --git a/src/libs/tools/colorlabels.c b/src/libs/tools/colorlabels.c index d6aed035a19..2b445c5f778 100644 --- a/src/libs/tools/colorlabels.c +++ b/src/libs/tools/colorlabels.c @@ -278,7 +278,7 @@ static void _lib_colorlabels_button_press_callback(GtkGestureSingle *gesture, in const gint colorlabel = _get_colorlabel(self, w); - if(gtk_gesture_single_get_button(gesture) == GDK_BUTTON_SECONDARY + if(gtk_gesture_single_get_current_button(gesture) == GDK_BUTTON_SECONDARY && colorlabel != 5) // The button to reset colorlabels needs no description { d->colorlabel = colorlabel; From cef1230a39a41639ee62217efa1e8a30844f69f3 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 15:54:07 -0300 Subject: [PATCH 74/95] gtk4-prep: add dt_gui_get_widget() macro and apply across all files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a short-hand macro for the verbose gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(x)) pattern that appears 156 times across 60 files. dt_gui_get_widget(x) → gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(x)) --- src/bauhaus/bauhaus.c | 10 +++++----- src/chart/main.c | 4 ++-- src/develop/blend_gui.c | 28 ++++++++++++++-------------- src/develop/imageop.c | 4 ++-- src/dtgtk/culling.c | 2 +- src/dtgtk/range.c | 2 +- src/dtgtk/resetlabel.c | 2 +- src/dtgtk/thumbnail.c | 16 ++++++++-------- src/dtgtk/thumbtable.c | 4 ++-- src/gui/accelerators.c | 4 ++-- src/gui/color_picker_proxy.c | 2 +- src/gui/gtk.c | 2 +- src/gui/gtk.h | 3 +++ src/gui/preferences.c | 4 ++-- src/gui/preferences_ai.c | 4 ++-- src/iop/ashift.c | 2 +- src/iop/atrous.c | 10 +++++----- src/iop/basecurve.c | 10 +++++----- src/iop/colorchecker.c | 4 ++-- src/iop/colorcorrection.c | 6 +++--- src/iop/colorzones.c | 10 +++++----- src/iop/denoiseprofile.c | 8 ++++---- src/iop/levels.c | 6 +++--- src/iop/liquify.c | 2 +- src/iop/lowlight.c | 8 ++++---- src/iop/lut3d.c | 2 +- src/iop/monochrome.c | 8 ++++---- src/iop/rawdenoise.c | 8 ++++---- src/iop/retouch.c | 6 +++--- src/iop/rgbcurve.c | 10 +++++----- src/iop/rgblevels.c | 6 +++--- src/iop/spots.c | 2 +- src/iop/temperature.c | 2 +- src/iop/tonecurve.c | 10 +++++----- src/iop/zonesystem.c | 6 +++--- src/libs/collect.c | 2 +- src/libs/colorpicker.c | 2 +- src/libs/duplicate.c | 2 +- src/libs/export.c | 6 +++--- src/libs/filtering.c | 6 +++--- src/libs/filters/colors.c | 2 +- src/libs/filters/filename.c | 2 +- src/libs/filters/misc.c | 2 +- src/libs/geotagging.c | 2 +- src/libs/histogram.c | 2 +- src/libs/history.c | 2 +- src/libs/import.c | 6 +++--- src/libs/lib.c | 2 +- src/libs/location.c | 4 ++-- src/libs/map_locations.c | 2 +- src/libs/masks.c | 2 +- src/libs/metadata.c | 2 +- src/libs/modulegroups.c | 10 +++++----- src/libs/navigation.c | 4 ++-- src/libs/neural_restore.c | 4 ++-- src/libs/snapshots.c | 2 +- src/libs/tagging.c | 12 ++++++------ src/libs/tools/colorlabels.c | 6 +++--- src/libs/tools/filter.c | 2 +- src/libs/tools/lighttable.c | 4 ++-- src/libs/tools/viewswitcher.c | 2 +- src/views/darkroom.c | 4 ++-- 62 files changed, 159 insertions(+), 156 deletions(-) diff --git a/src/bauhaus/bauhaus.c b/src/bauhaus/bauhaus.c index c3d02be1865..f386fc2701d 100644 --- a/src/bauhaus/bauhaus.c +++ b/src/bauhaus/bauhaus.c @@ -717,7 +717,7 @@ static void _window_motion_cb(GtkEventControllerMotion *controller, gdouble y, gpointer user_data) { - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); + GtkWidget *widget = dt_gui_get_widget(controller); GdkEvent *event = gtk_get_current_event(); if(!event) return; const gdouble root_x = dt_gdk_event_get_root_x(event); @@ -730,7 +730,7 @@ static void _window_motion_cb(GtkEventControllerMotion *controller, static void _popup_leave_notify_cb(GtkEventControllerMotion *controller, gpointer user_data) { - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); + GtkWidget *widget = dt_gui_get_widget(controller); gtk_widget_set_state_flags(widget, GTK_STATE_FLAG_NORMAL, TRUE); } @@ -758,7 +758,7 @@ static void _popup_button_press_cb(GtkGestureSingle *gesture, GdkEvent *cur_event = gtk_get_current_event(); if(cur_event) { - if(dt_gdk_event_get_window(cur_event) != gtk_widget_get_window(gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)))) + if(dt_gdk_event_get_window(cur_event) != gtk_widget_get_window(dt_gui_get_widget(gesture))) { gdk_event_free(cur_event); _popup_reject(); @@ -786,7 +786,7 @@ static void _popup_button_press_cb(GtkGestureSingle *gesture, } bh->change_active = TRUE; - GtkWidget *w_current = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + GtkWidget *w_current = dt_gui_get_widget(gesture); GdkEvent *current_event = gtk_get_current_event(); if(current_event) { @@ -3946,7 +3946,7 @@ static void _widget_button_press(GtkGestureSingle *gesture, dt_bauhaus_widget_t *w = DT_BAUHAUS_WIDGET(widget); dt_bauhaus_t *bh = darktable.bauhaus; gboolean passthrough_from_histogram = - gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)) != widget; + dt_gui_get_widget(gesture) != widget; if(!passthrough_from_histogram) { diff --git a/src/chart/main.c b/src/chart/main.c index da7cebe7877..59de32d50c1 100644 --- a/src/chart/main.c +++ b/src/chart/main.c @@ -176,7 +176,7 @@ static void _motion_cb_source(GtkEventControllerMotion *controller, gdouble y, dt_lut_t *self) { - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); + GtkWidget *widget = dt_gui_get_widget(controller); const gboolean res = handle_motion(widget, x, y, self, &self->source); if(res) { @@ -190,7 +190,7 @@ static void _motion_cb_reference(GtkEventControllerMotion *controller, gdouble y, dt_lut_t *self) { - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); + GtkWidget *widget = dt_gui_get_widget(controller); const gboolean res = handle_motion(widget, x, y, self, &self->reference); if(res) { diff --git a/src/develop/blend_gui.c b/src/develop/blend_gui.c index ba69c65e438..c6449d2788b 100644 --- a/src/develop/blend_gui.c +++ b/src/develop/blend_gui.c @@ -749,7 +749,7 @@ static void _blendop_blend_order_clicked(GtkGestureSingle *gesture, { DT_GUARD_GUI_UPDATE(); - GtkWidget *button = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + GtkWidget *button = dt_gui_get_widget(gesture); dt_develop_blend_params_t *bp = module->blend_params; const gboolean active = !(bp->blend_mode & DEVELOP_BLEND_REVERSE); @@ -1360,7 +1360,7 @@ static void _blendop_blendif_showmask_clicked(GtkGestureSingle *gesture, if(gtk_gesture_single_get_current_button(gesture) != GDK_BUTTON_PRIMARY) return; - GtkWidget *button = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + GtkWidget *button = dt_gui_get_widget(gesture); const gboolean has_mask_display = module->request_mask_display @@ -1413,7 +1413,7 @@ static void _blendop_masks_modes_none_clicked(GtkGestureSingle *gesture, dt_iop_module_t *module) { DT_GUARD_GUI_UPDATE(); - GtkWidget *button = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + GtkWidget *button = dt_gui_get_widget(gesture); dt_iop_gui_blend_data_t *data = module->blend_data; if(gtk_gesture_single_get_current_button(gesture) == GDK_BUTTON_PRIMARY @@ -1508,7 +1508,7 @@ static void _blendop_masks_modes_uni_toggled(GtkGestureSingle *gesture, gdouble y, dt_iop_module_t *module) { - GtkWidget *button = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + GtkWidget *button = dt_gui_get_widget(gesture); _blendop_masks_modes_toggle(GTK_TOGGLE_BUTTON(button), module, DEVELOP_MASK_ENABLED); } @@ -1518,7 +1518,7 @@ static void _blendop_masks_modes_drawn_toggled(GtkGestureSingle *gesture, gdouble y, dt_iop_module_t *module) { - GtkWidget *button = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + GtkWidget *button = dt_gui_get_widget(gesture); _blendop_masks_modes_toggle(GTK_TOGGLE_BUTTON(button), module, DEVELOP_MASK_ENABLED | DEVELOP_MASK_MASK); } @@ -1529,7 +1529,7 @@ static void _blendop_masks_modes_param_toggled(GtkGestureSingle *gesture, gdouble y, dt_iop_module_t *module) { - GtkWidget *button = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + GtkWidget *button = dt_gui_get_widget(gesture); _blendop_masks_modes_toggle(GTK_TOGGLE_BUTTON(button), module, DEVELOP_MASK_ENABLED | DEVELOP_MASK_CONDITIONAL); } @@ -1540,7 +1540,7 @@ static void _blendop_masks_modes_both_toggled(GtkGestureSingle *gesture, double y, dt_iop_module_t *module) { - GtkWidget *button = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + GtkWidget *button = dt_gui_get_widget(gesture); _blendop_masks_modes_toggle(GTK_TOGGLE_BUTTON(button), module, DEVELOP_MASK_ENABLED | DEVELOP_MASK_MASK_CONDITIONAL); } @@ -1551,7 +1551,7 @@ static void _blendop_masks_modes_raster_toggled(GtkGestureSingle *gesture, gdouble y, dt_iop_module_t *module) { - GtkWidget *button = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + GtkWidget *button = dt_gui_get_widget(gesture); _blendop_masks_modes_toggle(GTK_TOGGLE_BUTTON(button), module, DEVELOP_MASK_ENABLED | DEVELOP_MASK_RASTER); } @@ -1562,7 +1562,7 @@ static void _blendop_blendif_suppress_toggled(GtkGestureSingle *gesture, gdouble y, dt_iop_module_t *module) { - GtkWidget *togglebutton_w = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + GtkWidget *togglebutton_w = dt_gui_get_widget(gesture); GtkToggleButton *togglebutton = GTK_TOGGLE_BUTTON(togglebutton_w); module->suppress_mask = !gtk_toggle_button_get_active(togglebutton); DT_GUARD_GUI_UPDATE(); @@ -1633,7 +1633,7 @@ static void _blendop_masks_add_shape(GtkGestureSingle *gesture, gdouble y, dt_iop_module_t *self) { - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + GtkWidget *widget = dt_gui_get_widget(gesture); dt_iop_gui_blend_data_t *bd = self->blend_data; @@ -1762,7 +1762,7 @@ static void _blendop_masks_polarity_callback(GtkGestureSingle *gesture, { DT_GUARD_GUI_UPDATE(); - GtkWidget *togglebutton = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + GtkWidget *togglebutton = dt_gui_get_widget(gesture); const int active = !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(togglebutton)); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(togglebutton), active); @@ -2221,7 +2221,7 @@ static void _blendop_blendif_enter_cb(GtkEventControllerMotion *controller, { if(dt_atomic_get_int(&darktable.gui->reset) != 0) return; - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); + GtkWidget *widget = dt_gui_get_widget(controller); dt_iop_gui_blend_data_t *data = module->blend_data; dt_dev_pixelpipe_display_mask_t mode = DT_DEV_PIXELPIPE_DISPLAY_NONE; @@ -2320,7 +2320,7 @@ static gboolean _blendop_blendif_key_press_cb(GtkEventControllerKey *controller, { if(dt_atomic_get_int(&darktable.gui->reset) != 0) return FALSE; - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); + GtkWidget *widget = dt_gui_get_widget(controller); dt_iop_gui_blend_data_t *data = module->blend_data; gboolean handled = FALSE; @@ -2988,7 +2988,7 @@ static void _raster_polarity_callback(GtkGestureSingle *gesture, { DT_GUARD_GUI_UPDATE(); - GtkWidget *togglebutton = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + GtkWidget *togglebutton = dt_gui_get_widget(gesture); dt_develop_blend_params_t *bp = self->blend_params; diff --git a/src/develop/imageop.c b/src/develop/imageop.c index 575e6b52a44..da90ecf11ad 100644 --- a/src/develop/imageop.c +++ b/src/develop/imageop.c @@ -1092,7 +1092,7 @@ static gboolean _rename_module_key_pressed(GtkEventControllerKey *controller, GdkModifierType state, dt_iop_module_t *module) { - GtkWidget *entry = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); + GtkWidget *entry = dt_gui_get_widget(controller); gboolean ended = FALSE; if(keyval == GDK_KEY_Return || keyval == GDK_KEY_KP_Enter) @@ -2523,7 +2523,7 @@ static void _presets_popup_clicked(GtkGestureSingle *gesture, const gboolean disabled = !module->default_enabled && module->hide_enable_button; if(disabled) return; - GtkWidget *button = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + GtkWidget *button = dt_gui_get_widget(gesture); GtkMenu *menu = dt_gui_presets_popup_menu_show_for_module(module); g_signal_connect(G_OBJECT(menu), "deactivate", diff --git a/src/dtgtk/culling.c b/src/dtgtk/culling.c index 77a2c7d6b59..ded4149073f 100644 --- a/src/dtgtk/culling.c +++ b/src/dtgtk/culling.c @@ -822,7 +822,7 @@ static gboolean _event_draw(GtkWidget *widget, static void _event_leave_cb(GtkEventControllerMotion *controller, dt_culling_t *table) { - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); + GtkWidget *widget = dt_gui_get_widget(controller); // if the leaving cause is the hide of the widget, no mouseover change if(!gtk_widget_is_visible(widget)) { diff --git a/src/dtgtk/range.c b/src/dtgtk/range.c index 342f8b07b12..beaa7c1736c 100644 --- a/src/dtgtk/range.c +++ b/src/dtgtk/range.c @@ -1183,7 +1183,7 @@ static void _popup_show(GtkDarktableRangeSelect *range, GtkWidget *w) static void _event_entry_press_cb(GtkGestureSingle *gesture, int n_press, double x, double y, GtkDarktableRangeSelect *range) { - GtkWidget *w = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + GtkWidget *w = dt_gui_get_widget(gesture); if(gtk_gesture_single_get_current_button(gesture) == GDK_BUTTON_SECONDARY) { _popup_show(range, w); diff --git a/src/dtgtk/resetlabel.c b/src/dtgtk/resetlabel.c index 195fcf17e86..0fac2de58ea 100644 --- a/src/dtgtk/resetlabel.c +++ b/src/dtgtk/resetlabel.c @@ -38,7 +38,7 @@ static void _reset_label_callback(GtkGestureSingle *gesture, { if(n_press >= 2) { - GtkDarktableResetLabel *label = DTGTK_RESET_LABEL(gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture))); + GtkDarktableResetLabel *label = DTGTK_RESET_LABEL(dt_gui_get_widget(gesture)); memcpy(((char *)label->module->params) + label->offset, ((char *)label->module->default_params) + label->offset, label->size); dt_iop_gui_update(label->module); diff --git a/src/dtgtk/thumbnail.c b/src/dtgtk/thumbnail.c index cdbe41067e5..8fe8677c1a0 100644 --- a/src/dtgtk/thumbnail.c +++ b/src/dtgtk/thumbnail.c @@ -1052,7 +1052,7 @@ static void _event_rating_release_cb(GtkGestureSingle *gesture, gdouble y, dt_thumbnail_t *thumb) { - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + GtkWidget *widget = dt_gui_get_widget(gesture); if(thumb->disable_actions) return; if(dtgtk_thumbnail_btn_is_hidden(widget)) @@ -1091,7 +1091,7 @@ static void _event_grouping_release_cb(GtkGestureSingle *gesture, gdouble y, dt_thumbnail_t *thumb) { - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + GtkWidget *widget = dt_gui_get_widget(gesture); if(thumb->disable_actions) return; if(dtgtk_thumbnail_btn_is_hidden(widget)) @@ -1144,7 +1144,7 @@ static void _event_audio_release_cb(GtkGestureSingle *gesture, gdouble y, dt_thumbnail_t *thumb) { - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + GtkWidget *widget = dt_gui_get_widget(gesture); if(thumb->disable_actions) return; if(dtgtk_thumbnail_btn_is_hidden(widget)) @@ -1318,7 +1318,7 @@ static void _event_box_enter_cb(GtkEventControllerMotion *controller, gdouble y, dt_thumbnail_t *thumb) { - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); + GtkWidget *widget = dt_gui_get_widget(controller); if(!thumb->disable_mouseover) dt_control_set_mouse_over_id(thumb->imgid); @@ -1330,7 +1330,7 @@ static void _event_box_enter_cb(GtkEventControllerMotion *controller, static void _event_box_leave_cb(GtkEventControllerMotion *controller, dt_thumbnail_t *thumb) { - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); + GtkWidget *widget = dt_gui_get_widget(controller); _set_flag(widget, GTK_STATE_FLAG_PRELIGHT, FALSE); _set_flag(thumb->w_image_box, GTK_STATE_FLAG_PRELIGHT, FALSE); @@ -1358,7 +1358,7 @@ static void _event_btn_enter_cb(GtkEventControllerMotion *controller, gdouble y, dt_thumbnail_t *thumb) { - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); + GtkWidget *widget = dt_gui_get_widget(controller); if(widget == thumb->w_reject) darktable.control->element = DT_VIEW_REJECT; @@ -1375,7 +1375,7 @@ static void _event_btn_enter_cb(GtkEventControllerMotion *controller, static void _event_btn_leave_cb(GtkEventControllerMotion *controller, dt_thumbnail_t *thumb) { - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); + GtkWidget *widget = dt_gui_get_widget(controller); if(widget == thumb->w_reject) darktable.control->element = -1; @@ -1386,7 +1386,7 @@ static void _event_star_enter_cb(GtkEventControllerMotion *controller, gdouble y, dt_thumbnail_t *thumb) { - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); + GtkWidget *widget = dt_gui_get_widget(controller); if(thumb->disable_actions) return; if(!thumb->disable_mouseover) diff --git a/src/dtgtk/thumbtable.c b/src/dtgtk/thumbtable.c index 4323f954ff1..cb080406c4d 100644 --- a/src/dtgtk/thumbtable.c +++ b/src/dtgtk/thumbtable.c @@ -1382,7 +1382,7 @@ static gboolean _event_draw(GtkWidget *widget, static void _event_leave_cb(GtkEventControllerMotion *controller, dt_thumbtable_t *table) { - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); + GtkWidget *widget = dt_gui_get_widget(controller); // if the leaving cause is the hide of the widget, no mouseover change if(!gtk_widget_is_visible(widget)) { @@ -1631,7 +1631,7 @@ static void _event_button_release_cb(GtkGestureSingle *gesture, } else { - GtkWidget *w = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + GtkWidget *w = dt_gui_get_widget(gesture); GtkSettings *settings = gtk_widget_get_settings(GTK_WIDGET(w)); guint double_click_time = 400; diff --git a/src/gui/accelerators.c b/src/gui/accelerators.c index 621b259a119..f12ddc31eae 100644 --- a/src/gui/accelerators.c +++ b/src/gui/accelerators.c @@ -1994,7 +1994,7 @@ static gboolean _view_key_pressed_cb(GtkEventControllerKey *controller, GdkModifierType state, GtkWidget *search_entry) { - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); + GtkWidget *widget = dt_gui_get_widget(controller); GtkTreeView *view = GTK_TREE_VIEW(widget); GtkTreeSelection *selection = gtk_tree_view_get_selection(view); @@ -2265,7 +2265,7 @@ static gboolean _action_find_and_expand(GtkTreeModel *model, static void _action_view_click_cb(GtkGestureSingle *gesture, int n_press, double x, double y, GtkTreeStore *model_data) { - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + GtkWidget *widget = dt_gui_get_widget(gesture); GtkTreeView *view = GTK_TREE_VIEW(widget); GtkTreeModel *model = gtk_tree_view_get_model(view); const guint button = gtk_gesture_single_get_button(gesture); diff --git a/src/gui/color_picker_proxy.c b/src/gui/color_picker_proxy.c index da4f6999f4c..831f5d8c52e 100644 --- a/src/gui/color_picker_proxy.c +++ b/src/gui/color_picker_proxy.c @@ -268,7 +268,7 @@ static void _color_picker_clicked(GtkGestureSingle *gesture, gdouble y, dt_iop_color_picker_t *self) { - GtkWidget *button = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + GtkWidget *button = dt_gui_get_widget(gesture); _color_picker_callback_button_press(button, NULL, self); } diff --git a/src/gui/gtk.c b/src/gui/gtk.c index 472c925b585..a10c1eb20bd 100644 --- a/src/gui/gtk.c +++ b/src/gui/gtk.c @@ -4883,7 +4883,7 @@ static gboolean _scroll_sidebar(GtkEventControllerScroll* controller, // decide whether to propogate them or scroll itself depending on // modifiers state, and this function will no longer be needed GtkWidget *const widget = - gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); + dt_gui_get_widget(controller); const GtkWidget *panel = NULL; if(dt_ui_panel_ancestor(darktable.gui->ui, DT_UI_PANEL_LEFT, widget)) panel = darktable.gui->ui->panels[DT_UI_PANEL_LEFT]; diff --git a/src/gui/gtk.h b/src/gui/gtk.h index c7d4540cf5a..f2913ec6bdf 100644 --- a/src/gui/gtk.h +++ b/src/gui/gtk.h @@ -616,6 +616,9 @@ GtkEventController *(dt_gui_connect_key)(GtkWidget *widget, ASSERT_FUNC_TYPE(pressed, gboolean(*)(GtkEventControllerKey *, guint, guint, GdkModifierType, __typeof__(data))), \ dt_gui_connect_key(GTK_WIDGET(widget), G_CALLBACK(pressed), (data))) +#define dt_gui_get_widget(controller) \ + gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)) + #define dt_gui_claim(gesture) \ gtk_gesture_set_state(GTK_GESTURE(gesture), GTK_EVENT_SEQUENCE_CLAIMED) #define dt_gui_deny(gesture) \ diff --git a/src/gui/preferences.c b/src/gui/preferences.c index 6f256b49846..23963bca906 100644 --- a/src/gui/preferences.c +++ b/src/gui/preferences.c @@ -914,7 +914,7 @@ static gboolean _search_key_pressed(GtkEventControllerKey *controller, GdkModifierType state, GtkWidget *search_entry) { - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); + GtkWidget *widget = dt_gui_get_widget(controller); GtkSearchEntry *entry = GTK_SEARCH_ENTRY(search_entry); // we build a temporary GdkEventKey to reuse dt_gui_search_start GdkEventKey event; @@ -1178,7 +1178,7 @@ static gboolean _delete_preset_key_pressed(GtkEventControllerKey *controller, GdkModifierType state, GtkTreeStore *model_store) { - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); + GtkWidget *widget = dt_gui_get_widget(controller); GtkTreeModel *model = GTK_TREE_MODEL(model_store); GtkTreeIter iter; GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget)); diff --git a/src/gui/preferences_ai.c b/src/gui/preferences_ai.c index 5e1b2e4511a..f983ff3f03c 100644 --- a/src/gui/preferences_ai.c +++ b/src/gui/preferences_ai.c @@ -1258,7 +1258,7 @@ static void _on_tree_motion_cb(GtkEventControllerMotion *controller, double x, double y, gpointer user_data) { - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); + GtkWidget *widget = dt_gui_get_widget(controller); GtkTreeView *tv = GTK_TREE_VIEW(widget); GdkWindow *bin = gtk_tree_view_get_bin_window(tv); if(!bin) return; @@ -1281,7 +1281,7 @@ static void _on_info_button_press_cb(GtkGestureSingle *gesture, int n_press, double x, double y, gpointer user_data) { - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + GtkWidget *widget = dt_gui_get_widget(gesture); if(gtk_gesture_single_get_button(gesture) != 1) return; dt_prefs_ai_data_t *data = (dt_prefs_ai_data_t *)user_data; diff --git a/src/iop/ashift.c b/src/iop/ashift.c index 86c18afdd50..862f0838a6f 100644 --- a/src/iop/ashift.c +++ b/src/iop/ashift.c @@ -5473,7 +5473,7 @@ static void _event_structure_auto_clicked(GtkGestureSingle *gesture, gdouble y, dt_iop_module_t *self) { - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + GtkWidget *widget = dt_gui_get_widget(gesture); DT_GUARD_GUI_UPDATE(); if(gtk_gesture_single_get_current_button(gesture) == GDK_BUTTON_PRIMARY) diff --git a/src/iop/atrous.c b/src/iop/atrous.c index 0cf35d9fefd..147a6f02a7f 100644 --- a/src/iop/atrous.c +++ b/src/iop/atrous.c @@ -1034,7 +1034,7 @@ static void area_enter_notify(GtkEventControllerMotion *controller, g->in_curve = TRUE; if(!g->dragging) g->x_move = -1; - gtk_widget_queue_draw(gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller))); + gtk_widget_queue_draw(dt_gui_get_widget(controller)); } static void area_leave_notify(GtkEventControllerMotion *controller, @@ -1044,7 +1044,7 @@ static void area_leave_notify(GtkEventControllerMotion *controller, g->in_curve = FALSE; if(!g->dragging) g->x_move = -1; - gtk_widget_queue_draw(gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller))); + gtk_widget_queue_draw(dt_gui_get_widget(controller)); } // fills in new parameters based on mouse position (in 0,1) @@ -1388,7 +1388,7 @@ static void area_motion_notify(GtkEventControllerMotion *controller, { dt_iop_atrous_gui_data_t *g = self->gui_data; dt_iop_atrous_params_t *p = self->params; - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); + GtkWidget *widget = dt_gui_get_widget(controller); const int inset = INSET; GtkAllocation allocation; gtk_widget_get_allocation(widget, &allocation); @@ -1474,7 +1474,7 @@ static void area_button_press(GtkGestureSingle *gesture, if(gtk_gesture_single_get_current_button(gesture) != GDK_BUTTON_PRIMARY) return; - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + GtkWidget *widget = dt_gui_get_widget(gesture); if(n_press >= 2) { @@ -1528,7 +1528,7 @@ static void area_scrolled(GtkEventControllerScroll *controller, dt_iop_module_t *self) { dt_iop_atrous_gui_data_t *g = self->gui_data; - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); + GtkWidget *widget = dt_gui_get_widget(controller); if(dt_modifier_eq(controller, GDK_MOD1_MASK)) { diff --git a/src/iop/basecurve.c b/src/iop/basecurve.c index e64f8968c19..87129ac80b6 100644 --- a/src/iop/basecurve.c +++ b/src/iop/basecurve.c @@ -1536,7 +1536,7 @@ static void dt_iop_basecurve_leave_notify(GtkEventControllerMotion *controller, dt_iop_basecurve_gui_data_t *g = self->gui_data; if(!(dt_key_modifier_state() & GDK_BUTTON1_MASK)) g->selected = -1; - gtk_widget_queue_draw(gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller))); + gtk_widget_queue_draw(dt_gui_get_widget(controller)); } static float to_log(const float x, const float base) @@ -1778,7 +1778,7 @@ static void dt_iop_basecurve_motion_notify(GtkEventControllerMotion *controller, gdouble y, dt_iop_module_t *self) { - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); + GtkWidget *widget = dt_gui_get_widget(controller); dt_iop_basecurve_gui_data_t *g = self->gui_data; dt_iop_basecurve_params_t *p = self->params; int ch = 0; @@ -1850,7 +1850,7 @@ static void dt_iop_basecurve_button_press(GtkGestureSingle *gesture, gdouble y, dt_iop_module_t *self) { - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + GtkWidget *widget = dt_gui_get_widget(gesture); dt_iop_basecurve_params_t *p = self->params; const dt_iop_basecurve_params_t *const d = self->default_params; dt_iop_basecurve_gui_data_t *g = self->gui_data; @@ -1988,7 +1988,7 @@ static gboolean _move_point_internal(dt_iop_module_t *self, static void _scrolled(GtkEventControllerScroll *controller, gdouble dx, gdouble dy, dt_iop_module_t *self) { dt_iop_basecurve_gui_data_t *g = self->gui_data; - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); + GtkWidget *widget = dt_gui_get_widget(controller); if(g->selected < 0) return; @@ -2005,7 +2005,7 @@ static gboolean dt_iop_basecurve_key_press(GtkEventControllerKey *controller, GdkModifierType state, dt_iop_module_t *self) { - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); + GtkWidget *widget = dt_gui_get_widget(controller); dt_iop_basecurve_gui_data_t *g = self->gui_data; if(g->selected < 0) return TRUE; diff --git a/src/iop/colorchecker.c b/src/iop/colorchecker.c index 730df9e250a..2e1037ed704 100644 --- a/src/iop/colorchecker.c +++ b/src/iop/colorchecker.c @@ -1389,7 +1389,7 @@ static void checker_motion_notify( // highlight? dt_iop_colorchecker_params_t *p = self->params; dt_iop_colorchecker_gui_data_t *g = self->gui_data; - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); + GtkWidget *widget = dt_gui_get_widget(controller); GtkAllocation allocation; gtk_widget_get_allocation(widget, &allocation); @@ -1429,7 +1429,7 @@ static void checker_button_press( { dt_iop_colorchecker_params_t *p = self->params; dt_iop_colorchecker_gui_data_t *g = self->gui_data; - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + GtkWidget *widget = dt_gui_get_widget(gesture); GtkAllocation allocation; gtk_widget_get_allocation(widget, &allocation); diff --git a/src/iop/colorcorrection.c b/src/iop/colorcorrection.c index d8058967d25..a03a65ad6a9 100644 --- a/src/iop/colorcorrection.c +++ b/src/iop/colorcorrection.c @@ -357,7 +357,7 @@ static void dt_iop_colorcorrection_motion_notify(GtkEventControllerMotion *contr gdouble y, dt_iop_module_t *self) { - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); + GtkWidget *widget = dt_gui_get_widget(controller); dt_iop_colorcorrection_gui_data_t *g = self->gui_data; dt_iop_colorcorrection_params_t *p = self->params; const int inset = DT_COLORCORRECTION_INSET; @@ -438,7 +438,7 @@ static void dt_iop_colorcorrection_leave_notify(GtkEventControllerMotion *contro static void dt_iop_colorcorrection_scrolled(GtkEventControllerScroll *controller, gdouble dx, gdouble dy, dt_iop_module_t *self) { - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); + GtkWidget *widget = dt_gui_get_widget(controller); dt_iop_colorcorrection_gui_data_t *g = self->gui_data; dt_iop_colorcorrection_params_t *p = self->params; @@ -454,7 +454,7 @@ static void dt_iop_colorcorrection_scrolled(GtkEventControllerScroll *controller static gboolean dt_iop_colorcorrection_key_press(GtkEventControllerKey *controller, guint keyval, guint keycode, GdkModifierType state, dt_iop_module_t *self) { - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); + GtkWidget *widget = dt_gui_get_widget(controller); dt_iop_colorcorrection_gui_data_t *g = self->gui_data; dt_iop_colorcorrection_params_t *p = self->params; if(g->selected < 1) return FALSE; diff --git a/src/iop/colorzones.c b/src/iop/colorzones.c index 7fc40bbdb4d..d63403828c9 100644 --- a/src/iop/colorzones.c +++ b/src/iop/colorzones.c @@ -1860,7 +1860,7 @@ static void _area_scrolled_callback(GtkEventControllerScroll *controller, gdouble dy, dt_iop_module_t *self) { - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); + GtkWidget *widget = dt_gui_get_widget(controller); dt_iop_colorzones_gui_data_t *g = self->gui_data; dt_iop_colorzones_params_t *p = self->params; @@ -1918,7 +1918,7 @@ static void _area_motion_notify_callback(GtkEventControllerMotion *controller, gdouble y, dt_iop_module_t *self) { - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); + GtkWidget *widget = dt_gui_get_widget(controller); dt_iop_colorzones_gui_data_t *g = self->gui_data; dt_iop_colorzones_params_t *p = self->params; @@ -2088,7 +2088,7 @@ static void _area_button_press_callback(GtkGestureSingle *gesture, gdouble y, dt_iop_module_t *self) { - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + GtkWidget *widget = dt_gui_get_widget(gesture); dt_iop_colorzones_gui_data_t *g = self->gui_data; dt_iop_colorzones_params_t *p = self->params; const dt_iop_colorzones_params_t *const d = self->default_params; @@ -2239,7 +2239,7 @@ static void _area_leave_notify_callback(GtkEventControllerMotion *controller, g->mouse_y = -fabs(g->mouse_y); if(!(dt_key_modifier_state() & GDK_BUTTON1_MASK)) g->selected = -1; - gtk_widget_queue_draw(gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller))); + gtk_widget_queue_draw(dt_gui_get_widget(controller)); } static gboolean _area_key_press_callback(GtkEventControllerKey *controller, @@ -2248,7 +2248,7 @@ static gboolean _area_key_press_callback(GtkEventControllerKey *controller, GdkModifierType state, dt_iop_module_t *self) { - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); + GtkWidget *widget = dt_gui_get_widget(controller); dt_iop_colorzones_gui_data_t *g = self->gui_data; if(darktable.develop->darkroom_skip_mouse_events) return FALSE; diff --git a/src/iop/denoiseprofile.c b/src/iop/denoiseprofile.c index 5aab0fd1962..9fc04a510f8 100644 --- a/src/iop/denoiseprofile.c +++ b/src/iop/denoiseprofile.c @@ -3449,7 +3449,7 @@ static void denoiseprofile_motion_notify(GtkEventControllerMotion *controller, { dt_iop_denoiseprofile_gui_data_t *g = self->gui_data; dt_iop_denoiseprofile_params_t *p = self->params; - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); + GtkWidget *widget = dt_gui_get_widget(controller); const int inset = DT_IOP_DENOISE_PROFILE_INSET; GtkAllocation allocation; gtk_widget_get_allocation(widget, &allocation); @@ -3485,7 +3485,7 @@ static void denoiseprofile_button_press(GtkGestureSingle *gesture, if(gtk_gesture_single_get_current_button(gesture) != GDK_BUTTON_PRIMARY) return; - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + GtkWidget *widget = dt_gui_get_widget(gesture); if(n_press >= 2) { @@ -3534,7 +3534,7 @@ static void denoiseprofile_leave_notify(GtkEventControllerMotion *controller, { dt_iop_denoiseprofile_gui_data_t *g = self->gui_data; if(!g->dragging) g->mouse_y = -1.0; - gtk_widget_queue_draw(gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller))); + gtk_widget_queue_draw(dt_gui_get_widget(controller)); } static void denoiseprofile_scrolled(GtkEventControllerScroll *controller, @@ -3548,7 +3548,7 @@ static void denoiseprofile_scrolled(GtkEventControllerScroll *controller, { g->mouse_radius = CLAMP(g->mouse_radius * (1.f - 0.1f * dy), 0.2f / DT_IOP_DENOISE_PROFILE_BANDS, 1.f); - gtk_widget_queue_draw(gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller))); + gtk_widget_queue_draw(dt_gui_get_widget(controller)); } } diff --git a/src/iop/levels.c b/src/iop/levels.c index 16c5b692f83..f03a30670cc 100644 --- a/src/iop/levels.c +++ b/src/iop/levels.c @@ -701,7 +701,7 @@ static void dt_iop_levels_leave_notify(GtkEventControllerMotion *controller, dt_ { dt_iop_levels_gui_data_t *g = self->gui_data; g->mouse_x = g->mouse_y = -1.0; - gtk_widget_queue_draw(gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller))); + gtk_widget_queue_draw(dt_gui_get_widget(controller)); } static gboolean dt_iop_levels_area_draw(GtkWidget *widget, cairo_t *crf, dt_iop_module_t *self) @@ -866,7 +866,7 @@ static void dt_iop_levels_motion_notify(GtkEventControllerMotion *controller, gd { dt_iop_levels_gui_data_t *g = self->gui_data; dt_iop_levels_params_t *p = self->params; - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); + GtkWidget *widget = dt_gui_get_widget(controller); const int inset = DT_GUI_CURVE_EDITOR_INSET; GtkAllocation allocation; gtk_widget_get_allocation(widget, &allocation); @@ -945,7 +945,7 @@ static void dt_iop_levels_scroll(GtkEventControllerScroll *controller, gdouble d { dt_iop_levels_gui_data_t *g = self->gui_data; dt_iop_levels_params_t *p = self->params; - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); + GtkWidget *widget = dt_gui_get_widget(controller); dt_iop_color_picker_reset(self, TRUE); diff --git a/src/iop/liquify.c b/src/iop/liquify.c index 5b4dc153c50..4ae571472be 100644 --- a/src/iop/liquify.c +++ b/src/iop/liquify.c @@ -3628,7 +3628,7 @@ static void btn_make_radio_callback(GtkGestureSingle *gesture, gdk_event_free(event); } - GtkWidget *btn = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + GtkWidget *btn = dt_gui_get_widget(gesture); _btn_make_radio_cb(GTK_TOGGLE_BUTTON(btn), ctrl_pressed, self); } diff --git a/src/iop/lowlight.c b/src/iop/lowlight.c index 50fd9caa171..14990657cfb 100644 --- a/src/iop/lowlight.c +++ b/src/iop/lowlight.c @@ -668,7 +668,7 @@ static void lowlight_motion_notify(GtkEventControllerMotion *controller, gdouble { dt_iop_lowlight_gui_data_t *g = self->gui_data; dt_iop_lowlight_params_t *p = self->params; - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); + GtkWidget *widget = dt_gui_get_widget(controller); const int inset = DT_IOP_LOWLIGHT_INSET; GtkAllocation allocation; gtk_widget_get_allocation(widget, &allocation); @@ -723,7 +723,7 @@ static void lowlight_button_press(GtkGestureSingle *gesture, gint n_press, gdoub if(gtk_gesture_single_get_current_button(gesture) != GDK_BUTTON_PRIMARY) return; - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + GtkWidget *widget = dt_gui_get_widget(gesture); if(n_press >= 2) { @@ -765,7 +765,7 @@ static void lowlight_leave_notify(GtkEventControllerMotion *controller, dt_iop_m { dt_iop_lowlight_gui_data_t *g = self->gui_data; if(!g->dragging) g->mouse_y = -1.0; - gtk_widget_queue_draw(gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller))); + gtk_widget_queue_draw(dt_gui_get_widget(controller)); } static void lowlight_scrolled(GtkEventControllerScroll *controller, gdouble dx, gdouble dy, dt_iop_module_t *self) @@ -775,7 +775,7 @@ static void lowlight_scrolled(GtkEventControllerScroll *controller, gdouble dx, if(dy != 0.0) { g->mouse_radius = CLAMP(g->mouse_radius * (1.0 - 0.1 * dy), 0.2 / DT_IOP_LOWLIGHT_BANDS, 1.0); - gtk_widget_queue_draw(gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller))); + gtk_widget_queue_draw(dt_gui_get_widget(controller)); } } diff --git a/src/iop/lut3d.c b/src/iop/lut3d.c index f26dcd9bd7c..5df24ec9427 100644 --- a/src/iop/lut3d.c +++ b/src/iop/lut3d.c @@ -1477,7 +1477,7 @@ static void _mouse_scroll(GtkEventControllerScroll *controller, gdouble dx, gdouble dy, dt_iop_module_t *self) { - GtkWidget *view = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); + GtkWidget *view = dt_gui_get_widget(controller); GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(view)); GtkTreeIter iter; GtkTreeModel *model = gtk_tree_view_get_model((GtkTreeView *)view); diff --git a/src/iop/monochrome.c b/src/iop/monochrome.c index d18d90d11d7..e1205e2eb65 100644 --- a/src/iop/monochrome.c +++ b/src/iop/monochrome.c @@ -457,7 +457,7 @@ static void _monochrome_motion_notify(GtkEventControllerMotion *controller, gdou { const float old_a = p->a, old_b = p->b; const int inset = DT_COLORCORRECTION_INSET; - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); + GtkWidget *widget = dt_gui_get_widget(controller); GtkAllocation allocation; gtk_widget_get_allocation(widget, &allocation); int width = allocation.width - 2 * inset, height = allocation.height - 2 * inset; @@ -478,7 +478,7 @@ static void _monochrome_button_press(GtkGestureSingle *gesture, gint n_press, gd dt_iop_monochrome_gui_data_t *g = self->gui_data; dt_iop_monochrome_params_t *p = self->params; - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + GtkWidget *widget = dt_gui_get_widget(gesture); dt_iop_color_picker_reset(self, TRUE); if(n_press >= 2) @@ -511,7 +511,7 @@ static void _monochrome_button_release(GtkGestureSingle *gesture, gint n_press, return; dt_iop_monochrome_gui_data_t *g = self->gui_data; - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + GtkWidget *widget = dt_gui_get_widget(gesture); dt_iop_color_picker_reset(self, TRUE); g->dragging = 0; dt_dev_add_history_item(darktable.develop, self, TRUE); @@ -536,7 +536,7 @@ static void _monochrome_scrolled(GtkEventControllerScroll *controller, gdouble d const float old_size = p->size; p->size = CLAMP(p->size - dy * 0.1, 0.5f, 3.0f); if(old_size != p->size) dt_dev_add_history_item(darktable.develop, self, TRUE); - gtk_widget_queue_draw(gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller))); + gtk_widget_queue_draw(dt_gui_get_widget(controller)); } } diff --git a/src/iop/rawdenoise.c b/src/iop/rawdenoise.c index a175e5dfc96..f0043cbde31 100644 --- a/src/iop/rawdenoise.c +++ b/src/iop/rawdenoise.c @@ -770,7 +770,7 @@ static void rawdenoise_motion_notify(GtkEventControllerMotion *controller, gdoub { dt_iop_rawdenoise_gui_data_t *g = self->gui_data; dt_iop_rawdenoise_params_t *p = self->params; - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); + GtkWidget *widget = dt_gui_get_widget(controller); const int inset = DT_IOP_RAWDENOISE_INSET; GtkAllocation allocation; gtk_widget_get_allocation(widget, &allocation); @@ -801,7 +801,7 @@ static void rawdenoise_button_press(GtkGestureSingle *gesture, gint n_press, gdo if(gtk_gesture_single_get_current_button(gesture) != GDK_BUTTON_PRIMARY) return; - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + GtkWidget *widget = dt_gui_get_widget(gesture); if(n_press >= 2) { @@ -843,7 +843,7 @@ static void rawdenoise_leave_notify(GtkEventControllerMotion *controller, dt_iop { dt_iop_rawdenoise_gui_data_t *g = self->gui_data; if(!g->dragging) g->mouse_y = -1.0; - gtk_widget_queue_draw(gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller))); + gtk_widget_queue_draw(dt_gui_get_widget(controller)); } static void rawdenoise_scrolled(GtkEventControllerScroll *controller, gdouble dx, gdouble dy, dt_iop_module_t *self) @@ -853,7 +853,7 @@ static void rawdenoise_scrolled(GtkEventControllerScroll *controller, gdouble dx if(dy != 0.0) { g->mouse_radius = CLAMP(g->mouse_radius * (1.0 - 0.1 * dy), 0.2 / DT_IOP_RAWDENOISE_BANDS, 1.0); - gtk_widget_queue_draw(gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller))); + gtk_widget_queue_draw(dt_gui_get_widget(controller)); } } diff --git a/src/iop/retouch.c b/src/iop/retouch.c index 67e83e20d5c..5c6934393f2 100644 --- a/src/iop/retouch.c +++ b/src/iop/retouch.c @@ -1249,7 +1249,7 @@ static void rt_wdbar_button_press(GtkGestureSingle *gesture, gint n_press, gdoub dt_iop_request_focus(self); dt_iop_retouch_gui_data_t *g = self->gui_data; - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + GtkWidget *widget = dt_gui_get_widget(gesture); GtkAllocation allocation; gtk_widget_get_allocation(widget, &allocation); const int inset = round(RT_WDBAR_INSET * allocation.height); @@ -1318,7 +1318,7 @@ static void rt_wdbar_motion_notify(GtkEventControllerMotion *controller, { dt_iop_retouch_gui_data_t *g = self->gui_data; dt_iop_retouch_params_t *p = self->params; - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); + GtkWidget *widget = dt_gui_get_widget(controller); GtkAllocation allocation; gtk_widget_get_allocation(widget, &allocation); @@ -1897,7 +1897,7 @@ static void rt_add_shape_callback(GtkGestureSingle *gesture, if(dt_atomic_get_int(&darktable.gui->reset) != 0) return; - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + GtkWidget *widget = dt_gui_get_widget(gesture); dt_iop_color_picker_reset(self, TRUE); diff --git a/src/iop/rgbcurve.c b/src/iop/rgbcurve.c index 3eab46584f6..87ca4275377 100644 --- a/src/iop/rgbcurve.c +++ b/src/iop/rgbcurve.c @@ -648,7 +648,7 @@ static void _area_scrolled_callback(GtkEventControllerScroll *controller, gdouble dy, dt_iop_module_t *self) { - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); + GtkWidget *widget = dt_gui_get_widget(controller); dt_iop_rgbcurve_params_t *p = self->params; dt_iop_rgbcurve_gui_data_t *g = self->gui_data; @@ -698,7 +698,7 @@ static gboolean _area_key_press_callback(GtkEventControllerKey *controller, GdkModifierType state, dt_iop_module_t *self) { - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); + GtkWidget *widget = dt_gui_get_widget(controller); dt_iop_rgbcurve_params_t *p = self->params; dt_iop_rgbcurve_gui_data_t *g = self->gui_data; @@ -749,7 +749,7 @@ static void _area_leave_notify_callback(GtkEventControllerMotion *controller, if(!(dt_key_modifier_state() & GDK_BUTTON1_MASK)) g->selected = -1; - gtk_widget_queue_draw(gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller))); + gtk_widget_queue_draw(dt_gui_get_widget(controller)); } static gboolean _area_draw_callback(GtkWidget *widget, @@ -1165,7 +1165,7 @@ static void _area_motion_notify_callback(GtkEventControllerMotion *controller, gdouble y, dt_iop_module_t *self) { - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); + GtkWidget *widget = dt_gui_get_widget(controller); dt_iop_rgbcurve_gui_data_t *g = self->gui_data; dt_iop_rgbcurve_params_t *p = self->params; @@ -1289,7 +1289,7 @@ static void _area_button_press_callback(GtkGestureSingle *gesture, gdouble y, dt_iop_module_t *self) { - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + GtkWidget *widget = dt_gui_get_widget(gesture); dt_iop_rgbcurve_params_t *p = self->params; const dt_iop_rgbcurve_params_t *const d = self->default_params; dt_iop_rgbcurve_gui_data_t *g = self->gui_data; diff --git a/src/iop/rgblevels.c b/src/iop/rgblevels.c index ba557b08902..8ea698fa777 100644 --- a/src/iop/rgblevels.c +++ b/src/iop/rgblevels.c @@ -365,7 +365,7 @@ static void _area_leave_notify_callback(GtkEventControllerMotion *controller, { dt_iop_rgblevels_gui_data_t *g = self->gui_data; g->mouse_x = g->mouse_y = -1.0; - gtk_widget_queue_draw(gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller))); + gtk_widget_queue_draw(dt_gui_get_widget(controller)); } static gboolean _area_draw_callback(GtkWidget *widget, @@ -554,7 +554,7 @@ static void _area_motion_notify_callback(GtkEventControllerMotion *controller, { dt_iop_rgblevels_gui_data_t *g = self->gui_data; dt_iop_rgblevels_params_t *p = self->params; - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); + GtkWidget *widget = dt_gui_get_widget(controller); const int inset = DT_GUI_CURVE_EDITOR_INSET; GtkAllocation allocation; gtk_widget_get_allocation(widget, &allocation); @@ -654,7 +654,7 @@ static void _area_scroll_callback(GtkEventControllerScroll *controller, { dt_iop_rgblevels_gui_data_t *g = self->gui_data; dt_iop_rgblevels_params_t *p = self->params; - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); + GtkWidget *widget = dt_gui_get_widget(controller); _turn_selregion_picker_off(self); diff --git a/src/iop/spots.c b/src/iop/spots.c index 5b730938dca..d498bde6756 100644 --- a/src/iop/spots.c +++ b/src/iop/spots.c @@ -337,7 +337,7 @@ static void _add_shape_callback(GtkGestureSingle *gesture, { if(dt_atomic_get_int(&darktable.gui->reset) != 0) return; - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + GtkWidget *widget = dt_gui_get_widget(gesture); const dt_iop_spots_gui_data_t *g = self->gui_data; gboolean creation_continuous = FALSE; diff --git a/src/iop/temperature.c b/src/iop/temperature.c index cb6581af477..a0448e2df33 100644 --- a/src/iop/temperature.c +++ b/src/iop/temperature.c @@ -1738,7 +1738,7 @@ static void _btn_toggled(GtkGestureSingle *gesture, { if(dt_atomic_get_int(&darktable.gui->reset) != 0) return; - GtkWidget *togglebutton = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + GtkWidget *togglebutton = dt_gui_get_widget(gesture); dt_iop_temperature_gui_data_t *g = (dt_iop_temperature_gui_data_t*)self->gui_data; const int preset = togglebutton == g->btn_asshot ? DT_IOP_TEMP_AS_SHOT : diff --git a/src/iop/tonecurve.c b/src/iop/tonecurve.c index caef05148ab..834a9346207 100644 --- a/src/iop/tonecurve.c +++ b/src/iop/tonecurve.c @@ -1167,7 +1167,7 @@ static void _scrolled(GtkEventControllerScroll *controller, gdouble dy, dt_iop_module_t *self) { - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); + GtkWidget *widget = dt_gui_get_widget(controller); dt_iop_tonecurve_params_t *p = self->params; dt_iop_tonecurve_gui_data_t *g = self->gui_data; @@ -1191,7 +1191,7 @@ static gboolean dt_iop_tonecurve_key_press(GtkEventControllerKey *controller, GdkModifierType state, dt_iop_module_t *self) { - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); + GtkWidget *widget = dt_gui_get_widget(controller); dt_iop_tonecurve_params_t *p = self->params; dt_iop_tonecurve_gui_data_t *g = self->gui_data; @@ -1343,7 +1343,7 @@ static void dt_iop_tonecurve_leave_notify(GtkEventControllerMotion *controller, dt_iop_tonecurve_gui_data_t *g = self->gui_data; if(!(dt_key_modifier_state() & GDK_BUTTON1_MASK)) g->selected = -1; - gtk_widget_queue_draw(gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller))); + gtk_widget_queue_draw(dt_gui_get_widget(controller)); } static void picker_scale(const float *in, float *out) @@ -1748,7 +1748,7 @@ static void dt_iop_tonecurve_motion_notify(GtkEventControllerMotion *controller, gdouble y, dt_iop_module_t *self) { - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); + GtkWidget *widget = dt_gui_get_widget(controller); dt_iop_tonecurve_gui_data_t *g = self->gui_data; dt_iop_tonecurve_params_t *p = self->params; @@ -1831,7 +1831,7 @@ static void dt_iop_tonecurve_button_press(GtkGestureSingle *gesture, gdouble y, dt_iop_module_t *self) { - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + GtkWidget *widget = dt_gui_get_widget(gesture); dt_iop_tonecurve_params_t *p = self->params; const dt_iop_tonecurve_params_t *const d = self->default_params; dt_iop_tonecurve_gui_data_t *g = self->gui_data; diff --git a/src/iop/zonesystem.c b/src/iop/zonesystem.c index 611af790951..9464214ab08 100644 --- a/src/iop/zonesystem.c +++ b/src/iop/zonesystem.c @@ -570,7 +570,7 @@ static void dt_iop_zonesystem_bar_button_press(GtkGestureSingle *gesture, gint n { dt_iop_zonesystem_params_t *p = self->params; dt_iop_zonesystem_gui_data_t *g = self->gui_data; - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + GtkWidget *widget = dt_gui_get_widget(gesture); const int inset = DT_ZONESYSTEM_INSET; GtkAllocation allocation; gtk_widget_get_allocation(widget, &allocation); @@ -624,7 +624,7 @@ static void dt_iop_zonesystem_bar_scrolled(GtkEventControllerScroll *controller, p->size = CLAMP(p->size - dy, 4, MAX_ZONE_SYSTEM_SIZE); p->zone[cs] = -1; dt_dev_add_history_item(darktable.develop, self, TRUE); - gtk_widget_queue_draw(gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller))); + gtk_widget_queue_draw(dt_gui_get_widget(controller)); } } @@ -641,7 +641,7 @@ static void dt_iop_zonesystem_bar_motion_notify(GtkEventControllerMotion *contro { dt_iop_zonesystem_params_t *p = self->params; dt_iop_zonesystem_gui_data_t *g = self->gui_data; - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); + GtkWidget *widget = dt_gui_get_widget(controller); const int inset = DT_ZONESYSTEM_INSET; GtkAllocation allocation; gtk_widget_get_allocation(widget, &allocation); diff --git a/src/libs/collect.c b/src/libs/collect.c index 924a739ac38..1495cd74383 100644 --- a/src/libs/collect.c +++ b/src/libs/collect.c @@ -636,7 +636,7 @@ static void view_onButtonPressed_cb(GtkGestureSingle *gesture, int n_press, double x, double y, dt_lib_collect_t *d) { - GtkWidget *treeview = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + GtkWidget *treeview = dt_gui_get_widget(gesture); static GdkModifierType last_mod_state = 0; GdkEvent *event = gtk_get_current_event(); diff --git a/src/libs/colorpicker.c b/src/libs/colorpicker.c index 6aad6cd00c3..82e02f173d5 100644 --- a/src/libs/colorpicker.c +++ b/src/libs/colorpicker.c @@ -521,7 +521,7 @@ static void _live_sample_button_cb(GtkGestureSingle *gesture, gdouble y, dt_colorpicker_sample_t *sample) { - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + GtkWidget *widget = dt_gui_get_widget(gesture); const guint button = gtk_gesture_single_get_current_button(gesture); if(button == GDK_BUTTON_PRIMARY) { diff --git a/src/libs/duplicate.c b/src/libs/duplicate.c index 021a775fdd1..18ca22530f1 100644 --- a/src/libs/duplicate.c +++ b/src/libs/duplicate.c @@ -183,7 +183,7 @@ static void _lib_duplicate_thumb_press_callback(GtkGestureSingle *gesture, dt_lib_module_t *self) { dt_lib_duplicate_t *d = self->data; - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + GtkWidget *widget = dt_gui_get_widget(gesture); dt_thumbnail_t *thumb = (dt_thumbnail_t *)g_object_get_data(G_OBJECT(widget), "thumb"); const dt_imgid_t imgid = thumb->imgid; diff --git a/src/libs/export.c b/src/libs/export.c index 980ad7e1238..6b3772a9248 100644 --- a/src/libs/export.c +++ b/src/libs/export.c @@ -571,7 +571,7 @@ static void _scale_mdlclick_cb(GtkGestureSingle *gesture, int n_press, double x, double y, dt_lib_export_t *d) { - GtkWidget *spin = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + GtkWidget *spin = dt_gui_get_widget(gesture); if(gtk_gesture_single_get_current_button(gesture) == GDK_BUTTON_MIDDLE) { dt_conf_set_string(CONFIG_PREFIX "resizing_factor", "1"); @@ -589,7 +589,7 @@ static void _widht_mdlclick_cb(GtkGestureSingle *gesture, int n_press, double x, double y, dt_lib_export_t *d) { - GtkWidget *spin = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + GtkWidget *spin = dt_gui_get_widget(gesture); if(gtk_gesture_single_get_current_button(gesture) == GDK_BUTTON_MIDDLE) { dt_conf_set_int(CONFIG_PREFIX "width", 0); @@ -607,7 +607,7 @@ static void _height_mdlclick_cb(GtkGestureSingle *gesture, int n_press, double x, double y, dt_lib_export_t *d) { - GtkWidget *spin = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + GtkWidget *spin = dt_gui_get_widget(gesture); if(gtk_gesture_single_get_current_button(gesture) == GDK_BUTTON_MIDDLE) { dt_conf_set_int(CONFIG_PREFIX "height", 0); diff --git a/src/libs/filtering.c b/src/libs/filtering.c index a55f9a19cb6..d5c7c8d0a70 100644 --- a/src/libs/filtering.c +++ b/src/libs/filtering.c @@ -1164,7 +1164,7 @@ static void _event_rule_close_cb(GtkGestureSingle *gesture, int n_press, double x, double y, dt_lib_module_t *self) { - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + GtkWidget *widget = dt_gui_get_widget(gesture); dt_lib_filtering_rule_t *rule = (dt_lib_filtering_rule_t *)g_object_get_data(G_OBJECT(widget), "rule"); if(rule->manual_widget_set) return; @@ -1667,7 +1667,7 @@ static void _topbar_rule_remove_cb(GtkGestureSingle *gesture, int n_press, double x, double y, dt_lib_module_t *self) { - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + GtkWidget *widget = dt_gui_get_widget(gesture); dt_lib_filtering_rule_t *rule = (dt_lib_filtering_rule_t *)g_object_get_data(G_OBJECT(widget), "rule"); if(rule->manual_widget_set) return; dt_lib_filtering_t *d = self->data; @@ -1932,7 +1932,7 @@ static void _sort_close_cb(GtkGestureSingle *gesture, int n_press, double x, double y, dt_lib_module_t *self) { - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + GtkWidget *widget = dt_gui_get_widget(gesture); _widgets_sort_t *sort = (_widgets_sort_t *)g_object_get_data(G_OBJECT(widget), "sort"); if(sort->lib->manual_sort_set) return; diff --git a/src/libs/filters/colors.c b/src/libs/filters/colors.c index 41a557ec4c1..c10398b360a 100644 --- a/src/libs/filters/colors.c +++ b/src/libs/filters/colors.c @@ -105,7 +105,7 @@ static gboolean _colors_clicked_old(GtkWidget *w, GdkEventButton *e, _widgets_co static void _colors_clicked_gesture(GtkGestureSingle *gesture, gint n_press, gdouble x, gdouble y, _widgets_colors_t *colors) { - GtkWidget *w = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + GtkWidget *w = dt_gui_get_widget(gesture); // double click reset the widget if(gtk_gesture_single_get_current_button(gesture) == GDK_BUTTON_PRIMARY && n_press >= 2) diff --git a/src/libs/filters/filename.c b/src/libs/filters/filename.c index da7655462f1..bbbaa83a2cd 100644 --- a/src/libs/filters/filename.c +++ b/src/libs/filters/filename.c @@ -237,7 +237,7 @@ static void _filename_update_selection(_widgets_filename_t *filename) static void _filename_press(GtkGestureSingle *gesture, gint n_press, gdouble x, gdouble y, _widgets_filename_t *filename) { - GtkWidget *w = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + GtkWidget *w = dt_gui_get_widget(gesture); if(gtk_gesture_single_get_current_button(gesture) == GDK_BUTTON_SECONDARY) { diff --git a/src/libs/filters/misc.c b/src/libs/filters/misc.c index fc18805bcf8..db767ead1b6 100644 --- a/src/libs/filters/misc.c +++ b/src/libs/filters/misc.c @@ -267,7 +267,7 @@ static void _misc_press(GtkGestureSingle *gesture, gdouble y, _widgets_misc_t *misc) { - GtkWidget *w = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + GtkWidget *w = dt_gui_get_widget(gesture); if(gtk_gesture_single_get_current_button(gesture) == GDK_BUTTON_SECONDARY) { diff --git a/src/libs/geotagging.c b/src/libs/geotagging.c index 9392eb41e85..4e50a22599b 100644 --- a/src/libs/geotagging.c +++ b/src/libs/geotagging.c @@ -1450,7 +1450,7 @@ static void _datetime_scroll_over(GtkEventControllerScroll *controller, dt_lib_geotagging_t *d = self->data; if(!d->editing) { - GtkWidget* w = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); + GtkWidget* w = dt_gui_get_widget(controller); int i = 0; for(i = 0; i < DT_GEOTAG_PARTS_NB; i++) if(w == d->dt.widget[i]) break; diff --git a/src/libs/histogram.c b/src/libs/histogram.c index 9884de9b0e0..79b0e8de0d4 100644 --- a/src/libs/histogram.c +++ b/src/libs/histogram.c @@ -561,7 +561,7 @@ static void _eventbox_motion_notify_callback(GtkEventControllerMotion *controlle // pass-through on otherwise -> exposure dragging reaches scope. // For the split option we test the inner button_box_split, not the full-width // outer_box_split, so dragging still works across the rest of the top. - GtkWidget *eb = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); + GtkWidget *eb = dt_gui_get_widget(controller); gtk_overlay_set_overlay_pass_through (GTK_OVERLAY(s->overlay), s->button_box_left, !_pointer_over_widget(eb, s->button_box_left, x, y)); diff --git a/src/libs/history.c b/src/libs/history.c index 792a6d9328d..68cc852afed 100644 --- a/src/libs/history.c +++ b/src/libs/history.c @@ -1259,7 +1259,7 @@ static void _lib_history_button_clicked_callback(GtkGestureSingle *gesture, gdouble y, dt_lib_module_t *self) { - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + GtkWidget *widget = dt_gui_get_widget(gesture); const dt_imgid_t imgid = darktable.develop->image_storage.id; if(!dt_is_valid_imgid(imgid)) return; diff --git a/src/libs/import.c b/src/libs/import.c index 6cb99cfeef5..b4127b2cd45 100644 --- a/src/libs/import.c +++ b/src/libs/import.c @@ -560,7 +560,7 @@ static void _files_button_press_cb(GtkGestureSingle *gesture, int n_press, double x, double y, dt_lib_module_t *self) { - GtkWidget *view = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + GtkWidget *view = dt_gui_get_widget(gesture); dt_lib_import_t *d = self->data; if(n_press == 1) { @@ -1266,7 +1266,7 @@ static void _places_button_press_cb(GtkGestureSingle *gesture, int n_press, double x, double y, dt_lib_module_t *self) { - GtkWidget *view = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + GtkWidget *view = dt_gui_get_widget(gesture); GtkTreePath *path = NULL; if(gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(view), (gint)x, (gint)y, &path, NULL, NULL, NULL)) @@ -1301,7 +1301,7 @@ static void _folders_button_press_cb(GtkGestureSingle *gesture, int n_press, double x, double y, dt_lib_module_t *self) { - GtkWidget *view = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + GtkWidget *view = dt_gui_get_widget(gesture); dt_lib_import_t *d = self->data; GdkModifierType state; diff --git a/src/libs/lib.c b/src/libs/lib.c index 24f51c6aaf8..05c3f43d156 100644 --- a/src/libs/lib.c +++ b/src/libs/lib.c @@ -991,7 +991,7 @@ static void _presets_popup_gesture_cb(GtkGestureSingle *gesture, gdouble y, dt_lib_module_t *module) { - _presets_popup_callback(gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)), module); + _presets_popup_callback(dt_gui_get_widget(gesture), module); } void dt_lib_gui_set_expanded(dt_lib_module_t *module, const gboolean expanded) diff --git a/src/libs/location.c b/src/libs/location.c index d5ad2cde2e6..c6c743aaa52 100644 --- a/src/libs/location.c +++ b/src/libs/location.c @@ -156,13 +156,13 @@ void gui_cleanup(dt_lib_module_t *self) static void _event_box_enter(GtkEventControllerMotion *controller, gdouble x, gdouble y, gpointer user_data) { - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); + GtkWidget *widget = dt_gui_get_widget(controller); gtk_widget_set_state_flags(widget, GTK_STATE_FLAG_PRELIGHT, FALSE); } static void _event_box_leave(GtkEventControllerMotion *controller, gpointer user_data) { - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); + GtkWidget *widget = dt_gui_get_widget(controller); gtk_widget_unset_state_flags(widget, GTK_STATE_FLAG_PRELIGHT); } diff --git a/src/libs/map_locations.c b/src/libs/map_locations.c index 24ac6004a2b..a035ca1f39e 100644 --- a/src/libs/map_locations.c +++ b/src/libs/map_locations.c @@ -838,7 +838,7 @@ static void _click_on_view(GtkGestureSingle *gesture, dt_lib_module_t *self) { dt_lib_map_locations_t *d = self->data; - GtkWidget *view = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + GtkWidget *view = dt_gui_get_widget(gesture); gboolean editing; g_object_get(G_OBJECT(d->renderer), "editing", &editing, NULL); diff --git a/src/libs/masks.c b/src/libs/masks.c index 10d21f3aa4c..85e1e8db1d7 100644 --- a/src/libs/masks.c +++ b/src/libs/masks.c @@ -1224,7 +1224,7 @@ static void _tree_selection_change(GtkTreeSelection *selection, dt_lib_masks_t * static void _tree_button_pressed_cb(GtkGestureSingle *gesture, int n_press, double x, double y, dt_lib_module_t *self) { - GtkWidget *treeview = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + GtkWidget *treeview = dt_gui_get_widget(gesture); // we first need to adjust selection GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)); GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(treeview)); diff --git a/src/libs/metadata.c b/src/libs/metadata.c index ecb6f6beb81..d976a41fcfb 100644 --- a/src/libs/metadata.c +++ b/src/libs/metadata.c @@ -424,7 +424,7 @@ static gboolean _key_pressed_cb(GtkEventControllerKey *controller, GdkModifierType state, dt_lib_module_t *self) { - GtkWidget *textview = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); + GtkWidget *textview = dt_gui_get_widget(controller); dt_lib_metadata_t *d = self->data; switch(keyval) diff --git a/src/libs/modulegroups.c b/src/libs/modulegroups.c index 4db6db4a78a..b5b495ba01f 100644 --- a/src/libs/modulegroups.c +++ b/src/libs/modulegroups.c @@ -2692,7 +2692,7 @@ static void _manage_direct_popup(GtkGestureSingle *gesture, if(gtk_gesture_single_get_current_button(gesture) != GDK_BUTTON_SECONDARY) return; - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + GtkWidget *widget = dt_gui_get_widget(gesture); dt_lib_modulegroups_group_t *gr = g_object_get_data(G_OBJECT(widget), "group"); if(!g_strcmp0(gr->name, C_("modulegroup", "deprecated"))) return; _manage_module_add_popup(widget, gr, @@ -2708,7 +2708,7 @@ static void _manage_direct_basic_popup(GtkGestureSingle *gesture, if(gtk_gesture_single_get_current_button(gesture) != GDK_BUTTON_SECONDARY) return; - _manage_basics_add_popup(gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)), self, TRUE); + _manage_basics_add_popup(dt_gui_get_widget(gesture), self, TRUE); } static void _manage_direct_module_popup(GtkGestureSingle *gesture, @@ -2720,7 +2720,7 @@ static void _manage_direct_module_popup(GtkGestureSingle *gesture, if(gtk_gesture_single_get_current_button(gesture) != GDK_BUTTON_SECONDARY) return; - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + GtkWidget *widget = dt_gui_get_widget(gesture); dt_action_t *module = g_object_get_data(G_OBJECT(widget), "module"); int nba = 0; // nb of already present items @@ -2754,7 +2754,7 @@ static void _manage_direct_active_popup(GtkGestureSingle *gesture, return; dt_lib_modulegroups_t *d = self->data; - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + GtkWidget *widget = dt_gui_get_widget(gesture); GtkWidget *pop = gtk_menu_new(); gtk_widget_set_name(pop, "modulegroups-popup"); @@ -3285,7 +3285,7 @@ static void _manage_editor_group_icon_changed(GtkGestureSingle *gesture, gdouble y, dt_lib_modulegroups_group_t *gr) { - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + GtkWidget *widget = dt_gui_get_widget(gesture); const char *ic = (char *)g_object_get_data(G_OBJECT(widget), "ic_name"); g_free(gr->icon); gr->icon = g_strdup(ic); diff --git a/src/libs/navigation.c b/src/libs/navigation.c index f67d52e12e6..90614fc2c95 100644 --- a/src/libs/navigation.c +++ b/src/libs/navigation.c @@ -419,7 +419,7 @@ static void _lib_navigation_motion_notify_callback(GtkEventControllerMotion *con double x, double y, dt_lib_module_t *self) { - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); + GtkWidget *widget = dt_gui_get_widget(controller); GtkAllocation allocation; gtk_widget_get_allocation(widget, &allocation); _lib_navigation_set_position(self, x, y, @@ -590,7 +590,7 @@ static void _lib_navigation_button_press_callback(GtkGestureSingle *gesture, int dt_lib_module_t *self) { dt_lib_navigation_t *d = self->data; - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + GtkWidget *widget = dt_gui_get_widget(gesture); GtkAllocation allocation; gtk_widget_get_allocation(widget, &allocation); const guint button = gtk_gesture_single_get_button(gesture); diff --git a/src/libs/neural_restore.c b/src/libs/neural_restore.c index 64ab4b4d3a8..d1767455d3e 100644 --- a/src/libs/neural_restore.c +++ b/src/libs/neural_restore.c @@ -3928,7 +3928,7 @@ static void _preview_button_press_cb(GtkGestureSingle *gesture, int n_press, double ex, double ey, dt_lib_module_t *self) { - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + GtkWidget *widget = dt_gui_get_widget(gesture); dt_lib_neural_restore_t *d = (dt_lib_neural_restore_t *)self->data; if(gtk_gesture_single_get_button(gesture) != 1) return; @@ -4023,7 +4023,7 @@ static void _preview_motion_cb(GtkEventControllerMotion *controller, double ex, double ey, dt_lib_module_t *self) { - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); + GtkWidget *widget = dt_gui_get_widget(controller); dt_lib_neural_restore_t *d = (dt_lib_neural_restore_t *)self->data; // move crop rectangle while hovering in picking mode diff --git a/src/libs/snapshots.c b/src/libs/snapshots.c index ae25f49dce7..a0493448ea9 100644 --- a/src/libs/snapshots.c +++ b/src/libs/snapshots.c @@ -569,7 +569,7 @@ static void _lib_button_button_pressed_callback(GtkGestureSingle *gesture, dt_lib_module_t *self) { dt_lib_snapshots_t *d = self->data; - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + GtkWidget *widget = dt_gui_get_widget(gesture); const int index = _look_for_widget(self, widget, FALSE); diff --git a/src/libs/tagging.c b/src/libs/tagging.c index b7db3796a83..95aba8e33de 100644 --- a/src/libs/tagging.c +++ b/src/libs/tagging.c @@ -1476,7 +1476,7 @@ static void _click_on_view_attached(GtkGestureSingle *gesture, dt_lib_module_t *self) { dt_lib_tagging_t *d = self->data; - GtkWidget *view = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + GtkWidget *view = dt_gui_get_widget(gesture); _unselect_all_in_view(d->dictionary_view); const guint button = gtk_gesture_single_get_current_button(gesture); @@ -1538,7 +1538,7 @@ static gboolean _attached_key_pressed(GtkEventControllerKey *controller, dt_lib_tagging_t *d = self->data; _unselect_all_in_view(d->dictionary_view); - GtkWidget *view = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); + GtkWidget *view = dt_gui_get_widget(controller); GtkTreeIter iter; GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(d->attached_view)); GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(view)); @@ -1619,7 +1619,7 @@ static gboolean _enter_key_pressed(GtkEventControllerKey *controller, dt_lib_module_t *self) { dt_lib_tagging_t *d = self->data; - GtkWidget *entry = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); + GtkWidget *entry = dt_gui_get_widget(controller); switch(keyval) { case GDK_KEY_Return: @@ -2654,7 +2654,7 @@ static void _click_on_view_dictionary(GtkGestureSingle *gesture, dt_lib_module_t *self) { dt_lib_tagging_t *d = self->data; - GtkWidget *view = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + GtkWidget *view = dt_gui_get_widget(gesture); _unselect_all_in_view(d->attached_view); GdkEvent *event = gtk_get_current_event(); @@ -2738,7 +2738,7 @@ static gboolean _dictionary_key_pressed(GtkEventControllerKey *controller, _unselect_all_in_view(d->attached_view); GtkTreeIter iter; GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(d->dictionary_view)); - GtkWidget *view = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); + GtkWidget *view = dt_gui_get_widget(controller); GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(view)); gboolean res = FALSE; if(gtk_tree_selection_get_selected(selection, &model, &iter)) @@ -3807,7 +3807,7 @@ static gboolean _lib_tagging_tag_key_press(GtkEventControllerKey *controller, case GDK_KEY_Return: case GDK_KEY_KP_Enter: { - GtkWidget *entry = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); + GtkWidget *entry = dt_gui_get_widget(controller); dt_gui_cursor_set_busy(); const gchar *tag = gtk_entry_get_text(GTK_ENTRY(entry)); const gboolean res = dt_tag_attach_string_list(tag, d->floating_tag_imgs, TRUE); diff --git a/src/libs/tools/colorlabels.c b/src/libs/tools/colorlabels.c index 2b445c5f778..a6e66f686c2 100644 --- a/src/libs/tools/colorlabels.c +++ b/src/libs/tools/colorlabels.c @@ -90,7 +90,7 @@ static void _lib_colorlabels_enter_notify_callback(GtkEventControllerMotion *con double x, double y, dt_lib_module_t *self) { - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); + GtkWidget *widget = dt_gui_get_widget(controller); const gint colorlabel = _get_colorlabel(self, widget); darktable.control->element = (colorlabel + 1) % 6; @@ -180,7 +180,7 @@ static gboolean _lib_colorlabels_key_press_cb(GtkEventControllerKey *controller, case GDK_KEY_Return: case GDK_KEY_KP_Enter: { - GtkWidget *entry = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); + GtkWidget *entry = dt_gui_get_widget(controller); char confname[128]; const gchar *label = gtk_entry_get_text(GTK_ENTRY(entry)); snprintf(confname, sizeof(confname), "colorlabel/%s", @@ -273,7 +273,7 @@ static void _lib_colorlabels_button_press_callback(GtkGestureSingle *gesture, in double x, double y, dt_lib_module_t *self) { - GtkWidget *w = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + GtkWidget *w = dt_gui_get_widget(gesture); dt_lib_colorlabels_t *d = self->data; const gint colorlabel = _get_colorlabel(self, w); diff --git a/src/libs/tools/filter.c b/src/libs/tools/filter.c index 0fd692968e1..2bbe480755f 100644 --- a/src/libs/tools/filter.c +++ b/src/libs/tools/filter.c @@ -91,7 +91,7 @@ static void _pref_show(GtkGestureSingle *gesture, gdouble y, dt_lib_module_t *self) { - GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + GtkWidget *widget = dt_gui_get_widget(gesture); dt_view_filtering_show_pref_menu(darktable.view_manager, widget); } diff --git a/src/libs/tools/lighttable.c b/src/libs/tools/lighttable.c index c79188a4214..0c1a9852f68 100644 --- a/src/libs/tools/lighttable.c +++ b/src/libs/tools/lighttable.c @@ -213,7 +213,7 @@ static void _lib_lighttable_layout_btn_release_cb(GtkGestureSingle *gesture, int double x, double y, dt_lib_module_t *self) { - GtkWidget *w = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + GtkWidget *w = dt_gui_get_widget(gesture); dt_lib_tool_lighttable_t *d = self->data; const gboolean active @@ -276,7 +276,7 @@ static void _lib_lighttable_restricted_btn_release_cb(GtkGestureSingle *gesture, dt_lib_module_t *self) { _lib_lighttable_do_restricted_btn(self, - gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture))); + dt_gui_get_widget(gesture)); } static void _lib_lighttable_key_accel_toggle_filemanager(dt_action_t *action) diff --git a/src/libs/tools/viewswitcher.c b/src/libs/tools/viewswitcher.c index 3232f2b98cd..19b178eaf70 100644 --- a/src/libs/tools/viewswitcher.c +++ b/src/libs/tools/viewswitcher.c @@ -182,7 +182,7 @@ static void _lib_viewswitcher_enter_callback(GtkEventControllerMotion *controlle double x, double y, GtkWidget *label) { - GtkWidget *w = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)); + GtkWidget *w = dt_gui_get_widget(controller); /* if not active view lets highlight */ if(strcmp(g_object_get_data(G_OBJECT(w), "view-label"), dt_view_manager_name(darktable.view_manager))) gtk_widget_set_state_flags(label, GTK_STATE_FLAG_PRELIGHT, FALSE); diff --git a/src/views/darkroom.c b/src/views/darkroom.c index abd64dc0674..e115cedec74 100644 --- a/src/views/darkroom.c +++ b/src/views/darkroom.c @@ -2774,7 +2774,7 @@ static void _quickbutton_pressed_cb(GtkGestureSingle *gesture, gdouble y, GtkWidget *popover) { - GtkWidget *button = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + GtkWidget *button = dt_gui_get_widget(gesture); /* secondary click: show popup immediately */ if(gtk_gesture_single_get_button(gesture) == GDK_BUTTON_SECONDARY) @@ -5071,7 +5071,7 @@ static void _second_window_button_released_callback(GtkGestureSingle *gesture, { if(gtk_gesture_single_get_button(gesture) == GDK_BUTTON_PRIMARY) _dt_second_window_change_cursor(dev, "default"); - GtkWidget *w = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); + GtkWidget *w = dt_gui_get_widget(gesture); gtk_widget_queue_draw(w); } From 60f7fc2b8765971ec71a1bf29d0eb8bdb7d138d7 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 15:59:49 -0300 Subject: [PATCH 75/95] gtk4-prep: clean up histogram scroll callback TODO MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace outdated FIXME comment with a proper GTK4 migration note. The original TODO asked for a helper to extract event flags — gtk_get_current_event_state() already provides this in GTK3, and gtk_event_controller_get_current_event_state() will be the GTK4 equivalent. Also removed several other stale FIXMEs about scroll handling scope that are outside the scope of this change. --- src/libs/histogram.c | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/src/libs/histogram.c b/src/libs/histogram.c index 79b0e8de0d4..36ae4569647 100644 --- a/src/libs/histogram.c +++ b/src/libs/histogram.c @@ -484,13 +484,15 @@ static void _eventbox_scroll_callback(GtkEventControllerScroll* self, const gdouble dy, dt_scopes_t *s) { + // GTK4 note: gtk_get_current_event() returns NULL inside event controller + // callbacks in GTK4. For state checks, use + // gtk_event_controller_get_current_event_state(GTK_EVENT_CONTROLLER(self), &state) + // instead. For forwarding the event via gtk_widget_event(), use + // gtk_gesture_get_last_event() and gdk_event_copy() if needed. GdkEvent *event = gtk_get_current_event(); if(!event) return; if(gdk_event_get_event_type(event) == GDK_SCROLL) { - // FIXME: so long as we have event, test its flags -- and for GTK 4 we can - // use gtk_get_current_event() and get flags -- make a helper function to do - // this. if(dt_modifier_is(dt_gdk_event_get_state(event), GDK_SHIFT_MASK | GDK_MOD1_MASK)) { @@ -499,20 +501,8 @@ static void _eventbox_scroll_callback(GtkEventControllerScroll* self, } else if(s->highlight != DT_SCOPES_HIGHLIGHT_NONE) { - // FIXME: should scroll for exposure change be handled by each scope, rather than here? - // FIXME: should handle smooth scrolling rather than discrete? - // FIXME: should scrolling of scope be handled in the drawable rather than - // the eventbox. - // get the dominant direction, standardize on delta < 0 => up==right const gdouble delta = fabs(dx) > fabs(dy) ? -dx : dy; - // for exposure ('highlight') mode: we want up/right: brighten the image - // -> increase exposure, or decrease black point (exposure handles that); - // in vectorscope, rgb parade, parts of the visualization moves upwards; - // in histogram, to the right. - // dt_dev_exposure_handle_event requires 'delta' in the 'brighten' > 0 convention, that is also what - // drag events emit - dt_dev_exposure_handle_event(0, - delta, dt_gdk_event_get_state(event), s->highlight == DT_SCOPES_HIGHLIGHT_BLACK_POINT); } From 318ae35e9977c7fbebab093c4d5412a7d838c8a5 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 16:00:57 -0300 Subject: [PATCH 76/95] gtk4-prep: update histogram scroll callback GTK4 note MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Only changed the stale 'make a helper' TODO — replaced it with a proper GTK4 migration note about using gtk_event_controller_get_current_event_state(). Preserved the existing UI/UX FIXMEs about scroll handling placement. --- src/libs/histogram.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/libs/histogram.c b/src/libs/histogram.c index 36ae4569647..d9b01fbb2a6 100644 --- a/src/libs/histogram.c +++ b/src/libs/histogram.c @@ -501,8 +501,20 @@ static void _eventbox_scroll_callback(GtkEventControllerScroll* self, } else if(s->highlight != DT_SCOPES_HIGHLIGHT_NONE) { + // FIXME: should scroll for exposure change be handled by each scope, rather than here? + // FIXME: should handle smooth scrolling rather than discrete? + // FIXME: should scrolling of scope be handled in the drawable rather than + // the eventbox. + // get the dominant direction, standardize on delta < 0 => up==right const gdouble delta = fabs(dx) > fabs(dy) ? -dx : dy; + // for exposure ('highlight') mode: we want up/right: brighten the image + // -> increase exposure, or decrease black point (exposure handles that); + // in vectorscope, rgb parade, parts of the visualization moves upwards; + // in histogram, to the right. + // dt_dev_exposure_handle_event requires 'delta' in the 'brighten' > 0 convention, that is also what + // drag events emit + dt_dev_exposure_handle_event(0, - delta, dt_gdk_event_get_state(event), s->highlight == DT_SCOPES_HIGHLIGHT_BLACK_POINT); } From e7803b93a8c47f790a41cd72e1315a9787f88970 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 16:04:03 -0300 Subject: [PATCH 77/95] gtk4-prep: add dt_gui_get_scroll_unit_delta(s)_fallback helpers Scroll event controller callbacks receive (dx, dy) but no raw GdkEventScroll *, so they need gtk_get_current_event() to use the smooth-scroll accumulation logic in dt_gui_get_scroll_unit_deltas(). Add fallback helpers that try the current event first and fall back to the raw dx/dy values, reducing the boilerplate from ~7 lines of event-dance to a single call. Also cleans up 3 call sites: - bauhaus.c: _popup_scroll_cb (combobox + slider branches) - imageop.c: _presets_scrolled --- src/bauhaus/bauhaus.c | 24 ++---------------------- src/develop/imageop.c | 12 +----------- src/gui/gtk.c | 30 ++++++++++++++++++++++++++++++ src/gui/gtk.h | 5 +++++ 4 files changed, 38 insertions(+), 33 deletions(-) diff --git a/src/bauhaus/bauhaus.c b/src/bauhaus/bauhaus.c index f386fc2701d..49b22e05325 100644 --- a/src/bauhaus/bauhaus.c +++ b/src/bauhaus/bauhaus.c @@ -535,18 +535,7 @@ static void _popup_scroll_cb(GtkEventControllerScroll *controller, { // match keyboard: right & down -> next int delta_x = 0, delta_y = 0; - GdkEvent *event = gtk_get_current_event(); - if(event) - { - dt_gui_get_scroll_unit_deltas((const GdkEventScroll *)event, &delta_x, &delta_y); - gdk_event_free(event); - } - else - { - // fallback: use raw values if no current event - delta_x = (int)dx; - delta_y = (int)dy; - } + dt_gui_get_scroll_unit_deltas_fallback(dx, dy, &delta_x, &delta_y); const int delta = abs(delta_x) > abs(delta_y) ? delta_x : delta_y; if(delta != 0) _combobox_next_sensitive(w, delta, 0, w->combobox.mute_scrolling); @@ -554,16 +543,7 @@ static void _popup_scroll_cb(GtkEventControllerScroll *controller, else { int delta = 0; - GdkEvent *event = gtk_get_current_event(); - if(event) - { - dt_gui_get_scroll_unit_delta((const GdkEventScroll *)event, &delta); - gdk_event_free(event); - } - else - { - delta = -(int)dy; - } + dt_gui_get_scroll_unit_delta_fallback(dy, &delta); _slider_zoom_range(w, delta); } } diff --git a/src/develop/imageop.c b/src/develop/imageop.c index da90ecf11ad..5c6e06b5696 100644 --- a/src/develop/imageop.c +++ b/src/develop/imageop.c @@ -2542,17 +2542,7 @@ static void _presets_scrolled(GtkEventControllerScroll *controller, // preset cycling: right==down==next int delta_x = 0, delta_y = 0; - GdkEvent *event = gtk_get_current_event(); - if(event) - { - dt_gui_get_scroll_unit_deltas((const GdkEventScroll *)event, &delta_x, &delta_y); - gdk_event_free(event); - } - else - { - delta_x = (int)dx; - delta_y = (int)dy; - } + dt_gui_get_scroll_unit_deltas_fallback(dx, dy, &delta_x, &delta_y); const int delta = abs(delta_x) > abs(delta_y) ? delta_x : delta_y; dt_gui_presets_apply_adjacent_preset(module, delta); } diff --git a/src/gui/gtk.c b/src/gui/gtk.c index a10c1eb20bd..84634dd35fc 100644 --- a/src/gui/gtk.c +++ b/src/gui/gtk.c @@ -624,6 +624,36 @@ gboolean dt_gui_get_scroll_unit_delta(const GdkEventScroll *event, return FALSE; } +gboolean dt_gui_get_scroll_unit_deltas_fallback(const gdouble dx, + const gdouble dy, + int *delta_x, + int *delta_y) +{ + GdkEvent *event = gtk_get_current_event(); + if(event) + { + const gboolean ok = dt_gui_get_scroll_unit_deltas((const GdkEventScroll *)event, delta_x, delta_y); + gdk_event_free(event); + return ok; + } + // fallback: use raw values if no current event available + *delta_x = (int)dx; + *delta_y = (int)dy; + return TRUE; +} + +gboolean dt_gui_get_scroll_unit_delta_fallback(const gdouble dy, + int *delta) +{ + int delta_x, delta_y; + if(dt_gui_get_scroll_unit_deltas_fallback(0, dy, &delta_x, &delta_y)) + { + *delta = abs(delta_x) > abs(delta_y) ? -delta_x : delta_y; + return TRUE; + } + return FALSE; +} + static gboolean _draw_borders(GtkWidget *widget, cairo_t *crf, const gpointer user_data) diff --git a/src/gui/gtk.h b/src/gui/gtk.h index f2913ec6bdf..d72f6514236 100644 --- a/src/gui/gtk.h +++ b/src/gui/gtk.h @@ -247,6 +247,11 @@ gboolean dt_gui_get_scroll_delta(const GdkEventScroll *event, gdouble *delta); * Effectively makes smooth scroll events act like old-style unit * scroll events. */ gboolean dt_gui_get_scroll_unit_delta(const GdkEventScroll *event, int *delta); +/* Same as above but for use inside scroll-event-controller callbacks where the + * raw dx/dy are available but no GdkEventScroll *. Tries gtk_get_current_event() + * first for smooth-scroll accumulation, falls back to casting the raw values. */ +gboolean dt_gui_get_scroll_unit_deltas_fallback(gdouble dx, gdouble dy, int *delta_x, int *delta_y); +gboolean dt_gui_get_scroll_unit_delta_fallback(gdouble dy, int *delta); /* * new ui api From 9f418626ed2d2252b282ce39a176338e2e517725 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 17:22:46 -0300 Subject: [PATCH 78/95] gtk4-prep: restore explicit event masks on NO_WINDOW drawing areas MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GtkDrawingArea (and its dtgtk subclass) is a NO_WINDOW widget — it doesn't have its own GdkWindow. GtkEventController adds event masks via gtk_widget_add_events(), but on NO_WINDOW widgets this may not propagate correctly to the parent's GdkWindow in all GTK3 versions. Restore explicit GDK_POINTER_MOTION_MASK, GDK_BUTTON_PRESS_MASK, GDK_BUTTON_RELEASE_MASK, GDK_ENTER_NOTIFY_MASK, GDK_LEAVE_NOTIFY_MASK on all converted drawing areas that lost them during the event controller conversion. The controllers also request these masks, but explicit gtk_widget_set_events/add_events is the proven path for NO_WINDOW widgets. Affects: ratings, range, colorzones, rgbcurve, tonecurve, monochrome, basecurve, colorcorrection, colorequal, toneequal, zonesystem, and colorpicker drawing areas. --- src/bauhaus/bauhaus.c | 5 ++++- src/dtgtk/range.c | 4 +++- src/iop/basecurve.c | 5 +++++ src/iop/colorcorrection.c | 5 +++++ src/iop/colorequal.c | 5 ++++- src/iop/colorzones.c | 6 ++++++ src/iop/monochrome.c | 4 ++++ src/iop/rgbcurve.c | 5 +++++ src/iop/tonecurve.c | 5 +++++ src/iop/toneequal.c | 6 +++++- src/iop/zonesystem.c | 4 ++++ src/libs/colorpicker.c | 5 +++++ src/libs/tools/ratings.c | 5 ++++- 13 files changed, 59 insertions(+), 5 deletions(-) diff --git a/src/bauhaus/bauhaus.c b/src/bauhaus/bauhaus.c index 49b22e05325..14d1ced3ce7 100644 --- a/src/bauhaus/bauhaus.c +++ b/src/bauhaus/bauhaus.c @@ -1023,7 +1023,10 @@ void dt_bauhaus_init() gtk_container_add(GTK_CONTAINER(pop->window), pop->area); gtk_widget_set_can_focus(pop->area, TRUE); gtk_widget_add_events(pop->area, - darktable.gui->scroll_mask); + GDK_POINTER_MOTION_MASK + | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + | GDK_KEY_PRESS_MASK | GDK_LEAVE_NOTIFY_MASK + | darktable.gui->scroll_mask); GObject *window = G_OBJECT(pop->window); GObject *area = G_OBJECT(pop->area); diff --git a/src/dtgtk/range.c b/src/dtgtk/range.c index beaa7c1736c..0d8b6c5bc53 100644 --- a/src/dtgtk/range.c +++ b/src/dtgtk/range.c @@ -1679,7 +1679,9 @@ GtkWidget *dtgtk_range_select_new(const gchar *property, const gboolean show_ent // the graph band range->band = gtk_drawing_area_new(); - gtk_widget_set_events(range->band, GDK_STRUCTURE_MASK); + gtk_widget_set_events(range->band, GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + | GDK_STRUCTURE_MASK + | GDK_LEAVE_NOTIFY_MASK | GDK_POINTER_MOTION_MASK); g_signal_connect(G_OBJECT(range->band), "draw", G_CALLBACK(_event_band_draw), range); g_signal_connect(G_OBJECT(range->band), "style-updated", G_CALLBACK(_dt_pref_changed), range); dt_gui_connect_click_all(range->band, _event_band_press_cb, _event_band_release_cb, range); diff --git a/src/iop/basecurve.c b/src/iop/basecurve.c index 87129ac80b6..ef972eac2dc 100644 --- a/src/iop/basecurve.c +++ b/src/iop/basecurve.c @@ -2122,6 +2122,11 @@ void gui_init(dt_iop_module_t *self) gtk_widget_set_can_focus(GTK_WIDGET(g->area), TRUE); g_signal_connect(G_OBJECT(g->area), "draw", G_CALLBACK(dt_iop_basecurve_draw), self); + gtk_widget_add_events(GTK_WIDGET(g->area), + GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK + | GDK_BUTTON_RELEASE_MASK + | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK + | darktable.gui->scroll_mask); dt_gui_connect_click(g->area, dt_iop_basecurve_button_press, NULL, self); dt_gui_connect_motion(g->area, dt_iop_basecurve_motion_notify, NULL, dt_iop_basecurve_leave_notify, self); dt_gui_connect_scroll(g->area, GTK_EVENT_CONTROLLER_SCROLL_BOTH_AXES diff --git a/src/iop/colorcorrection.c b/src/iop/colorcorrection.c index a03a65ad6a9..f659010b6aa 100644 --- a/src/iop/colorcorrection.c +++ b/src/iop/colorcorrection.c @@ -255,6 +255,11 @@ void gui_init(dt_iop_module_t *self) "use mouse wheel to change saturation.")); gtk_widget_set_can_focus(GTK_WIDGET(g->area), TRUE); g_signal_connect(G_OBJECT(g->area), "draw", G_CALLBACK(dt_iop_colorcorrection_draw), self); + gtk_widget_add_events(GTK_WIDGET(g->area), + GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK + | GDK_BUTTON_RELEASE_MASK + | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK + | darktable.gui->scroll_mask); dt_gui_connect_click(g->area, dt_iop_colorcorrection_button_press, NULL, self); dt_gui_connect_motion(g->area, dt_iop_colorcorrection_motion_notify, NULL, dt_iop_colorcorrection_leave_notify, self); dt_gui_connect_scroll(g->area, GTK_EVENT_CONTROLLER_SCROLL_BOTH_AXES diff --git a/src/iop/colorequal.c b/src/iop/colorequal.c index 14cf8eccda3..e58d19d3b3d 100644 --- a/src/iop/colorequal.c +++ b/src/iop/colorequal.c @@ -2979,9 +2979,12 @@ void gui_init(dt_iop_module_t *self) gtk_widget_set_tooltip_text(GTK_WIDGET(g->area), _("double-click to reset the curve\nmiddle-click to toggle sliders visibility\nalt+scroll to change page")); gtk_widget_set_can_focus(GTK_WIDGET(g->area), TRUE); g_signal_connect(G_OBJECT(g->area), "draw", G_CALLBACK(_iop_colorequalizer_draw), self); + gtk_widget_add_events(GTK_WIDGET(g->area), + GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK + | GDK_BUTTON_RELEASE_MASK + | darktable.gui->scroll_mask); dt_gui_connect_click_all(g->area, _area_button_press_callback, _area_button_release_callback, self); dt_gui_connect_motion(g->area, _area_motion_notify_callback, NULL, NULL, self); - gtk_widget_add_events(GTK_WIDGET(g->area), darktable.gui->scroll_mask); dt_gui_connect_scroll(g->area, GTK_EVENT_CONTROLLER_SCROLL_BOTH_AXES | GTK_EVENT_CONTROLLER_SCROLL_DISCRETE, _area_scrolled_callback, self); diff --git a/src/iop/colorzones.c b/src/iop/colorzones.c index d63403828c9..87dd0fa77df 100644 --- a/src/iop/colorzones.c +++ b/src/iop/colorzones.c @@ -2698,6 +2698,11 @@ void gui_init(dt_iop_module_t *self) gtk_widget_set_can_focus(GTK_WIDGET(g->area), TRUE); g_signal_connect(G_OBJECT(g->area), "draw", G_CALLBACK(_area_draw_callback), self); + gtk_widget_add_events(GTK_WIDGET(g->area), + GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK + | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK + | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK + | darktable.gui->scroll_mask); dt_gui_connect_click(g->area, _area_button_press_callback, _area_button_release_callback, self); dt_gui_connect_motion(g->area, _area_motion_notify_callback, NULL, _area_leave_notify_callback, self); dt_gui_connect_scroll(g->area, GTK_EVENT_CONTROLLER_SCROLL_BOTH_AXES @@ -2707,6 +2712,7 @@ void gui_init(dt_iop_module_t *self) g_signal_connect(G_OBJECT(g->bottom_area), "draw", G_CALLBACK(_bottom_area_draw_callback), self); + gtk_widget_add_events(GTK_WIDGET(g->bottom_area), GDK_BUTTON_PRESS_MASK); dt_gui_connect_click(g->bottom_area, _bottom_area_button_press_callback, NULL, self); g->interpolator = dt_bauhaus_combobox_new_interpolation(self); diff --git a/src/iop/monochrome.c b/src/iop/monochrome.c index e1205e2eb65..c91c302daa3 100644 --- a/src/iop/monochrome.c +++ b/src/iop/monochrome.c @@ -552,6 +552,10 @@ void gui_init(dt_iop_module_t *self) dt_action_define_iop(self, NULL, N_("grid"), GTK_WIDGET(g->area), NULL); g_signal_connect(G_OBJECT(g->area), "draw", G_CALLBACK(_monochrome_draw), self); + gtk_widget_add_events(GTK_WIDGET(g->area), + GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK + | GDK_BUTTON_RELEASE_MASK | GDK_LEAVE_NOTIFY_MASK + | darktable.gui->scroll_mask); dt_gui_connect_click(g->area, _monochrome_button_press, _monochrome_button_release, self); dt_gui_connect_motion(g->area, _monochrome_motion_notify, NULL, _monochrome_leave_notify, self); dt_gui_connect_scroll(g->area, GTK_EVENT_CONTROLLER_SCROLL_BOTH_AXES diff --git a/src/iop/rgbcurve.c b/src/iop/rgbcurve.c index 87ca4275377..148d5e85457 100644 --- a/src/iop/rgbcurve.c +++ b/src/iop/rgbcurve.c @@ -1521,6 +1521,11 @@ void gui_init(dt_iop_module_t *self) gtk_widget_set_can_focus(GTK_WIDGET(g->area), TRUE); g_signal_connect(G_OBJECT(g->area), "draw", G_CALLBACK(_area_draw_callback), self); + gtk_widget_add_events(GTK_WIDGET(g->area), + GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK + | GDK_BUTTON_RELEASE_MASK + | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK + | darktable.gui->scroll_mask); dt_gui_connect_click(g->area, _area_button_press_callback, NULL, self); dt_gui_connect_motion(g->area, _area_motion_notify_callback, NULL, _area_leave_notify_callback, self); dt_gui_connect_scroll(g->area, GTK_EVENT_CONTROLLER_SCROLL_BOTH_AXES diff --git a/src/iop/tonecurve.c b/src/iop/tonecurve.c index 834a9346207..c7b92043841 100644 --- a/src/iop/tonecurve.c +++ b/src/iop/tonecurve.c @@ -1293,6 +1293,11 @@ void gui_init(dt_iop_module_t *self) gtk_widget_set_can_focus(GTK_WIDGET(g->area), TRUE); g_signal_connect(G_OBJECT(g->area), "draw", G_CALLBACK(dt_iop_tonecurve_draw), self); + gtk_widget_add_events(GTK_WIDGET(g->area), + GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK + | GDK_BUTTON_RELEASE_MASK + | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK + | darktable.gui->scroll_mask); dt_gui_connect_click(g->area, dt_iop_tonecurve_button_press, NULL, self); dt_gui_connect_motion(g->area, dt_iop_tonecurve_motion_notify, NULL, dt_iop_tonecurve_leave_notify, self); dt_gui_connect_scroll(g->area, GTK_EVENT_CONTROLLER_SCROLL_BOTH_AXES diff --git a/src/iop/toneequal.c b/src/iop/toneequal.c index f67109b7ee6..990c0cf96ff 100644 --- a/src/iop/toneequal.c +++ b/src/iop/toneequal.c @@ -3281,9 +3281,13 @@ void gui_init(dt_iop_module_t *self) gtk_widget_set_vexpand(GTK_WIDGET(g->area), TRUE); gtk_widget_set_can_focus(GTK_WIDGET(g->area), TRUE); g_signal_connect(G_OBJECT(g->area), "draw", G_CALLBACK(area_draw), self); + gtk_widget_add_events(GTK_WIDGET(g->area), + GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK + | GDK_BUTTON_RELEASE_MASK + | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK + | darktable.gui->scroll_mask); dt_gui_connect_click(g->area, area_button_press, area_button_release, self); dt_gui_connect_motion(g->area, area_motion_notify, NULL, area_leave_notify, self); - gtk_widget_add_events(GTK_WIDGET(g->area), darktable.gui->scroll_mask); dt_gui_connect_scroll(g->area, GTK_EVENT_CONTROLLER_SCROLL_BOTH_AXES | GTK_EVENT_CONTROLLER_SCROLL_DISCRETE, area_scroll, self); diff --git a/src/iop/zonesystem.c b/src/iop/zonesystem.c index 9464214ab08..d7859e9b89e 100644 --- a/src/iop/zonesystem.c +++ b/src/iop/zonesystem.c @@ -443,6 +443,10 @@ void gui_init(dt_iop_module_t *self) "left-click on a border to create a marker\n" "right-click on a marker to delete it")); g_signal_connect(G_OBJECT(g->zones), "draw", G_CALLBACK(dt_iop_zonesystem_bar_draw), self); + gtk_widget_add_events(GTK_WIDGET(g->zones), + GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK + | GDK_BUTTON_RELEASE_MASK | GDK_LEAVE_NOTIFY_MASK + | darktable.gui->scroll_mask); dt_gui_connect_click_all(g->zones, dt_iop_zonesystem_bar_button_press, dt_iop_zonesystem_bar_button_release, self); dt_gui_connect_motion(g->zones, dt_iop_zonesystem_bar_motion_notify, NULL, dt_iop_zonesystem_bar_leave_notify, self); dt_gui_connect_scroll(g->zones, GTK_EVENT_CONTROLLER_SCROLL_BOTH_AXES diff --git a/src/libs/colorpicker.c b/src/libs/colorpicker.c index 82e02f173d5..39dc733fe61 100644 --- a/src/libs/colorpicker.c +++ b/src/libs/colorpicker.c @@ -621,6 +621,7 @@ static void _add_sample(GtkButton *widget, _("hover to highlight sample on canvas,\n" "click to lock sample,\n" "right-click to load sample area into active color picker")); + gtk_widget_add_events(sample->color_patch, GDK_BUTTON_PRESS_MASK); dt_gui_connect_click_all(sample->color_patch, _live_sample_button_cb, NULL, sample); g_signal_connect(G_OBJECT(sample->color_patch), "draw", G_CALLBACK(_sample_draw_callback), sample); @@ -726,6 +727,9 @@ void gui_init(dt_lib_module_t *self) gtk_widget_set_tooltip_text(color_patch, _("click to (un)hide large color patch")); g_signal_connect(G_OBJECT(color_patch), "draw", G_CALLBACK(_sample_draw_callback), &data->primary_sample); + gtk_widget_set_events(color_patch, + GDK_BUTTON_PRESS_MASK + | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK); dt_gui_connect_click(color_patch, _large_patch_toggle_cb, NULL, data); dt_gui_connect_motion(color_patch, NULL, _sample_enter_callback, _sample_leave_callback, &data->primary_sample); GtkWidget *color_patch_wrapper = dt_gui_hbox(dt_gui_expand(color_patch)); @@ -772,6 +776,7 @@ void gui_init(dt_lib_module_t *self) data->primary_sample.color_patch = color_patch = gtk_drawing_area_new(); gtk_widget_set_tooltip_text(color_patch, _("click to (un)hide large color patch")); + gtk_widget_set_events(color_patch, GDK_BUTTON_PRESS_MASK); dt_gui_connect_click(color_patch, _large_patch_toggle_cb, NULL, data); g_signal_connect(G_OBJECT(color_patch), "draw", G_CALLBACK(_sample_draw_callback), &data->primary_sample); diff --git a/src/libs/tools/ratings.c b/src/libs/tools/ratings.c index ce08f042b71..d7a01e36aba 100644 --- a/src/libs/tools/ratings.c +++ b/src/libs/tools/ratings.c @@ -90,7 +90,10 @@ void gui_init(dt_lib_module_t *self) GtkWidget *drawing = gtk_drawing_area_new(); - gtk_widget_set_events(drawing, GDK_EXPOSURE_MASK | GDK_STRUCTURE_MASK); + gtk_widget_set_events(drawing, GDK_EXPOSURE_MASK | GDK_STRUCTURE_MASK + | GDK_POINTER_MOTION_MASK + | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK + | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK); /* connect callbacks */ gtk_widget_set_tooltip_text(drawing, _("set star rating for selected images")); From f098290bdf19b17d90024319e8e10b77e253c5e8 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 17:22:51 -0300 Subject: [PATCH 79/95] gtk4-prep: use signal handlers for bauhaus popup (GTK_WINDOW_POPUP quirk) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GtkEventControllerMotion and GtkEventControllerKey don't receive events on GTK_WINDOW_POPUP windows in GTK3. This is a known issue with this window type — motion and key events never reach the controllers even with explicit event masks set. Replace the motion and key controllers on the popup with direct signal handler connections (motion-notify-event, leave-notify-event, key-press-event). Click and scroll controllers are kept since those work fine. GTK4 TODO: the popup should be migrated to GtkPopover which uses proper event controllers. --- src/bauhaus/bauhaus.c | 46 ++++++++++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/src/bauhaus/bauhaus.c b/src/bauhaus/bauhaus.c index 14d1ced3ce7..8ba15ae249c 100644 --- a/src/bauhaus/bauhaus.c +++ b/src/bauhaus/bauhaus.c @@ -692,26 +692,33 @@ static void _window_motion_handle(GtkWidget *widget, gtk_widget_queue_draw(pop->area); } -static void _window_motion_cb(GtkEventControllerMotion *controller, - gdouble x, - gdouble y, - gpointer user_data) +// GTK4 TODO: This popup uses GTK_WINDOW_POPUP which has compatibility issues +// with GtkEventControllerKey and GtkEventControllerMotion on GTK3 — motion +// and key events don't reach the controllers on this window type. The signal +// handlers below are the fallback. For GTK4, the popup should be migrated to +// GtkPopover or a GtkWindow with proper event controllers. + +static gboolean _window_motion_handler(GtkWidget *widget, GdkEventMotion *event, + gpointer user_data) +{ + _window_motion_handle(widget, + dt_gdk_event_get_root_x(event), + dt_gdk_event_get_root_y(event), + dt_gdk_event_get_state(event)); + return TRUE; +} + +static gboolean _popup_leave_handler(GtkWidget *widget, GdkEventCrossing *event, + gpointer user_data) { - GtkWidget *widget = dt_gui_get_widget(controller); - GdkEvent *event = gtk_get_current_event(); - if(!event) return; - const gdouble root_x = dt_gdk_event_get_root_x(event); - const gdouble root_y = dt_gdk_event_get_root_y(event); - const GdkModifierType state = dt_gdk_event_get_state(event); - gdk_event_free(event); - _window_motion_handle(widget, root_x, root_y, state); + gtk_widget_set_state_flags(widget, GTK_STATE_FLAG_NORMAL, TRUE); + return TRUE; } -static void _popup_leave_notify_cb(GtkEventControllerMotion *controller, +static gboolean _popup_key_handler(GtkWidget *widget, GdkEventKey *event, gpointer user_data) { - GtkWidget *widget = dt_gui_get_widget(controller); - gtk_widget_set_state_flags(widget, GTK_STATE_FLAG_NORMAL, TRUE); + return _popup_key_press(NULL, dt_gdk_event_get_keyval(event), 0, dt_gdk_event_get_state(event), NULL); } static void _popup_button_release_cb(GtkGestureSingle *gesture, @@ -789,6 +796,8 @@ static void _window_show(GtkWidget *w, gpointer user_data) { // make sure combo popup handles button release gtk_grab_add(GTK_WIDGET(user_data)); + // grab keyboard focus so the popup receives key events + gtk_widget_grab_focus(GTK_WIDGET(user_data)); } static void _widget_leave(GtkEventControllerMotion *controller, @@ -1017,6 +1026,7 @@ void dt_bauhaus_init() gtk_window_set_modal(GTK_WINDOW(pop->window), TRUE); gtk_window_set_type_hint(GTK_WINDOW(pop->window), GDK_WINDOW_TYPE_HINT_POPUP_MENU); + gtk_widget_add_events(pop->window, GDK_POINTER_MOTION_MASK); pop->area = gtk_drawing_area_new(); g_object_set(pop->area, "expand", TRUE, NULL); @@ -1036,9 +1046,9 @@ void dt_bauhaus_init() "moved-to-rect", G_CALLBACK(_window_moved_to_rect), NULL); g_signal_connect(window, "show", G_CALLBACK(_window_show), area); g_signal_connect(area, "draw", G_CALLBACK(_popup_draw), NULL); - dt_gui_connect_key(area, _popup_key_press, NULL); - dt_gui_connect_motion(area, NULL, NULL, _popup_leave_notify_cb, NULL); - dt_gui_connect_motion(window, _window_motion_cb, NULL, NULL, NULL); + g_signal_connect(window, "motion-notify-event", G_CALLBACK(_window_motion_handler), NULL); + g_signal_connect(area, "leave-notify-event", G_CALLBACK(_popup_leave_handler), NULL); + g_signal_connect(area, "key-press-event", G_CALLBACK(_popup_key_handler), NULL); dt_gui_connect_click_all(area, _popup_button_press_cb, _popup_button_release_cb, NULL); dt_gui_connect_scroll(area, GTK_EVENT_CONTROLLER_SCROLL_BOTH_AXES | GTK_EVENT_CONTROLLER_SCROLL_DISCRETE, From 07291ad0027ae7b65412ba5cf87c9d553b58e793 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 17:22:56 -0300 Subject: [PATCH 80/95] gtk4-prep: use clicked signal for filter preferences button Replace gesture controller with the GtkButton ::clicked signal for the filter preferences button. Gesture controllers on custom button widgets (dtgtk_button) can conflict with the button's internal event handling. ::clicked is the standard GTK4-compatible way to handle button presses. --- src/libs/tools/filter.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/libs/tools/filter.c b/src/libs/tools/filter.c index 2bbe480755f..705925e9455 100644 --- a/src/libs/tools/filter.c +++ b/src/libs/tools/filter.c @@ -85,14 +85,9 @@ static GtkWidget *_lib_filter_get_count(dt_lib_module_t *self) return d->count; } -static void _pref_show(GtkGestureSingle *gesture, - gint n_press, - gdouble x, - gdouble y, - dt_lib_module_t *self) +static void _pref_show(GtkButton *button, dt_lib_module_t *self) { - GtkWidget *widget = dt_gui_get_widget(gesture); - dt_view_filtering_show_pref_menu(darktable.view_manager, widget); + dt_view_filtering_show_pref_menu(darktable.view_manager, GTK_WIDGET(button)); } void gui_init(dt_lib_module_t *self) @@ -106,7 +101,7 @@ void gui_init(dt_lib_module_t *self) GtkWidget *bt = dtgtk_button_new(dtgtk_cairo_paint_filtering_menu, 0, NULL); gtk_widget_set_tooltip_text(bt, _("filter preferences")); - dt_gui_connect_click(bt, _pref_show, NULL, self); + g_signal_connect(G_OBJECT(bt), "clicked", G_CALLBACK(_pref_show), self); gtk_box_pack_start(GTK_BOX(self->widget), bt, FALSE, TRUE, 0); d->filter_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); From cb674d58373bf2891bcec145d0531027157a14f8 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 17:23:01 -0300 Subject: [PATCH 81/95] gtk4-prep: restore button-inside-header guard in IOP module headers The GTK_IS_BUTTON(gtk_get_event_widget(event)) check was lost during the event controller conversion. Without it, clicking on any button inside the module header (presets, reset, enable, multiinstance) also toggles the expander, causing the module to open/close unexpectedly. GTK4: use gtk_gesture_get_last_event(gesture) instead of gtk_get_current_event(). --- src/develop/imageop.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/develop/imageop.c b/src/develop/imageop.c index 5c6e06b5696..3cc4b1288c6 100644 --- a/src/develop/imageop.c +++ b/src/develop/imageop.c @@ -2777,6 +2777,19 @@ static void _iop_plugin_header_released(GtkGestureSingle *gesture, { if(n_press >= 2) return; + // ignore clicks on buttons inside the header (presets, reset, enable, multiinstance) + // GTK4: use gtk_gesture_get_last_event(gesture) instead of gtk_get_current_event() + GdkEvent *event = gtk_get_current_event(); + if(event) + { + if(GTK_IS_BUTTON(gtk_get_event_widget(event))) + { + gdk_event_free(event); + return; + } + gdk_event_free(event); + } + const guint button = gtk_gesture_single_get_current_button(gesture); if(button == GDK_BUTTON_PRIMARY) From fadb56d457a74c7b761e702598a04b511ded827e Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 17:23:06 -0300 Subject: [PATCH 82/95] gtk4-prep: fix lib module header and button event handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Fix arrow button: replace gtk_gesture_single_get_button() with _get_current_button() — the arrow was connected via click_all (button=0), so get_button() always returned 0, making the arrow completely unresponsive. - Restore GTK_IS_BUTTON guard in header release callback — prevents button clicks inside the header from toggling the expander. - Switch presets button from gesture (press=reset, release=popup) to GtkButton ::clicked signal, which only does the popup. The old gesture approach reset the module on every press. - Add dt_gui_claim() to the reset callback so the event is consumed, preventing the button's internal handling from also firing. --- src/libs/lib.c | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/src/libs/lib.c b/src/libs/lib.c index 05c3f43d156..a3f15255648 100644 --- a/src/libs/lib.c +++ b/src/libs/lib.c @@ -973,6 +973,7 @@ static void _lib_gui_reset_callback(GtkGestureSingle *gesture, module->gui_reset(module); if(module->has_preset_label(module)) gtk_label_set_text(GTK_LABEL(module->preset_label), ""); + dt_gui_claim(gesture); } static void _presets_popup_callback(GtkWidget *button, @@ -985,14 +986,6 @@ static void _presets_popup_callback(GtkWidget *button, dtgtk_button_set_active(DTGTK_BUTTON(button), FALSE); } -static void _presets_popup_gesture_cb(GtkGestureSingle *gesture, - gint n_press, - gdouble x, - gdouble y, - dt_lib_module_t *module) -{ - _presets_popup_callback(dt_gui_get_widget(gesture), module); -} void dt_lib_gui_set_expanded(dt_lib_module_t *module, const gboolean expanded) { @@ -1042,7 +1035,7 @@ static void _lib_plugin_arrow_button_press_cb(GtkGestureSingle *gesture, dt_lib_module_t *module) { if(n_press > 1) return; - const guint button = gtk_gesture_single_get_button(gesture); + const guint button = gtk_gesture_single_get_current_button(gesture); GdkModifierType state; gtk_get_current_event_state(&state); @@ -1108,6 +1101,18 @@ static void _lib_plugin_header_button_release_cb(GtkGestureSingle *gesture, gdouble y, dt_lib_module_t *module) { + // ignore clicks on buttons inside the header (presets, reset, enable) + // GTK4: use gtk_gesture_get_last_event(gesture) instead of gtk_get_current_event() + GdkEvent *event = gtk_get_current_event(); + if(event) + { + if(GTK_IS_BUTTON(gtk_get_event_widget(event))) + { + gdk_event_free(event); + return; + } + gdk_event_free(event); + } _lib_plugin_arrow_button_press_cb(gesture, n_press, x, y, module); } @@ -1308,7 +1313,7 @@ GtkWidget *dt_lib_gui_get_expander(dt_lib_module_t *module) // FIXME separately define as darkroom widget shortcut/action, // because not automatically registered via lib if presets btn // has been loaded to be shown outside expander - dt_gui_connect_click(module->presets_button, _presets_popup_gesture_cb, NULL, module); + g_signal_connect(G_OBJECT(module->presets_button), "clicked", G_CALLBACK(_presets_popup_callback), module); } module->expander = NULL; return NULL; @@ -1334,7 +1339,7 @@ GtkWidget *dt_lib_gui_get_expander(dt_lib_module_t *module) } /* setup the header box */ - dt_gui_connect_click(header_evb, _lib_plugin_arrow_button_press_cb, _lib_plugin_header_button_release_cb, module); + dt_gui_connect_click(header_evb, NULL, _lib_plugin_header_button_release_cb, module); dt_gui_connect_motion(header_evb, NULL, _header_enter_notify_callback, NULL, GINT_TO_POINTER(DT_ACTION_ELEMENT_SHOW)); /* (un)focus module when entering/leaving body */ @@ -1379,7 +1384,7 @@ GtkWidget *dt_lib_gui_get_expander(dt_lib_module_t *module) /* add preset button if module has implementation */ module->presets_button = dtgtk_button_new(dtgtk_cairo_paint_presets, 0, NULL); gtk_widget_set_tooltip_text(module->presets_button, _("presets and preferences")); - dt_gui_connect_click(module->presets_button, _lib_gui_reset_callback, _presets_popup_gesture_cb, module); + g_signal_connect(G_OBJECT(module->presets_button), "clicked", G_CALLBACK(_presets_popup_callback), module); dt_gui_connect_motion(module->presets_button, NULL, _header_enter_notify_callback, NULL, GINT_TO_POINTER(DT_ACTION_ELEMENT_PRESETS)); if(!module->get_params && !module->set_preferences) From 20d27e3853800366bbd56fdbf4150badb3401f1a Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 17:30:40 -0300 Subject: [PATCH 83/95] gtk4-prep: update copyright year for timeline.c --- src/libs/tools/timeline.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/tools/timeline.c b/src/libs/tools/timeline.c index 8ac47879fc7..02f68e3a04a 100644 --- a/src/libs/tools/timeline.c +++ b/src/libs/tools/timeline.c @@ -1,6 +1,6 @@ /* This file is part of darktable, - Copyright (C) 2019-2021 darktable developers. + Copyright (C) 2019-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 From f3d66a2e720eddf064b2f366a1d86dc35d03d89f Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 17:48:54 -0300 Subject: [PATCH 84/95] gtk4-prep: fix stale static gboolean in preferences_ai click callback --- src/gui/gtk.h | 2 +- src/gui/preferences_ai.c | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/gui/gtk.h b/src/gui/gtk.h index d72f6514236..2732df4656c 100644 --- a/src/gui/gtk.h +++ b/src/gui/gtk.h @@ -550,7 +550,7 @@ void dt_gui_hide_collapsible_section(const dt_gui_collapsible_section_t *cs); gboolean dt_gui_long_click(const guint second, const guint first); -#define ASSERT_FUNC_TYPE(func, expected_type) (void)(1 ? (func) : (expected_type)0) +#define ASSERT_FUNC_TYPE(func, expected_type) (void)(sizeof((func), (expected_type)0)) GtkGestureSingle *(dt_gui_connect_click)(GtkWidget *widget, GCallback pressed, diff --git a/src/gui/preferences_ai.c b/src/gui/preferences_ai.c index f983ff3f03c..ce18431ecfc 100644 --- a/src/gui/preferences_ai.c +++ b/src/gui/preferences_ai.c @@ -608,7 +608,6 @@ static void _on_provider_changed(GtkWidget *widget, gpointer user_data) } // double-click on label resets the enable toggle to default -static gboolean static void _reset_enable_click_cb(GtkGestureSingle *gesture, int n_press, double x, double y, GtkWidget *widget) From 19b892af4cceef01aa7528788ffb73535e88e761 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 18:15:28 -0300 Subject: [PATCH 85/95] gtk4-prep: fix ASSERT_FUNC_TYPE macro for NULL callbacks Use a simple cast (expected_type)(func) instead of the ternary or comma-operator tricks. Casting NULL to a function pointer type is valid C, and G_CALLBACK casts in the actual call already enforce the real type checking. --- src/gui/gtk.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/gtk.h b/src/gui/gtk.h index 2732df4656c..7453badf47f 100644 --- a/src/gui/gtk.h +++ b/src/gui/gtk.h @@ -550,7 +550,7 @@ void dt_gui_hide_collapsible_section(const dt_gui_collapsible_section_t *cs); gboolean dt_gui_long_click(const guint second, const guint first); -#define ASSERT_FUNC_TYPE(func, expected_type) (void)(sizeof((func), (expected_type)0)) +#define ASSERT_FUNC_TYPE(func, expected_type) (void)((expected_type)(func)) GtkGestureSingle *(dt_gui_connect_click)(GtkWidget *widget, GCallback pressed, From 1fa2ac3ebefd00c4b41726a7207fd1cacfbe3d61 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 20:08:04 -0300 Subject: [PATCH 86/95] gtk4-prep: simplify filtering rule removal logic When removing a filtering rule, the same config-shifting code was duplicated between the main panel's close button and the topbar popover's remove button. This pulls it into a shared helper. Along the way, a few issues in the topbar popover's removal function are cleaned up: a redundant data lookup, a GList that was never freed, and a parent widget that was looked up twice. --- src/libs/filtering.c | 130 ++++++++++++++++--------------------------- 1 file changed, 47 insertions(+), 83 deletions(-) diff --git a/src/libs/filtering.c b/src/libs/filtering.c index d5c7c8d0a70..efb2fd51d47 100644 --- a/src/libs/filtering.c +++ b/src/libs/filtering.c @@ -1160,6 +1160,47 @@ static void _event_rule_disable(GtkWidget *widget, dt_lib_filtering_rule_t *rule _widget_header_update(rule); } +static void _rule_remove_config_entries(dt_lib_module_t *self, dt_lib_filtering_rule_t *rule) +{ + dt_lib_filtering_t *d = rule->lib; + if(d->nb_rules <= 0) return; + d->nb_rules--; + dt_conf_set_int("plugins/lighttable/filtering/num_rules", d->nb_rules); + + // move up all still active rules by one. + for(int i = rule->num; i < DT_COLLECTION_MAX_RULES - 1; i++) + { + char confname[200] = { 0 }; + snprintf(confname, sizeof(confname), "plugins/lighttable/filtering/mode%1d", i + 1); + const int mode = dt_conf_get_int(confname); + snprintf(confname, sizeof(confname), "plugins/lighttable/filtering/item%1d", i + 1); + const int item = dt_conf_get_int(confname); + snprintf(confname, sizeof(confname), "plugins/lighttable/filtering/off%1d", i + 1); + const int off = dt_conf_get_int(confname); + snprintf(confname, sizeof(confname), "plugins/lighttable/filtering/top%1d", i + 1); + const int top = dt_conf_get_int(confname); + snprintf(confname, sizeof(confname), "plugins/lighttable/filtering/string%1d", i + 1); + gchar *string = dt_conf_get_string(confname); + if(string) + { + snprintf(confname, sizeof(confname), "plugins/lighttable/filtering/mode%1d", i); + dt_conf_set_int(confname, mode); + snprintf(confname, sizeof(confname), "plugins/lighttable/filtering/item%1d", i); + dt_conf_set_int(confname, item); + snprintf(confname, sizeof(confname), "plugins/lighttable/filtering/off%1d", i); + dt_conf_set_int(confname, off); + snprintf(confname, sizeof(confname), "plugins/lighttable/filtering/top%1d", i); + dt_conf_set_int(confname, top); + snprintf(confname, sizeof(confname), "plugins/lighttable/filtering/string%1d", i); + dt_conf_set_string(confname, string); + g_free(string); + } + } + + _filters_gui_update(self); + dt_collection_update_query(darktable.collection, DT_COLLECTION_CHANGE_RELOAD, rule->prop, NULL); +} + static void _event_rule_close_cb(GtkGestureSingle *gesture, int n_press, double x, double y, dt_lib_module_t *self) @@ -1169,48 +1210,7 @@ static void _event_rule_close_cb(GtkGestureSingle *gesture, int n_press, if(rule->manual_widget_set) return; if(!rule->topbar) - { - // decrease the nb of active rules - dt_lib_filtering_t *d = rule->lib; - if(d->nb_rules <= 0) return; - d->nb_rules--; - dt_conf_set_int("plugins/lighttable/filtering/num_rules", d->nb_rules); - - // move up all still active rules by one. - for(int i = rule->num; i < DT_COLLECTION_MAX_RULES - 1; i++) - { - char confname[200] = { 0 }; - snprintf(confname, sizeof(confname), "plugins/lighttable/filtering/mode%1d", i + 1); - const int mode = dt_conf_get_int(confname); - snprintf(confname, sizeof(confname), "plugins/lighttable/filtering/item%1d", i + 1); - const int item = dt_conf_get_int(confname); - snprintf(confname, sizeof(confname), "plugins/lighttable/filtering/off%1d", i + 1); - const int off = dt_conf_get_int(confname); - snprintf(confname, sizeof(confname), "plugins/lighttable/filtering/top%1d", i + 1); - const int top = dt_conf_get_int(confname); - snprintf(confname, sizeof(confname), "plugins/lighttable/filtering/string%1d", i + 1); - gchar *string = dt_conf_get_string(confname); - if(string) - { - snprintf(confname, sizeof(confname), "plugins/lighttable/filtering/mode%1d", i); - dt_conf_set_int(confname, mode); - snprintf(confname, sizeof(confname), "plugins/lighttable/filtering/item%1d", i); - dt_conf_set_int(confname, item); - snprintf(confname, sizeof(confname), "plugins/lighttable/filtering/off%1d", i); - dt_conf_set_int(confname, off); - snprintf(confname, sizeof(confname), "plugins/lighttable/filtering/top%1d", i); - dt_conf_set_int(confname, top); - snprintf(confname, sizeof(confname), "plugins/lighttable/filtering/string%1d", i); - dt_conf_set_string(confname, string); - g_free(string); - } - } - - _filters_gui_update(self); - dt_collection_update_query(darktable.collection, DT_COLLECTION_CHANGE_RELOAD, rule->prop, NULL); - } - else - return; + _rule_remove_config_entries(self, rule); } static gboolean _rule_available_for_topbar(const dt_collection_properties_t prop) @@ -1677,55 +1677,19 @@ static void _topbar_rule_remove_cb(GtkGestureSingle *gesture, int n_press, _topbar_update(self); // remove the rule - dt_lib_filtering_rule_t *r = (dt_lib_filtering_rule_t *)g_object_get_data(G_OBJECT(widget), "rule"); - if(!r->manual_widget_set && !r->topbar) - { - if(d->nb_rules > 0) - { - d->nb_rules--; - dt_conf_set_int("plugins/lighttable/filtering/num_rules", d->nb_rules); - for(int i = r->num; i < DT_COLLECTION_MAX_RULES - 1; i++) - { - char confname[200] = { 0 }; - snprintf(confname, sizeof(confname), "plugins/lighttable/filtering/mode%1d", i + 1); - const int mode = dt_conf_get_int(confname); - snprintf(confname, sizeof(confname), "plugins/lighttable/filtering/item%1d", i + 1); - const int item = dt_conf_get_int(confname); - snprintf(confname, sizeof(confname), "plugins/lighttable/filtering/off%1d", i + 1); - const int off = dt_conf_get_int(confname); - snprintf(confname, sizeof(confname), "plugins/lighttable/filtering/top%1d", i + 1); - const int top = dt_conf_get_int(confname); - snprintf(confname, sizeof(confname), "plugins/lighttable/filtering/string%1d", i + 1); - gchar *string = dt_conf_get_string(confname); - if(string) - { - snprintf(confname, sizeof(confname), "plugins/lighttable/filtering/mode%1d", i); - dt_conf_set_int(confname, mode); - snprintf(confname, sizeof(confname), "plugins/lighttable/filtering/item%1d", i); - dt_conf_set_int(confname, item); - snprintf(confname, sizeof(confname), "plugins/lighttable/filtering/off%1d", i); - dt_conf_set_int(confname, off); - snprintf(confname, sizeof(confname), "plugins/lighttable/filtering/top%1d", i); - dt_conf_set_int(confname, top); - snprintf(confname, sizeof(confname), "plugins/lighttable/filtering/string%1d", i); - dt_conf_set_string(confname, string); - g_free(string); - } - } - _filters_gui_update(self); - dt_collection_update_query(darktable.collection, DT_COLLECTION_CHANGE_RELOAD, r->prop, NULL); - } - } + _rule_remove_config_entries(self, rule); // reconstruct the combobox GtkWidget *hb = gtk_widget_get_parent(widget); - GList *childs = gtk_container_get_children(GTK_CONTAINER(gtk_widget_get_parent(hb))); + GtkWidget *popover_vbox = gtk_widget_get_parent(hb); + GList *childs = gtk_container_get_children(GTK_CONTAINER(popover_vbox)); GtkWidget *combo = g_list_last(childs)->data; + g_list_free(childs); dt_bauhaus_combobox_clear(combo); _topbar_populate_rules_combo(combo, d); // remove the entry from the popover - gtk_container_remove(GTK_CONTAINER(gtk_widget_get_parent(hb)), hb); + gtk_container_remove(GTK_CONTAINER(popover_vbox), hb); } static GtkWidget *_topbar_menu_new_rule(dt_lib_filtering_rule_t *rule, dt_lib_module_t *self) From 190d0f5f4b633d9aaf4cbc52cc7f574be757d46b Mon Sep 17 00:00:00 2001 From: Arecsu Date: Fri, 31 Jul 2026 17:07:43 -0300 Subject: [PATCH 87/95] gtk4-prep: convert missed retouch togglebutton callbacks to gestures --- src/iop/retouch.c | 130 +++++++++++++++++++++++++--------------------- 1 file changed, 72 insertions(+), 58 deletions(-) diff --git a/src/iop/retouch.c b/src/iop/retouch.c index 5c6934393f2..902cf02ba93 100644 --- a/src/iop/retouch.c +++ b/src/iop/retouch.c @@ -1612,22 +1612,26 @@ void color_picker_apply(dt_iop_module_t *self, dt_dev_add_history_item(darktable.develop, self, TRUE); } -static gboolean rt_copypaste_scale_callback(GtkToggleButton *togglebutton, - GdkEventButton *event, - dt_iop_module_t *self) +static void rt_copypaste_scale_callback(GtkGestureSingle *gesture, + int n_press, + double x, + double y, + dt_iop_module_t *self) { - DT_TRY_GUI_UPDATE(TRUE); + if(dt_atomic_get_int(&darktable.gui->reset) != 0) return; + + GtkWidget *widget = dt_gui_get_widget(gesture); int scale_copied = 0; - const int active = !gtk_toggle_button_get_active(togglebutton); + const int active = !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)); dt_iop_retouch_params_t *p = self->params; dt_iop_retouch_gui_data_t *g = self->gui_data; - if(togglebutton == (GtkToggleButton *)g->bt_copy_scale) + if(widget == g->bt_copy_scale) { g->copied_scale = (active) ? p->curr_scale : -1; } - else if(togglebutton == (GtkToggleButton *)g->bt_paste_scale) + else if(widget == g->bt_paste_scale) { rt_paste_forms_from_scale(p, g->copied_scale, p->curr_scale); rt_show_forms_for_current_scale(self); @@ -1643,18 +1647,18 @@ static gboolean rt_copypaste_scale_callback(GtkToggleButton *togglebutton, gtk_widget_set_sensitive(g->bt_paste_scale, g->copied_scale >= 0); - DT_LEAVE_GUI_UPDATE(); - if(scale_copied) dt_dev_add_history_item(darktable.develop, self, TRUE); - - return TRUE; } -static gboolean rt_display_wavelet_scale_callback(GtkToggleButton *togglebutton, - GdkEventButton *event, - dt_iop_module_t *self) +static void rt_display_wavelet_scale_callback(GtkGestureSingle *gesture, + int n_press, + double x, + double y, + dt_iop_module_t *self) { - DT_GUARD_GUI_UPDATE(TRUE); + if(dt_atomic_get_int(&darktable.gui->reset) != 0) return; + + GtkWidget *widget = dt_gui_get_widget(gesture); dt_iop_retouch_params_t *p = self->params; dt_iop_retouch_gui_data_t *g = self->gui_data; @@ -1666,16 +1670,16 @@ static gboolean rt_display_wavelet_scale_callback(GtkToggleButton *togglebutton, dt_control_log(_("cannot display scales when the blending mask is displayed")); DT_ENTER_GUI_UPDATE(); - gtk_toggle_button_set_active(togglebutton, FALSE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), FALSE); DT_LEAVE_GUI_UPDATE(); - return TRUE; + return; } if(self->off) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(self->off), 1); dt_iop_request_focus(self); - g->display_wavelet_scale = !gtk_toggle_button_get_active(togglebutton); + g->display_wavelet_scale = !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)); rt_show_hide_controls(self); @@ -1697,8 +1701,7 @@ static gboolean rt_display_wavelet_scale_callback(GtkToggleButton *togglebutton, dt_dev_reprocess_center(self->dev, self->iop_order); - gtk_toggle_button_set_active(togglebutton, g->display_wavelet_scale); - return TRUE; + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), g->display_wavelet_scale); } static void rt_develop_ui_pipe_finished_callback(gpointer instance, @@ -1740,11 +1743,13 @@ static void rt_develop_ui_pipe_finished_callback(gpointer instance, gtk_widget_queue_draw(GTK_WIDGET(g->wd_bar)); } -static gboolean rt_auto_levels_callback(GtkToggleButton *togglebutton, - GdkEventButton *event, - dt_iop_module_t *self) +static void rt_auto_levels_callback(GtkGestureSingle *gesture, + int n_press, + double x, + double y, + dt_iop_module_t *self) { - DT_GUARD_GUI_UPDATE(FALSE); + if(dt_atomic_get_int(&darktable.gui->reset) != 0) return; dt_iop_retouch_gui_data_t *g = self->gui_data; @@ -1759,8 +1764,6 @@ static gboolean rt_auto_levels_callback(GtkToggleButton *togglebutton, dt_iop_gui_leave_critical_section(self); dt_iop_refresh_center(self); - - return TRUE; } static void rt_mask_opacity_callback(GtkWidget *slider, @@ -1921,31 +1924,38 @@ static void rt_add_shape_callback(GtkGestureSingle *gesture, rt_shape_is_being_added(self, DT_MASKS_BRUSH)); } -static gboolean rt_select_algorithm_callback(GtkToggleButton *togglebutton, - GdkEventButton *e, - dt_iop_module_t *self) +static void rt_select_algorithm_callback(GtkGestureSingle *gesture, + int n_press, + double x, + double y, + dt_iop_module_t *self) { - DT_TRY_GUI_UPDATE(FALSE); + if(dt_atomic_get_int(&darktable.gui->reset) != 0) return; + + GtkWidget *widget = dt_gui_get_widget(gesture); dt_iop_retouch_params_t *p = self->params; dt_iop_retouch_gui_data_t *g = self->gui_data; dt_iop_retouch_algo_type_t new_algo = DT_IOP_RETOUCH_HEAL; - if(togglebutton == (GtkToggleButton *)g->bt_blur) + if(widget == g->bt_blur) new_algo = DT_IOP_RETOUCH_BLUR; - else if(togglebutton == (GtkToggleButton *)g->bt_clone) + else if(widget == g->bt_clone) new_algo = DT_IOP_RETOUCH_CLONE; - else if(togglebutton == (GtkToggleButton *)g->bt_heal) + else if(widget == g->bt_heal) new_algo = DT_IOP_RETOUCH_HEAL; - else if(togglebutton == (GtkToggleButton *)g->bt_fill) + else if(widget == g->bt_fill) new_algo = DT_IOP_RETOUCH_FILL; // check if we have to do something gboolean accept = TRUE; + GdkEvent *event = gtk_get_current_event(); + const GdkModifierType state = event ? dt_gdk_event_get_state(event) : 0; + const int index = rt_get_selected_shape_index(p); - if(index >= 0 && dt_modifier_is(e->state, GDK_CONTROL_MASK)) + if(index >= 0 && dt_modifier_is(state, GDK_CONTROL_MASK)) { if(new_algo != p->rt_forms[index].algorithm) { @@ -1980,11 +1990,11 @@ static gboolean rt_select_algorithm_callback(GtkToggleButton *togglebutton, if(!accept) { - DT_LEAVE_GUI_UPDATE(); - return FALSE; + if(event) gdk_event_free(event); + return; } - if(index >= 0 && dt_modifier_is(e->state, GDK_CONTROL_MASK)) + if(index >= 0 && dt_modifier_is(state, GDK_CONTROL_MASK)) { if(p->algorithm != p->rt_forms[index].algorithm) { @@ -2017,12 +2027,12 @@ static gboolean rt_select_algorithm_callback(GtkToggleButton *togglebutton, dt_control_queue_redraw_center(); } - DT_LEAVE_GUI_UPDATE(); + if(event) gdk_event_free(event); dt_dev_add_history_item(darktable.develop, self, TRUE); // if we have the shift key pressed, we set it as default - if(dt_modifier_is(e->state, GDK_SHIFT_MASK)) + if(dt_modifier_is(state, GDK_SHIFT_MASK)) { dt_conf_set_int("plugins/darkroom/retouch/default_algo", p->algorithm); // and we show a toat msg to confirm @@ -2035,15 +2045,17 @@ static gboolean rt_select_algorithm_callback(GtkToggleButton *togglebutton, else if(p->algorithm == DT_IOP_RETOUCH_BLUR) dt_control_log(_("default tool changed to %s"), _("blur")); } - - return TRUE; } -static gboolean rt_showmask_callback(GtkToggleButton *togglebutton, - GdkEventButton *event, - dt_iop_module_t *self) +static void rt_showmask_callback(GtkGestureSingle *gesture, + int n_press, + double x, + double y, + dt_iop_module_t *self) { - DT_GUARD_GUI_UPDATE(TRUE); + if(dt_atomic_get_int(&darktable.gui->reset) != 0) return; + + GtkWidget *widget = dt_gui_get_widget(gesture); dt_iop_retouch_gui_data_t *g = self->gui_data; @@ -2053,11 +2065,11 @@ static gboolean rt_showmask_callback(GtkToggleButton *togglebutton, { dt_control_log(_("cannot display masks when the blending mask is displayed")); - gtk_toggle_button_set_active(togglebutton, FALSE); - return TRUE; + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), FALSE); + return; } - g->mask_display = !gtk_toggle_button_get_active(togglebutton); + g->mask_display = !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)); if(self->off) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(self->off), 1); @@ -2065,26 +2077,28 @@ static gboolean rt_showmask_callback(GtkToggleButton *togglebutton, dt_iop_refresh_center(self); - gtk_toggle_button_set_active(togglebutton, g->mask_display); - return TRUE; + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), g->mask_display); } -static gboolean rt_suppress_callback(GtkToggleButton *togglebutton, - GdkEventButton *event, - dt_iop_module_t *self) +static void rt_suppress_callback(GtkGestureSingle *gesture, + int n_press, + double x, + double y, + dt_iop_module_t *self) { - DT_GUARD_GUI_UPDATE(TRUE); + if(dt_atomic_get_int(&darktable.gui->reset) != 0) return; + + GtkWidget *widget = dt_gui_get_widget(gesture); dt_iop_retouch_gui_data_t *g = self->gui_data; - g->suppress_mask = !gtk_toggle_button_get_active(togglebutton); + g->suppress_mask = !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)); if(self->off) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(self->off), 1); dt_iop_request_focus(self); dt_iop_refresh_center(self); - gtk_toggle_button_set_active(togglebutton, g->suppress_mask); - return TRUE; + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), g->suppress_mask); } void gui_changed(dt_iop_module_t *self, GtkWidget *w, void *previous) From b82f56448f97408e69eb9c9e293eac70f89d0429 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Fri, 31 Jul 2026 19:05:16 -0300 Subject: [PATCH 88/95] gtk4-prep: fix gesture button detection and long-press timing on press/release callbacks --- src/dtgtk/culling.c | 4 ++-- src/dtgtk/thumbtable.c | 4 ++-- src/libs/filtering.c | 2 +- src/libs/navigation.c | 2 +- src/libs/tools/global_toolbox.c | 11 ++++++----- src/libs/tools/log_history.c | 4 ++-- src/libs/tools/timeline.c | 2 +- src/views/darkroom.c | 17 ++++++++++++----- 8 files changed, 27 insertions(+), 19 deletions(-) diff --git a/src/dtgtk/culling.c b/src/dtgtk/culling.c index ded4149073f..6a91fea3232 100644 --- a/src/dtgtk/culling.c +++ b/src/dtgtk/culling.c @@ -876,10 +876,10 @@ static void _event_button_press_cb(GtkGestureSingle *gesture, * occurs for primary button). * * GTK4 migration: remove the ternary and just call - * gtk_gesture_single_get_button(gesture) directly — GtkGestureClick + * gtk_gesture_single_get_current_button(gesture) directly — GtkGestureClick * will provide a valid gesture pointer for all n_press values. */ const guint button = gesture - ? gtk_gesture_single_get_button(gesture) + ? gtk_gesture_single_get_current_button(gesture) : GDK_BUTTON_PRIMARY; if(button == GDK_BUTTON_PRIMARY && n_press == 1) diff --git a/src/dtgtk/thumbtable.c b/src/dtgtk/thumbtable.c index cb080406c4d..e3873de9a6a 100644 --- a/src/dtgtk/thumbtable.c +++ b/src/dtgtk/thumbtable.c @@ -1453,10 +1453,10 @@ static void _event_button_press_cb(GtkGestureSingle *gesture, * occurs for primary button). * * GTK4 migration: remove the ternary and just call - * gtk_gesture_single_get_button(gesture) directly — GtkGestureClick + * gtk_gesture_single_get_current_button(gesture) directly — GtkGestureClick * will provide a valid gesture pointer for all n_press values. */ const guint button = gesture - ? gtk_gesture_single_get_button(gesture) + ? gtk_gesture_single_get_current_button(gesture) : GDK_BUTTON_PRIMARY; const dt_imgid_t id = dt_control_get_mouse_over_id(); diff --git a/src/libs/filtering.c b/src/libs/filtering.c index efb2fd51d47..d3b417ef279 100644 --- a/src/libs/filtering.c +++ b/src/libs/filtering.c @@ -1049,7 +1049,7 @@ static void _topbar_label_press_cb(GtkGestureSingle *gesture, int n_press, dt_lib_module_t *self) { //reset on double-click - if(gtk_gesture_single_get_button(gesture) == GDK_BUTTON_PRIMARY && n_press >= 2) + if(gtk_gesture_single_get_current_button(gesture) == GDK_BUTTON_PRIMARY && n_press >= 2) _topbar_reset(self); } diff --git a/src/libs/navigation.c b/src/libs/navigation.c index 90614fc2c95..ef38bc55437 100644 --- a/src/libs/navigation.c +++ b/src/libs/navigation.c @@ -593,7 +593,7 @@ static void _lib_navigation_button_press_callback(GtkGestureSingle *gesture, int GtkWidget *widget = dt_gui_get_widget(gesture); GtkAllocation allocation; gtk_widget_get_allocation(widget, &allocation); - const guint button = gtk_gesture_single_get_button(gesture); + const guint button = gtk_gesture_single_get_current_button(gesture); if(button == GDK_BUTTON_PRIMARY || button == GDK_BUTTON_SECONDARY) { diff --git a/src/libs/tools/global_toolbox.c b/src/libs/tools/global_toolbox.c index 7d961b4f8cf..64e0290c037 100644 --- a/src/libs/tools/global_toolbox.c +++ b/src/libs/tools/global_toolbox.c @@ -503,7 +503,7 @@ void gui_init(dt_lib_module_t *self) "\n" "right-click to exit mapping mode")); g_signal_connect(G_OBJECT(d->keymap_button), "clicked", G_CALLBACK(_lib_keymap_button_clicked), d); - dt_gui_connect_click(d->keymap_button, _lib_keymap_button_pressed, _lib_keymap_button_released, (gpointer)(d)); + dt_gui_connect_click_all(d->keymap_button, _lib_keymap_button_pressed, _lib_keymap_button_released, (gpointer)(d)); // the rest of these is added in reverse order as they are always put at the end of the container. // that's done so that buttons added via Lua will come first. @@ -792,10 +792,14 @@ static void _lib_keymap_button_clicked(GtkWidget *widget, gpointer user_data) } } +static guint _keymap_button_start_time = 0; + static void _lib_keymap_button_pressed(GtkGestureSingle *gesture, gint n_press, gdouble x, gdouble y, gpointer user_data) { darktable.control->confirm_mapping = !(dt_key_modifier_state() & GDK_CONTROL_MASK); + _keymap_button_start_time = gtk_get_current_event_time(); + if(gtk_gesture_single_get_current_button(gesture) == GDK_BUTTON_SECONDARY) { _show_shortcuts_prefs(NULL); @@ -804,16 +808,13 @@ static void _lib_keymap_button_pressed(GtkGestureSingle *gesture, gint n_press, static void _lib_keymap_button_released(GtkGestureSingle *gesture, gint n_press, gdouble x, gdouble y, gpointer user_data) { - static guint start_time = 0; - guint current_time = gtk_get_current_event_time(); int delay = 0; g_object_get(gtk_settings_get_default(), "gtk-long-press-time", &delay, NULL); - if(current_time - start_time > (guint)delay) + if(gtk_get_current_event_time() - _keymap_button_start_time > (guint)delay) { _show_shortcuts_prefs(NULL); } - start_time = current_time; } #ifdef USE_LUA diff --git a/src/libs/tools/log_history.c b/src/libs/tools/log_history.c index b92c3d0a160..e9e1435df93 100644 --- a/src/libs/tools/log_history.c +++ b/src/libs/tools/log_history.c @@ -138,7 +138,7 @@ static void _label_button_press_cb(GtkGestureSingle *gesture, int n_press, double x, double y, gpointer user_data) { - if(gtk_gesture_single_get_button(gesture) == GDK_BUTTON_SECONDARY) + if(gtk_gesture_single_get_current_button(gesture) == GDK_BUTTON_SECONDARY) dt_gui_claim(gesture); } @@ -146,7 +146,7 @@ static void _button_press_cb(GtkGestureSingle *gesture, int n_press, double x, double y, dt_lib_module_t *self) { - const guint button = gtk_gesture_single_get_button(gesture); + const guint button = gtk_gesture_single_get_current_button(gesture); if(button == GDK_BUTTON_PRIMARY || button == GDK_BUTTON_SECONDARY) { dt_lib_log_history_t *d = self->data; diff --git a/src/libs/tools/timeline.c b/src/libs/tools/timeline.c index 02f68e3a04a..f3d5119a9cd 100644 --- a/src/libs/tools/timeline.c +++ b/src/libs/tools/timeline.c @@ -1080,7 +1080,7 @@ static void _lib_timeline_button_press_callback(GtkGestureSingle *gesture, { dt_lib_timeline_t *strip = self->data; - const guint button = gtk_gesture_single_get_button(gesture); + const guint button = gtk_gesture_single_get_current_button(gesture); if(button == GDK_BUTTON_PRIMARY && n_press == 1) { diff --git a/src/views/darkroom.c b/src/views/darkroom.c index e115cedec74..166d1e8bc6b 100644 --- a/src/views/darkroom.c +++ b/src/views/darkroom.c @@ -2768,6 +2768,8 @@ const dt_action_def_t _action_def_move _action_elements_move, NULL, TRUE }; +static guint _quickbutton_start_time = 0; + static void _quickbutton_pressed_cb(GtkGestureSingle *gesture, gint n_press, gdouble x, @@ -2777,12 +2779,16 @@ static void _quickbutton_pressed_cb(GtkGestureSingle *gesture, GtkWidget *button = dt_gui_get_widget(gesture); /* secondary click: show popup immediately */ - if(gtk_gesture_single_get_button(gesture) == GDK_BUTTON_SECONDARY) + if(gtk_gesture_single_get_current_button(gesture) == GDK_BUTTON_SECONDARY) { gtk_popover_set_relative_to(GTK_POPOVER(popover), button); g_object_set(G_OBJECT(popover), "transitions-enabled", FALSE, NULL); _toolbar_show_popup(popover); } + else + { + _quickbutton_start_time = gtk_get_current_event_time(); + } } static void _quickbutton_released_cb(GtkGestureSingle *gesture, @@ -2792,11 +2798,12 @@ static void _quickbutton_released_cb(GtkGestureSingle *gesture, GtkWidget *popover) { /* primary button long-press: show popup */ - if(gtk_gesture_single_get_button(gesture) == GDK_BUTTON_PRIMARY) + if(gtk_gesture_single_get_current_button(gesture) == GDK_BUTTON_PRIMARY) { int delay = 0; g_object_get(gtk_settings_get_default(), "gtk-long-press-time", &delay, NULL); - _toolbar_show_popup(popover); + if(gtk_get_current_event_time() - _quickbutton_start_time > (guint)delay) + _toolbar_show_popup(popover); } } @@ -5038,7 +5045,7 @@ static void _second_window_button_pressed_callback(GtkGestureSingle *gesture, if(pinned_dev && pinned_dev->gui_leaving) pinned_dev = NULL; dt_dev_viewport_t *port = pinned_dev ? &pinned_dev->preview2 : &dev->preview2; - const guint button = gtk_gesture_single_get_button(gesture); + const guint button = gtk_gesture_single_get_current_button(gesture); // Handle double-click to reset zoom and center if(n_press == 2 && button == GDK_BUTTON_PRIMARY) @@ -5069,7 +5076,7 @@ static void _second_window_button_released_callback(GtkGestureSingle *gesture, gdouble y, dt_develop_t *dev) { - if(gtk_gesture_single_get_button(gesture) == GDK_BUTTON_PRIMARY) _dt_second_window_change_cursor(dev, "default"); + if(gtk_gesture_single_get_current_button(gesture) == GDK_BUTTON_PRIMARY) _dt_second_window_change_cursor(dev, "default"); GtkWidget *w = dt_gui_get_widget(gesture); gtk_widget_queue_draw(w); From a63860cb163489d8511391927c4b1c610d24b4fa Mon Sep 17 00:00:00 2001 From: Arecsu Date: Fri, 31 Jul 2026 19:05:40 -0300 Subject: [PATCH 89/95] gtk4-prep: prevent stacking multiple shortcuts dialogs --- src/libs/tools/global_toolbox.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/libs/tools/global_toolbox.c b/src/libs/tools/global_toolbox.c index 64e0290c037..d1328fd2a50 100644 --- a/src/libs/tools/global_toolbox.c +++ b/src/libs/tools/global_toolbox.c @@ -658,8 +658,17 @@ static void _set_mapping_mode_cursor(GtkWidget *widget) g_object_unref(cursor); } +static gboolean _shortcuts_dialog_open = FALSE; + static void _show_shortcuts_prefs(GtkWidget *w) { + /* guard against re-entrant calls: a long-press or right-click on the + * keymap button can trigger both the pressed and the released gesture + * callback while the (modeless) dialog is already running */ + if(_shortcuts_dialog_open) + return; + _shortcuts_dialog_open = TRUE; + GtkWidget *shortcuts_dialog = gtk_dialog_new_with_buttons(_("shortcuts"), GTK_WINDOW(dt_ui_main_window(darktable.gui->ui)), GTK_DIALOG_DESTROY_WITH_PARENT, NULL, NULL); if(!_shortcuts_dialog_posize.w) @@ -679,6 +688,8 @@ static void _show_shortcuts_prefs(GtkWidget *w) gtk_dialog_run(GTK_DIALOG(shortcuts_dialog)); gtk_widget_destroy(shortcuts_dialog); + + _shortcuts_dialog_open = FALSE; } static void _main_do_event_keymap(GdkEvent *event, gpointer data) From f255f4efdce93269a9ab89a85068f591cf2f35d2 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Fri, 31 Jul 2026 19:05:43 -0300 Subject: [PATCH 90/95] gtk4-prep: convert gesture coordinates to bin-window space in treeviews --- src/gui/preferences_ai.c | 7 ++++++- src/libs/collect.c | 8 +++++++- src/libs/import.c | 30 +++++++++++++++++++++++------- 3 files changed, 36 insertions(+), 9 deletions(-) diff --git a/src/gui/preferences_ai.c b/src/gui/preferences_ai.c index ce18431ecfc..00e1fa5b632 100644 --- a/src/gui/preferences_ai.c +++ b/src/gui/preferences_ai.c @@ -1288,7 +1288,12 @@ static void _on_info_button_press_cb(GtkGestureSingle *gesture, int n_press, GtkTreePath *path = NULL; GtkTreeViewColumn *column = NULL; - if(!gtk_tree_view_get_path_at_pos(tv, (gint)x, (gint)y, + /* gesture coordinates are relative to the widget allocation, while + * gtk_tree_view_get_path_at_pos() expects bin-window coordinates */ + gint bin_x, bin_y; + gtk_tree_view_convert_widget_to_bin_window_coords(tv, (gint)x, (gint)y, &bin_x, &bin_y); + + if(!gtk_tree_view_get_path_at_pos(tv, bin_x, bin_y, &path, &column, NULL, NULL)) return; diff --git a/src/libs/collect.c b/src/libs/collect.c index 1495cd74383..2c37fa11fb7 100644 --- a/src/libs/collect.c +++ b/src/libs/collect.c @@ -641,10 +641,16 @@ static void view_onButtonPressed_cb(GtkGestureSingle *gesture, int n_press, GdkEvent *event = gtk_get_current_event(); + /* gesture coordinates are relative to the widget allocation, while + * gtk_tree_view_get_path_at_pos() expects bin-window coordinates */ + gint bin_x, bin_y; + gtk_tree_view_convert_widget_to_bin_window_coords(GTK_TREE_VIEW(treeview), + (gint)x, (gint)y, &bin_x, &bin_y); + /* Get tree path for row that was clicked */ GtkTreePath *path = NULL; const gboolean get_path = gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(treeview), - (gint)x, (gint)y, + bin_x, bin_y, &path, NULL, NULL, NULL); GdkModifierType mod_state; diff --git a/src/libs/import.c b/src/libs/import.c index b4127b2cd45..6ee7d4a03ab 100644 --- a/src/libs/import.c +++ b/src/libs/import.c @@ -562,13 +562,18 @@ static void _files_button_press_cb(GtkGestureSingle *gesture, int n_press, { GtkWidget *view = dt_gui_get_widget(gesture); dt_lib_import_t *d = self->data; + /* gesture coordinates are relative to the widget allocation, while the + * treeview coordinate APIs expect bin-window coordinates */ + gint bin_x, bin_y; + gtk_tree_view_convert_widget_to_bin_window_coords(GTK_TREE_VIEW(view), + (gint)x, (gint)y, &bin_x, &bin_y); if(n_press == 1) { GtkTreePath *path = NULL; GtkTreeViewColumn *column = NULL; // Get tree path for row that was clicked if(gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(view), - (gint)x, (gint)y, + bin_x, bin_y, &path, &column, NULL, NULL)) { if(column == d->from.pixcol) @@ -590,7 +595,7 @@ static void _files_button_press_cb(GtkGestureSingle *gesture, int n_press, GtkTreePath *path = NULL; // Get tree path for row that was clicked if(gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(view), - (gint)x, (gint)y, + bin_x, bin_y, &path, NULL, NULL, NULL)) { GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(view)); @@ -1268,8 +1273,13 @@ static void _places_button_press_cb(GtkGestureSingle *gesture, int n_press, { GtkWidget *view = dt_gui_get_widget(gesture); GtkTreePath *path = NULL; + /* gesture coordinates are relative to the widget allocation, while the + * treeview coordinate APIs expect bin-window coordinates */ + gint bin_x, bin_y; + gtk_tree_view_convert_widget_to_bin_window_coords(GTK_TREE_VIEW(view), + (gint)x, (gint)y, &bin_x, &bin_y); if(gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(view), - (gint)x, (gint)y, &path, NULL, NULL, NULL)) + bin_x, bin_y, &path, NULL, NULL, NULL)) { GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(view)); GtkTreeIter iter; @@ -1304,6 +1314,12 @@ static void _folders_button_press_cb(GtkGestureSingle *gesture, int n_press, GtkWidget *view = dt_gui_get_widget(gesture); dt_lib_import_t *d = self->data; + /* gesture coordinates are relative to the widget allocation, while the + * treeview coordinate APIs expect bin-window coordinates */ + gint bin_x, bin_y; + gtk_tree_view_convert_widget_to_bin_window_coords(GTK_TREE_VIEW(view), + (gint)x, (gint)y, &bin_x, &bin_y); + GdkModifierType state; gtk_get_current_event_state(&state); @@ -1313,15 +1329,15 @@ static void _folders_button_press_cb(GtkGestureSingle *gesture, int n_press, { GtkTreePath *path = NULL; if(gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(view), - x, y, &path, NULL, NULL, NULL)) + bin_x, bin_y, &path, NULL, NULL, NULL)) { GdkRectangle rect; gtk_tree_view_get_cell_area(GTK_TREE_VIEW(view), path, d->from.foldercol, &rect); const gboolean blank = gtk_tree_view_is_blank_at_pos(GTK_TREE_VIEW(view), - x, y, + bin_x, bin_y, NULL, NULL, NULL, NULL); // select and save new folder only if not click on expander - if(blank || (x > rect.x)) + if(blank || (bin_x > rect.x)) { GtkTreeSelection *selection = gtk_tree_view_get_selection(d->from.folderview); gtk_tree_selection_select_path(selection, path); @@ -1342,7 +1358,7 @@ static void _folders_button_press_cb(GtkGestureSingle *gesture, int n_press, { GtkTreePath *path = NULL; gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(view), - x, y, &path, NULL, NULL, NULL); + bin_x, bin_y, &path, NULL, NULL, NULL); if(path) { if(gtk_tree_view_row_expanded(d->from.folderview, path)) From cd42cdb43a64f63e81afb75bb3be4e3114a50d4c Mon Sep 17 00:00:00 2001 From: Arecsu Date: Fri, 31 Jul 2026 19:05:43 -0300 Subject: [PATCH 91/95] gtk4-prep: make key event controllers work on GTK3 --- src/gui/gtk.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 61 insertions(+), 2 deletions(-) diff --git a/src/gui/gtk.c b/src/gui/gtk.c index 84634dd35fc..39bdc7323a7 100644 --- a/src/gui/gtk.c +++ b/src/gui/gtk.c @@ -5039,6 +5039,47 @@ GtkEventController *(dt_gui_connect_scroll)(GtkWidget *widget, return controller; } +/* + * GTK3 bridge for GtkEventControllerKey. + * + * On GTK3, key events are delivered to the toplevel window, not to the + * focus widget, so a key controller with GTK_PHASE_TARGET attached to a + * widget never receives them. This bridge connects the classic + * "key-press-event" signal (which GTK routes to the focus widget) and + * forwards to the controller-style callback so the GTK4 API can be used + * unchanged. + * + * GTK4 migration: DELETE this entire bridge; dt_gui_connect_key() then + * connects the controller's "key-pressed" signal directly. + */ +#if !GTK_CHECK_VERSION(4, 0, 0) +typedef struct _KeyBridgeData +{ + GCallback cb; + gpointer data; + GtkEventControllerKey *controller; +} KeyBridgeData; + +static void _key_bridge_free(gpointer p, GClosure *cl) +{ + g_free(p); +} + +static gboolean _key_bridge_handler(GtkWidget *widget, GdkEventKey *event, gpointer user) +{ + KeyBridgeData *d = user; + guint keyval; + guint16 keycode; + GdkModifierType state; + gdk_event_get_keyval((GdkEvent *)event, &keyval); + gdk_event_get_keycode((GdkEvent *)event, &keycode); + gdk_event_get_state((GdkEvent *)event, &state); + + return ((gboolean(*)(GtkEventControllerKey *, guint, guint, GdkModifierType, gpointer))d->cb) + (d->controller, keyval, keycode, state, d->data); +} +#endif + GtkEventController *(dt_gui_connect_key)(GtkWidget *widget, GCallback pressed, gpointer data) @@ -5048,12 +5089,30 @@ GtkEventController *(dt_gui_connect_key)(GtkWidget *widget, g_object_weak_ref(G_OBJECT(widget), (GWeakNotify) g_object_unref, controller); // GTK4 gtk_widget_add_controller(widget, GTK_EVENT_CONTROLLER(controller)); - if(pressed) g_signal_connect(controller, "key-pressed", G_CALLBACK(pressed), data); + if(pressed) + { +#if GTK_CHECK_VERSION(4, 0, 0) + g_signal_connect(controller, "key-pressed", G_CALLBACK(pressed), data); +#else + /* GtkEventControllerKey with GTK_PHASE_TARGET never fires on GTK3: + * key events are delivered to the toplevel window, not to the focus + * widget, so the TARGET-phase controllers are never reached. Connect + * the classic key-press-event signal instead, which GTK routes to the + * focus widget (this is what the pre-migration code did). The + * controller is still returned so callers can use dt_gui_get_widget() + * and the GTK4 migration keeps the controller path above. */ + KeyBridgeData *d = g_new0(KeyBridgeData, 1); + d->cb = pressed; + d->data = data; + d->controller = GTK_EVENT_CONTROLLER_KEY(controller); + g_signal_connect_data(widget, "key-press-event", + G_CALLBACK(_key_bridge_handler), d, _key_bridge_free, 0); +#endif + } return controller; } - static int busy_nest_count = 0; void dt_gui_cursor_set_busy() From a8ae37a1256ae2549347596ddc1fc7df84db1cf1 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Fri, 31 Jul 2026 19:05:51 -0300 Subject: [PATCH 92/95] gtk4-prep: allow deleting shortcuts with the backspace key --- src/gui/accelerators.c | 90 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 74 insertions(+), 16 deletions(-) diff --git a/src/gui/accelerators.c b/src/gui/accelerators.c index f12ddc31eae..0d60615d2a8 100644 --- a/src/gui/accelerators.c +++ b/src/gui/accelerators.c @@ -1988,6 +1988,36 @@ static void _shortcut_row_activated(GtkTreeView *tree_view, _grab_in_tree_view(tree_view); } +static gboolean _shortcut_delete_selected(GtkTreeView *view) +{ + GtkTreeSelection *selection = gtk_tree_view_get_selection(view); + GtkTreeIter iter; + GtkTreeModel *model = NULL; + if(!gtk_tree_selection_get_selected(selection, &model, &iter)) + return FALSE; + + GSequenceIter *shortcut_iter = NULL; + gtk_tree_model_get(model, &iter, 0, &shortcut_iter, -1); + + if(_is_shortcut_category(shortcut_iter)) + return FALSE; + + dt_shortcut_t *s = g_sequence_get(shortcut_iter); + + if(dt_gui_show_yes_no_dialog(_("removing shortcut"), "", + s->is_default ? s->views ? + _("disable the selected default shortcut?") : + _("restore the selected default shortcut?") : + _("remove the selected shortcut?"))) + { + _remove_shortcut(shortcut_iter); + + dt_shortcuts_save(NULL, FALSE); + } + + return TRUE; +} + static gboolean _view_key_pressed_cb(GtkEventControllerKey *controller, guint keyval, guint keycode, @@ -2028,22 +2058,10 @@ static gboolean _view_key_pressed_cb(GtkEventControllerKey *controller, _shortcut_copy_lua(NULL, s, NULL); } - // GDK_KEY_BackSpace moves to parent in tree - if(keyval == GDK_KEY_Delete || keyval == GDK_KEY_KP_Delete) - { - if(dt_gui_show_yes_no_dialog(_("removing shortcut"), "", - s->is_default ? s->views ? - _("disable the selected default shortcut?") : - _("restore the selected default shortcut?") : - _("remove the selected shortcut?"))) - { - _remove_shortcut(shortcut_iter); - - dt_shortcuts_save(NULL, FALSE); - } - - return TRUE; - } + // GDK_KEY_BackSpace is the delete key on macOS; it is also + // accepted when deleting presets, so keep it consistent here + if(keyval == GDK_KEY_Delete || keyval == GDK_KEY_KP_Delete || keyval == GDK_KEY_BackSpace) + return _shortcut_delete_selected(view); } } } @@ -2860,6 +2878,43 @@ static void _notice_clicked(GtkWidget *button, dt_conf_set_bool("accel/hide_notice", TRUE); } +/* The shortcuts treeview consumes GDK_KEY_BackSpace ("select-cursor-parent") + * in its own key handling before any handler connected on the treeview runs, + * so the delete keys are intercepted at the toplevel instead, before the key + * event is propagated to the focus widget. GDK_KEY_BackSpace is the delete + * key on macOS. */ +static gboolean _shortcuts_dialog_key_pressed(GtkWidget *widget, + GdkEventKey *event, + gpointer user_data) +{ + GtkWidget *view = user_data; + + if(gtk_window_get_focus(GTK_WINDOW(widget)) != view) + return FALSE; + + guint keyval; + gdk_event_get_keyval((GdkEvent *)event, &keyval); + + if(keyval == GDK_KEY_Delete || keyval == GDK_KEY_KP_Delete || keyval == GDK_KEY_BackSpace) + return _shortcut_delete_selected(GTK_TREE_VIEW(view)); + + return FALSE; +} + +static void _shortcuts_view_realized(GtkWidget *widget, gpointer user_data) +{ + if(g_object_get_data(G_OBJECT(widget), "accel-dialog-key-connected")) + return; + g_object_set_data(G_OBJECT(widget), "accel-dialog-key-connected", GINT_TO_POINTER(TRUE)); + + GtkWidget *toplevel = gtk_widget_get_toplevel(widget); + if(!toplevel || !GTK_IS_WINDOW(toplevel)) + return; + + g_signal_connect(G_OBJECT(toplevel), "key-press-event", + G_CALLBACK(_shortcuts_dialog_key_pressed), widget); +} + GtkWidget *dt_shortcuts_prefs(GtkWidget *widget) { // Save the shortcuts before editing @@ -2904,6 +2959,9 @@ GtkWidget *dt_shortcuts_prefs(GtkWidget *widget) g_signal_connect(G_OBJECT(search_shortcuts), "stop-search", G_CALLBACK(dt_gui_search_stop), shortcuts_view); gtk_tree_view_set_search_entry(shortcuts_view, GTK_ENTRY(search_shortcuts)); + // intercept the delete keys at the toplevel, see _shortcuts_dialog_key_pressed + g_signal_connect(G_OBJECT(shortcuts_view), "realize", + G_CALLBACK(_shortcuts_view_realized), NULL); gtk_tree_selection_set_select_function(gtk_tree_view_get_selection(shortcuts_view), _shortcut_selection_function, NULL, NULL); From 52e56489aa1480619173f60eca948cbd659cd18a Mon Sep 17 00:00:00 2001 From: Arecsu Date: Fri, 31 Jul 2026 19:05:54 -0300 Subject: [PATCH 93/95] gtk4-prep: fix click handling on the shortcuts actions treeview --- src/gui/accelerators.c | 45 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 41 insertions(+), 4 deletions(-) diff --git a/src/gui/accelerators.c b/src/gui/accelerators.c index 0d60615d2a8..d1070e9f3ab 100644 --- a/src/gui/accelerators.c +++ b/src/gui/accelerators.c @@ -2281,23 +2281,46 @@ static gboolean _action_find_and_expand(GtkTreeModel *model, return FALSE; } +/* Claim the event sequence in CAPTURE phase so the treeview's internal + * GtkGestureMultiPress (GTK_PHASE_BUBBLE) does NOT process clicks. + * The pre-migration button-press-event handler consumed the events + * (return TRUE), which suppressed the internal gesture; the gesture + * controller replacement must do the same, otherwise the two gestures + * fight over row selection and expansion. + * + * GTK4 migration: the pattern is the same — just rename + * GtkGestureMultiPress to GtkGestureClick. */ +static void _gesture_begin_claim(GtkGesture *gesture, + GdkEventSequence *sequence, + gpointer user_data) +{ + gtk_gesture_set_sequence_state(gesture, sequence, GTK_EVENT_SEQUENCE_CLAIMED); +} + static void _action_view_click_cb(GtkGestureSingle *gesture, int n_press, double x, double y, GtkTreeStore *model_data) { GtkWidget *widget = dt_gui_get_widget(gesture); GtkTreeView *view = GTK_TREE_VIEW(widget); GtkTreeModel *model = gtk_tree_view_get_model(view); - const guint button = gtk_gesture_single_get_button(gesture); + const guint button = gtk_gesture_single_get_current_button(gesture); if(button == GDK_BUTTON_PRIMARY) { GtkTreeSelection *selection = gtk_tree_view_get_selection(view); + /* gesture coordinates are relative to the widget allocation, while + * gtk_tree_view_get_path_at_pos() expects bin-window coordinates */ + gint bin_x, bin_y; + gtk_tree_view_convert_widget_to_bin_window_coords(view, (gint)x, (gint)y, &bin_x, &bin_y); + GtkTreePath *path = NULL; - if(gtk_tree_view_get_path_at_pos(view, (gint)x, (gint)y, + if(gtk_tree_view_get_path_at_pos(view, bin_x, bin_y, &path, NULL, NULL, NULL)) { - if(n_press == 2) + if(n_press >= 2) { + /* the internal gesture that would emit "row-activated" on + * double-click is suppressed, so activate the row ourselves */ gtk_tree_selection_select_path(selection, path); _action_row_activated(view, path, NULL, model); } @@ -2313,6 +2336,7 @@ static void _action_view_click_cb(GtkGestureSingle *gesture, int n_press, double } gtk_widget_grab_focus(widget); + gtk_tree_path_free(path); } else gtk_tree_selection_unselect_all(selection); @@ -3067,7 +3091,20 @@ GtkWidget *dt_shortcuts_prefs(GtkWidget *widget) gtk_widget_set_name(GTK_WIDGET(actions_view), "actions_view"); g_signal_connect(G_OBJECT(actions_view), "row-activated", G_CALLBACK(_action_row_activated), _actions_store); - dt_gui_connect_click_all(actions_view, _action_view_click_cb, NULL, _actions_store); + + { + // the internal treeview gesture would fight our click handling; + // claim the sequence in CAPTURE phase to suppress it, replicating + // the event consumption of the pre-migration handler + GtkGesture *gesture = gtk_gesture_multi_press_new(GTK_WIDGET(actions_view)); + gtk_event_controller_set_propagation_phase(GTK_EVENT_CONTROLLER(gesture), + GTK_PHASE_CAPTURE); + g_object_weak_ref(G_OBJECT(actions_view), (GWeakNotify)g_object_unref, gesture); + gtk_gesture_single_set_button(GTK_GESTURE_SINGLE(gesture), 0); + g_signal_connect(gesture, "pressed", G_CALLBACK(_action_view_click_cb), _actions_store); + g_signal_connect(gesture, "begin", G_CALLBACK(_gesture_begin_claim), NULL); + } + dt_gui_connect_key(actions_view, _view_key_pressed_cb, search_actions); g_signal_connect(G_OBJECT(gtk_tree_view_get_selection(actions_view)), "changed", From 9ab4fb90ad2b08773f8cdd9fabaa6d2484364a91 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Tue, 4 Aug 2026 10:35:16 -0300 Subject: [PATCH 94/95] gtk4-prep: pass NULL pipe to dt_iop_commit_blend_params after upstream signature change --- src/develop/imageop.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/develop/imageop.c b/src/develop/imageop.c index 3cc4b1288c6..e33c394c021 100644 --- a/src/develop/imageop.c +++ b/src/develop/imageop.c @@ -2480,7 +2480,7 @@ static void _gui_reset_clicked(GtkGestureSingle *gesture, } /* reset to default params */ dt_iop_reload_defaults(module); - dt_iop_commit_blend_params(module, module->default_blendop_params); + dt_iop_commit_blend_params(module, module->default_blendop_params, NULL); /* reset ui to its defaults */ dt_iop_gui_reset(module); @@ -2489,6 +2489,8 @@ static void _gui_reset_clicked(GtkGestureSingle *gesture, dt_iop_gui_update(module); dt_dev_add_history_item(module->dev, module, TRUE); + + dt_dev_add_history_item(module->dev, module, TRUE); } // rebuild the accelerators From 88e6de86b308b1658d7d68a5abef084cafb255d2 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Tue, 4 Aug 2026 10:35:16 -0300 Subject: [PATCH 95/95] gtk4-prep: mirror main view pan/pinch behavior in darkroom second window --- src/gui/gtk.c | 1 - src/gui/gtk.h | 3 ++ src/views/darkroom.c | 93 +++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 91 insertions(+), 6 deletions(-) diff --git a/src/gui/gtk.c b/src/gui/gtk.c index 39bdc7323a7..09ce56f10eb 100644 --- a/src/gui/gtk.c +++ b/src/gui/gtk.c @@ -80,7 +80,6 @@ #define DT_UI_PANEL_MODULE_SPACING 0 #define DT_UI_PANEL_BOTTOM_DEFAULT_SIZE 120 -#define DT_UI_SCROLL_SMOOTH_DELTA_SCALE 50.0 #ifdef GDK_WINDOWING_QUARTZ // macOS has a fixed DPI of 72 diff --git a/src/gui/gtk.h b/src/gui/gtk.h index 7453badf47f..3352a6d4bd9 100644 --- a/src/gui/gtk.h +++ b/src/gui/gtk.h @@ -223,6 +223,9 @@ double dt_get_screen_resolution(GtkWidget *widget); * modifiers are pressed to indicate the control should be scrolled, then remove * the modifiers from the event before returning false */ gboolean dt_gui_ignore_scroll(GdkEventScroll *event); +/* Scale factor converting normalized smooth scroll deltas (as returned by + * dt_gui_get_scroll_deltas() on macOS) back to pixels for panning. */ +#define DT_UI_SCROLL_SMOOTH_DELTA_SCALE 50.0 /* Return requested scroll delta(s) from event. If delta_x or delta_y * is NULL, do not return that delta. Return TRUE if requested deltas * can be retrieved. Handles both GDK_SCROLL_UP/DOWN/LEFT/RIGHT and diff --git a/src/views/darkroom.c b/src/views/darkroom.c index 166d1e8bc6b..8e4dfe93729 100644 --- a/src/views/darkroom.c +++ b/src/views/darkroom.c @@ -5021,17 +5021,98 @@ static void _second_window_scrolled_callback(GtkEventControllerScroll *controlle dt_dev_viewport_t *port = pinned_dev ? &pinned_dev->preview2 : &dev->preview2; + const GdkEvent *current = gtk_get_current_event(); + if(!current) return; + GdkModifierType state; gtk_get_current_event_state(&state); + + // Two-finger trackpad scroll pans the image, like the main darkroom view's + // _scrolled()/gesture_pan path. The mouse wheel zooms. Ctrl forces zoom + // even for smooth scrolls. + if(dt_gdk_event_get_scroll_direction(current) == GDK_SCROLL_SMOOTH + && !dt_modifier_is(state, GDK_CONTROL_MASK)) + { + const GdkEventScroll *scroll = (const GdkEventScroll *)current; + gdouble pan_dx = 0.0, pan_dy = 0.0; + if(!dt_gui_get_scroll_deltas(scroll, &pan_dx, &pan_dy)) return; + pan_dx *= DT_UI_SCROLL_SMOOTH_DELTA_SCALE; + pan_dy *= DT_UI_SCROLL_SMOOTH_DELTA_SCALE; + dt_print(DT_DEBUG_INPUT, + "[darkroom second window] pan dx=%.3f dy=%.3f", pan_dx, pan_dy); + if(pan_dx != 0.0 || pan_dy != 0.0) + dt_dev_zoom_move(port, DT_ZOOM_MOVE, 1.0f, 0, pan_dx, pan_dy, TRUE); + return; + } + + int delta_y; + if(!dt_gui_get_scroll_unit_delta((const GdkEventScroll *)current, &delta_y)) return; const gboolean constrained = dev->constrain_zoom && !dt_modifier_is(state, GDK_CONTROL_MASK); gdouble x = 0.0, y = 0.0; - const GdkEvent *current = gtk_get_current_event(); - if(current) gdk_event_get_coords(current, &x, &y); - dt_dev_zoom_move(port, DT_ZOOM_SCROLL, 0.0f, dy < 0 ? 1 : 0, + gdk_event_get_coords(current, &x, &y); + dt_print(DT_DEBUG_INPUT, + "[darkroom second window] scroll zoom delta_y=%d", delta_y); + dt_dev_zoom_move(port, DT_ZOOM_SCROLL, 0.0f, delta_y < 0 ? 1 : 0, x, y, constrained); } +static gboolean _second_window_pinch_callback(GtkWidget *widget, + GdkEvent *event, + dt_develop_t *dev) +{ + if(dt_gdk_event_get_type(event) != GDK_TOUCHPAD_PINCH) return FALSE; + if(!darktable.gui->touchpad_gestures_enabled) return FALSE; + + // Use pinned viewport if pinned, otherwise main dev's preview2 + dt_develop_t *pinned_dev = dev->preview2_pinned ? dev->preview2_pinned_dev : NULL; + if(pinned_dev && pinned_dev->gui_leaving) pinned_dev = NULL; + + dt_dev_viewport_t *port = pinned_dev ? &pinned_dev->preview2 : &dev->preview2; + + const GdkEventTouchpadPinch *pinch = &event->touchpad_pinch; + const gboolean constrained = + dev->constrain_zoom && !dt_modifier_is(pinch->state, GDK_CONTROL_MASK); + + // Zoom the second window proportionally to the pinch scale, mirroring the + // main darkroom view's gesture_pinch(). + static float begin_tscale = 0.0f; + + if(pinch->phase == GDK_TOUCHPAD_GESTURE_PHASE_BEGIN) + { + begin_tscale = + dt_dev_get_zoom_scale(port, port->zoom, 1 << port->closeup, FALSE) * port->ppd; + return TRUE; + } + if(pinch->phase == GDK_TOUCHPAD_GESTURE_PHASE_END + || pinch->phase == GDK_TOUCHPAD_GESTURE_PHASE_CANCEL) + { + begin_tscale = 0.0f; + return TRUE; + } + if(pinch->phase != GDK_TOUCHPAD_GESTURE_PHASE_UPDATE) return FALSE; + if(begin_tscale <= 0.0f || pinch->scale <= 0.0) return FALSE; + + const float ppd = port->ppd; + const float fitscale = dt_dev_get_zoom_scale(port, DT_ZOOM_FIT, 1, FALSE); + const float tscalefloor = MIN(0.5f * fitscale * ppd, 1.0f); + const float tscale = CLAMP(begin_tscale * pinch->scale, tscalefloor, 16.0f); + const float zoom_scale = tscale / ppd; + + // Convert root (screen-absolute) pinch coords to widget-local, which is the + // coordinate space dt_dev_zoom_move() anchors the zoom to. + int ox = 0, oy = 0; + GdkWindow *win = gtk_widget_get_window(widget); + if(win) gdk_window_get_origin(win, &ox, &oy); + const float x_local = (float)pinch->x_root - ox; + const float y_local = (float)pinch->y_root - oy; + dt_print(DT_DEBUG_INPUT, + "[darkroom second window] pinch scale=%.6f tscale=%.6f zoom_scale=%.6f", + pinch->scale, tscale, zoom_scale); + dt_dev_zoom_move(port, DT_ZOOM_FREE, zoom_scale, 0, x_local, y_local, constrained); + return TRUE; +} + static void _second_window_button_pressed_callback(GtkGestureSingle *gesture, gint n_press, gdouble x, @@ -5453,14 +5534,16 @@ static void _darkroom_display_second_window(dt_develop_t *dev) | GDK_BUTTON_RELEASE_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK + | GDK_TOUCHPAD_GESTURE_MASK | darktable.gui->scroll_mask); /* connect callbacks */ g_signal_connect(G_OBJECT(dev->preview2.widget), "draw", G_CALLBACK(_second_window_draw_callback), dev); - dt_gui_connect_scroll(dev->preview2.widget, GTK_EVENT_CONTROLLER_SCROLL_BOTH_AXES - | GTK_EVENT_CONTROLLER_SCROLL_DISCRETE, + dt_gui_connect_scroll(dev->preview2.widget, GTK_EVENT_CONTROLLER_SCROLL_BOTH_AXES, _second_window_scrolled_callback, dev); + g_signal_connect(G_OBJECT(dev->preview2.widget), "event", + G_CALLBACK(_second_window_pinch_callback), dev); dt_gui_connect_click_all(dev->preview2.widget, _second_window_button_pressed_callback, _second_window_button_released_callback, dev); dt_gui_connect_motion(dev->preview2.widget, _second_window_mouse_moved_callback, NULL, _second_window_leave_callback, dev); g_signal_connect(G_OBJECT(dev->preview2.widget), "configure-event",