From 36b61323243fab47e6996d6e5d0075e1e5a618eb Mon Sep 17 00:00:00 2001 From: Julian Winkler Date: Tue, 22 Aug 2023 13:49:09 +0200 Subject: [PATCH] fix reference counting for GtkWidgets created from java GtkWidgets extend GInitiallyUnowned and are automatically freed when removing from parent widget. We need to add an extra reference, to make sure the object keeps alive as long as the java widget has a reference to it --- .../generated_headers/android_view_View.h | 8 ++++++++ src/api-impl-jni/views/android_view_View.c | 7 ++++++- src/api-impl-jni/views/android_view_ViewGroup.c | 2 +- .../widgets/android_opengl_GLSurfaceView.c | 2 +- .../widgets/android_view_SurfaceView.c | 2 +- .../widgets/android_widget_FrameLayout.c | 2 +- .../widgets/android_widget_ImageView.c | 2 +- .../widgets/android_widget_LinearLayout.c | 2 +- .../widgets/android_widget_RelativeLayout.c | 2 +- .../widgets/android_widget_ScrollView.c | 2 +- src/api-impl-jni/widgets/android_widget_TextView.c | 2 +- src/api-impl/android/view/View.java | 14 +++++++++++++- 12 files changed, 36 insertions(+), 11 deletions(-) diff --git a/src/api-impl-jni/generated_headers/android_view_View.h b/src/api-impl-jni/generated_headers/android_view_View.h index 193c9a3d..02aaf7ed 100644 --- a/src/api-impl-jni/generated_headers/android_view_View.h +++ b/src/api-impl-jni/generated_headers/android_view_View.h @@ -255,6 +255,14 @@ JNIEXPORT jlong JNICALL Java_android_view_View_native_1constructor JNIEXPORT void JNICALL Java_android_view_View_native_1set_1size_1request (JNIEnv *, jobject, jint, jint); +/* + * Class: android_view_View + * Method: native_destructor + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_android_view_View_native_1destructor + (JNIEnv *, jobject, jlong); + /* * Class: android_view_View * Method: nativeInvalidate diff --git a/src/api-impl-jni/views/android_view_View.c b/src/api-impl-jni/views/android_view_View.c index 38ec04a9..9d558430 100644 --- a/src/api-impl-jni/views/android_view_View.c +++ b/src/api-impl-jni/views/android_view_View.c @@ -176,7 +176,7 @@ gboolean tick_callback(GtkWidget* widget, GdkFrameClock* frame_clock, gpointer u JNIEXPORT jlong JNICALL Java_android_view_View_native_1constructor(JNIEnv *env, jobject this, jobject context, jobject attrs) { - GtkWidget *wrapper = wrapper_widget_new(); + GtkWidget *wrapper = g_object_ref(wrapper_widget_new()); GtkWidget *area = gtk_drawing_area_new(); wrapper_widget_set_child(WRAPPER_WIDGET(wrapper), area); wrapper_widget_set_jobject(WRAPPER_WIDGET(wrapper), env, this); @@ -191,3 +191,8 @@ JNIEXPORT void JNICALL Java_android_view_View_nativeInvalidate(JNIEnv *env, jcla gtk_widget_queue_draw(gtk_widget_get_parent(widget)); } + +JNIEXPORT void JNICALL Java_android_view_View_native_1destructor(JNIEnv *env, jobject this, jlong widget_ptr) +{ + g_object_unref(gtk_widget_get_parent(_PTR(widget_ptr))); +} diff --git a/src/api-impl-jni/views/android_view_ViewGroup.c b/src/api-impl-jni/views/android_view_ViewGroup.c index b607d4ec..6dd7b395 100644 --- a/src/api-impl-jni/views/android_view_ViewGroup.c +++ b/src/api-impl-jni/views/android_view_ViewGroup.c @@ -14,7 +14,7 @@ */ JNIEXPORT jlong JNICALL Java_android_view_ViewGroup_native_1constructor(JNIEnv *env, jobject this, jobject context, jobject attrs) { - GtkWidget *wrapper = wrapper_widget_new(); + GtkWidget *wrapper = g_object_ref(wrapper_widget_new()); GtkWidget *box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 1); // spacing of 1 wrapper_widget_set_child(WRAPPER_WIDGET(wrapper), box); gtk_widget_set_name(GTK_WIDGET(box), "ViewGroup"); diff --git a/src/api-impl-jni/widgets/android_opengl_GLSurfaceView.c b/src/api-impl-jni/widgets/android_opengl_GLSurfaceView.c index c71715cf..76451af0 100644 --- a/src/api-impl-jni/widgets/android_opengl_GLSurfaceView.c +++ b/src/api-impl-jni/widgets/android_opengl_GLSurfaceView.c @@ -56,7 +56,7 @@ extern int FIXME__HEIGHT; JNIEXPORT jlong JNICALL Java_android_opengl_GLSurfaceView_native_1constructor(JNIEnv *env, jobject this, jobject context, jobject attrs) { - GtkWidget *wrapper = wrapper_widget_new(); + GtkWidget *wrapper = g_object_ref(wrapper_widget_new()); gtk_widget_set_vexpand(wrapper, TRUE); GtkWidget *gl_area = gtk_gl_area_new(); wrapper_widget_set_child(WRAPPER_WIDGET(wrapper), gl_area); diff --git a/src/api-impl-jni/widgets/android_view_SurfaceView.c b/src/api-impl-jni/widgets/android_view_SurfaceView.c index 72f23a2f..5ee84cc2 100644 --- a/src/api-impl-jni/widgets/android_view_SurfaceView.c +++ b/src/api-impl-jni/widgets/android_view_SurfaceView.c @@ -85,7 +85,7 @@ static void on_resize(GtkWidget* self, gint width, gint height, struct jni_callb JNIEXPORT jlong JNICALL Java_android_view_SurfaceView_native_1constructor(JNIEnv *env, jobject this, jobject context, jobject attrs) { - GtkWidget *wrapper = wrapper_widget_new(); + GtkWidget *wrapper = g_object_ref(wrapper_widget_new()); GtkWidget *dummy = surface_view_widget_new(); gtk_widget_set_name(dummy, "dummy widget for SurfaceView"); wrapper_widget_set_child(WRAPPER_WIDGET(wrapper), dummy); diff --git a/src/api-impl-jni/widgets/android_widget_FrameLayout.c b/src/api-impl-jni/widgets/android_widget_FrameLayout.c index 1cc2d808..6fdda5a9 100644 --- a/src/api-impl-jni/widgets/android_widget_FrameLayout.c +++ b/src/api-impl-jni/widgets/android_widget_FrameLayout.c @@ -77,7 +77,7 @@ void frame_layout_widget_insert_child_at_index(FrameLayoutWidget *parent, GtkWid JNIEXPORT jlong JNICALL Java_android_widget_FrameLayout_native_1constructor(JNIEnv *env, jobject this, jobject context, jobject attrs) { - GtkWidget *wrapper = wrapper_widget_new(); + GtkWidget *wrapper = g_object_ref(wrapper_widget_new()); GtkWidget *frame_layout = frame_layout_widget_new(); wrapper_widget_set_child(WRAPPER_WIDGET(wrapper), frame_layout); gtk_widget_set_name(GTK_WIDGET(frame_layout), "FrameLayout"); diff --git a/src/api-impl-jni/widgets/android_widget_ImageView.c b/src/api-impl-jni/widgets/android_widget_ImageView.c index efe98457..0bd63d76 100644 --- a/src/api-impl-jni/widgets/android_widget_ImageView.c +++ b/src/api-impl-jni/widgets/android_widget_ImageView.c @@ -9,7 +9,7 @@ JNIEXPORT jlong JNICALL Java_android_widget_ImageView_native_1constructor(JNIEnv *env, jobject this, jobject context, jobject attrs) { - GtkWidget *wrapper = wrapper_widget_new(); + GtkWidget *wrapper = g_object_ref(wrapper_widget_new()); GtkWidget *image = gtk_picture_new_for_resource("/org/gtk/libgtk/icons/16x16/status/image-missing.png"); // show "broken image" icon wrapper_widget_set_child(WRAPPER_WIDGET(wrapper), image); wrapper_widget_set_jobject(WRAPPER_WIDGET(wrapper), env, this); diff --git a/src/api-impl-jni/widgets/android_widget_LinearLayout.c b/src/api-impl-jni/widgets/android_widget_LinearLayout.c index c9df4853..9b3ecbf8 100644 --- a/src/api-impl-jni/widgets/android_widget_LinearLayout.c +++ b/src/api-impl-jni/widgets/android_widget_LinearLayout.c @@ -14,7 +14,7 @@ JNIEXPORT jlong JNICALL Java_android_widget_LinearLayout_native_1constructor(JNI { int orientation = attribute_set_get_int(env, attrs, "orientation", NULL, 1); - GtkWidget *wrapper = wrapper_widget_new(); + GtkWidget *wrapper = g_object_ref(wrapper_widget_new()); GtkWidget *box = gtk_box_new(orientation ? GTK_ORIENTATION_VERTICAL : GTK_ORIENTATION_HORIZONTAL, 1); // spacing of 1 wrapper_widget_set_child(WRAPPER_WIDGET(wrapper), box); gtk_widget_set_name(GTK_WIDGET(box), "LinearLayout"); diff --git a/src/api-impl-jni/widgets/android_widget_RelativeLayout.c b/src/api-impl-jni/widgets/android_widget_RelativeLayout.c index 74ab1b81..619b7857 100644 --- a/src/api-impl-jni/widgets/android_widget_RelativeLayout.c +++ b/src/api-impl-jni/widgets/android_widget_RelativeLayout.c @@ -14,7 +14,7 @@ JNIEXPORT jlong JNICALL Java_android_widget_RelativeLayout_native_1constructor(J { int orientation = attribute_set_get_int(env, attrs, "orientation", NULL, 1); - GtkWidget *wrapper = wrapper_widget_new(); + GtkWidget *wrapper = g_object_ref(wrapper_widget_new()); GtkWidget *box = gtk_box_new(orientation ? GTK_ORIENTATION_VERTICAL : GTK_ORIENTATION_HORIZONTAL, 1); // spacing of 1 wrapper_widget_set_child(WRAPPER_WIDGET(wrapper), box); gtk_widget_set_name(GTK_WIDGET(box), "RelativeLayout"); diff --git a/src/api-impl-jni/widgets/android_widget_ScrollView.c b/src/api-impl-jni/widgets/android_widget_ScrollView.c index 6fe6ba75..99263204 100644 --- a/src/api-impl-jni/widgets/android_widget_ScrollView.c +++ b/src/api-impl-jni/widgets/android_widget_ScrollView.c @@ -14,7 +14,7 @@ JNIEXPORT jlong JNICALL Java_android_widget_ScrollView_native_1constructor(JNIEn { int orientation = attribute_set_get_int(env, attrs, "orientation", NULL, 0); - GtkWidget *wrapper = wrapper_widget_new(); + GtkWidget *wrapper = g_object_ref(wrapper_widget_new()); GtkWidget *box = gtk_box_new(orientation ? GTK_ORIENTATION_VERTICAL : GTK_ORIENTATION_HORIZONTAL, 1); // spacing of 1 wrapper_widget_set_child(WRAPPER_WIDGET(wrapper), box); gtk_widget_set_name(GTK_WIDGET(box), "ScrollView"); diff --git a/src/api-impl-jni/widgets/android_widget_TextView.c b/src/api-impl-jni/widgets/android_widget_TextView.c index 2bea8c0a..8a03b766 100644 --- a/src/api-impl-jni/widgets/android_widget_TextView.c +++ b/src/api-impl-jni/widgets/android_widget_TextView.c @@ -13,7 +13,7 @@ JNIEXPORT jlong JNICALL Java_android_widget_TextView_native_1constructor(JNIEnv // _SET_OBJ_FIELD(this, "text", "Ljava/lang/String;", _JSTRING(text)); //TODO: sadly this might be needed, but it's not atm - GtkWidget *wrapper = wrapper_widget_new(); + GtkWidget *wrapper = g_object_ref(wrapper_widget_new()); GtkWidget *label = gtk_label_new(text); wrapper_widget_set_child(WRAPPER_WIDGET(wrapper), label); return _INTPTR(label); diff --git a/src/api-impl/android/view/View.java b/src/api-impl/android/view/View.java index 20057671..1369961d 100644 --- a/src/api-impl/android/view/View.java +++ b/src/api-impl/android/view/View.java @@ -775,7 +775,9 @@ public class View extends Object { public static HashMap view_by_id = new HashMap(); - public View() {} // FIXME + public View() { + this(Context.this_application); + } // FIXME public View(Context context, AttributeSet attrs) { this(context, attrs, 0); @@ -843,6 +845,7 @@ public class View extends Object { protected native long native_constructor(Context context, AttributeSet attrs); // will create a custom GtkWidget with a custom drawing function private native void native_set_size_request(int width, int height); + protected native void native_destructor(long widget); // --- stubs @@ -1052,4 +1055,13 @@ public class View extends Object { public int getVisibility() {return View.VISIBLE;} public boolean isInEditMode() {return false;} + + @Override + protected void finalize() throws Throwable { + try { + native_destructor(widget); + } finally { + super.finalize(); + } + } }