From 23e7d32924ef5a8cdae7973dbef61c47517e65ab Mon Sep 17 00:00:00 2001 From: Julian Winkler Date: Fri, 19 Jul 2024 14:06:52 +0200 Subject: [PATCH] Button/ImageButton: consume touch events Androids button consumes touch events, while GTKs button lets touch events propagate to the parent. This previously caused some glitches with buttons inside a CoordinatorLayout. --- src/api-impl-jni/widgets/WrapperWidget.c | 24 +++++++++++++++++++ src/api-impl-jni/widgets/WrapperWidget.h | 1 + .../widgets/android_widget_Button.c | 1 + .../widgets/android_widget_ImageButton.c | 1 + 4 files changed, 27 insertions(+) diff --git a/src/api-impl-jni/widgets/WrapperWidget.c b/src/api-impl-jni/widgets/WrapperWidget.c index a74fba28..d9eff71f 100644 --- a/src/api-impl-jni/widgets/WrapperWidget.c +++ b/src/api-impl-jni/widgets/WrapperWidget.c @@ -224,3 +224,27 @@ void wrapper_widget_set_background(WrapperWidget *wrapper, GdkPaintable *paintab } gtk_picture_set_paintable(GTK_PICTURE(wrapper->background), paintable); } + +static gboolean on_touch_event_consume(GtkEventControllerLegacy *controller, GdkEvent *event) { + switch(gdk_event_get_event_type(event)) { + case GDK_BUTTON_PRESS: + case GDK_TOUCH_BEGIN: + case GDK_BUTTON_RELEASE: + case GDK_TOUCH_END: + case GDK_MOTION_NOTIFY: + case GDK_TOUCH_UPDATE: + return TRUE; + default: + return FALSE; + } +} + +// Add default on touch listener, which just consumes all events to prevent bubbling to the parent +void wrapper_widget_consume_touch_events(WrapperWidget *wrapper) +{ + GtkEventController *controller = GTK_EVENT_CONTROLLER(gtk_event_controller_legacy_new()); + g_signal_connect(controller, "event", G_CALLBACK(on_touch_event_consume), NULL); + gtk_widget_add_controller(GTK_WIDGET(wrapper), controller); + g_object_set_data(G_OBJECT(wrapper), "on_touch_listener", controller); + +} diff --git a/src/api-impl-jni/widgets/WrapperWidget.h b/src/api-impl-jni/widgets/WrapperWidget.h index 2a9d72d1..9ca71bb7 100644 --- a/src/api-impl-jni/widgets/WrapperWidget.h +++ b/src/api-impl-jni/widgets/WrapperWidget.h @@ -35,6 +35,7 @@ void wrapper_widget_set_jobject(WrapperWidget *wrapper, JNIEnv *env, jobject job void wrapper_widget_queue_draw(WrapperWidget *wrapper); void wrapper_widget_set_layout_params(WrapperWidget *wrapper, int width, int height); void wrapper_widget_set_background(WrapperWidget *wrapper, GdkPaintable *paintable); +void wrapper_widget_consume_touch_events(WrapperWidget *wrapper); void _setOnTouchListener(JNIEnv *env, jobject this, GtkWidget *widget, jobject on_touch_listener); diff --git a/src/api-impl-jni/widgets/android_widget_Button.c b/src/api-impl-jni/widgets/android_widget_Button.c index f30febd9..376ca376 100644 --- a/src/api-impl-jni/widgets/android_widget_Button.c +++ b/src/api-impl-jni/widgets/android_widget_Button.c @@ -14,6 +14,7 @@ JNIEXPORT jlong JNICALL Java_android_widget_Button_native_1constructor(JNIEnv *e GtkWidget *wrapper = g_object_ref(wrapper_widget_new()); GtkWidget *label = gtk_button_new_with_label(text); wrapper_widget_set_child(WRAPPER_WIDGET(wrapper), label); + wrapper_widget_consume_touch_events(WRAPPER_WIDGET(wrapper)); // Android button consumes touch events return _INTPTR(label); } diff --git a/src/api-impl-jni/widgets/android_widget_ImageButton.c b/src/api-impl-jni/widgets/android_widget_ImageButton.c index af6cc737..1c41a4a4 100644 --- a/src/api-impl-jni/widgets/android_widget_ImageButton.c +++ b/src/api-impl-jni/widgets/android_widget_ImageButton.c @@ -14,6 +14,7 @@ JNIEXPORT jlong JNICALL Java_android_widget_ImageButton_native_1constructor(JNIE GtkWidget *image = gtk_picture_new_for_resource("/org/gtk/libgtk/icons/16x16/status/image-missing.png"); // show "broken image" icon gtk_button_set_child(GTK_BUTTON(button), image); wrapper_widget_set_child(WRAPPER_WIDGET(wrapper), button); + wrapper_widget_consume_touch_events(WRAPPER_WIDGET(wrapper)); // Android button consumes touch events wrapper_widget_set_jobject(WRAPPER_WIDGET(wrapper), env, this); return _INTPTR(button);