[gjs] GObject: register interfaces before creating the class



commit 2405137343a8f9697f677a0f0044868971b6574e
Author: Giovanni Campagna <gcampagna src gnome org>
Date:   Mon Nov 19 20:03:26 2012 +0100

    GObject: register interfaces before creating the class
    
    Recent GType emits a warning and fails if g_type_add_interface_static()
    is called on a GType that had its class referenced already, so we need
    to register interfaces before even creating the JS class (as that references
    the GType class)
    
    https://bugzilla.gnome.org/show_bug.cgi?id=688214

 gi/object.c                  |   81 +++++++++++++++++++++++++----------------
 modules/overrides/GObject.js |   16 +++-----
 2 files changed, 55 insertions(+), 42 deletions(-)
---
diff --git a/gi/object.c b/gi/object.c
index 7e83a15..018acd1 100644
--- a/gi/object.c
+++ b/gi/object.c
@@ -2265,6 +2265,17 @@ gjs_object_class_init(GObjectClass *class,
                                                            G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
 }
 
+static inline void
+gjs_add_interface(GType instance_type,
+                  GType interface_type)
+{
+    static GInterfaceInfo interface_vtable = { NULL, NULL, NULL };
+
+    g_type_add_interface_static(instance_type,
+                                interface_type,
+                                &interface_vtable);
+}
+
 static JSBool
 gjs_register_type(JSContext *cx,
                   uintN      argc,
@@ -2272,7 +2283,7 @@ gjs_register_type(JSContext *cx,
 {
     jsval *argv = JS_ARGV(cx, vp);
     gchar *name;
-    JSObject *parent, *constructor;
+    JSObject *parent, *constructor, *interfaces;
     GType instance_type, parent_type;
     GTypeQuery query;
     GTypeModule *type_module;
@@ -2291,13 +2302,16 @@ gjs_register_type(JSContext *cx,
 	0,    /* n_preallocs */
 	(GInstanceInitFunc) NULL,
     };
+    jsuint i, n_interfaces;
+    GType *iface_types;
 
     JS_BeginRequest(cx);
 
     if (!gjs_parse_args(cx, "register_type",
-                        "os", argc, argv,
+                        "oso", argc, argv,
                         "parent", &parent,
-                        "name", &name))
+                        "name", &name,
+                        "interfaces", &interfaces))
         return JS_FALSE;
 
     if (!parent)
@@ -2306,6 +2320,35 @@ gjs_register_type(JSContext *cx,
     if (!do_base_typecheck(cx, parent, JS_TRUE))
         return JS_FALSE;
 
+    if (!JS_IsArrayObject(cx, interfaces)) {
+        gjs_throw(cx, "Invalid parameter interfaces (expected Array)");
+        return JS_FALSE;
+    }
+
+    if (!JS_GetArrayLength(cx, interfaces, &n_interfaces))
+        return JS_FALSE;
+
+    iface_types = g_alloca(sizeof(GType) * n_interfaces);
+
+    /* We do interface addition in two passes so that any failure
+       is caught early, before registering the GType (which we can't undo) */
+    for (i = 0; i < n_interfaces; i++) {
+        jsval iface_val;
+        GType iface_type;
+
+        if (!JS_GetElement(cx, interfaces, i, &iface_val))
+            return JS_FALSE;
+
+        if (!JSVAL_IS_OBJECT(iface_val) ||
+            ((iface_type = gjs_gtype_get_actual_gtype(cx, JSVAL_TO_OBJECT(iface_val)))
+             == G_TYPE_INVALID)) {
+            gjs_throw(cx, "Invalid parameter interfaces (element %d was not a GType)", i);
+            return JS_FALSE;
+        }
+
+        iface_types[i] = iface_type;
+    }
+
     if (g_type_from_name(name) != G_TYPE_INVALID) {
         gjs_throw (cx, "Type name %s is already registered", name);
         return JS_FALSE;
@@ -2338,6 +2381,9 @@ gjs_register_type(JSContext *cx,
 
     g_type_set_qdata (instance_type, gjs_is_custom_type_quark(), GINT_TO_POINTER (1));
 
+    for (i = 0; i < n_interfaces; i++)
+        gjs_add_interface(instance_type, iface_types[i]);
+
     /* create a custom JSClass */
     if (!gjs_define_object_class(cx, NULL, instance_type, &constructor, NULL))
         return JS_FALSE;
@@ -2350,35 +2396,6 @@ 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;
-
-    if (!do_base_typecheck(cx, object, JS_TRUE))
-        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)
diff --git a/modules/overrides/GObject.js b/modules/overrides/GObject.js
index e5cf3d6..7902abc 100644
--- a/modules/overrides/GObject.js
+++ b/modules/overrides/GObject.js
@@ -29,17 +29,15 @@ const GObjectMeta = new Lang.Class({
     Extends: Lang.Class,
 
     _init: function(params) {
-        this.parent(params);
-
         // retrieve all parameters and remove them from params before chaining
 
         let properties = params.Properties;
         let signals = params.Signals;
-        let ifaces = params.Implements;
 
         delete params.Properties;
         delete params.Signals;
-        delete params.Implements;
+
+        this.parent(params);
 
         if (properties) {
             for (let prop in properties) {
@@ -63,11 +61,6 @@ const GObjectMeta = new Lang.Class({
             }
         }
 
-        if (ifaces) {
-            for (let i = 0; i < ifaces.length; i++)
-                Gi.add_interface(this.prototype, ifaces[i]);
-        }
-
         for (let prop in params) {
             let value = this.prototype[prop];
             if (typeof value === 'function') {
@@ -121,7 +114,10 @@ const GObjectMeta = new Lang.Class({
         if (!this._isValidClass(parent))
             throw new TypeError('GObject.Class used with invalid base class (is ' + parent + ')');
 
-        let newClass = Gi.register_type(parent.prototype, gtypename);
+        let interfaces = params.Implements || [];
+        delete params.Implements;
+
+        let newClass = Gi.register_type(parent.prototype, gtypename, interfaces);
 
         // See Class.prototype._construct in lang.js for the reasoning
         // behind this direct __proto__ set.



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