[gjs: 2/3] fundamental: Use value or instance pointer when no get/set funcs are provided




commit 696163987e19cf4f6263538915c41256ae08cad1
Author: Marco Trevisan (TreviƱo) <mail 3v1n0 net>
Date:   Thu Apr 8 00:12:02 2021 +0200

    fundamental: Use value or instance pointer when no get/set funcs are provided
    
    Some fundamental types are providing value set/get functions however
    this is not mandatory as the fundamental can be just retrieved from the
    GValue pointer or we can build a GValue using the instance and gtype.
    
    A case for this are Gdk4 Events that does not provide such functions,
    making impossible to use events signals.
    
    Add tests simulating this, depending on a new gobject-introspection type
    that respects this constrain.
    
    Fixes: #398

 gi/fundamental.cpp                    | 13 ++++++++++++-
 installed-tests/js/testFundamental.js | 26 ++++++++++++++++++++++++++
 2 files changed, 38 insertions(+), 1 deletion(-)
---
diff --git a/gi/fundamental.cpp b/gi/fundamental.cpp
index a4d1e32c..0e83028c 100644
--- a/gi/fundamental.cpp
+++ b/gi/fundamental.cpp
@@ -443,6 +443,11 @@ JSObject* FundamentalInstance::object_for_gvalue(JSContext* cx,
     auto* proto_priv = FundamentalPrototype::for_gtype(cx, gtype);
     void* fobj;
     if (!proto_priv->call_get_value_function(value, &fobj)) {
+        if (G_VALUE_HOLDS(value, gtype) && g_value_fits_pointer(value)) {
+            return FundamentalInstance::object_for_c_ptr(
+                cx, g_value_peek_pointer(value));
+        }
+
         gjs_throw(cx, "Failed to convert GValue to a fundamental instance");
         return nullptr;
     }
@@ -457,7 +462,13 @@ bool FundamentalBase::to_gvalue(JSContext* cx, JS::HandleObject obj,
         !priv->check_is_instance(cx, "convert to GValue"))
         return false;
 
-    if (!priv->to_instance()->set_value(gvalue)) {
+    auto* instance = priv->to_instance();
+    if (!instance->set_value(gvalue)) {
+        if (g_type_is_a(instance->gtype(), G_VALUE_TYPE(gvalue))) {
+            g_value_set_instance(gvalue, instance->m_ptr);
+            return true;
+        }
+
         gjs_throw(cx,
                   "Fundamental object does not support conversion to a GValue");
         return false;
diff --git a/installed-tests/js/testFundamental.js b/installed-tests/js/testFundamental.js
index 19b638a8..3274cf6c 100644
--- a/installed-tests/js/testFundamental.js
+++ b/installed-tests/js/testFundamental.js
@@ -7,6 +7,9 @@ const {GObject, Regress} = imports.gi;
 const TestObj = GObject.registerClass({
     Signals: {
         'test-fundamental-value-funcs': {param_types: [Regress.TestFundamentalSubObject.$gtype]},
+        'test-fundamental-no-funcs': {param_types:
+            Regress.TestFundamentalObjectNoGetSetFunc
+                ? [Regress.TestFundamentalObjectNoGetSetFunc.$gtype] : []},
     },
 }, class TestObj extends GObject.Object {});
 
@@ -21,4 +24,27 @@ describe('Fundamental type support', function () {
         obj.emit('test-fundamental-value-funcs', fund);
         expect(signalSpy).toHaveBeenCalledWith(obj, fund);
     });
+
+    it('can marshal a custom fundamental type into a GValue if contains a pointer and does not provide 
setter and getters', function () {
+        const fund = new Regress.TestFundamentalObjectNoGetSetFunc('foo');
+        expect(() => GObject.strdup_value_contents(fund)).not.toThrow();
+
+        const obj = new TestObj();
+        const signalSpy = jasmine.createSpy('signalSpy');
+        obj.connect('test-fundamental-no-funcs', signalSpy);
+        obj.connect('test-fundamental-no-funcs', (_o, f) =>
+            expect(f.get_data()).toBe('foo'));
+        obj.emit('test-fundamental-no-funcs', fund);
+        expect(signalSpy).toHaveBeenCalledWith(obj, fund);
+    }).pend('https://gitlab.gnome.org/GNOME/gobject-introspection/-/merge_requests/268');
+
+    it('cannot marshal a custom fundamental type into a GValue of different gtype', function () {
+        const fund = new Regress.TestFundamentalObjectNoGetSetFunc('foo');
+
+        const obj = new TestObj();
+        const signalSpy = jasmine.createSpy('signalSpy');
+        obj.connect('test-fundamental-value-funcs', signalSpy);
+        expect(() => obj.emit('test-fundamental-value-funcs', fund)).toThrowError(
+            /conversion to a GValue/);
+    }).pend('https://gitlab.gnome.org/GNOME/gobject-introspection/-/merge_requests/268');
 });


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