Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
b44dfc4
gtk4-prep: add dt_gui_connect_click_secondary and use it for right-cl…
Arecsu Aug 9, 2026
7d78e8b
gtk4-prep: migrate dialog enter handling to key controllers
Arecsu Aug 9, 2026
64260fd
gtk4-prep: convert simple button/motion/key handlers to controllers
Arecsu Aug 9, 2026
b91b228
gtk4-prep: notebook input and bauhaus popup motion to controllers
Arecsu Aug 9, 2026
d2257be
gtk4-prep: convert preset and style menu item handling to gestures
Arecsu Aug 9, 2026
5afcb85
gtk4-prep: remove synthetic event paths from shortcuts and menus
Arecsu Aug 9, 2026
c4a742c
gtk4-prep: gradientslider input via event controllers
Arecsu Aug 9, 2026
0b056dc
gtk4-prep: lighttable center viewport and pinch to controllers
Arecsu Aug 9, 2026
e4ce307
gtk4-prep: panel-scroll gating and resize-wrap on controllers
Arecsu Aug 9, 2026
b01b690
gtk4-prep: read controller/gesture events instead of gtk_get_current_…
Arecsu Aug 9, 2026
b02359d
gtk4-prep: guard the GTK3-owned event free in the thumbtable filemana…
Arecsu Aug 10, 2026
3fb0d4e
gtk4-prep: share the touchpad pinch GtkGestureZoom bridge
Arecsu Aug 10, 2026
d97a9be
gtk4-prep: share and guard the alt+scroll channel-tab forwarding
Arecsu Aug 10, 2026
d92faa6
fix: connect the non-expandable lib presets 'clicked' handler only once
Arecsu Aug 10, 2026
3ecb1f2
libs: resolve the non-expandable presets button FIXME and wire it once
Arecsu Aug 10, 2026
ebd26ab
gtk4-prep: route the last alt+scroll forwarders through dt_gui_forwar…
Arecsu Aug 10, 2026
cc7416c
gtk4-prep: share the preset popup menu builder between libs and iops
Arecsu Aug 10, 2026
fd9b0d6
dtgtk: add the button+tooltip+action+click factory and convert call s…
Arecsu Aug 10, 2026
05b0da4
modulegroups: share the popup menu creation and anchoring
Arecsu Aug 10, 2026
eac6d91
dtgtk: pass the button factory extras as a named config struct
Arecsu Aug 10, 2026
0cbfa9d
dtgtk: convert the last factory-shaped button sites
Arecsu Aug 10, 2026
124bd2a
dtgtk: support tooltip markup in the button factory
Arecsu Aug 10, 2026
70721dd
dtgtk: togglebutton factory and convert the wiring cluster
Arecsu Aug 10, 2026
9c2c48f
fix: preset popup menu leaves a bare separator for writeprotect presets
Arecsu Aug 10, 2026
3ba54aa
gtk4-prep: fix review findings from the event-controller sweep
Arecsu Aug 10, 2026
22674d4
gtk4-prep: fix stale _color_picker_widget_toggle call after rename
Arecsu Aug 13, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
121 changes: 79 additions & 42 deletions src/bauhaus/bauhaus.c
Original file line number Diff line number Diff line change
Expand Up @@ -701,27 +701,30 @@ static void _window_motion_handle(GtkWidget *widget,
// 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)
static void _window_motion_handler(GtkEventControllerMotion *controller,
gdouble x,
gdouble y,
gpointer user_data)
{
_window_motion_handle(widget,
dt_gdk_event_get_root_x(event),
dt_gdk_event_get_root_y(event),
dt_gdk_event_get_state(event));
return TRUE;
// the popup window is a toplevel, but take root coordinates anyway to stay
// in the same coordinate space as the old GdkEvent handler (GTK4 falls
// back to surface-relative coordinates, see dt_gui_get_event_coords())
gdouble root_x = 0.0, root_y = 0.0;
GdkEvent *event = dt_gui_get_current_event(GTK_EVENT_CONTROLLER(controller));
if(event) dt_gui_get_event_coords(event, &root_x, &root_y);
_window_motion_handle(gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(controller)),
root_x, root_y,
dt_gui_get_current_event_state(GTK_EVENT_CONTROLLER(controller)));
#if !GTK_CHECK_VERSION(4, 0, 0)
if(event) gdk_event_free(event);
#endif
}

static gboolean _popup_leave_handler(GtkWidget *widget, GdkEventCrossing *event,
gpointer user_data)
static void _popup_leave_cb(GtkEventControllerMotion *controller,
gpointer user_data)
{
GtkWidget *widget = dt_gui_get_widget(controller);
gtk_widget_set_state_flags(widget, GTK_STATE_FLAG_NORMAL, TRUE);
return TRUE;
}

