Skip to content

gtk4-prep: event controllers - #21659

Open
Arecsu wants to merge 86 commits into
darktable-org:masterfrom
Arecsu:gtk4/event-controllers-all
Open

gtk4-prep: event controllers#21659
Arecsu wants to merge 86 commits into
darktable-org:masterfrom
Arecsu:gtk4/event-controllers-all

Conversation

@Arecsu

@Arecsu Arecsu commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Huge PR. Needs further testing to see if interactions, keyboard events, mouse, trackpad, scrolls, anything in the UI UX responds ok, across Linux, macOS, Windows.

I've been testing this, polishing code, fixing bugs across the commits. So far so good. But I'm pretty sure I might be missing something, somewhere, deep down a weird module used by a small fraction of people, or could be even obvious issues which I didn't notice.

Mostly mechanical changes, but so many of them had to be made for their particular context. Some code clean up here and there, helpers, macros, but mostly porting to be gtk4 compatible.

Given all changes across files are somewhat related to one another, I concluded that splitting this into many PRs will be more of a time and effort block than anything else. A bug that might happen to a particular module might have its solution (or bug) related to a similar code path somewhere else. So, that's my logic for having this PR in one go.

I need help in testing this!

Skipped in this PR

Focus events (focus-in-event/focus-out-event, ~30 callers): GtkEventControllerFocus doesn't exist in GTK 3.24 — it's a GTK4-only class. We can't convert these until we actually switch to GTK4, so they stay as g_signal_connect for now and will become a mechanical find-and-replace at migration time.

Dialog enter key (dt_handle_dialog_enter, ~6 callers): These bind Enter to "ok" in modal dialogs using g_signal_connect(dialog, "key-press-event", ...). On GTK4, GtkDialog handles this natively, so the workaround can simply be deleted — no conversion needed. It's deferred because it touches the same foundation layer in gtk.c that's being left alone until the switch.

Foundation infrastructure in gtk.c itself (~33 signals): These are the remaining event signals inside src/gui/gtk.c that cover low-level UI — the panel resize handles (12 signals), notebook tab reordering (3), scrollable containers, toast/log widgets, and most importantly the internals of dt_gui_connect_click() and dt_gui_connect_double_click() themselves. These can't be converted on GTK 3.24 because they involve window-level event propagation, scrolled-window interaction, and the gesture controller creation code that everything else depends on. They stay as-is until the actual GTK4 switch, when the whole helper layer can be replaced, I guess, with native GTK4 APIs.

Related: #20433

Arecsu added 30 commits July 27, 2026 00:19
Restore the scroll event masks that were removed when cleaning up
gtk_widget_add_events() calls during the event controller conversion.
Both widgets still use the old g_signal_connect('scroll-event', ...)
for event forwarding (colorequal forwards to notebook/sliders,
tonequal controls propagation), which requires GDK_SCROLL_MASK in
the widget's event mask to function.
- Properly indent closing brace in tonecurve.c secondary-button handler
- Add missing newline before closing brace in colorzones.c
- Remove stray duplicate void gui_init line in map_locations.c
Update copyright end-year to 2026 in files touched by event controller
conversion that still had outdated ranges.
Arecsu added 27 commits July 27, 2026 15:10
…mGpsMap incompatible with gesture controllers)"

This reverts commit 4f60af5.
…Map uses widget class vfuncs, not GtkGesture)
- Replace gtk_gesture_single_get_button() with _get_current_button()
  in _popup_button_press_cb and _popup_button_release_cb.  The
  gesture uses click_all (button=0), so get_button() always returns
  0, making all button-type checks silently dead.
- Restore window validation guard that was dropped during conversion:
  reject events whose GdkWindow doesn't match the popup area widget.
- Restore BUTTON1_MASK injection on the forwarded motion state,
  needed for the correct motion tolerance calculation (400 vs 50px).
- Restore dt_gui_get_scroll_unit_deltas() usage in _popup_scroll_cb
  to accumulate smooth-scroll events properly instead of truncating
  fractional deltas to zero.
Replace gtk_gesture_single_get_button() with _get_current_button()
in _event_band_press_cb and _event_entry_press_cb.  Both callbacks
are connected via click_all (button=0), so get_button() always
returns 0, making drag, double-click reset, and right-click popup
all non-functional.
_area_scrolled_callback calls gtk_get_current_event() but never
frees the returned event, leaking one GdkEvent per scroll event
in the colorequal graph.
Both _blendop_blendif_showmask_clicked and
_blendop_masks_modes_none_clicked lost their GDK_BUTTON_PRIMARY
checks during the event controller conversion.  These callbacks are
connected via dt_iop_togglebutton_new which uses a gesture with
button=0 (all buttons), so non-primary clicks would incorrectly
trigger mask display toggles and mask mode changes.
_presets_scrolled was using raw dx/dy values directly, which
truncates fractional smooth-scroll deltas to zero on trackpads.
Restore dt_gui_get_scroll_unit_deltas() to accumulate events until
a full scroll unit is reached, with a raw-value fallback.
Replace gtk_gesture_single_get_button() with _get_current_button()
in 6 lib module callbacks that are connected via click_all (button=0):

