diff --git a/src/bauhaus/bauhaus.c b/src/bauhaus/bauhaus.c
index edb14a90e748..18a54880ab3e 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);
@@ -517,8 +525,9 @@ 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;
@@ -526,19 +535,17 @@ static gboolean _popup_scroll(GtkWidget *widget,
{
// 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;
+ 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);
- }
}
else
{
int delta = 0;
- if(dt_gui_get_scroll_unit_delta(event, &delta))
- _slider_zoom_range(w, delta);
+ dt_gui_get_scroll_unit_delta_fallback(dy, &delta);
+ _slider_zoom_range(w, delta);
}
- return TRUE;
}
static void _window_moved_to_rect(GdkWindow *window,
@@ -596,9 +603,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;
@@ -612,16 +620,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();
@@ -658,7 +666,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))))
@@ -673,7 +681,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);
@@ -682,72 +690,114 @@ static gboolean _window_motion_notify(GtkWidget *widget,
}
gtk_widget_queue_draw(pop->area);
- return TRUE;
}
-static gboolean _popup_leave_notify(GtkWidget *widget,
- GdkEventCrossing *event,
- 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)
{
- gtk_widget_set_state_flags(widget, GTK_STATE_FLAG_NORMAL, TRUE);
+ _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_button_release(GtkWidget *widget,
- GdkEventButton *event,
+static gboolean _popup_leave_handler(GtkWidget *widget, GdkEventCrossing *event,
gpointer user_data)
{
- if(darktable.bauhaus->change_active && dt_gdk_event_get_button(event) != GDK_BUTTON_MIDDLE)
- _popup_hide();
-
+ gtk_widget_set_state_flags(widget, GTK_STATE_FLAG_NORMAL, TRUE);
return TRUE;
}
-static gboolean _popup_button_press(GtkWidget *widget,
- GdkEventButton *event,
+static gboolean _popup_key_handler(GtkWidget *widget, GdkEventKey *event,
gpointer user_data)
{
- if(dt_gdk_event_get_window(event) != gtk_widget_get_window(widget))
- {
- _popup_reject();
- return 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,
+ gint n_press,
+ gdouble x,
+ gdouble y,
+ gpointer user_data)
+{
+ if(darktable.bauhaus->change_active && gtk_gesture_single_get_current_button(gesture) != GDK_BUTTON_MIDDLE)
+ _popup_hide();
+}
+
+static void _popup_button_press_cb(GtkGestureSingle *gesture,
+ gint n_press,
+ gdouble x,
+ gdouble y,
+ gpointer user_data)
+{
dt_bauhaus_t *bh = darktable.bauhaus;
dt_bauhaus_widget_t *w = bh->current;
+ const guint button = gtk_gesture_single_get_current_button(gesture);
- if(dt_gdk_event_get_button(event) == GDK_BUTTON_PRIMARY)
+ // 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(dt_gui_get_widget(gesture)))
+ {
+ gdk_event_free(cur_event);
+ _popup_reject();
+ return;
+ }
+ gdk_event_free(cur_event);
+ }
+
+ 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 = dt_gui_get_widget(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),
+ motion_state);
+ gdk_event_free(current_event);
+ }
}
- 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)
{
// 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,
@@ -976,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);
@@ -994,13 +1045,14 @@ 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, "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);
+ 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,
+ _popup_scroll_cb, NULL);
dt_action_define(&darktable.control->actions_focus, NULL, N_("sliders"),
NULL, &_action_def_focus_slider);
@@ -3762,16 +3814,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:
@@ -3837,22 +3891,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;
@@ -3867,7 +3936,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 60bce19eb21b..59de32d50c16 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 = dt_gui_get_widget(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 = dt_gui_get_widget(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/develop/blend_gui.c b/src/develop/blend_gui.c
index b9289771678d..c6449d2788b1 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 = dt_gui_get_widget(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,74 @@ 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);
-
- 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);
+ DT_GUARD_GUI_UPDATE();
- module->request_mask_display &=
- ~(DT_DEV_PIXELPIPE_DISPLAY_MASK
- | DT_DEV_PIXELPIPE_DISPLAY_CHANNEL
- | DT_DEV_PIXELPIPE_DISPLAY_ANY);
+ if(gtk_gesture_single_get_current_button(gesture) != GDK_BUTTON_PRIMARY) return;
- 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);
+ GtkWidget *button = dt_gui_get_widget(gesture);
- gtk_toggle_button_set_active
- (button,
- module->request_mask_display != DT_DEV_PIXELPIPE_DISPLAY_NONE);
+ const gboolean has_mask_display =
+ module->request_mask_display
+ & (DT_DEV_PIXELPIPE_DISPLAY_MASK
+ | DT_DEV_PIXELPIPE_DISPLAY_CHANNEL);
+
+ module->request_mask_display &=
+ ~(DT_DEV_PIXELPIPE_DISPLAY_MASK
+ | DT_DEV_PIXELPIPE_DISPLAY_CHANNEL
+ | DT_DEV_PIXELPIPE_DISPLAY_ANY);
+
+ 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 = dt_gui_get_widget(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(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
@@ -1421,8 +1431,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,51 +1502,70 @@ 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 = dt_gui_get_widget(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 = dt_gui_get_widget(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 = dt_gui_get_widget(gesture);
+ _blendop_masks_modes_toggle(GTK_TOGGLE_BUTTON(button), module,
+ 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 = dt_gui_get_widget(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,
- 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 = dt_gui_get_widget(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 = 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(FALSE);
+ DT_GUARD_GUI_UPDATE();
if(module->off) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(module->off), TRUE);
dt_iop_request_focus(module);
@@ -1547,12 +1574,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;
@@ -1564,15 +1591,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;
@@ -1598,21 +1625,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 = dt_gui_get_widget(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;
@@ -1625,13 +1652,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
@@ -1659,88 +1686,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 = dt_gui_get_widget(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;
@@ -1750,9 +1775,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,
@@ -2192,28 +2215,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 = 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;
- // 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))
+ GdkModifierType state;
+ if(gtk_get_current_event_state(&state))
{
- 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))
- {
- 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 +2263,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 +2292,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 +2309,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 = dt_gui_get_widget(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 +2683,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);
@@ -2957,20 +2980,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 = dt_gui_get_widget(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)
diff --git a/src/develop/imageop.c b/src/develop/imageop.c
index 1f7531228f20..bb9099601310 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 = dt_gui_get_widget(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,37 @@ 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;
+
+ 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",
+ 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
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);
- }
-
- return TRUE;
+ 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);
}
gboolean dt_iop_has_focus(const dt_iop_module_t *module)
@@ -2586,48 +2706,59 @@ 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;
+ // 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(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 +2768,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 +3152,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 +3174,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 +3311,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 +3361,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,
diff --git a/src/develop/imageop_gui.c b/src/develop/imageop_gui.c
index 5112a3d8b75b..1e74365ae622 100644
--- a/src/develop/imageop_gui.c
+++ b/src/develop/imageop_gui.c
@@ -241,12 +241,36 @@ 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)
{
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);
+ 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);
+ }
if(!ctrl_label)
gtk_widget_set_tooltip_text(w, _(label));
diff --git a/src/dtgtk/culling.c b/src/dtgtk/culling.c
index 22f1c5c58200..df2b61bec7d1 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,
@@ -809,118 +819,137 @@ 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 = dt_gui_get_widget(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;
+
+ // 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 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;
-
- dt_control_set_mouse_over_id(NO_IMGID);
- return TRUE;
+ // 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 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;
+ /*
+ * 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_current_button(gesture) directly — GtkGestureClick
+ * will provide a valid gesture pointer for all n_press values. */
+ const guint button = gesture
+ ? gtk_gesture_single_get_current_button(gesture)
+ : GDK_BUTTON_PRIMARY;
- 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 +960,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 +1012,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 +1021,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 +1054,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 +1238,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");
@@ -1225,20 +1246,22 @@ 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);
- 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);
+ /* 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/range.c b/src/dtgtk/range.c
index a376ef8b1900..0d8b6c5bc531 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 = dt_gui_get_widget(gesture);
+ if(gtk_gesture_single_get_current_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_current_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,13 @@ 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
+ 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), "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 +1718,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 +1726,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)));
}
diff --git a/src/dtgtk/resetlabel.c b/src/dtgtk/resetlabel.c
index 78198de16e01..0fac2de58ea8 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(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);
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;
}
diff --git a/src/dtgtk/thumbnail.c b/src/dtgtk/thumbnail.c
index 16d300b1021d..8fe8677c1a0b 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 = dt_gui_get_widget(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 = dt_gui_get_widget(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 = dt_gui_get_widget(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 = dt_gui_get_widget(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 = dt_gui_get_widget(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 = dt_gui_get_widget(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 = dt_gui_get_widget(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 = dt_gui_get_widget(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);
diff --git a/src/dtgtk/thumbtable.c b/src/dtgtk/thumbtable.c
index a9b4d60987c5..a3068559d991 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,
@@ -1375,43 +1379,48 @@ 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 = dt_gui_get_widget(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;
+
+ // 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 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;
-
- dt_control_set_mouse_over_id(NO_IMGID);
- return TRUE;
+ // 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)
@@ -1427,25 +1436,41 @@ 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);
+ /*
+ * 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_current_button(gesture) directly — GtkGestureClick
+ * will provide a valid gesture pointer for all n_press values. */
+ const guint button = gesture
+ ? gtk_gesture_single_get_current_button(gesture)
+ : GDK_BUTTON_PRIMARY;
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 +1480,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 +1523,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 +1545,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 +1575,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 +1594,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 +1631,8 @@ static gboolean _event_button_release(GtkWidget *widget,
}
else
{
- GtkSettings *settings = gtk_widget_get_settings(GTK_WIDGET (widget));
+ GtkWidget *w = dt_gui_get_widget(gesture);
+ GtkSettings *settings = gtk_widget_get_settings(GTK_WIDGET(w));
guint double_click_time = 400;
if(settings)
@@ -1631,7 +1661,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 +1692,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 +2601,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);
@@ -2594,20 +2621,22 @@ 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);
- 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);
+ /* 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,
diff --git a/src/gui/accelerators.c b/src/gui/accelerators.c
index 5267e9fdaee8..d1070e9f3ab9 100644
--- a/src/gui/accelerators.c
+++ b/src/gui/accelerators.c
@@ -1988,10 +1988,43 @@ 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 _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,
+ GdkModifierType state,
+ GtkWidget *search_entry)
+{
+ GtkWidget *widget = dt_gui_get_widget(controller);
GtkTreeView *view = GTK_TREE_VIEW(widget);
GtkTreeSelection *selection = gtk_tree_view_get_selection(view);
@@ -2002,7 +2035,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,32 +2053,20 @@ 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(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);
}
}
}
- 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,23 +2281,46 @@ static gboolean _action_find_and_expand(GtkTreeModel *model,
return FALSE;
}
-static gboolean _action_view_click(GtkWidget *widget,
- GdkEventButton *event,
- gpointer data)
+/* 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_current_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);
+ /* 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)dt_gdk_event_get_x(event), (gint)dt_gdk_event_get_y(event),
+ if(gtk_tree_view_get_path_at_pos(view, bin_x, bin_y,
&path, NULL, NULL, NULL))
{
- if(dt_gdk_event_get_type(event) == GDK_DOUBLE_BUTTON_PRESS)
+ 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);
}
@@ -2292,19 +2336,18 @@ static gboolean _action_view_click(GtkWidget *widget,
}
gtk_widget_grab_focus(widget);
+ gtk_tree_path_free(path);
}
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,
@@ -2859,6 +2902,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
@@ -2903,6 +2983,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);
@@ -2910,8 +2993,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 +3091,21 @@ 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);
+
+ {
+ // 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",
G_CALLBACK(_action_selection_changed), shortcuts_view);
@@ -4853,12 +4946,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 +5007,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);
}
}
diff --git a/src/gui/color_picker_proxy.c b/src/gui/color_picker_proxy.c
index 5d41713689eb..831f5d8c52e3 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 = dt_gui_get_widget(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;
diff --git a/src/gui/gtk.c b/src/gui/gtk.c
index db66a1753834..39bdc7323a75 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)
@@ -4769,6 +4799,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 +4873,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);
@@ -4820,7 +4913,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];
@@ -4946,6 +5039,79 @@ 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)
+{
+ 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)
+ {
+#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;
diff --git a/src/gui/gtk.h b/src/gui/gtk.h
index 30fa078f9c12..7453badf47fd 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
@@ -545,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)((expected_type)(func))
GtkGestureSingle *(dt_gui_connect_click)(GtkWidget *widget,
GCallback pressed,
@@ -558,6 +563,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,
@@ -588,6 +614,16 @@ 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_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/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"),
diff --git a/src/gui/preferences.c b/src/gui/preferences.c
index a33784ecc2da..23963bca906f 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;
@@ -281,16 +285,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 +327,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 +380,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 +444,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 +511,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);
@@ -905,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 = 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;
+ 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());
@@ -1014,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..."));
@@ -1040,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);
@@ -1153,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 = 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));
- // 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
@@ -1345,23 +1368,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 +1412,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 +1431,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 +1472,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 +1541,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 +1582,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;
}
diff --git a/src/gui/preferences_ai.c b/src/gui/preferences_ai.c
index ec27e2eb7ac1..00e1fa5b632a 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"
@@ -610,33 +608,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 +1253,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 = dt_gui_get_widget(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 +1273,35 @@ 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 = 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;
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),
+ /* 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 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 +1316,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 +1426,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 +1534,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 +1548,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 +1575,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 +1592,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 +1672,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 +1841,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);
diff --git a/src/iop/ashift.c b/src/iop/ashift.c
index 55b45f5c4b20..862f0838a6fa 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 = dt_gui_get_widget(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/atrous.c b/src/iop/atrous.c
index be17168bd28d..147a6f02a7f3 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(dt_gui_get_widget(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(dt_gui_get_widget(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 = dt_gui_get_widget(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 = dt_gui_get_widget(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 = dt_gui_get_widget(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/basecurve.c b/src/iop/basecurve.c
index c1ed5ffaad0f..ef972eac2dc5 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(dt_gui_get_widget(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 = 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;
@@ -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 = 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;
@@ -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 = dt_gui_get_widget(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 = dt_gui_get_widget(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,19 @@ 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);
+ 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
+ | 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)
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/colorchecker.c b/src/iop/colorchecker.c
index 548790259d67..2e1037ed7044 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 = dt_gui_get_widget(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 = dt_gui_get_widget(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/colorcorrection.c b/src/iop/colorcorrection.c
index 93c19dd2337d..f659010b6aaf 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,19 @@ 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);
+ 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
+ | 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 +357,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 = 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;
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 +401,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 +431,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 = dt_gui_get_widget(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 = 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;
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 +489,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;
diff --git a/src/iop/colorequal.c b/src/iop/colorequal.c
index 10e8be9394db..e58d19d3b3da 100644
--- a/src/iop/colorequal.c
+++ b/src/iop/colorequal.c
@@ -2697,88 +2697,84 @@ 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);
+ gdk_event_free(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,21 +2978,16 @@ 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);
+ g_signal_connect(G_OBJECT(g->area), "draw", G_CALLBACK(_iop_colorequalizer_draw), self);
gtk_widget_add_events(GTK_WIDGET(g->area),
- GDK_BUTTON_PRESS_MASK
- | GDK_POINTER_MOTION_MASK
+ GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_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);
- g_signal_connect(G_OBJECT(g->area), "scroll-event",
- G_CALLBACK(_area_scrolled_callback), self);
+ | 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);
+ 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);
diff --git a/src/iop/colorzones.c b/src/iop/colorzones.c
index e3ab99c47a8f..87dd0fa77df5 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,
@@ -1857,73 +1855,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 = dt_gui_get_widget(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(dy == 0.0) return;
- 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_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);
-
- 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);
+ GtkAllocation allocation;
+ gtk_widget_get_allocation(widget, &allocation);
- 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 = dt_gui_get_widget(controller);
dt_iop_colorzones_gui_data_t *g = self->gui_data;
dt_iop_colorzones_params_t *p = self->params;
@@ -1941,10 +1936,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 +1949,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 +1958,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 +1967,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 +1998,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 +2014,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 +2037,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 +2080,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 = 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;
- 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 +2119,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 +2142,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 +2165,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 +2181,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 +2205,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(dt_gui_get_widget(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 = dt_gui_get_widget(controller);
dt_iop_colorzones_gui_data_t *g = self->gui_data;
if(darktable.develop->darkroom_skip_mouse_events) return FALSE;
@@ -2270,22 +2257,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 +2281,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 +2698,22 @@ 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->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
+ | GTK_EVENT_CONTROLLER_SCROLL_DISCRETE,
+ _area_scrolled_callback, self);
+ dt_gui_connect_key(g->area, _area_key_press_callback, self);
- gtk_widget_add_events(GTK_WIDGET(g->bottom_area), GDK_BUTTON_PRESS_MASK);
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);
+ 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);
dt_gui_box_add(self->widget, g->interpolator);
diff --git a/src/iop/denoiseprofile.c b/src/iop/denoiseprofile.c
index 4c5a6cbf4c8e..9fc04a510f86 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 = dt_gui_get_widget(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 = dt_gui_get_widget(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(dt_gui_get_widget(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(dt_gui_get_widget(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..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;
@@ -4165,110 +4169,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 +4321,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 +4348,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..f03a30670ccf 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(dt_gui_get_widget(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 = dt_gui_get_widget(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 = dt_gui_get_widget(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/liquify.c b/src/iop/liquify.c
index 15728296bd35..4ae571472be5 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);
}
}
@@ -3092,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;
@@ -3230,7 +3239,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 +3300,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 +3309,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 +3531,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 +3542,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("");
@@ -3550,8 +3559,22 @@ static gboolean btn_make_radio_callback(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(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);
@@ -3585,12 +3608,29 @@ 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)
+{
+ 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 = dt_gui_get_widget(gesture);
+
+ _btn_make_radio_cb(GTK_TOGGLE_BUTTON(btn), ctrl_pressed, self);
}
void gui_update(dt_iop_module_t *self)
@@ -3676,7 +3716,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/lowlight.c b/src/iop/lowlight.c
index 2cd9602b218e..14990657cfbd 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 = dt_gui_get_widget(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 = dt_gui_get_widget(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(dt_gui_get_widget(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(dt_gui_get_widget(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/lut3d.c b/src/iop/lut3d.c
index e79efc566432..5df24ec94275 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_iop_module_t *self)
{
+ 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);
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);
@@ -1491,10 +1494,9 @@ static gboolean _mouse_scroll(GtkWidget *view, GdkEventScroll *event, dt_lib_mod
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
@@ -1748,7 +1750,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/monochrome.c b/src/iop/monochrome.c
index 60ab86691855..c91c302daa38 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 = dt_gui_get_widget(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 = dt_gui_get_widget(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 = dt_gui_get_widget(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(dt_gui_get_widget(controller));
}
-
- return TRUE;
}
void gui_init(dt_iop_module_t *self)
@@ -558,17 +551,16 @@ 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);
+ 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
+ | 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..f0043cbde319 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 = dt_gui_get_widget(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 = dt_gui_get_widget(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(dt_gui_get_widget(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(dt_gui_get_widget(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..902cf02ba93b 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 = dt_gui_get_widget(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 = dt_gui_get_widget(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,
@@ -1626,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);
@@ -1657,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;
@@ -1680,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);
@@ -1711,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,
@@ -1754,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;
@@ -1773,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,
@@ -1813,19 +1802,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;
@@ -1845,7 +1840,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();
@@ -1856,7 +1851,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)
{
@@ -1890,24 +1885,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 = dt_gui_get_widget(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);
@@ -1919,35 +1922,40 @@ 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,
- 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)
{
@@ -1982,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)
{
@@ -2019,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
@@ -2037,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;
@@ -2055,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);
@@ -2067,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)
@@ -2532,20 +2544,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/rgbcurve.c b/src/iop/rgbcurve.c
index 149ae6c059db..148d5e854574 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 = dt_gui_get_widget(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 = dt_gui_get_widget(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(dt_gui_get_widget(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 = dt_gui_get_widget(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 = 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;
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,20 @@ 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);
+ 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
+ | 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,
diff --git a/src/iop/rgblevels.c b/src/iop/rgblevels.c
index 3dfa1c9b0e8b..8ea698fa777e 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(dt_gui_get_widget(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 = dt_gui_get_widget(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 = dt_gui_get_widget(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/spots.c b/src/iop/spots.c
index 03148fdd6afe..d498bde67569 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 = dt_gui_get_widget(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 55f6e284fa8a..a0448e2df337 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 = 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 :
@@ -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)
@@ -1995,9 +1997,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 +2031,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 +2133,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
diff --git a/src/iop/tonecurve.c b/src/iop/tonecurve.c
index 192a8b6fe1f3..c7b92043841a 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 = dt_gui_get_widget(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(g->selected < 0)
- return TRUE;
+ if((autoscale_ab != DT_S_SCALE_MANUAL) && ch != ch_L) return;
- 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 = dt_gui_get_widget(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,19 @@ 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);
+ 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
+ | 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 +1342,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(dt_gui_get_widget(controller));
}
static void picker_scale(const float *in, float *out)
@@ -1752,10 +1748,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 = dt_gui_get_widget(controller);
dt_iop_tonecurve_gui_data_t *g = self->gui_data;
dt_iop_tonecurve_params_t *p = self->params;
@@ -1765,7 +1763,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 +1776,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 +1798,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 +1826,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 = 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;
@@ -1842,10 +1846,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 +1859,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 +1887,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 +1900,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 +1908,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 +1939,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,7 +1950,6 @@ 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 +1962,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
diff --git a/src/iop/toneequal.c b/src/iop/toneequal.c
index 2ed7f896223f..a5d95cfe66be 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);
@@ -2941,12 +2943,11 @@ 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;
+ DT_GUARD_GUI_UPDATE();
+ if(!self->enabled) return;
dt_iop_toneequalizer_gui_data_t *g = self->gui_data;
@@ -2960,33 +2961,37 @@ 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_GUARD_GUI_UPDATE();
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 +3013,28 @@ 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;
+ DT_GUARD_GUI_UPDATE();
+ if(!self->enabled) return;
dt_iop_toneequalizer_gui_data_t *g = self->gui_data;
dt_iop_toneequalizer_params_t *p = self->params;
@@ -3046,7 +3044,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 +3054,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,64 +3079,61 @@ 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;
+ DT_GUARD_GUI_UPDATE();
+ 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,
- 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);
+ // scroll is already filtered by _scroll_sidebar in the proxy,
+ // so only valid scroll events on the area widget reach here.
}
-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,25 +3278,19 @@ 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);
- g_signal_connect(G_OBJECT(g->area), "scroll-event",
- G_CALLBACK(area_scroll), 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);
+ 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);
@@ -3401,8 +3390,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..d7859e9b89e7 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,15 @@ 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);
+ 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 +569,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 = dt_gui_get_widget(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 +589,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 +601,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(dt_gui_get_widget(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 = dt_gui_get_widget(controller);
const int inset = DT_ZONESYSTEM_INSET;
GtkAllocation allocation;
gtk_widget_get_allocation(widget, &allocation);
@@ -666,8 +656,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 +694,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/collect.c b/src/libs/collect.c
index e0306005bd89..2c37fa11fb77 100644
--- a/src/libs/collect.c
+++ b/src/libs/collect.c
@@ -632,31 +632,45 @@ 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 = dt_gui_get_widget(gesture);
+ static GdkModifierType last_mod_state = 0;
+
+ 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)dt_gdk_event_get_x(event), (gint)dt_gdk_event_get_y(event),
+ bin_x, bin_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 +692,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 +704,38 @@ static gboolean view_onButtonPressed(GtkWidget *treeview,
gtk_tree_selection_select_path(selection, path);
}
+ 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)
|| (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 +3605,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 +3670,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 +4059,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 +4070,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();
diff --git a/src/libs/colorpicker.c b/src/libs/colorpicker.c
index dcb68aec1206..39dc733fe618 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 = dt_gui_get_widget(gesture);
+ const guint button = gtk_gesture_single_get_current_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,16 @@ 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);
+ 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);
@@ -734,18 +725,13 @@ 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);
+ 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));
gtk_widget_set_name(GTK_WIDGET(color_patch_wrapper), "color-picker-area");
gtk_widget_show(color_patch);
@@ -786,17 +772,12 @@ 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);
diff --git a/src/libs/duplicate.c b/src/libs/duplicate.c
index a0b054e5d3e0..18ca22530f12 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 = 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;
- 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/export.c b/src/libs/export.c
index 3e4558e52242..6b3772a92485 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 = 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");
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 = dt_gui_get_widget(gesture);
+ 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, 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 = dt_gui_get_widget(gesture);
+ 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, 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);
diff --git a/src/libs/filtering.c b/src/libs/filtering.c
index 978a4d869d08..d3b417ef279d 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_current_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,56 +1160,57 @@ 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 _rule_remove_config_entries(dt_lib_module_t *self, dt_lib_filtering_rule_t *rule)
{
- 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;
+ 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);
- if(!rule->topbar)
+ // move up all still active rules by one.
+ for(int i = rule->num; i < DT_COLLECTION_MAX_RULES - 1; i++)
{
- // decrease the nb of active rules
- dt_lib_filtering_t *d = rule->lib;
- if(d->nb_rules <= 0) return FALSE;
- 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)
{
- 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);
- }
+ 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 FALSE;
- return TRUE;
+ _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)
+{
+ 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;
+
+ if(!rule->topbar)
+ _rule_remove_config_entries(self, rule);
}
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 = 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 TRUE;
+ if(rule->manual_widget_set) return;
dt_lib_filtering_t *d = self->data;
// unpin the rule
@@ -1676,19 +1677,19 @@ static gboolean _topbar_rule_remove(GtkWidget *widget, GdkEventButton *event, dt
_topbar_update(self);
// remove the rule
- _event_rule_close(widget, NULL, self);
+ _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);
-
- return TRUE;
+ 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)
@@ -1698,7 +1699,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 +1775,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 +1892,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 = 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 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 +1924,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 +1976,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);
}
diff --git a/src/libs/filters/colors.c b/src/libs/filters/colors.c
index b497d068befe..c10398b360a0 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
@@ -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 = dt_gui_get_widget(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;
@@ -212,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)
@@ -236,7 +290,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,9 +349,8 @@ 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);
- g_signal_connect(G_OBJECT(colors->colors[k]), "enter-notify-event", G_CALLBACK(_colors_enter_notify),
- GINT_TO_POINTER(k));
+ dt_gui_connect_click(colors->colors[k], _colors_clicked_gesture, NULL, colors);
+ 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);
@@ -307,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);
diff --git a/src/libs/filters/filename.c b/src/libs/filters/filename.c
index 95a91cbae1e0..bbbaa83a2cd6 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
@@ -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 = dt_gui_get_widget(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..db767ead1b62 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
@@ -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 = dt_gui_get_widget(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)
{
diff --git a/src/libs/geotagging.c b/src/libs/geotagging.c
index e148be82e1cd..4e50a22599b7 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)
@@ -1447,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;
@@ -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/histogram.c b/src/libs/histogram.c
index 9884de9b0e0c..d9b01fbb2a68 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))
{
@@ -561,7 +563,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 4f181c05f015..68cc852afed1 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 = dt_gui_get_widget(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/import.c b/src/libs/import.c
index 4979ff448411..6ee7d4a03ab1 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,24 @@ 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 = dt_gui_get_widget(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))
+ /* 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)dt_gdk_event_get_x(event), (gint)dt_gdk_event_get_y(event),
+ bin_x, bin_y,
&path, &column, NULL, NULL))
{
if(column == d->from.pixcol)
@@ -581,17 +585,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),
+ bin_x, bin_y,
&path, NULL, NULL, NULL))
{
GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
@@ -599,10 +603,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 +1267,19 @@ 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 = 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)dt_gdk_event_get_x(event), (gint)dt_gdk_event_get_y(event), &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;
@@ -1280,10 +1288,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 +1302,42 @@ 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 = dt_gui_get_widget(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)
+
+ /* 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);
+
+ 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))
+ 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),
- dt_gdk_event_get_x(event), dt_gdk_event_get_y(event),
+ bin_x, bin_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 || (bin_x > rect.x))
{
GtkTreeSelection *selection = gtk_tree_view_get_selection(d->from.folderview);
gtk_tree_selection_select_path(selection, path);
@@ -1337,26 +1350,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);
+ bin_x, bin_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 +1478,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 +1502,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 +1912,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);
diff --git a/src/libs/lib.c b/src/libs/lib.c
index ac184700f848..a3f15255648a 100644
--- a/src/libs/lib.c
+++ b/src/libs/lib.c
@@ -964,30 +964,29 @@ 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;
+ dt_gui_claim(gesture);
}
-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;
}
+
void dt_lib_gui_set_expanded(dt_lib_module_t *module, const gboolean expanded)
{
if(!module->expander || !module->arrow) return;
@@ -1029,24 +1028,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;
-
- dt_lib_module_t *module = (dt_lib_module_t *)user_data;
+ if(n_press > 1) return;
+ const guint button = gtk_gesture_single_get_current_button(gesture);
+ GdkModifierType state;
+ gtk_get_current_event_state(&state);
- 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 +1084,36 @@ 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);
+ // 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);
}
static void show_module_callback(dt_lib_module_t *module)
@@ -1140,23 +1154,44 @@ 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)
+ // 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);
+ }
+}
- return FALSE;
+static void _body_leave_callback(GtkEventControllerMotion *controller,
+ dt_lib_module_t *module)
+{
+ // clear focused module when leaving
+ // 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,
@@ -1278,8 +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
- 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), "clicked", G_CALLBACK(_presets_popup_callback), module);
}
module->expander = NULL;
return NULL;
@@ -1305,18 +1339,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, 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 */
- 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 +1352,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 +1384,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));
+ 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)
gtk_widget_set_sensitive(GTK_WIDGET(module->presets_button), FALSE);
@@ -1372,11 +1395,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 +1732,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;
}
}
diff --git a/src/libs/location.c b/src/libs/location.c
index 225353e6af08..c6c743aaa52c 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,
@@ -156,16 +154,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 = dt_gui_get_widget(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 = dt_gui_get_widget(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 +172,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);
@@ -212,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, (gpointer)param);
}
return eb;
}
@@ -443,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,
diff --git a/src/libs/map_locations.c b/src/libs/map_locations.c
index d0ebe63e79b8..a035ca1f39e2 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 = dt_gui_get_widget(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,16 +880,15 @@ 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(dt_lib_module_t *self)
@@ -921,7 +925,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/masks.c b/src/libs/masks.c
index f1031e86cece..85e1e8db1d7e 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 = 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));
@@ -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_current_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"))),
diff --git a/src/libs/metadata.c b/src/libs/metadata.c
index 5c22763252f8..d976a41fcfbf 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 = dt_gui_get_widget(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);
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/modulegroups.c b/src/libs/modulegroups.c
index ca199e82d4f5..b5b495ba01f5 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
@@ -2658,65 +2668,69 @@ 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 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 = 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,
+ 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(dt_gui_get_widget(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 = dt_gui_get_widget(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 +2744,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 = dt_gui_get_widget(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 +2849,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 +2867,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 +2979,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 +3003,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"));
@@ -3001,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();
@@ -3138,7 +3158,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 +3279,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 = 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);
@@ -3267,7 +3293,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 +3311,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 +3321,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 +3331,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 +3341,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 +3351,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 +3361,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 +3371,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 +3381,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 +3391,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);
diff --git a/src/libs/navigation.c b/src/libs/navigation.c
index 1925d1bd3f78..b26f50f4c3aa 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 = dt_gui_get_widget(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 = dt_gui_get_widget(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_current_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
diff --git a/src/libs/neural_restore.c b/src/libs/neural_restore.c
index 915dd398f196..d1767455d3e0 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 = dt_gui_get_widget(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 = dt_gui_get_widget(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
diff --git a/src/libs/snapshots.c b/src/libs/snapshots.c
index 18cec1fa3920..a0493448ea95 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 = dt_gui_get_widget(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");
diff --git a/src/libs/tagging.c b/src/libs/tagging.c
index 55b56393ef2b..95aba8e33de8 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 = dt_gui_get_widget(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_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))
{
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 = 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));
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 = dt_gui_get_widget(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 = dt_gui_get_widget(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_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
+ || (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 = 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))
{
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 = 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);
@@ -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);
diff --git a/src/libs/tools/colorlabels.c b/src/libs/tools/colorlabels.c
index 8e125a560912..a6e66f686c26 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 = dt_gui_get_widget(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 = dt_gui_get_widget(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 = dt_gui_get_widget(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_current_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
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..705925e9455c 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
@@ -85,10 +85,9 @@ 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(GtkButton *button, dt_lib_module_t *self)
{
- dt_view_filtering_show_pref_menu(darktable.view_manager, widget);
- return TRUE;
+ dt_view_filtering_show_pref_menu(darktable.view_manager, GTK_WIDGET(button));
}
void gui_init(dt_lib_module_t *self)
@@ -102,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"));
- g_signal_connect(G_OBJECT(bt), "button-press-event", G_CALLBACK(_pref_show), 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);
diff --git a/src/libs/tools/global_toolbox.c b/src/libs/tools/global_toolbox.c
index ca92f0a4fb5e..d1328fd2a50b 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_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.
@@ -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)
@@ -792,25 +803,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 guint _keymap_button_start_time = 0;
+
+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);
+
+ _keymap_button_start_time = gtk_get_current_event_time();
- 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)
+{
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(gtk_get_current_event_time() - _keymap_button_start_time > (guint)delay)
{
_show_shortcuts_prefs(NULL);
- return TRUE;
- }
- else
- {
- start_time = dt_gdk_event_get_time(event);
- return FALSE;
}
}
diff --git a/src/libs/tools/lighttable.c b/src/libs/tools/lighttable.c
index 39c77e5d4142..0c1a9852f68d 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 = dt_gui_get_widget(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,
+ dt_gui_get_widget(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);
diff --git a/src/libs/tools/log_history.c b/src/libs/tools/log_history.c
index b4ba8dfc472b..e9e1435df933 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_current_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_current_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);
diff --git a/src/libs/tools/ratings.c b/src/libs/tools/ratings.c
index 148c83ca362c..d7a01e36abae 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,17 @@ 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
+ 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
- | GDK_STRUCTURE_MASK);
+ | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_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 +178,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 +202,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;
}
diff --git a/src/libs/tools/timeline.c b/src/libs/tools/timeline.c
index aa2ec475ad2d..f3d5119a9cd6 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
@@ -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_current_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);
diff --git a/src/libs/tools/viewswitcher.c b/src/libs/tools/viewswitcher.c
index 766911f3acd1..19b178eaf70a 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 = dt_gui_get_widget(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;
}
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);
}
diff --git a/src/views/darkroom.c b/src/views/darkroom.c
index dfb5caa78459..5e3b8819fc28 100644
--- a/src/views/darkroom.c
+++ b/src/views/darkroom.c
@@ -2756,38 +2756,48 @@ 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 guint start_time = 0;
+static guint _quickbutton_start_time = 0;
- int delay = 0;
- g_object_get(gtk_settings_get_default(), "gtk-long-press-time", &delay, NULL);
+static void _quickbutton_pressed_cb(GtkGestureSingle *gesture,
+ gint n_press,
+ gdouble x,
+ gdouble y,
+ GtkWidget *popover)
+{
+ GtkWidget *button = dt_gui_get_widget(gesture);
- 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_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);
- return TRUE;
}
else
{
- start_time = dt_gdk_event_get_time(event);
- return FALSE;
+ _quickbutton_start_time = gtk_get_current_event_time();
+ }
+}
+
+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_current_button(gesture) == GDK_BUTTON_PRIMARY)
+ {
+ int delay = 0;
+ g_object_get(gtk_settings_get_default(), "gtk-long-press-time", &delay, NULL);
+ if(gtk_get_current_event_time() - _quickbutton_start_time > (guint)delay)
+ _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
@@ -4564,7 +4574,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");
@@ -4985,82 +5004,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_current_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_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);
- 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 +5098,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 +5168,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 +5179,24 @@ 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)
+ GdkEvent *event = gtk_get_current_event();
+ if(event && event->crossing.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);
+ gdk_event_free(event);
+ return;
}
- return FALSE;
+ 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);
}
// Callback for the pin button in the overlay
@@ -5232,13 +5258,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 +5451,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);
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);
diff --git a/src/views/map.c b/src/views/map.c
index 047f6bd1f46a..2676ee17a2a5 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,28 @@ 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);
+ /* 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);
@@ -1850,91 +1873,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(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->loc.drag
+ && lib->loc.main.id > 0)
{
- 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)
+ 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)
{
- const GList *sel_img = lib->selected_images;
- if(entry->imgid == GPOINTER_TO_INT(sel_img->data))
+ 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(event && lib->start_drag
+ && lib->selected_images)
+ {
+ 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))
+ {
+ 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 +1986,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 +1999,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 +2044,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 +2105,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 +2114,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 +2149,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 +2158,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 +2220,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 +2263,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)