static gboolean _popup_key_handler(GtkWidget *widget, GdkEventKey *event,
gpointer user_data)
{
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,
Expand All @@ -744,18 +747,25 @@ static void _popup_button_press_cb(GtkGestureSingle *gesture,
dt_bauhaus_widget_t *w = bh->current;
const guint button = gtk_gesture_single_get_current_button(gesture);

// reject clicks that come from outside the popup area window
GdkEvent *cur_event = gtk_get_current_event();
if(cur_event)
// reject clicks that come from outside the popup area window. Under GTK3
// the popup holds a grab (gtk_grab_add() in _window_show), so foreign
// clicks still arrive at this gesture and the window comparison rejects
// them. GTK4 removed gtk_grab_add(): pointer events are only delivered
// inside the popup's own surface, so there is nothing foreign to reject --
// and gtk_widget_get_surface() is not public API; the naive
// gtk_native_get_surface(gtk_widget_get_native()) replacement would always
// return the event's own surface and never fire.
#if GTK_CHECK_VERSION(4, 0, 0)
/* GTK4: no foreign clicks to reject (see above). */
#else
const GdkEvent *cur_event = gtk_gesture_get_last_event(GTK_GESTURE(gesture), NULL);
if(cur_event
&& dt_gdk_event_get_window(cur_event) != gtk_widget_get_window(dt_gui_get_widget(gesture)))
{
if(dt_gdk_event_get_window(cur_event) != gtk_widget_get_window(dt_gui_get_widget(gesture)))
{
gdk_event_free(cur_event);
_popup_reject();
return;
}
gdk_event_free(cur_event);
_popup_reject();
return;
}
#endif

if(button == GDK_BUTTON_PRIMARY)
{
Expand All @@ -767,8 +777,8 @@ static void _popup_button_press_cb(GtkGestureSingle *gesture,
&& !dt_gui_long_click(gdk_event_get_time(gtk_gesture_get_last_event(GTK_GESTURE(gesture), NULL)), bh->opentime))
{
// counts as double click, reset:
GdkModifierType state;
gtk_get_current_event_state(&state);
const GdkModifierType state =
dt_gui_get_current_event_state(GTK_EVENT_CONTROLLER(gesture));
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))))
Expand All @@ -777,7 +787,7 @@ static void _popup_button_press_cb(GtkGestureSingle *gesture,

bh->change_active = TRUE;
GtkWidget *w_current = dt_gui_get_widget(gesture);
GdkEvent *current_event = gtk_get_current_event();
const GdkEvent *current_event = gtk_gesture_get_last_event(GTK_GESTURE(gesture), NULL);
if(current_event)
{
GdkModifierType motion_state = dt_gdk_event_get_state(current_event);
Expand All @@ -786,7 +796,6 @@ static void _popup_button_press_cb(GtkGestureSingle *gesture,
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(button == GDK_BUTTON_MIDDLE && w->type == DT_BAUHAUS_SLIDER)
Expand Down Expand Up @@ -1049,9 +1058,9 @@ void dt_bauhaus_init()
"moved-to-rect", G_CALLBACK(_window_moved_to_rect), NULL);
g_signal_connect(window, "show", G_CALLBACK(_window_show), area);
g_signal_connect(area, "draw", G_CALLBACK(_popup_draw), NULL);
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_motion(pop->window, _window_motion_handler, NULL, NULL, NULL);
dt_gui_connect_motion(area, NULL, NULL, _popup_leave_cb, NULL);
dt_gui_connect_key(area, _popup_key_press, 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,
Expand Down Expand Up @@ -3343,12 +3352,14 @@ void dt_bauhaus_widget_show_popup(GtkWidget *widget)

if(w->type == DT_BAUHAUS_TOGGLE) return;

#if !GTK_CHECK_VERSION(4, 0, 0)
GdkEvent *event = gtk_get_current_event();
if(event)
{
bh->opentime = gdk_event_get_time(event);
gdk_event_free(event);
}
#endif
bh->mouse_x = 0;
bh->mouse_y = 0;
_popup_show(widget);
Expand Down Expand Up @@ -3397,7 +3408,7 @@ static void _widget_scroll(GtkEventControllerScroll *controller,
double dx, double dy,
GtkWidget *widget)
{
GdkEvent *event = gtk_get_current_event();
GdkEvent *event = dt_gui_get_current_event(GTK_EVENT_CONTROLLER(controller));
if(!event || gdk_event_get_event_type(event) != GDK_SCROLL)
dt_print(DT_DEBUG_ALWAYS, "[_widget_scroll] called on non-scroll event");
else if(darktable.control->mapping_widget)
Expand Down Expand Up @@ -3446,7 +3457,9 @@ static void _widget_scroll(GtkEventControllerScroll *controller,
}
}
}
#if !GTK_CHECK_VERSION(4, 0, 0)
if(event) gdk_event_free(event);
#endif
}

static gboolean _widget_key_press(GtkWidget *widget, GdkEventKey *event)
Expand Down Expand Up @@ -3881,18 +3894,41 @@ static gboolean _popup_key_press(GtkEventControllerKey *controller,
break;
default:
{
/* GTK3 reads the key string from the event; GTK4 dropped the key-event
* string, so derive the unicode character from the keyval instead
* (single-character input only -- composed input goes through GTK4's
* IM handling, not this controller). */
const gchar *str;
#if GTK_CHECK_VERSION(4, 0, 0)
gchar keybuf[7];
const gunichar uc = gdk_keyval_to_unicode(keyval);
if(!uc) return FALSE;
const gint len = g_unichar_to_utf8(uc, keybuf);
keybuf[len] = '\0';
str = keybuf;
#else
GdkEvent *event = gtk_get_current_event();
if(!event) return FALSE;
const gchar *str = ((GdkEventKey *)event)->string;
str = ((GdkEventKey *)event)->string;
if(!str)
{
gdk_event_free(event);
return FALSE;
}
#endif
if(!str || !g_utf8_validate(str, -1, NULL))
{
#if !GTK_CHECK_VERSION(4, 0, 0)
gdk_event_free(event);
#endif
return FALSE;
}
const gunichar c = g_utf8_get_char(str);
if(!g_unichar_isprint(c))
{
#if !GTK_CHECK_VERSION(4, 0, 0)
gdk_event_free(event);
#endif
return FALSE;
}
const long int char_width = g_utf8_next_char(str) - str;
Expand All @@ -3905,7 +3941,9 @@ static gboolean _popup_key_press(GtkEventControllerKey *controller,

if(!is_combo) _start_cursor(-1);
}
#if !GTK_CHECK_VERSION(4, 0, 0)
gdk_event_free(event);
#endif
break;
}
}
Expand Down Expand Up @@ -3959,12 +3997,8 @@ static void _widget_button_press(GtkGestureSingle *gesture,
}
else if(button == GDK_BUTTON_SECONDARY || w->type == DT_BAUHAUS_COMBOBOX)
{
GdkEvent *const event = gtk_get_current_event();
if(event)
{
bh->opentime = gdk_event_get_time(event);
gdk_event_free(event);
}
const GdkEvent *const event = gtk_gesture_get_last_event(GTK_GESTURE(gesture), NULL);
if(event) bh->opentime = gdk_event_get_time((GdkEvent *)event);
bh->mouse_x = x;
bh->mouse_y = y;
_popup_show(widget);
Expand Down Expand Up @@ -4057,10 +4091,13 @@ static void _widget_motion(GtkEventControllerMotion *controller,
const float steps = floorf((x - bh->mouse_x) / scaled_step);
// the current event may be NULL for synthetic motions; fall back to
// the global keyboard state in that case
GdkEvent *const event = gtk_get_current_event();
GdkEvent *const event =
dt_gui_get_current_event(GTK_EVENT_CONTROLLER(controller));
const GdkModifierType motion_state = event ? dt_gdk_event_get_state(event)
: dt_key_modifier_state();
#if !GTK_CHECK_VERSION(4, 0, 0)
if(event) gdk_event_free(event);
#endif
_slider_add_step(widget, copysignf(1, d->factor) * steps,
motion_state, FALSE);

Expand Down
15 changes: 7 additions & 8 deletions src/chart/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ 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, gdouble mx, gdouble my, dt_lut_t *self, image_t *image);
static gboolean handle_motion(GtkEventControllerMotion *controller, 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, gdouble mx, gdouble my, image_t *image, float *x, float *y);
static void update_corner(image_t *image, int which, float *x, float *y);
Expand Down Expand Up @@ -176,8 +176,7 @@ static void _motion_cb_source(GtkEventControllerMotion *controller,
gdouble y,
dt_lut_t *self)
{
GtkWidget *widget = dt_gui_get_widget(controller);
const gboolean res = handle_motion(widget, x, y, self, &self->source);
const gboolean res = handle_motion(controller, x, y, self, &self->source);
if(res)
{
collect_source_patches(self);
Expand All @@ -190,19 +189,19 @@ static void _motion_cb_reference(GtkEventControllerMotion *controller,
gdouble y,
dt_lut_t *self)
{
GtkWidget *widget = dt_gui_get_widget(controller);
const gboolean res = handle_motion(widget, x, y, self, &self->reference);
const gboolean res = handle_motion(controller, x, y, self, &self->reference);
if(res)
{
collect_reference_patches(self);
update_table(self);
}
}

static gboolean handle_motion(GtkWidget *widget, gdouble mx, gdouble my, dt_lut_t *self, image_t *image)
static gboolean handle_motion(GtkEventControllerMotion *controller, gdouble mx, gdouble my, dt_lut_t *self, image_t *image)
{
GdkModifierType state;
gtk_get_current_event_state(&state);
GtkWidget *widget = dt_gui_get_widget(controller);
const GdkModifierType state =
dt_gui_get_current_event_state(GTK_EVENT_CONTROLLER(controller));
if(!(state & GDK_BUTTON1_MASK) || !image->image) return FALSE;

// mouse -> 0..1
Expand Down
Loading
Loading