- collect:   view_onButtonPressed_cb
- colorpicker: _live_sample_button_cb
- export:    _widht_mdlclick_cb, _height_mdlclick_cb, _scale_mdlclick_cb
- tagging:  _click_on_view_dictionary, _click_on_view_attached
- colorlabels: _lib_colorlabels_button_press_callback
- masks:    _tree_button_pressed_cb

get_button() returns the configured button (always 0 for click_all),
not the actual event button, making all button-type checks
unconditionally false.
Add a short-hand macro for the verbose
  gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(x))
pattern that appears 156 times across 60 files.

  dt_gui_get_widget(x)  →  gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(x))
Replace outdated FIXME comment with a proper GTK4 migration note.
The original TODO asked for a helper to extract event flags —
gtk_get_current_event_state() already provides this in GTK3,
and gtk_event_controller_get_current_event_state() will be the
GTK4 equivalent.  Also removed several other stale FIXMEs about
scroll handling scope that are outside the scope of this change.
Only changed the stale 'make a helper' TODO — replaced it with
a proper GTK4 migration note about using
gtk_event_controller_get_current_event_state().  Preserved the
existing UI/UX FIXMEs about scroll handling placement.
Scroll event controller callbacks receive (dx, dy) but no raw
GdkEventScroll *, so they need gtk_get_current_event() to use the
smooth-scroll accumulation logic in dt_gui_get_scroll_unit_deltas().

Add fallback helpers that try the current event first and fall back
to the raw dx/dy values, reducing the boilerplate from ~7 lines of
event-dance to a single call.

Also cleans up 3 call sites:
- bauhaus.c: _popup_scroll_cb (combobox + slider branches)
- imageop.c: _presets_scrolled
GtkDrawingArea (and its dtgtk subclass) is a NO_WINDOW widget — it
doesn't have its own GdkWindow.  GtkEventController adds event masks
via gtk_widget_add_events(), but on NO_WINDOW widgets this may not
propagate correctly to the parent's GdkWindow in all GTK3 versions.

Restore explicit GDK_POINTER_MOTION_MASK, GDK_BUTTON_PRESS_MASK,
GDK_BUTTON_RELEASE_MASK, GDK_ENTER_NOTIFY_MASK, GDK_LEAVE_NOTIFY_MASK
on all converted drawing areas that lost them during the event
controller conversion.  The controllers also request these masks,
but explicit gtk_widget_set_events/add_events is the proven path
for NO_WINDOW widgets.

Affects: ratings, range, colorzones, rgbcurve, tonecurve,
monochrome, basecurve, colorcorrection, colorequal, toneequal,
zonesystem, and colorpicker drawing areas.
…irk)

GtkEventControllerMotion and GtkEventControllerKey don't receive
events on GTK_WINDOW_POPUP windows in GTK3.  This is a known issue
with this window type — motion and key events never reach the
controllers even with explicit event masks set.

Replace the motion and key controllers on the popup with direct
signal handler connections (motion-notify-event, leave-notify-event,
key-press-event).  Click and scroll controllers are kept since
those work fine.

GTK4 TODO: the popup should be migrated to GtkPopover which uses
proper event controllers.
Replace gesture controller with the GtkButton ::clicked signal for
the filter preferences button.  Gesture controllers on custom button
widgets (dtgtk_button) can conflict with the button's internal event
handling.  ::clicked is the standard GTK4-compatible way to handle
button presses.
The GTK_IS_BUTTON(gtk_get_event_widget(event)) check was lost during
the event controller conversion.  Without it, clicking on any button
inside the module header (presets, reset, enable, multiinstance) also
toggles the expander, causing the module to open/close unexpectedly.

GTK4: use gtk_gesture_get_last_event(gesture) instead of
gtk_get_current_event().
- Fix arrow button: replace gtk_gesture_single_get_button() with
  _get_current_button() — the arrow was connected via click_all
  (button=0), so get_button() always returned 0, making the arrow
  completely unresponsive.
- Restore GTK_IS_BUTTON guard in header release callback — prevents
  button clicks inside the header from toggling the expander.
- Switch presets button from gesture (press=reset, release=popup) to
  GtkButton ::clicked signal, which only does the popup.  The old
  gesture approach reset the module on every press.
- Add dt_gui_claim() to the reset callback so the event is consumed,
  preventing the button's internal handling from also firing.
Use a simple cast (expected_type)(func) instead of the ternary or
comma-operator tricks.  Casting NULL to a function pointer type is valid
C, and G_CALLBACK casts in the actual call already enforce the real
type checking.
@Arecsu
Arecsu force-pushed the gtk4/event-controllers-all branch from b8a350c to 676138c Compare July 27, 2026 21:29
@Arecsu
Arecsu marked this pull request as ready for review July 27, 2026 21:39
When removing a filtering rule, the same config-shifting code was
duplicated between the main panel's close button and the topbar
popover's remove button.  This pulls it into a shared helper.

Along the way, a few issues in the topbar popover's removal
function are cleaned up: a redundant data lookup, a GList that
was never freed, and a parent widget that was looked up twice.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant