From 065fd96308307343f03f40d563475ece6ed57e29 Mon Sep 17 00:00:00 2001 From: Mis012 Date: Tue, 31 Oct 2023 23:14:47 +0100 Subject: [PATCH] api-impl-jni: make invalidate() work inside the draw callback this lets us remove the tick callback, and only call onDraw when it's actually necessary --- src/api-impl-jni/views/android_view_View.c | 2 +- src/api-impl-jni/widgets/WrapperWidget.c | 30 ++++++++++++++++------ src/api-impl-jni/widgets/WrapperWidget.h | 3 +++ 3 files changed, 26 insertions(+), 9 deletions(-) diff --git a/src/api-impl-jni/views/android_view_View.c b/src/api-impl-jni/views/android_view_View.c index ff99c6f1..35624d7a 100644 --- a/src/api-impl-jni/views/android_view_View.c +++ b/src/api-impl-jni/views/android_view_View.c @@ -267,7 +267,7 @@ JNIEXPORT jlong JNICALL Java_android_view_View_native_1constructor(JNIEnv *env, JNIEXPORT void JNICALL Java_android_view_View_nativeInvalidate(JNIEnv *env, jclass class, jlong widget_ptr) { GtkWidget *widget = GTK_WIDGET(_PTR(widget_ptr)); - gtk_widget_queue_draw(gtk_widget_get_parent(widget)); + wrapper_widget_queue_draw(WRAPPER_WIDGET(gtk_widget_get_parent(widget))); } JNIEXPORT void JNICALL Java_android_view_View_native_1destructor(JNIEnv *env, jobject this, jlong widget_ptr) diff --git a/src/api-impl-jni/widgets/WrapperWidget.c b/src/api-impl-jni/widgets/WrapperWidget.c index ab30087a..e63fc7c7 100644 --- a/src/api-impl-jni/widgets/WrapperWidget.c +++ b/src/api-impl-jni/widgets/WrapperWidget.c @@ -74,6 +74,7 @@ GtkWidget * wrapper_widget_new(void) void wrapper_widget_set_child(WrapperWidget *parent, GtkWidget *child) // TODO: make sure there can only be one child { gtk_widget_insert_before(child, GTK_WIDGET(parent), NULL); + parent->child = child; } #define MEASURE_SPEC_EXACTLY (1 << 30) @@ -95,12 +96,23 @@ static void on_mapped(GtkWidget* self, gpointer data) } } -// FIXME: this is used in one other place as well, should probably go in util.c or gtk_util.c? -gboolean tick_callback(GtkWidget* widget, GdkFrameClock* frame_clock, gpointer user_data) +static guint sk_area_queue_queue_redraw(GtkWidget *sk_area) { - gtk_widget_queue_draw(widget); - gtk_widget_queue_draw(gtk_widget_get_parent(widget)); - return G_SOURCE_CONTINUE; + gtk_widget_queue_draw(sk_area); + return G_SOURCE_REMOVE; +} + +void wrapper_widget_queue_draw(WrapperWidget *wrapper) +{ + if(wrapper->sk_area) { + /* schedule the call to gtk_widget_queue_draw for a future event loop pass in case we're currently inside the sk_area's snapshot */ + /* GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations. */ + g_idle_add_full(G_PRIORITY_HIGH_IDLE + 20, G_SOURCE_FUNC(sk_area_queue_queue_redraw), wrapper->sk_area, NULL); + } + + if(wrapper->child) + gtk_widget_queue_draw(wrapper->child); + gtk_widget_queue_draw(GTK_WIDGET(wrapper)); } void wrapper_widget_set_jobject(WrapperWidget *wrapper, JNIEnv *env, jobject jobj) @@ -114,9 +126,11 @@ void wrapper_widget_set_jobject(WrapperWidget *wrapper, JNIEnv *env, jobject job wrapper->draw_method = draw_method; GtkWidget *sk_area = sk_area_new(); + gtk_widget_set_sensitive(sk_area, false); sk_area_set_draw_func(SK_AREA_WIDGET(sk_area), skia_draw_func, wrapper); gtk_widget_insert_before(sk_area, GTK_WIDGET(wrapper), NULL); - gtk_widget_add_tick_callback(sk_area, tick_callback, NULL, NULL); + wrapper->sk_area = sk_area; +// gtk_widget_add_tick_callback(sk_area, tick_callback, NULL, NULL); } jmethodID measure_method = _METHOD(_CLASS(jobj), "onMeasure", "(II)V"); @@ -128,7 +142,7 @@ void wrapper_widget_set_jobject(WrapperWidget *wrapper, JNIEnv *env, jobject job jmethodID ontouchevent_method = _METHOD(_CLASS(jobj), "onTouchEvent", "(Landroid/view/MotionEvent;)Z"); if (ontouchevent_method != handle_cache.view.onTouchEvent) { - /* use gtk_widget_get_first_child since the jobject may not have the "widget" variable set yet */ - _setOnTouchListener(env, jobj, gtk_widget_get_first_child(GTK_WIDGET(wrapper)), NULL); + /* use wrapper->child since the jobject may not have the "widget" variable set yet */ + _setOnTouchListener(env, jobj, wrapper->child, NULL); } } diff --git a/src/api-impl-jni/widgets/WrapperWidget.h b/src/api-impl-jni/widgets/WrapperWidget.h index f736dcbc..fdc60275 100644 --- a/src/api-impl-jni/widgets/WrapperWidget.h +++ b/src/api-impl-jni/widgets/WrapperWidget.h @@ -9,6 +9,8 @@ G_DECLARE_FINAL_TYPE (WrapperWidget, wrapper_widget, WRAPPER, WIDGET, GtkWidget) struct _WrapperWidget { GtkWidget parent_instance; + GtkWidget *child; + GtkWidget *sk_area; JavaVM *jvm; jobject jobj; jobject canvas; @@ -24,6 +26,7 @@ struct _WrapperWidgetClass GtkWidget * wrapper_widget_new(void); void wrapper_widget_set_child(WrapperWidget *parent, GtkWidget *child); void wrapper_widget_set_jobject(WrapperWidget *wrapper, JNIEnv *env, jobject jobj); +void wrapper_widget_queue_draw(WrapperWidget *wrapper); void _setOnTouchListener(JNIEnv *env, jobject this, GtkWidget *widget, jobject on_touch_listener);