[gjs] object: Support accessing fields on GObjects
- From: Philip Chimento <pchimento src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gjs] object: Support accessing fields on GObjects
- Date: Wed, 28 Dec 2016 01:31:43 +0000 (UTC)
commit 8ebb803ef9223a8ddefe158bf6cd34fce15952e0
Author: Philip Chimento <philip chimento gmail com>
Date: Sun Dec 18 19:28:19 2016 -0800
object: Support accessing fields on GObjects
This adds support for accessing fields in GObject instance structures as
if they were JS properties.
There are a few caveats:
- If there is a GObject property of the same name, the field is
inaccessible.
- GObject Introspection doesn't support reading fields that are of a
complex type, so we throw an exception if you try to read one of those.
- Unfortunately the /*< private >*/ annotation doesn't seem to show up in
the GIR file, so there is no difference between private and public
fields (I think that only gtk-doc uses that annotation.)
https://bugzilla.gnome.org/show_bug.cgi?id=563391
gi/object.cpp | 75 ++++++++++++++++++++++
installed-tests/js/testEverythingEncapsulated.js | 25 +++++++
2 files changed, 100 insertions(+), 0 deletions(-)
---
diff --git a/gi/object.cpp b/gi/object.cpp
index f742fc2..be3abde 100644
--- a/gi/object.cpp
+++ b/gi/object.cpp
@@ -298,6 +298,73 @@ get_prop_from_g_param(JSContext *context,
return true;
}
+static bool
+get_prop_from_field(JSContext *cx,
+ JS::HandleObject obj,
+ ObjectInstance *priv,
+ const char *name,
+ JS::MutableHandleValue value_p)
+{
+ if (priv->info == NULL)
+ return true; /* Not resolved, but no error; leave value_p untouched */
+
+ int n_fields = g_object_info_get_n_fields(priv->info);
+ int ix;
+ GIFieldInfo *field = NULL;
+ for (ix = 0; ix < n_fields; ix++) {
+ field = g_object_info_get_field(priv->info, ix);
+ const char *field_name = g_base_info_get_name((GIBaseInfo *) field);
+ if (strcmp(name, field_name) == 0)
+ break;
+ g_clear_pointer(&field, g_base_info_unref);
+ }
+
+ if (field == NULL)
+ return true;
+
+ bool retval = true;
+ GITypeInfo *type = NULL;
+ GITypeTag tag;
+ GIArgument arg = { 0 };
+
+ if (!(g_field_info_get_flags(field) & GI_FIELD_IS_READABLE))
+ goto out;
+
+ gjs_debug_jsprop(GJS_DEBUG_GOBJECT, "Overriding %s with GObject field",
+ name);
+
+ type = g_field_info_get_type(field);
+ tag = g_type_info_get_tag(type);
+ if (tag == GI_TYPE_TAG_ARRAY ||
+ tag == GI_TYPE_TAG_INTERFACE ||
+ tag == GI_TYPE_TAG_GLIST ||
+ tag == GI_TYPE_TAG_GSLIST ||
+ tag == GI_TYPE_TAG_GHASH ||
+ tag == GI_TYPE_TAG_ERROR) {
+ gjs_throw(cx, "Can't get field %s; GObject introspection supports only "
+ "fields with simple types, not %s", name,
+ g_type_tag_to_string(tag));
+ retval = false;
+ goto out;
+ }
+
+ retval = g_field_info_get_field(field, priv->gobj, &arg);
+ if (!retval) {
+ gjs_throw(cx, "Error getting field %s from object", name);
+ goto out;
+ }
+
+ retval = gjs_value_from_g_argument(cx, value_p, type, &arg, true);
+ /* copy_structs is irrelevant because g_field_info_get_field() doesn't
+ * handle boxed types */
+
+out:
+ if (type != NULL)
+ g_base_info_unref((GIBaseInfo *) type);
+ g_base_info_unref((GIBaseInfo *) field);
+ return retval;
+}
+
/* a hook on getting a property; set value_p to override property's value.
* Return value is false on OOM/exception.
*/
@@ -329,6 +396,14 @@ object_instance_get_prop(JSContext *context,
goto out;
ret = get_prop_from_g_param(context, obj, priv, name, value_p);
+ if (!ret)
+ goto out;
+
+ if (!value_p.isUndefined())
+ goto out;
+
+ /* Fall back to fields */
+ ret = get_prop_from_field(context, obj, priv, name, value_p);
out:
g_free(name);
diff --git a/installed-tests/js/testEverythingEncapsulated.js
b/installed-tests/js/testEverythingEncapsulated.js
index ee09b79..4349a3e 100644
--- a/installed-tests/js/testEverythingEncapsulated.js
+++ b/installed-tests/js/testEverythingEncapsulated.js
@@ -189,3 +189,28 @@ describe('Introspected boxed types', function () {
expect(boxed.some_long).toEqual(5);
});
});
+
+describe('Introspected GObject', function () {
+ let obj;
+ beforeEach(function () {
+ obj = new Regress.TestObj({
+ // These properties have backing public fields with different names
+ int: 42,
+ float: 3.1416,
+ double: 2.71828,
+ });
+ });
+
+ it('can access fields with simple types', function () {
+ // Compare the values gotten through the GObject property getters to the
+ // values of the backing fields
+ expect(obj.some_int8).toEqual(obj.int);
+ expect(obj.some_float).toEqual(obj.float);
+ expect(obj.some_double).toEqual(obj.double);
+ });
+
+ it('cannot access fields with complex types (GI limitation)', function () {
+ expect(() => obj.parent_instance).toThrow();
+ expect(() => obj.function_ptr).toThrow();
+ });
+});
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]