From eba9c7037cbd9a721b85cb887f6f1523bc9bb7c4 Mon Sep 17 00:00:00 2001 From: Daniel Panero Date: Sun, 17 Nov 2024 15:59:53 +0100 Subject: [PATCH] JavaWidget: add debug info for GTK Inspector --- src/api-impl-jni/util.c | 3 + src/api-impl-jni/util.h | 3 + src/api-impl-jni/widgets/WrapperWidget.c | 92 ++++++++++++++++++++++++ src/api-impl/android/view/View.java | 24 +++++++ 4 files changed, 122 insertions(+) diff --git a/src/api-impl-jni/util.c b/src/api-impl-jni/util.c index 44ff49a7..93135b62 100644 --- a/src/api-impl-jni/util.c +++ b/src/api-impl-jni/util.c @@ -137,6 +137,9 @@ void set_up_handle_cache(JNIEnv *env) handle_cache.view.layoutInternal = _METHOD(handle_cache.view.class, "layoutInternal", "(II)V"); handle_cache.view.measure = _METHOD(handle_cache.view.class, "measure", "(II)V"); handle_cache.view.performLongClick = _METHOD(handle_cache.view.class, "performLongClick", "(FF)Z"); + handle_cache.view.getId = _METHOD(handle_cache.view.class, "getId", "()I"); + handle_cache.view.getIdName = _METHOD(handle_cache.view.class, "getIdName", "()Ljava/lang/String;"); + handle_cache.view.getAllSuperClasses = _METHOD(handle_cache.view.class, "getAllSuperClasses", "()Ljava/lang/String;"); handle_cache.asset_manager.class = _REF((*env)->FindClass(env, "android/content/res/AssetManager")); handle_cache.asset_manager.extractFromAPK = _STATIC_METHOD(handle_cache.asset_manager.class, "extractFromAPK", "(Ljava/lang/String;Ljava/lang/String;)V"); diff --git a/src/api-impl-jni/util.h b/src/api-impl-jni/util.h index 2b5e15e7..3c65e830 100644 --- a/src/api-impl-jni/util.h +++ b/src/api-impl-jni/util.h @@ -83,6 +83,9 @@ struct handle_cache { jmethodID layoutInternal; jmethodID measure; jmethodID performLongClick; + jmethodID getId; + jmethodID getIdName; + jmethodID getAllSuperClasses; } view; struct { jclass class; diff --git a/src/api-impl-jni/widgets/WrapperWidget.c b/src/api-impl-jni/widgets/WrapperWidget.c index 5d617888..ca8d1bb8 100644 --- a/src/api-impl-jni/widgets/WrapperWidget.c +++ b/src/api-impl-jni/widgets/WrapperWidget.c @@ -10,6 +10,87 @@ G_DEFINE_TYPE(WrapperWidget, wrapper_widget, GTK_TYPE_WIDGET) +typedef enum { ATL_ID = 1, ATL_ID_NAME, ATL_CLASS_NAME, ATL_SUPER_CLASS_NAMES, N_PROPERTIES } WrapperWidgetProperty; +static GParamSpec *wrapper_widget_properties[N_PROPERTIES] = { NULL, }; + +static void wrapper_widget_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) +{ + switch ((WrapperWidgetProperty) property_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void wrapper_widget_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) +{ + WrapperWidget *self = WRAPPER_WIDGET(object); + + JNIEnv *env = get_jni_env(); + + jobject jobj = self->jobj; + jclass class = _CLASS(jobj); + + switch ((WrapperWidgetProperty) property_id) + { + case ATL_ID: + { + jint id_jint = (*env)->CallIntMethod(env, jobj, handle_cache.view.getId); + if((*env)->ExceptionCheck(env)) + (*env)->ExceptionDescribe(env); + + const char *id = g_markup_printf_escaped("0x%08x", id_jint); + g_value_set_string(value, id); + break; + } + + case ATL_ID_NAME: + { + jstring id_name_jstring = (*env)->CallObjectMethod(env, jobj, handle_cache.view.getIdName); + if((*env)->ExceptionCheck(env)) + (*env)->ExceptionDescribe(env); + + const char *id_name = (*env)->GetStringUTFChars(env, id_name_jstring, NULL); + g_value_set_string(value, id_name); + + (*env)->ReleaseStringUTFChars(env, id_name_jstring, id_name); + break; + } + + case ATL_CLASS_NAME: + { + jstring class_name_jstring = (*env)->CallObjectMethod(env, class, _METHOD(_CLASS(class), "getName", "()Ljava/lang/String;")); + if((*env)->ExceptionCheck(env)) + (*env)->ExceptionDescribe(env); + + const char *class_name = (*env)->GetStringUTFChars(env, class_name_jstring, NULL); + g_value_set_string(value, class_name); + + (*env)->ReleaseStringUTFChars(env, class_name_jstring, class_name); + break; + } + + case ATL_SUPER_CLASS_NAMES: + { + jstring super_classes_names_obj = (*env)->CallObjectMethod(env, jobj, handle_cache.view.getAllSuperClasses); + if((*env)->ExceptionCheck(env)) + (*env)->ExceptionDescribe(env); + + const char *super_classes_names = (*env)->GetStringUTFChars(env, super_classes_names_obj, NULL); + g_value_set_string(value, super_classes_names); + + (*env)->ReleaseStringUTFChars(env, super_classes_names_obj, super_classes_names); + break; + } + + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + static void wrapper_widget_init (WrapperWidget *wrapper_widget) { @@ -136,6 +217,17 @@ static void wrapper_widget_class_init(WrapperWidgetClass *class) widget_class->measure = wrapper_widget_measure; widget_class->size_allocate = wrapper_widget_allocate; widget_class->snapshot = wrapper_widget_snapshot; + + object_class->set_property = wrapper_widget_set_property; + object_class->get_property = wrapper_widget_get_property; + + // According to testing, these properties are not evaluated till we open the GtkInspector + wrapper_widget_properties[ATL_ID] = g_param_spec_string("ATL-id", "ATL: ID", "ID of the component", "", G_PARAM_READABLE); + wrapper_widget_properties[ATL_ID_NAME] = g_param_spec_string("ATL-id-name", "ATL: ID name", "Name of the ID of the component", "", G_PARAM_READABLE); + wrapper_widget_properties[ATL_CLASS_NAME] = g_param_spec_string("ATL-class-name", "ATL: Class name", "Name of the class of the component", "", G_PARAM_READABLE); + wrapper_widget_properties[ATL_SUPER_CLASS_NAMES] = g_param_spec_string("ATL-superclasses-names", "ATL: Super classes names", "Names of all the superclasses of the component class", "", G_PARAM_READABLE); + + g_object_class_install_properties (object_class, N_PROPERTIES, wrapper_widget_properties); } GtkWidget * wrapper_widget_new(void) diff --git a/src/api-impl/android/view/View.java b/src/api-impl/android/view/View.java index 4e295c84..9abbca08 100644 --- a/src/api-impl/android/view/View.java +++ b/src/api-impl/android/view/View.java @@ -1445,6 +1445,30 @@ public class View implements Drawable.Callback { public void setOverScrollMode(int mode) {} public int getId() {return id;} + public String getIdName() { + if(this.id == View.NO_ID) { + return "NO_ID"; + } + + try { + return getResources().getResourceName(this.id); + } catch (Resources.NotFoundException e) { + return "NOT_FOUND"; + } + + } + public String getAllSuperClasses() { + StringBuilder sb = new StringBuilder(); + Class currentClass = getClass(); + + sb.append(currentClass.getCanonicalName()); + currentClass = currentClass.getSuperclass(); + while (currentClass != null) { + sb.append(" << ").append(currentClass.getCanonicalName()); + currentClass = currentClass.getSuperclass(); + } + return sb.toString(); + } public boolean postDelayed(Runnable action, long delayMillis) { new Handler(Looper.getMainLooper()).postDelayed(action, delayMillis);