From 549c2e07ec38e206b5302dd300a584516afc97d9 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Sun, 26 Jul 2026 22:44:50 -0300 Subject: [PATCH 01/93] 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 db66a1753834..b0401cc676ff 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 30fa078f9c12..f4a1ee898853 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 be17168bd28d..0cf35d9fefd1 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 548790259d67..730df9e250a9 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 10e8be9394db..31f9c1f82ba7 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 4c5a6cbf4c8e..5aab0fd1962d 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 c452b571dc70..8a33c4ffd5f9 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 01d88bbafa00..16c5b692f838 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 2cd9602b218e..50fd9caa1710 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 60ab86691855..d18d90d11d78 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 3c6e445e1342..a175e5dfc965 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 7a825417a939..9acc137fe2d9 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 3dfa1c9b0e8b..ba557b08902c 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 2ed7f896223f..fd6ea29cf57e 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 b455b0814120..611af7909512 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 ca199e82d4f5..57ea20858612 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 dd66e30070681d0f175ae1544e420a6d4045f0e4 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Sun, 26 Jul 2026 22:49:07 -0300 Subject: [PATCH 02/93] 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 c1ed5ffaad0f..e64f8968c196 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 5172855270b684039376f173c9d1e3675253b69c Mon Sep 17 00:00:00 2001 From: Arecsu Date: Sun, 26 Jul 2026 22:56:12 -0300 Subject: [PATCH 03/93] 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 93c19dd2337d..d8058967d259 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 6d7af51175394868c3f7657706268f9494553ff4 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Sun, 26 Jul 2026 23:02:33 -0300 Subject: [PATCH 04/93] 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 149ae6c059db..3eab46584f66 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 bebeeda7066bd0057053242a881c07993a2427ee Mon Sep 17 00:00:00 2001 From: Arecsu Date: Sun, 26 Jul 2026 23:20:19 -0300 Subject: [PATCH 05/93] 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 e79efc566432..30fef567fb4c 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 192a8b6fe1f3..1e4fe8a1127a 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 0fef0277dadeca948573e4a4742b7051991b73ba Mon Sep 17 00:00:00 2001 From: Arecsu Date: Sun, 26 Jul 2026 23:32:37 -0300 Subject: [PATCH 06/93] 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 55b45f5c4b20..86c18afdd50c 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 e3ab99c47a8f..4aed5b4b9a58 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 fe0bbc1389129aa481bff943de5f8bc38e6af003 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 00:05:02 -0300 Subject: [PATCH 07/93] 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 1f7531228f20..de248f0b2865 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; } @@ -2305,6 +2368,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) @@ -2345,6 +2409,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) @@ -2363,21 +2467,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) @@ -2586,48 +2704,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); @@ -2637,16 +2753,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, @@ -3023,12 +3137,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); @@ -3047,23 +3159,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); @@ -3180,22 +3296,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 @@ -3236,9 +3346,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 556f7b651bed0ccb6466b00ac372c5bc75e7f5c5 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 00:05:05 -0300 Subject: [PATCH 08/93] 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 975af9eeb293..98876e14ace8 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 55f6e284fa8a..da14913030c0 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 cc95e08fb759f45b0fca653f7dbe01e1d38d3819 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 00:05:08 -0300 Subject: [PATCH 09/93] 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 78198de16e01..195fcf17e869 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 44d0c7a3075f924502767f4fe8f95027f47842ea Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 00:05:11 -0300 Subject: [PATCH 10/93] 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 5d41713689eb..da4f6999f4c7 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 9c223f9dab331fe5abe06ed88b2fa25f1e9feac1 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 00:05:14 -0300 Subject: [PATCH 11/93] 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 b497d068befe..7ed06d8b40a8 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 95a91cbae1e0..cd49a30a7b3b 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 2b6172bc932d..a07ecc551c6b 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 d1dea23665534470a78480bd9c3663e25fdc31d8 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 00:05:18 -0300 Subject: [PATCH 12/93] 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 a0b054e5d3e0..021a775fdd1f 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 4f181c05f015..792a6d9328d0 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 225353e6af08..c09fdc888c62 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 d0ebe63e79b8..f1618b07ac04 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 ed0c4ecb7cd7..4354ab110a93 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 18cec1fa3920..ae25f49dce78 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 8deb1a20abc053caf57d0336698054a5b62fb80e Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 00:05:21 -0300 Subject: [PATCH 13/93] 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 b954ba967952..ef19ebd0b3b3 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 1274619849ac..93f747098df3 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 ca92f0a4fb5e..7d961b4f8cf0 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 5d0da43694aa3f3f63bb89e2b6e30ede0922b5e0 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 00:17:41 -0300 Subject: [PATCH 14/93] 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 31f9c1f82ba7..96b2c40320e5 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 fd6ea29cf57e..3f3ab71859d2 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 21e749d56f12cb7c018e266c198ff322f37bd6cf Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 00:17:45 -0300 Subject: [PATCH 15/93] 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 4aed5b4b9a58..7fc40bbdb4d0 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 1e4fe8a1127a..caef05148ab7 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 f1618b07ac04..24ac6004a2b6 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 d8a349ef6d6363a7e156b7de57378548679fc1f3 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 00:17:49 -0300 Subject: [PATCH 16/93] 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 7ed06d8b40a8..e366fe4a0cc0 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 cd49a30a7b3b..da7655462f13 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 a07ecc551c6b..fc18805bcf82 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 93f747098df3..0fd692968e17 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 6cd9db3f94e8a9640d83766e3419f95f1c7516b6 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 00:41:34 -0300 Subject: [PATCH 17/93] 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 16d300b1021d..cdbe41067e5b 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 fa56b3e69e6f78acf8486fe7ffa364d1488b07bb Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 00:45:03 -0300 Subject: [PATCH 18/93] 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 ac184700f848..1734132c0e96 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 92a2e326e8e6c3a987aab2cc645c74edf7d8e8c1 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 00:47:27 -0300 Subject: [PATCH 19/93] 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 dcb68aec1206..a06f19b2b45a 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 4d6b9446232e44bb67689806582ac5e287fb451a Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 00:55:31 -0300 Subject: [PATCH 20/93] 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 dfb5caa78459..4b457e8d2d97 100644 --- a/src/views/darkroom.c +++ b/src/views/darkroom.c @@ -2756,38 +2756,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 @@ -4985,82 +4988,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, - 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, + 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; @@ -5071,20 +5082,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, @@ -5145,9 +5152,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, @@ -5155,22 +5163,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 @@ -5232,13 +5232,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; @@ -5430,16 +5425,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 1f5257ed94aebe7b0ed02fcd519a8ed26133034f Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 00:58:05 -0300 Subject: [PATCH 21/93] 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 a33784ecc2da..19b4bb2981e6 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 fc10b5310f01382b459f0924e1556b3178f47d9b Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 01:00:26 -0300 Subject: [PATCH 22/93] 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 fde7439b76f5..9311440f7085 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 2eeb263b39149c489bf42edcc2092e335ec90577 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 01:33:30 -0300 Subject: [PATCH 23/93] 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 a376ef8b1900..89f11d50a32d 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 0d81c413dfd5c6c85b3beee0adf521f2be452073 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 01:33:34 -0300 Subject: [PATCH 24/93] 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 f1031e86cece..d211306c7ddf 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 2c4107563725d1172dd8e6cdf50c7f1b8b99ef49 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 01:33:42 -0300 Subject: [PATCH 25/93] 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 edb14a90e748..58414db92521 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 6a9f197e786ca64f6b1929b098b2d2ebb1eb90cb Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 01:33:46 -0300 Subject: [PATCH 26/93] 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 aa2ec475ad2d..8ac47879fc70 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 62532fe39bd80e136009eaf369f26566e2b047ab Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 01:33:58 -0300 Subject: [PATCH 27/93] 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 22f1c5c58200..a65d92f4b3ea 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 @@ -1212,12 +1197,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"); @@ -1229,16 +1209,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 736d97843af5f073eb4e0d745259840a0cc3237b Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 01:34:00 -0300 Subject: [PATCH 28/93] 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 a9b4d60987c5..201cbb555c4b 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 f18af4a85e7791b15c738f40f4e4197c0bc1427b Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 01:34:02 -0300 Subject: [PATCH 29/93] 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 5267e9fdaee8..621b259a119d 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 5ce17a5e0ad9302d9e963897dc51e02023be03b0 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 01:35:08 -0300 Subject: [PATCH 30/93] 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 148c83ca362c..ce08f042b71e 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 a79d23490b88bba80cc8efc72f85c899893fe81e Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 01:36:28 -0300 Subject: [PATCH 31/93] 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 1925d1bd3f78..8b82475d9559 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 6fdd06a1fb2ba15e23d26ab99b26af043569fe5a Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 01:37:19 -0300 Subject: [PATCH 32/93] 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 b4ba8dfc472b..b92c3d0a1609 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 c0d8c8093341153a53e0f5aa8f56696584adb4cd Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 01:38:35 -0300 Subject: [PATCH 33/93] 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 766911f3acd1..3232f2b98cd0 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 49821d7a03cf1082a3988d02eaca45a7c7cab103 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 01:40:23 -0300 Subject: [PATCH 34/93] 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 8e125a560912..d6aed035a195 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 3b06de0ccc333bacf9d98ce94a068ecc7446d01a Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 01:41:39 -0300 Subject: [PATCH 35/93] 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 e366fe4a0cc0..41a557ec4c18 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 348b12d3b91ee41c378e7022a355e6724a305c61 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 01:42:37 -0300 Subject: [PATCH 36/93] 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 c09fdc888c62..312325936e94 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 741e9c64ec8056fcc96a61cd76c995636717e71a Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 01:44:00 -0300 Subject: [PATCH 37/93] 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 b9289771678d..dfd1219567d3 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 6dd2dc178fa3b24b98a625e88d0d3d543ad75dd3 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 01:47:12 -0300 Subject: [PATCH 38/93] 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 3e4558e52242..6cf6263685c3 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 cd691f407e4d859cf44744394aad2467bec1aa77 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 01:48:58 -0300 Subject: [PATCH 39/93] 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 915dd398f196..64ab4b4d3a81 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 70e2a4449e4f57972b5d3a3cd5c5f35ecba3ff35 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 01:50:28 -0300 Subject: [PATCH 40/93] 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 ec27e2eb7ac1..5e1b2e4511ac 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 b81fe8bdd5ffe6792618d9ef4f99798794ca934d Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 01:51:47 -0300 Subject: [PATCH 41/93] 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 662d3ca46539..6d4826315ca5 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 b3e6e7b4a03b2cf4f14021cb6a3994093ad4b884 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 01:52:47 -0300 Subject: [PATCH 42/93] 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 482018f26f12..7ead2465b15a 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 ef86d5a78668eee948f3c63ea7e227a40543ccfc Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 01:57:35 -0300 Subject: [PATCH 43/93] 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 978a4d869d08..a55f9a19cb6e 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 c003f69286a7242f6e9f91e8408c03e9b7f76f97 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 01:58:28 -0300 Subject: [PATCH 44/93] 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 39c77e5d4142..c79188a4214b 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 163f84da3071bd8a06dfd4baa62b11414ab9df4b Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 02:00:35 -0300 Subject: [PATCH 45/93] 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 4979ff448411..6cb99cfeef5a 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 25aef7703b2b096d5dcfd5703a3146dfd1fda7ef Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 02:02:03 -0300 Subject: [PATCH 46/93] 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 5c22763252f8..ecb6f6beb81e 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 46bbd143d28e8115f0d852c98579c850b2d6609a Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 02:06:52 -0300 Subject: [PATCH 47/93] 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 e0306005bd89..a71d176b0381 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 7bdabc7477c912b8f3901c58fd37e5456590ddbd Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 02:56:00 -0300 Subject: [PATCH 48/93] 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 a65d92f4b3ea..b4440d55a117 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, @@ -1205,8 +1215,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 201cbb555c4b..ee29408d2166 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 7218917d48b58d13d6ee234ba3e36b1648a92932 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 02:56:03 -0300 Subject: [PATCH 49/93] 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 58414db92521..9055aacc881d 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, @@ -3753,16 +3778,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: @@ -3828,22 +3855,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 63576221ea6835d529e1cbf03bd931f1dd3494c0 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 02:56:07 -0300 Subject: [PATCH 50/93] 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 55b56393ef2b..c13c444285fd 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 cf0e66652298c099619aa8230d66efc67123a5e3 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 02:56:10 -0300 Subject: [PATCH 51/93] 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 96b2c40320e5..028e6a2e299e 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 5a0439fe0ad3d9a5f738cfa2708168212ab1a971 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 02:56:12 -0300 Subject: [PATCH 52/93] 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 3f3ab71859d2..743351d0bb77 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 925bf15ed0dce87fe888f2f1d5828112a7f5bd91 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 02:56:18 -0300 Subject: [PATCH 53/93] 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 5112a3d8b75b..7bd38142dbba 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 8a33c4ffd5f9..621c61d722bb 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 15728296bd35..0243582b54d2 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 9acc137fe2d9..67e83e20d5ce 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 03148fdd6afe..5b730938dcad 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 da14913030c0..cb6581af477e 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 93332c0ea6d4966e6ba9784acd6b04d5b4a2e723 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 02:58:23 -0300 Subject: [PATCH 54/93] 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 dfd1219567d3..51e30bec8a84 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 0cf74a328460b1694e0b08a4f7570c26e4e8e6ae Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 02:59:06 -0300 Subject: [PATCH 55/93] 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 60bce19eb21b..da7cebe78771 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 19b4bb2981e6..6f256b49846f 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 e148be82e1cd..9392eb41e859 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 57ea20858612..4db6db4a78a2 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 047f6bd1f46a..7590758d8026 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 e2043f51e92688e64b39dd6edf837e527ba30af1 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 15:10:22 -0300 Subject: [PATCH 56/93] 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 7bd38142dbba..1e74365ae622 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 0243582b54d2..ba035990895e 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 6eae28fd3dc0845891afcde2d2cfd0d1427c3b71 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 15:10:28 -0300 Subject: [PATCH 57/93] 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 ba035990895e..5b4dc153c502 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 4b457e8d2d97..99807268d64a 100644 --- a/src/views/darkroom.c +++ b/src/views/darkroom.c @@ -4567,7 +4567,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"); @@ -5168,6 +5177,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 b62ce8664cb6656a3b3ea34cf1f10c050d3c1b5f Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 15:10:31 -0300 Subject: [PATCH 58/93] 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 b0401cc676ff..472c925b5857 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 f4a1ee898853..c7d4540cf5ad 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 698bc57b78e3bd19c50f4ad5ee812b4fd744fc28 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 15:10:34 -0300 Subject: [PATCH 59/93] 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 b4440d55a117..cda7132292bf 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) { @@ -1222,6 +1253,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 ee29408d2166..5b61b72fe971 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 fb6a985f009a05f0278ad1b9752aa0fa9d44c733 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 15:10:37 -0300 Subject: [PATCH 60/93] 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 51e30bec8a84..4a3410315f67 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 4723f79cb17147427584189270b0486cf65711b5 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 15:10:39 -0300 Subject: [PATCH 61/93] 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 9055aacc881d..525234278b0b 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 bc1c4c0a090251442048c0b5d390c635bbf8dcb9 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 15:10:42 -0300 Subject: [PATCH 62/93] 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 743351d0bb77..c8286ad52534 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 89949cd87e070b2ad052fe498cfc7350ccf4d7bf Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 15:10:45 -0300 Subject: [PATCH 63/93] 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 1734132c0e96..24f51c6aaf81 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 8e164e65c9a5c3b7c962184a6461cf6adcdad5eb Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 15:19:38 -0300 Subject: [PATCH 64/93] 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 30fef567fb4c..f26dcd9bd7c0 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 312325936e94..d5ad2cde2e60 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 7590758d8026..65d279186548 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 267b9fb80535e554c649d7c0136003c588fb122a Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 15:28:16 -0300 Subject: [PATCH 65/93] 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 65d279186548..047f6bd1f46a 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 213285ce4fde13407d303ab9a3307e6c33e2b1ed Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 15:31:49 -0300 Subject: [PATCH 66/93] 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 047f6bd1f46a..65d279186548 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 ad9f4bcd63f24f5df586879c3de29b8125176237 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 15:34:35 -0300 Subject: [PATCH 67/93] 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 65d279186548..2676ee17a2a5 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 099c963d4e409d057d8180632f7b72f525fddcec Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 15:51:10 -0300 Subject: [PATCH 68/93] 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 525234278b0b..201b0cd6d253 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 e3a76dbce96f1aab59068ca1a5dca582a0e06017 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 15:51:13 -0300 Subject: [PATCH 69/93] 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 89f11d50a32d..342f8b07b12f 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 e6b896597af942cb17364099ebb3dc58e430c7fc Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 15:51:17 -0300 Subject: [PATCH 70/93] 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 028e6a2e299e..14cf8eccda3d 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 e518e7ccf7c6f4768aeb9160852188d3abeea126 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 15:51:21 -0300 Subject: [PATCH 71/93] 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 4a3410315f67..ba69c65e4385 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 a55cf3eac82c6ff33b06a6529e7262617f268ceb Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 15:51:24 -0300 Subject: [PATCH 72/93] 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 de248f0b2865..82b4e7d16289 100644 --- a/src/develop/imageop.c +++ b/src/develop/imageop.c @@ -2494,7 +2494,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 1574bd8e0bc40775fc5f7f3d5d09a2171d9911e4 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 15:51:29 -0300 Subject: [PATCH 73/93] 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 a71d176b0381..924a739ac386 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 a06f19b2b45a..6aad6cd00c33 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 6cf6263685c3..980ad7e1238e 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 d211306c7ddf..10d21f3aa4c4 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 c13c444285fd..b7db3796a831 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 d6aed035a195..2b445c5f7785 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 93dbfc2373d8ba8611ec197a9225928aec175b15 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 15:54:07 -0300 Subject: [PATCH 74/93] 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 201b0cd6d253..9e8a475d0707 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) { @@ -3943,7 +3943,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 da7cebe78771..59de32d50c16 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 ba69c65e4385..c6449d2788b1 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 82b4e7d16289..7706e2f5e374 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) @@ -2476,7 +2476,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 cda7132292bf..35c67ef9aff0 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 342f8b07b12f..beaa7c1736c3 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 195fcf17e869..0fac2de58ea8 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 cdbe41067e5b..8fe8677c1a0b 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 5b61b72fe971..044259a48e86 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 621b259a119d..f12ddc31eaea 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 da4f6999f4c7..831f5d8c52e3 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 472c925b5857..a10c1eb20bd9 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 c7d4540cf5ad..f2913ec6bdfa 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 6f256b49846f..23963bca906f 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 5e1b2e4511ac..f983ff3f03cc 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 86c18afdd50c..862f0838a6fa 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 0cf35d9fefd1..147a6f02a7f3 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 e64f8968c196..87129ac80b67 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 730df9e250a9..2e1037ed7044 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 d8058967d259..a03a65ad6a9c 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 7fc40bbdb4d0..d63403828c96 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 5aab0fd1962d..9fc04a510f86 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 16c5b692f838..f03a30670ccf 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 5b4dc153c502..4ae571472be5 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 50fd9caa1710..14990657cfbd 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 f26dcd9bd7c0..5df24ec94275 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 d18d90d11d78..e1205e2eb65f 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 a175e5dfc965..f0043cbde319 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 67e83e20d5ce..5c6934393f24 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 3eab46584f66..87ca42753779 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 ba557b08902c..8ea698fa777e 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 5b730938dcad..d498bde67569 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 cb6581af477e..a0448e2df337 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 caef05148ab7..834a93462077 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 611af7909512..9464214ab08f 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 924a739ac386..1495cd743837 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 6aad6cd00c33..82e02f173d57 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 021a775fdd1f..18ca22530f12 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 980ad7e1238e..6b3772a92485 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 a55f9a19cb6e..d5c7c8d0a707 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 41a557ec4c18..c10398b360a0 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 da7655462f13..bbbaa83a2cd6 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 fc18805bcf82..db767ead1b62 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 9392eb41e859..4e50a22599b7 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 9884de9b0e0c..79b0e8de0d46 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 792a6d9328d0..68cc852afed1 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 6cb99cfeef5a..b4127b2cd45e 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 24f51c6aaf81..05c3f43d1568 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 d5ad2cde2e60..c6c743aaa52c 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 24ac6004a2b6..a035ca1f39e2 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 10d21f3aa4c4..85e1e8db1d7e 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 ecb6f6beb81e..d976a41fcfbf 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 4db6db4a78a2..b5b495ba01f5 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 8b82475d9559..17929e8eee2b 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 64ab4b4d3a81..d1767455d3e0 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 ae25f49dce78..a0493448ea95 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 b7db3796a831..95aba8e33de8 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 2b445c5f7785..a6e66f686c26 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 0fd692968e17..2bbe480755f9 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 c79188a4214b..0c1a9852f68d 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 3232f2b98cd0..19b178eaf70a 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 99807268d64a..3fca2b2ebbee 100644 --- a/src/views/darkroom.c +++ b/src/views/darkroom.c @@ -2762,7 +2762,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) @@ -5067,7 +5067,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 a8292b2c12f79fbe252a5067569ed0b06a755821 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 15:59:49 -0300 Subject: [PATCH 75/93] 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 79b0e8de0d46..36ae45696474 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 454603ea35e5bb7feeb80fe482801870a828d46e Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 16:00:57 -0300 Subject: [PATCH 76/93] 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 36ae45696474..d9b01fbb2a68 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 a4964beac3971748073f069187168dc517969032 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 16:04:03 -0300 Subject: [PATCH 77/93] 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 9e8a475d0707..0cc1c23c7bb5 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 7706e2f5e374..9db7bb6d3862 100644 --- a/src/develop/imageop.c +++ b/src/develop/imageop.c @@ -2495,17 +2495,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 a10c1eb20bd9..84634dd35fc8 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 f2913ec6bdfa..d72f65142367 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 7087e10e50481e8feabe008688c0ac6d402b7511 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 17:22:46 -0300 Subject: [PATCH 78/93] 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 0cc1c23c7bb5..755851b5ef48 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 beaa7c1736c3..0d8b6c5bc531 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 87129ac80b67..ef972eac2dc5 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 a03a65ad6a9c..f659010b6aaf 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 14cf8eccda3d..e58d19d3b3da 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 d63403828c96..87dd0fa77df5 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 e1205e2eb65f..c91c302daa38 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 87ca42753779..148d5e854574 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 834a93462077..c7b92043841a 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 c8286ad52534..a5d95cfe66be 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 9464214ab08f..d7859e9b89e7 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 82e02f173d57..39dc733fe618 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 ce08f042b71e..d7a01e36abae 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 d8af80a3792cb458757e667080f2a5ef8e2d3ec9 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 17:22:51 -0300 Subject: [PATCH 79/93] 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 755851b5ef48..18a54880ab3e 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 d98407a80c5e6b9e31f6afad9985307237dafc48 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 17:22:56 -0300 Subject: [PATCH 80/93] 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 2bbe480755f9..705925e9455c 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 0ad9cf8c58baa2c9fab0ad15cf16cc862c922e38 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 17:23:01 -0300 Subject: [PATCH 81/93] 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 9db7bb6d3862..bb9099601310 100644 --- a/src/develop/imageop.c +++ b/src/develop/imageop.c @@ -2730,6 +2730,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 c1d3dc5f5036f7f18569540161d62f606e4d7d16 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 17:23:06 -0300 Subject: [PATCH 82/93] 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 05c3f43d1568..a3f15255648a 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 5ede854898ef45ae671e23e47f9ff6996b350bf8 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 17:30:40 -0300 Subject: [PATCH 83/93] 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 8ac47879fc70..02f68e3a04a0 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 bf3b8b43b4da00aa5f068f28f901c5b08899d817 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 17:48:54 -0300 Subject: [PATCH 84/93] 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 d72f65142367..2732df4656c5 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 f983ff3f03cc..ce18431ecfc1 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 228f927b607d671ad2ce07db7657d51a1ac1b69e Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 18:15:28 -0300 Subject: [PATCH 85/93] 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 2732df4656c5..7453badf47fd 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 49e014166930c00f4ffee0cc1a9ca810d976c0ba Mon Sep 17 00:00:00 2001 From: Arecsu Date: Mon, 27 Jul 2026 20:08:04 -0300 Subject: [PATCH 86/93] 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 d5c7c8d0a707..efb2fd51d473 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 3065cae7bd48b02e2ac5a1b6076dc5aafb7631ad Mon Sep 17 00:00:00 2001 From: Arecsu Date: Fri, 31 Jul 2026 17:07:43 -0300 Subject: [PATCH 87/93] 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 5c6934393f24..902cf02ba93b 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 3368e0c1bfeccad61ab5438742548d510d296be7 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Fri, 31 Jul 2026 19:05:16 -0300 Subject: [PATCH 88/93] 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 35c67ef9aff0..df2b61bec7d1 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 044259a48e86..a3068559d991 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 efb2fd51d473..d3b417ef279d 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 17929e8eee2b..b26f50f4c3aa 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 7d961b4f8cf0..64e0290c037a 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 b92c3d0a1609..e9e1435df933 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 02f68e3a04a0..f3d5119a9cd6 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 3fca2b2ebbee..5e3b8819fc28 100644 --- a/src/views/darkroom.c +++ b/src/views/darkroom.c @@ -2756,6 +2756,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, @@ -2765,12 +2767,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, @@ -2780,11 +2786,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); } } @@ -5034,7 +5041,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) @@ -5065,7 +5072,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 a7433e5f91abcd42f4e7dc1dc4a8aa93252f6b5a Mon Sep 17 00:00:00 2001 From: Arecsu Date: Fri, 31 Jul 2026 19:05:40 -0300 Subject: [PATCH 89/93] 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 64e0290c037a..d1328fd2a50b 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 bae1b198c61a8254f1e2f23f5e2be0d9fd517629 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Fri, 31 Jul 2026 19:05:43 -0300 Subject: [PATCH 90/93] 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 ce18431ecfc1..00e1fa5b632a 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 1495cd743837..2c37fa11fb77 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 b4127b2cd45e..6ee7d4a03ab1 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 cf54806247956a3c7b08a4c032e1bafe737366ae Mon Sep 17 00:00:00 2001 From: Arecsu Date: Fri, 31 Jul 2026 19:05:43 -0300 Subject: [PATCH 91/93] 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 84634dd35fc8..39bdc7323a75 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 b5955c523e2f24dec35bf9bac858bbc14cb2fbc3 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Fri, 31 Jul 2026 19:05:51 -0300 Subject: [PATCH 92/93] 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 f12ddc31eaea..0d60615d2a8f 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 d7d545d40cc1f9370b616cfcda73affbe39dc147 Mon Sep 17 00:00:00 2001 From: Arecsu Date: Fri, 31 Jul 2026 19:05:54 -0300 Subject: [PATCH 93/93] 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 0d60615d2a8f..d1070e9f3ab9 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",