[gjs: 3/5] arg-cache: Support passing GValue objects, not only generated-gvalues




commit 1d0b4eafd0101269caaf311c042aef65c5c1bed4
Author: Marco Trevisan (TreviƱo) <mail 3v1n0 net>
Date:   Fri Oct 9 22:30:34 2020 +0200

    arg-cache: Support passing GValue objects, not only generated-gvalues
    
    When we create a GValue using the actual constructor we're holding
    internally a boxed type, and in such case we don't have to try to
    convert it to another GValue to pass around, but we should just use it
    as our argument.
    
    However, this can't be computed when parsing the argument, but depends
    case-by-case, as per this when we've a GValue and this is an object
    containing an actual GValue, pass it around and remember that we've not
    to free the returned argument, as that will be handled by the boxed
    wrapper.
    
    This allows to finally use some Gtk functions to get GValue parameters
    as "in/out" parameters, and the gvalue copy function.
    Add tests checking that this is the case.
    
    Fixes #74

 gi/arg-cache.cpp                       | 38 ++++++++++++++++++++++++++++------
 gi/function.h                          |  2 ++
 installed-tests/js/testGObjectValue.js |  9 ++++++++
 installed-tests/js/testGtk3.js         | 22 ++++++++++++++++++++
 4 files changed, 65 insertions(+), 6 deletions(-)
---
diff --git a/gi/arg-cache.cpp b/gi/arg-cache.cpp
index cb5d660d..90d8d0ce 100644
--- a/gi/arg-cache.cpp
+++ b/gi/arg-cache.cpp
@@ -545,8 +545,22 @@ static bool gjs_marshal_foreign_in_in(JSContext* cx, GjsArgumentCache* self,
 
 GJS_JSAPI_RETURN_CONVENTION
 static bool gjs_marshal_gvalue_in_in(JSContext* cx, GjsArgumentCache*,
-                                     GjsFunctionCallState*, GIArgument* arg,
-                                     JS::HandleValue value) {
+                                     GjsFunctionCallState* state,
+                                     GIArgument* arg, JS::HandleValue value) {
+    if (value.isObject()) {
+        JS::RootedObject obj(cx, &value.toObject());
+        GType gtype;
+
+        if (!gjs_gtype_get_actual_gtype(cx, obj, &gtype))
+            return false;
+
+        if (gtype == G_TYPE_VALUE) {
+            gjs_arg_set(arg, BoxedBase::to_c_ptr<GValue>(cx, obj));
+            state->ignore_release.insert(arg);
+            return true;
+        }
+    }
+
     GValue gvalue = G_VALUE_INIT;
 
     if (!gjs_value_to_g_value(cx, value, &gvalue))
@@ -966,6 +980,18 @@ static bool gjs_marshal_boxed_in_release(JSContext*, GjsArgumentCache* self,
     return true;
 }
 
+GJS_JSAPI_RETURN_CONVENTION
+static bool gjs_marshal_gvalue_in_maybe_release(JSContext* cx,
+                                                GjsArgumentCache* self,
+                                                GjsFunctionCallState* state,
+                                                GIArgument* in_arg,
+                                                GIArgument* out_arg) {
+    if (state->ignore_release.erase(in_arg))
+        return true;
+
+    return gjs_marshal_boxed_in_release(cx, self, state, in_arg, out_arg);
+}
+
 static void gjs_arg_cache_interface_free(GjsArgumentCache* self) {
     g_clear_pointer(&self->contents.info, g_base_info_unref);
 }
@@ -1058,10 +1084,10 @@ static const GjsArgumentMarshallers gvalue_in_marshallers = {
 };
 
 static const GjsArgumentMarshallers gvalue_in_transfer_none_marshallers = {
-    gjs_marshal_gvalue_in_in,  // in
-    gjs_marshal_skipped_out,  // out
-    gjs_marshal_boxed_in_release,  // release
-    gjs_arg_cache_interface_free,  // free
+    gjs_marshal_gvalue_in_in,             // in
+    gjs_marshal_skipped_out,              // out
+    gjs_marshal_gvalue_in_maybe_release,  // release
+    gjs_arg_cache_interface_free,         // free
 };
 
 static const GjsArgumentMarshallers gclosure_in_marshallers = {
diff --git a/gi/function.h b/gi/function.h
index b5c25acc..feec3cab 100644
--- a/gi/function.h
+++ b/gi/function.h
@@ -7,6 +7,7 @@
 
 #include <config.h>
 
+#include <unordered_set>
 #include <vector>
 
 #include <ffi.h>
@@ -86,6 +87,7 @@ struct GjsFunctionCallState {
     GIArgument* in_cvalues;
     GIArgument* out_cvalues;
     GIArgument* inout_original_cvalues;
+    std::unordered_set<GIArgument*> ignore_release;
     JS::RootedObject instance_object;
     bool call_completed;
 
diff --git a/installed-tests/js/testGObjectValue.js b/installed-tests/js/testGObjectValue.js
index 4e5d03ce..c063fbb8 100644
--- a/installed-tests/js/testGObjectValue.js
+++ b/installed-tests/js/testGObjectValue.js
@@ -68,6 +68,15 @@ describe('GObject value (GValue)', function () {
                 v[`set_${type}`](randomContent);
                 expect(v[`get_${type}`]()).toEqual(randomContent);
             });
+
+            it(`copies ${type}`, function () {
+                v[`set_${type}`](randomContent);
+
+                const other = new GObject.Value();
+                other.init(gtype);
+                v.copy(other);
+                expect(other[`get_${type}`]()).toEqual(randomContent);
+            });
         });
     });
 
diff --git a/installed-tests/js/testGtk3.js b/installed-tests/js/testGtk3.js
index 5a781567..009ee199 100644
--- a/installed-tests/js/testGtk3.js
+++ b/installed-tests/js/testGtk3.js
@@ -241,4 +241,26 @@ describe('Gtk overrides', function () {
         iter.stamp = 42;
         expect(iter.stamp).toEqual(42);
     });
+
+    it('can get style properties using GObject.Value', function () {
+        let win = new Gtk.ScrolledWindow();
+        let value = new GObject.Value();
+        value.init(GObject.TYPE_BOOLEAN);
+        win.style_get_property('scrollbars-within-bevel', value);
+        expect(value.get_boolean()).toBeDefined();
+
+        value.unset();
+        value.init(GObject.TYPE_INT);
+        let preVal = Math.max(512521, Math.random() * Number.MAX_SAFE_INTEGER);
+        value.set_int(preVal);
+        win.style_get_property('scrollbar-spacing', value);
+        expect(value.get_int()).not.toEqual(preVal);
+
+        win = new Gtk.Window();
+        value.unset();
+        value.init(GObject.TYPE_STRING);
+        value.set_string('EMPTY');
+        win.style_get_property('decoration-button-layout', value);
+        expect(value.get_string()).not.toEqual('EMPTY');
+    });
 });


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