[gjs] object: Add support for interfaces



commit e01184ada59cce3fdd0a3d6e1850d9557de32a46
Author: Giovanni Campagna <gcampagna src gnome org>
Date:   Mon Dec 12 17:14:41 2011 +0100

    object: Add support for interfaces
    
    Introduces a new Gi.add_interface internal method, that wraps
    g_type_add_interface(). Introduces support for interface vfuncs
    when hooking them, and for retrieving their C implementation from
    prototypes.

 gi/interface.c               |   12 +++++++
 gi/object.c                  |   69 +++++++++++++++++++++++++++++++++++++++++-
 modules/overrides/GObject.js |    7 ++++
 test/js/testGObjectClass.js  |   27 ++++++++++++++++-
 4 files changed, 113 insertions(+), 2 deletions(-)
---
diff --git a/gi/interface.c b/gi/interface.c
index 245e037..9ee7603 100644
--- a/gi/interface.c
+++ b/gi/interface.c
@@ -25,6 +25,7 @@
 #include <config.h>
 
 #include "function.h"
+#include "gtype.h"
 #include "interface.h"
 
 #include <gjs/gjs-module.h>
@@ -261,9 +262,20 @@ gjs_define_interface_class(JSContext       *context,
     JS_SetPrivate(context, prototype, priv);
 
     gjs_object_get_property(context, in_object, constructor_name, &value);
+
+    if (!JSVAL_IS_OBJECT(value)) {
+        gjs_throw(context, "Property '%s' does not look like a constructor",
+                  constructor_name);
+        return FALSE;
+    }
+
     constructor = JSVAL_TO_OBJECT(value);
     gjs_define_static_methods(context, constructor, priv->gtype, priv->info);
 
+    value = OBJECT_TO_JSVAL(gjs_gtype_create_gtype_wrapper(context, priv->gtype));
+    JS_DefineProperty(context, constructor, "$gtype", value,
+                      NULL, NULL, JSPROP_PERMANENT);
+
     if (prototype_p)
         *prototype_p = prototype;
 
diff --git a/gi/object.c b/gi/object.c
index 27618a3..4f66698 100644
--- a/gi/object.c
+++ b/gi/object.c
@@ -311,7 +311,11 @@ find_vfunc_on_parent(GIObjectInfo *info,
      * it when unrefing parents later */
     g_base_info_ref(info);
     parent = info;
-    vfunc = g_object_info_find_vfunc(parent, name);
+
+    /* Since it isn't possible to override a vfunc on
+     * an interface without reimplementing it, we don't need
+     * to search the parent types when looking for a vfunc. */
+    vfunc = g_object_info_find_vfunc_using_interfaces(parent, name, NULL);
     while (!vfunc && parent) {
         old_parent = parent;
         parent = g_object_info_get_parent(old_parent);
@@ -1828,6 +1832,37 @@ gjs_hook_up_vfunc(JSContext *cx,
 
     vfunc = find_vfunc_on_parent(info, name);
 
+    if (!vfunc) {
+        guint i, n_interfaces;
+        GType *interface_list;
+        GIInterfaceInfo *interface;
+
+        interface_list = g_type_interfaces(gtype, &n_interfaces);
+
+        for (i = 0; i < n_interfaces; i++) {
+            interface = (GIInterfaceInfo*)g_irepository_find_by_gtype(g_irepository_get_default(),
+                                                                      interface_list[i]);
+
+            /* The interface doesn't have to exist -- it could be private
+             * or dynamic. */
+            if (interface)
+                vfunc = g_interface_info_find_vfunc(interface, name);
+
+            g_base_info_unref((GIBaseInfo*)interface);
+            if (vfunc)
+                break;
+        }
+
+        g_free(interface_list);
+    }
+
+    if (!vfunc) {
+        gjs_throw(cx, "Could not find definition of virtual function %s", name);
+
+        g_free(name);
+        return JS_FALSE;
+    }
+
     find_vfunc_info(cx, gtype, vfunc, name, &implementor_vtable, &field_info);
     if (field_info != NULL) {
         GITypeInfo *type_info;
@@ -2028,6 +2063,32 @@ gjs_register_type(JSContext *cx,
 }
 
 static JSBool
+gjs_add_interface(JSContext *cx,
+                  uintN      argc,
+                  jsval     *vp)
+{
+    jsval *argv = JS_ARGV(cx, vp);
+    GInterfaceInfo interface_vtable = { NULL, NULL, NULL };
+    ObjectInstance *priv;
+    JSObject *object;
+    JSObject *iface_jsobj;
+
+    if (!gjs_parse_args(cx, "add_interface",
+                        "oo", argc, argv,
+                        "object", &object,
+                        "gtype", &iface_jsobj))
+        return JS_FALSE;
+
+    priv = priv_from_js(cx, object);
+
+    g_type_add_interface_static(priv->gtype,
+                                gjs_gtype_get_actual_gtype(cx, iface_jsobj),
+                                &interface_vtable);
+
+    return JS_TRUE;
+}
+
+static JSBool
 gjs_register_property(JSContext *cx,
                       uintN      argc,
                       jsval     *vp)
@@ -2157,6 +2218,12 @@ gjs_define_stuff(JSContext *context,
         return JS_FALSE;
 
     if (!JS_DefineFunction(context, module_obj,
+                           "add_interface",
+                           (JSNative)gjs_add_interface,
+                           2, GJS_MODULE_PROP_FLAGS))
+        return JS_FALSE;
+
+    if (!JS_DefineFunction(context, module_obj,
                            "hook_up_vfunc",
                            (JSNative)gjs_hook_up_vfunc,
                            3, GJS_MODULE_PROP_FLAGS))
diff --git a/modules/overrides/GObject.js b/modules/overrides/GObject.js
index 77d4ac8..0cb7d9b 100644
--- a/modules/overrides/GObject.js
+++ b/modules/overrides/GObject.js
@@ -60,8 +60,15 @@ const GObjectMeta = new Lang.Class({
                 }
             }
         }
+
+        if (params.Implements) {
+            for (let i = 0; i < params.Implements.length; i++)
+                Gi.add_interface(this.prototype, ifaces[i]);
+        }
+
         delete params.Properties;
         delete params.Signals;
+        delete params.Implements;
 
         for (let prop in params) {
             let value = this.prototype[prop];
diff --git a/test/js/testGObjectClass.js b/test/js/testGObjectClass.js
index 48ae5b6..ec2c79c 100644
--- a/test/js/testGObjectClass.js
+++ b/test/js/testGObjectClass.js
@@ -129,7 +129,22 @@ const MyApplication = new Lang.Class({
         this.emit('custom', n);
     }
 });
-printerr("almost");
+
+const MyInitable = new Lang.Class({
+    Name: 'MyInitable',
+    Extends: GObject.Object,
+    Implements: [ Gio.Initable ],
+
+    _init: function(params) {
+        this.parent(params);
+
+        this.inited = false;
+    },
+
+    vfunc_init: function(cancellable) { // error?
+        this.inited = true;
+    }
+});
 
 function testGObjectClass() {
     let myInstance = new MyObject();
@@ -233,4 +248,14 @@ function testSubclass() {
     assertEquals(73, v);
 }
 
+function testInterface() {
+    let instance = new MyInitable();
+    assertEquals(false, instance.inited);
+
+    instance.init(null);
+    assertEquals(true, instance.inited);
+
+    // assertTrue(instance instanceof Gio.Initable)
+}
+
 gjstestRun();



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