[gjs/ewlsh/gvalue-arguments] gi: Allow GObject.Value boxed type in nested contexts




commit 1980ebd44adb88918c9b61c640cfb5a3e56bd542
Author: Evan Welsh <contact evanwelsh com>
Date:   Sat Jan 15 11:36:59 2022 -0800

    gi: Allow GObject.Value boxed type in nested contexts
    
    Previously we only handled this conversion in the arg cache. This
    enables passing GObject.Value in arrays and other nested
    structures.

 gi/value.cpp                            | 41 +++++++++++++++++++++++++++++++++
 installed-tests/js/testGIMarshalling.js | 16 +++++++++++++
 2 files changed, 57 insertions(+)
---
diff --git a/gi/value.cpp b/gi/value.cpp
index af1f6702..d9e0bc5d 100644
--- a/gi/value.cpp
+++ b/gi/value.cpp
@@ -360,6 +360,47 @@ gjs_value_to_g_value_internal(JSContext      *context,
 
     gtype = G_VALUE_TYPE(gvalue);
 
+    if (value.isObject()) {
+        JS::RootedObject obj(context, &value.toObject());
+        GType boxed_gtype;
+
+        if (!gjs_gtype_get_actual_gtype(context, obj, &boxed_gtype))
+            return false;
+
+        // Don't unbox GValue if the GValue's gtype is GObject.Value
+        if (g_type_is_a(boxed_gtype, G_TYPE_VALUE) && gtype != G_TYPE_VALUE) {
+            if (no_copy) {
+                gjs_throw(
+                    context,
+                    "Cannot convert GObject.Value object without copying.");
+                return false;
+            }
+
+            GValue* source = BoxedBase::to_c_ptr<GValue>(context, obj);
+            // Only initialize the value if it doesn't have a type
+            // and our source GValue has been initialized
+            GType source_gtype = G_VALUE_TYPE(source);
+            if (gtype == 0) {
+                if (source_gtype == 0) {
+                    gjs_throw(context,
+                              "GObject.Value is not initialized with a type");
+                    return false;
+                }
+                g_value_init(gvalue, source_gtype);
+            }
+
+            GType dest_gtype = G_VALUE_TYPE(gvalue);
+            if (!g_value_type_compatible(source_gtype, dest_gtype)) {
+                gjs_throw(context, "GObject.Value expected GType %s, found %s",
+                          g_type_name(dest_gtype), g_type_name(source_gtype));
+                return false;
+            }
+
+            g_value_copy(source, gvalue);
+            return true;
+        }
+    }
+
     if (gtype == 0) {
         if (!gjs_value_guess_g_type(context, value, &gtype))
             return false;
diff --git a/installed-tests/js/testGIMarshalling.js b/installed-tests/js/testGIMarshalling.js
index 7d524919..22e1b973 100644
--- a/installed-tests/js/testGIMarshalling.js
+++ b/installed-tests/js/testGIMarshalling.js
@@ -814,6 +814,22 @@ describe('GValue', function () {
             .not.toThrow();
     });
 
+    it('array of boxed type GValues can be passed into a function', function () {
+        const value0 = new GObject.Value();
+        value0.init(GObject.TYPE_INT);
+        value0.set_int(42);
+        const value1 = new GObject.Value();
+        value1.init(String);
+        value1.set_string('42');
+        const value2 = new GObject.Value();
+        value2.init(Boolean);
+        value2.set_boolean(true);
+
+        const values = [value0, value1, value2];
+        expect(() => GIMarshallingTests.gvalue_flat_array(values))
+            .not.toThrow();
+    });
+
     it('array can be passed as an out argument and unpacked', function () {
         expect(GIMarshallingTests.return_gvalue_flat_array())
             .toEqual([42, '42', true]);


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