@@ -569,6 +569,100 @@ GtkEventController *(dt_gui_connect_motion)(GtkWidget *widget,
569569 ASSERT_FUNC_TYPE(leave, void (*)(GtkEventControllerMotion *, __typeof__(data))), \
570570 dt_gui_connect_motion(GTK_WIDGET(widget), G_CALLBACK(motion), G_CALLBACK(enter), G_CALLBACK(leave), (data)))
571571
572+ // Enable compile-time checking of signal handler signatures
573+ // Uncomment the _Static_assert to stop compilation on mismatch
574+ // Otherwise errors will be printed at runtime, but only when the signal is connected
575+ // (so all dialogs, menus etc must be opened to see all errors)
576+ // No code is generated when the test is passed
577+ #if 1 && !defined (__cplusplus)
578+ #undef G_CALLBACK
579+ static inline GCallback G_CALLBACK (void *f) { return (GCallback)f; } // as a macro it gets expanded before reaching here
580+ #define DISABLINGPREFIXG_CALLBACK
581+
582+ #define SIGNAME (num, signal, name ) !strcmp((signal), #name) ? 1 << num :
583+ #define RETURN_HANDLER (num, ret, instance, data, ...) ret(*)(__typeof__(instance), __VA_OPT__(__VA_ARGS__,) __typeof__(data)) : 1 << num,
584+ #define BOOL_HANDLER (num, instance, data, ...) RETURN_HANDLER(num, gboolean, instance, data, __VA_ARGS__)
585+ #define VOID_HANDLER (num, instance, data, ...) RETURN_HANDLER(num, void , instance, data, __VA_ARGS__)
586+ #define EVENT_HANDLER (instance, data, event ) BOOL_HANDLER(0 , instance, data, GdkEvent##event*) \
587+ BOOL_HANDLER (0 , instance, data, const GdkEvent##event*)
588+ #undef _Static_assert
589+ #undef g_signal_connect
590+ #define g_signal_connect (instance, signal, c_handler, data ) do { \
591+ const int required_signature = \
592+ SIGNAME (0 , signal, event) \
593+ SIGNAME (0 , signal, button-press-event) \
594+ SIGNAME (0 , signal, button-release-event) \
595+ SIGNAME (0 , signal, motion-notify-event) \
596+ SIGNAME (0 , signal, scroll-event) \
597+ SIGNAME (0 , signal, enter-notify-event) \
598+ SIGNAME (0 , signal, leave-notify-event) \
599+ SIGNAME (0 , signal, key-press-event) \
600+ SIGNAME (0 , signal, focus-out-event) \
601+ SIGNAME (0 , signal, focus-in-event) \
602+ SIGNAME (0 , signal, delete -event) \
603+ SIGNAME (0 | 1 << 1 | 1 << 2 , signal, changed) \
604+ SIGNAME (1 | 1 << 4 , signal, toggled) \
605+ SIGNAME (1 , signal, clicked) \
606+ SIGNAME (1 , signal, value-changed) \
607+ SIGNAME (1 , signal, value-reset) \
608+ SIGNAME (1 , signal, quad-pressed) \
609+ SIGNAME (1 , signal, show) \
610+ SIGNAME (1 , signal, stopped) \
611+ SIGNAME (1 , signal, stop-search) \
612+ SIGNAME (1 , signal, day_selected) \
613+ SIGNAME (1 , signal, day_selected-double -click) \
614+ SIGNAME (1 , signal, selection-changed) \
615+ SIGNAME (1 , signal, activate) \
616+ SIGNAME (1 , signal, deactivate) \
617+ SIGNAME (1 , signal, style-updated) \
618+ SIGNAME (1 , signal, color-set) \
619+ SIGNAME (3 , signal, moved-to-rect) \
620+ SIGNAME (5 , signal, query-tooltip) \
621+ SIGNAME (6 , signal, draw) \
622+ SIGNAME (8 , signal, cancel) \
623+ SIGNAME (8 , signal, size-allocate) \
624+ SIGNAME (8 , signal, drag-begin) \
625+ SIGNAME (8 , signal, drag-end) \
626+ SIGNAME (9 , signal, drag-leave) \
627+ SIGNAME (9 , signal, switch -page) \
628+ SIGNAME (10 , signal, drag-motion) \
629+ SIGNAME (10 , signal, drag-drop) \
630+ SIGNAME (30 , signal, pressed) \
631+ SIGNAME (30 , signal, released) \
632+ SIGNAME (30 , signal, motion) \
633+ SIGNAME (30 , signal, enter) \
634+ SIGNAME (30 , signal, leave) \
635+ 1 << 31 ; \
636+ const int found_signature = _Generic ((DISABLINGPREFIX##c_handler), \
637+ EVENT_HANDLER (instance, data, ) \
638+ EVENT_HANDLER (instance, data, Button) \
639+ EVENT_HANDLER (instance, data, Motion) \
640+ EVENT_HANDLER (instance, data, Scroll) \
641+ EVENT_HANDLER (instance, data, Key) \
642+ EVENT_HANDLER (instance, data, Focus) \
643+ EVENT_HANDLER (instance, data, Crossing) \
644+ VOID_HANDLER (1 , instance, data) \
645+ VOID_HANDLER (2 , instance, data, char *, GtkTreeIter*) \
646+ VOID_HANDLER (3 , instance, data, GdkRectangle*, GdkRectangle*, gboolean, gboolean) \
647+ VOID_HANDLER (4 , instance, data, char *) \
648+ BOOL_HANDLER (5 , instance, data, gint, gint, gboolean, GtkTooltip*) \
649+ BOOL_HANDLER (6 , instance, data, cairo_t *) \
650+ VOID_HANDLER (8 , instance, data, GdkRectangle*) \
651+ VOID_HANDLER (8 , instance, data, GdkEventSequence*) \
652+ VOID_HANDLER (8 , instance, data, GdkDragContext*) \
653+ VOID_HANDLER (9 , instance, data, GdkDragContext*, guint) \
654+ VOID_HANDLER (9 , instance, data, GtkWidget*, guint) \
655+ BOOL_HANDLER (10 , instance, data, GdkDragContext*, const gint, const gint, const guint) \
656+ GCallback : 1 << 30 , \
657+ default : 1 << 31 ); \
658+ if (required_signature == 1 << 31 ) \
659+ dt_print_nts_ext (" %s:%d: connecting unknown signal %s\n " , __FILE__, __LINE__, signal); \
660+ else if (!(required_signature & found_signature)) \
661+ dt_print_nts_ext (" %s:%d: connecting signal %s to %s with incorrect signature\n " , __FILE__, __LINE__, signal, #c_handler); \
662+ /* _Static_assert(required_signature & found_signature, "incorrect function connected to " signal );*/ \
663+ g_signal_connect_data ((instance), (signal), (c_handler), (data), NULL , (GConnectFlags) 0 ); } while (0 )
664+ #endif // __cplusplus
665+
572666// GTK4 gtk_event_controller_get_current_event_state(GTK_EVENT_CONTROLLER(controller));
573667#define dt_modifier_eq (controller, mask )\
574668 dt_modifier_is (dt_key_modifier_state(), mask)
0 commit comments