[gjs: 11/14] arg: Dynamically get the gtype from JS object when none is provided




commit ff7d5b3a66295db708c3d9724fa2a5223e69cb04
Author: Marco Trevisan (TreviƱo) <mail 3v1n0 net>
Date:   Fri Apr 9 07:36:17 2021 +0200

    arg: Dynamically get the gtype from JS object when none is provided
    
    In some cases we're handing interfaces with unsed GType, a case is
    GTypeInstance. When this happen we should rely on fallback marshaller
    and try to figure out the actual C container for this type getting the
    gtype from the JS object.
    
    This allows to use g_value_init_from_instance() correctly between the
    others cases.

 gi/arg-cache.cpp                       |  9 ++++++++
 gi/arg.cpp                             | 38 +++++++++++++++++++++++++++-------
 installed-tests/js/testGObjectValue.js |  9 ++++++++
 3 files changed, 49 insertions(+), 7 deletions(-)
---
diff --git a/gi/arg-cache.cpp b/gi/arg-cache.cpp
index 10b15fcc..7f1cead6 100644
--- a/gi/arg-cache.cpp
+++ b/gi/arg-cache.cpp
@@ -1389,6 +1389,15 @@ static bool gjs_arg_cache_build_interface_in_arg(JSContext* cx,
         case GI_INFO_TYPE_INTERFACE:
         case GI_INFO_TYPE_UNION: {
             GType gtype = g_registered_type_info_get_g_type(interface_info);
+
+            if (!is_instance_param && interface_type == GI_INFO_TYPE_STRUCT &&
+                gtype == G_TYPE_NONE &&
+                !g_struct_info_is_gtype_struct(interface_info)) {
+                // This covers cases such as GTypeInstance
+                self->marshallers = &fallback_in_marshallers;
+                return true;
+            }
+
             self->contents.object.gtype = gtype;
             self->contents.object.info = g_base_info_ref(interface_info);
 
diff --git a/gi/arg.cpp b/gi/arg.cpp
index 4574f98c..49224e83 100644
--- a/gi/arg.cpp
+++ b/gi/arg.cpp
@@ -1279,10 +1279,26 @@ static bool value_to_interface_gi_argument(
 
             gjs_arg_set(arg, klass);
             return true;
+        }
+
+        GType arg_gtype = gtype;
+        if (interface_type == GI_INFO_TYPE_STRUCT && gtype == G_TYPE_NONE &&
+            !g_struct_info_is_foreign(interface_info)) {
+            GType actual_gtype = G_TYPE_NONE;
+            // In case we have no known type from gi we should try to be
+            // more dynamic and try to get the type from JS, to handle the
+            // case in which we're handling a gpointer such as GTypeInstance
+            // FIXME(3v1n0): would be nice to know if GI would give this info
+            if (!gjs_gtype_get_actual_gtype(cx, obj, &actual_gtype))
+                return false;
+
+            if (G_TYPE_IS_INSTANTIATABLE(actual_gtype))
+                gtype = actual_gtype;
+        }
 
-        } else if ((interface_type == GI_INFO_TYPE_STRUCT ||
-                    interface_type == GI_INFO_TYPE_BOXED) &&
-                   !g_type_is_a(gtype, G_TYPE_CLOSURE)) {
+        if ((interface_type == GI_INFO_TYPE_STRUCT ||
+             interface_type == GI_INFO_TYPE_BOXED) &&
+            !g_type_is_a(gtype, G_TYPE_CLOSURE)) {
             // Handle Struct/Union first since we don't necessarily need a GType
             // for them. We special case Closures later, so skip them here.
             if (g_type_is_a(gtype, G_TYPE_BYTES) && JS_IsUint8Array(obj)) {
@@ -1293,14 +1309,22 @@ static bool value_to_interface_gi_argument(
                 return ErrorBase::transfer_to_gi_argument(
                     cx, obj, arg, GI_DIRECTION_IN, transfer);
             }
-            return BoxedBase::transfer_to_gi_argument(
-                cx, obj, arg, GI_DIRECTION_IN, transfer, gtype, interface_info);
+            if (arg_gtype != G_TYPE_NONE || gtype == G_TYPE_NONE ||
+                g_type_is_a(gtype, G_TYPE_BOXED) ||
+                g_type_is_a(gtype, G_TYPE_VALUE) ||
+                g_type_is_a(gtype, G_TYPE_VARIANT)) {
+                return BoxedBase::transfer_to_gi_argument(
+                    cx, obj, arg, GI_DIRECTION_IN, transfer, gtype,
+                    interface_info);
+            }
+        }
 
-        } else if (interface_type == GI_INFO_TYPE_UNION) {
+        if (interface_type == GI_INFO_TYPE_UNION) {
             return UnionBase::transfer_to_gi_argument(
                 cx, obj, arg, GI_DIRECTION_IN, transfer, gtype, interface_info);
+        }
 
-        } else if (gtype != G_TYPE_NONE) {
+        if (gtype != G_TYPE_NONE) {
             if (g_type_is_a(gtype, G_TYPE_OBJECT)) {
                 return ObjectBase::transfer_to_gi_argument(
                     cx, obj, arg, GI_DIRECTION_IN, transfer, gtype);
diff --git a/installed-tests/js/testGObjectValue.js b/installed-tests/js/testGObjectValue.js
index e890cf49..fc5147c4 100644
--- a/installed-tests/js/testGObjectValue.js
+++ b/installed-tests/js/testGObjectValue.js
@@ -169,6 +169,15 @@ describe('GObject value (GValue)', function () {
         }).pend('https://gitlab.gnome.org/GNOME/gobject-introspection/-/merge_requests/268');
     });
 
+    INSTANCED_TYPES.forEach(type => {
+        it(`initializes from instance of ${type}`, function () {
+            skipUnsupported(type);
+            const instance = getDefaultContentByType(type);
+            v.init_from_instance(instance);
+            expect(getContent(v, type)).toEqual(instance);
+        });
+    });
+
     afterEach(function () {
         v.unset();
     });


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]