[gjs: 1/2] Add override for g_binding_group_bind_full()




commit 38cbea482ad74935a4411b261632ef4ffbdc0807
Author: Florian Müllner <fmuellner gnome org>
Date:   Wed Aug 3 09:02:14 2022 +0200

    Add override for g_binding_group_bind_full()
    
    The function has the same issue as g_object_bind_property_full():
    
    The function itself isn't introspectable because two callbacks
    share the same closure/destroy.
    
    The binding-friendly _with_closures() variant doesn't work for us
    either, because we unwrap GValues when passing them to javascript,
    and GClosures have no way to specify annotations (like "(out)").
    
    Address this the same way as g_object_bind_property_full(), with
    a small wrapper and a custom override.

 installed-tests/js/testGObjectClass.js | 18 ++++++++++++++++++
 libgjs-private/gjs-util.c              | 22 ++++++++++++++++++++++
 libgjs-private/gjs-util.h              | 22 ++++++++++++++++++++++
 modules/core/overrides/GObject.js      |  4 ++++
 4 files changed, 66 insertions(+)
---
diff --git a/installed-tests/js/testGObjectClass.js b/installed-tests/js/testGObjectClass.js
index a10ac7aab..dede1a91d 100644
--- a/installed-tests/js/testGObjectClass.js
+++ b/installed-tests/js/testGObjectClass.js
@@ -1164,6 +1164,24 @@ describe('Property bindings', function () {
         expect(a.bool).toEqual(true);
         expect(b.string).toEqual('true');
     });
+
+    it('can be set up as a group', function () {
+        const group = new GObject.BindingGroup({source: a});
+        group.bind('string', b, 'string', GObject.BindingFlags.NONE);
+        a.string = 'foo';
+        expect(a.string).toEqual('foo');
+        expect(b.string).toEqual('foo');
+    });
+
+    it('can be set up as a group with custom mappings', function () {
+        const group = new GObject.BindingGroup({source: a});
+        group.bind_full('bool', b, 'string', GObject.BindingFlags.NONE,
+            (bind, source) => [true, `${source}`],
+            null);
+        a.bool = true;
+        expect(a.bool).toEqual(true);
+        expect(b.string).toEqual('true');
+    });
 });
 
 describe('Auto accessor generation', function () {
diff --git a/libgjs-private/gjs-util.c b/libgjs-private/gjs-util.c
index e18d99e62..e0033ce32 100644
--- a/libgjs-private/gjs-util.c
+++ b/libgjs-private/gjs-util.c
@@ -125,6 +125,28 @@ GBinding* gjs_g_object_bind_property_full(
                                                 to_closure, from_closure);
 }
 
+void gjs_g_binding_group_bind_full(
+    GBindingGroup* source, const char* source_property, GObject* target,
+    const char* target_property, GBindingFlags flags,
+    GjsBindingTransformFunc to_callback, void* to_data,
+    GDestroyNotify to_notify, GjsBindingTransformFunc from_callback,
+    void* from_data, GDestroyNotify from_notify) {
+    GClosure* to_closure = NULL;
+    GClosure* from_closure = NULL;
+
+    if (to_callback)
+        to_closure = g_cclosure_new(G_CALLBACK(to_callback), to_data,
+                                    G_CLOSURE_NOTIFY(to_notify));
+
+    if (from_callback)
+        from_closure = g_cclosure_new(G_CALLBACK(from_callback), from_data,
+                                      G_CLOSURE_NOTIFY(from_notify));
+
+    return g_binding_group_bind_with_closures(source, source_property, target,
+                                              target_property, flags,
+                                              to_closure, from_closure);
+}
+
 #undef G_CLOSURE_NOTIFY
 
 static GParamSpec* gjs_gtk_container_class_find_child_property(
diff --git a/libgjs-private/gjs-util.h b/libgjs-private/gjs-util.h
index 171a88682..f67d1db62 100644
--- a/libgjs-private/gjs-util.h
+++ b/libgjs-private/gjs-util.h
@@ -141,6 +141,28 @@ GBinding* gjs_g_object_bind_property_full(
     GDestroyNotify to_notify, GjsBindingTransformFunc from_callback,
     void* from_data, GDestroyNotify from_notify);
 
+/**
+ * gjs_g_binding_group_bind_full:
+ * @source:
+ * @source_property:
+ * @target:
+ * @target_property:
+ * @flags:
+ * @to_callback: (scope notified) (nullable):
+ * @to_data: (closure to_callback):
+ * @to_notify: (destroy to_data):
+ * @from_callback: (scope notified) (nullable):
+ * @from_data: (closure from_callback):
+ * @from_notify: (destroy from_data):
+ */
+GJS_EXPORT
+void gjs_g_binding_group_bind_full(
+    GBindingGroup* source, const char* source_property, GObject* target,
+    const char* target_property, GBindingFlags flags,
+    GjsBindingTransformFunc to_callback, void* to_data,
+    GDestroyNotify to_notify, GjsBindingTransformFunc from_callback,
+    void* from_data, GDestroyNotify from_notify);
+
 /* For imports.overrides.Gtk */
 GJS_EXPORT
 void gjs_gtk_container_child_set_property(GObject* container, GObject* child,
diff --git a/modules/core/overrides/GObject.js b/modules/core/overrides/GObject.js
index df6f9dc27..f3dce6865 100644
--- a/modules/core/overrides/GObject.js
+++ b/modules/core/overrides/GObject.js
@@ -689,6 +689,10 @@ function _init() {
         return GjsPrivate.g_object_bind_property_full(this, ...args);
     };
 
+    GObject.BindingGroup.prototype.bind_full = function (...args) {
+        return GjsPrivate.g_binding_group_bind_full(this, ...args);
+    };
+
     // fake enum for signal accumulators, keep in sync with gi/object.c
     GObject.AccumulatorType = {
         NONE: 0,


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