summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGiovanni Campagna <gcampagna@src.gnome.org>2011-12-12 17:14:41 +0100
committerJasper St. Pierre <jstpierre@mecheye.net>2012-02-03 17:44:51 -0500
commite01184ada59cce3fdd0a3d6e1850d9557de32a46 (patch)
tree129dcc5ec89a2b232b363a502ac331e1f7dcbda6
parentf7ce103431d871d003b8fa3f9433e33e220e7cee (diff)
downloadgjs-e01184ada59cce3fdd0a3d6e1850d9557de32a46.tar.gz
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.
-rw-r--r--gi/interface.c12
-rw-r--r--gi/object.c69
-rw-r--r--modules/overrides/GObject.js7
-rw-r--r--test/js/testGObjectClass.js27
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();