diff options
-rw-r--r-- | gi/interface.c | 12 | ||||
-rw-r--r-- | gi/object.c | 69 | ||||
-rw-r--r-- | modules/overrides/GObject.js | 7 | ||||
-rw-r--r-- | test/js/testGObjectClass.js | 27 |
4 files changed, 113 insertions, 2 deletions
diff --git a/gi/interface.c b/gi/interface.c index 245e0375..9ee76037 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 27618a36..4f66698c 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 77d4ac80..0cb7d9b7 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 48ae5b60..ec2c79ce 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(); |