[gjs] object: Implement gobject inheritance
- From: Jasper St. Pierre <jstpierre src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gjs] object: Implement gobject inheritance
- Date: Fri, 3 Feb 2012 22:48:13 +0000 (UTC)
commit 4a2f7c82eb702d0e21d30643461239a480b878e4
Author: Jasper St. Pierre <jstpierre mecheye net>
Date: Sun Nov 6 01:15:12 2011 -0400
object: Implement gobject inheritance
https://bugzilla.gnome.org/show_bug.cgi?id=663492
gi/object.c | 132 ++++++++++++++++++++++++++++++++++++++----
modules/lang.js | 2 +
modules/overrides/GObject.js | 42 +++++++++++++
3 files changed, 164 insertions(+), 12 deletions(-)
---
diff --git a/gi/object.c b/gi/object.c
index d19be58..3966421 100644
--- a/gi/object.c
+++ b/gi/object.c
@@ -138,7 +138,10 @@ object_instance_get_prop(JSContext *context,
"Get prop '%s' hook obj %p priv %p", name, obj, priv);
if (priv == NULL) {
- ret = JS_FALSE; /* wrong class passed in */
+ /* We won't have a private until the initializer is called, so
+ * don't mark a call to _init() an error. */
+ if (!g_str_equal(name, "_init"))
+ ret = JS_FALSE;
goto out;
}
if (priv->gobj == NULL) /* prototype, not an instance. */
@@ -691,6 +694,7 @@ init_object_private (JSContext *context,
goto out;
}
+ priv->gtype = proto_priv->gtype;
priv->info = proto_priv->info;
g_base_info_ref( (GIBaseInfo*) priv->info);
@@ -740,9 +744,12 @@ manage_js_gobject (JSContext *context,
g_object_unref(priv->gobj);
}
-GJS_NATIVE_CONSTRUCTOR_DECLARE(object_instance)
+static JSBool
+object_instance_init (JSContext *context,
+ JSObject **object,
+ uintN argc,
+ jsval *argv)
{
- GJS_NATIVE_CONSTRUCTOR_VARIABLES(object_instance)
ObjectInstance *priv;
GType gtype;
GParameter *params;
@@ -750,11 +757,9 @@ GJS_NATIVE_CONSTRUCTOR_DECLARE(object_instance)
GTypeQuery query;
JSObject *old_jsobj;
- GJS_NATIVE_CONSTRUCTOR_PRELUDE(object_instance);
-
- priv = init_object_private(context, object);
+ priv = init_object_private(context, *object);
- gtype = g_registered_type_info_get_g_type( (GIRegisteredTypeInfo*) priv->info);
+ gtype = priv->gtype;
if (gtype == G_TYPE_NONE) {
gjs_throw(context,
"No GType for object '%s'???",
@@ -762,7 +767,7 @@ GJS_NATIVE_CONSTRUCTOR_DECLARE(object_instance)
return JS_FALSE;
}
- if (!object_instance_props_to_g_parameters(context, object, argc, argv,
+ if (!object_instance_props_to_g_parameters(context, *object, argc, argv,
gtype,
¶ms, &n_params)) {
return JS_FALSE;
@@ -782,7 +787,7 @@ GJS_NATIVE_CONSTRUCTOR_DECLARE(object_instance)
* we're not actually using it, so just let it get collected. Avoiding
* this would require a non-trivial amount of work.
* */
- object = old_jsobj;
+ *object = old_jsobj;
g_object_unref(priv->gobj); /* We already own a reference */
priv->gobj = NULL;
goto out;
@@ -806,7 +811,7 @@ GJS_NATIVE_CONSTRUCTOR_DECLARE(object_instance)
/* we should already have a ref */
}
- manage_js_gobject(context, object, priv);
+ manage_js_gobject(context, *object, priv);
gjs_debug_lifecycle(GJS_DEBUG_GOBJECT,
"JSObject created with GObject %p %s",
@@ -816,11 +821,19 @@ GJS_NATIVE_CONSTRUCTOR_DECLARE(object_instance)
g_base_info_get_name ( (GIBaseInfo*) priv->info) ));
out:
- GJS_NATIVE_CONSTRUCTOR_FINISH(object_instance);
-
return JS_TRUE;
}
+GJS_NATIVE_CONSTRUCTOR_DECLARE(object_instance)
+{
+ GJS_NATIVE_CONSTRUCTOR_VARIABLES(object_instance)
+ JSBool ret;
+ GJS_NATIVE_CONSTRUCTOR_PRELUDE(object_instance);
+ ret = object_instance_init(context, &object, argc, argv);
+ GJS_NATIVE_CONSTRUCTOR_FINISH(object_instance);
+ return ret;
+}
+
static void
object_instance_finalize(JSContext *context,
JSObject *obj)
@@ -1201,11 +1214,25 @@ static struct JSClass gjs_object_instance_class = {
JSCLASS_NO_OPTIONAL_MEMBERS
};
+static JSBool
+init_func (JSContext *context,
+ uintN argc,
+ jsval *vp)
+{
+ jsval *argv = JS_ARGV(context, vp);
+ JSObject *obj = JS_THIS_OBJECT(context, vp);
+
+ JS_SET_RVAL(context, vp, JSVAL_VOID);
+
+ return object_instance_init(context, &obj, argc, argv);
+}
+
static JSPropertySpec gjs_object_instance_proto_props[] = {
{ NULL }
};
static JSFunctionSpec gjs_object_instance_proto_funcs[] = {
+ { "_init", (JSNative)init_func, 0, 0 },
{ "connect", (JSNative)connect_func, 0, 0 },
{ "connect_after", (JSNative)connect_after_func, 0, 0 },
{ "disconnect", (JSNative)disconnect_func, 0, 0 },
@@ -1618,3 +1645,84 @@ gjs_g_object_from_object(JSContext *context,
return priv->gobj;
}
+
+static JSBool
+gjs_register_type(JSContext *cx,
+ uintN argc,
+ jsval *vp)
+{
+ jsval *argv = JS_ARGV(cx, vp);
+ jsval gtype;
+ gchar *name;
+ JSObject *parent, *object;
+ GType instance_type, parent_type;
+ GTypeQuery query;
+ ObjectInstance *parent_priv, *priv;
+ GTypeInfo type_info = {
+ 0, /* class_size */
+
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+
+ (GClassInitFunc) NULL,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+
+ 0, /* instance_size */
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) NULL,
+ };
+
+ JS_BeginRequest(cx);
+
+ if (!gjs_parse_args(cx, "register_type",
+ "oos", argc, argv,
+ "parent", &parent,
+ "object", &object,
+ "name", &name))
+ return JS_FALSE;
+
+ if (!parent)
+ return JS_FALSE;
+
+ parent_priv = priv_from_js(cx, parent);
+
+ if (!parent_priv)
+ return JS_FALSE;
+
+ parent_type = parent_priv->gtype;
+
+ g_type_query(parent_type, &query);
+ type_info.class_size = query.class_size;
+ type_info.instance_size = query.instance_size;
+
+ instance_type = g_type_register_static(parent_type,
+ name,
+ &type_info,
+ 0);
+
+ priv = g_slice_new0(ObjectInstance);
+ priv->info = parent_priv->info;
+ priv->gtype = instance_type;
+
+ JS_SetPrivate(cx, object, priv);
+
+ JS_EndRequest(cx);
+
+ return JS_TRUE;
+}
+
+static JSBool
+gjs_define_stuff(JSContext *context,
+ JSObject *module_obj)
+{
+ if (!JS_DefineFunction(context, module_obj,
+ "register_type",
+ (JSNative)gjs_register_type,
+ 3, GJS_MODULE_PROP_FLAGS))
+ return JS_FALSE;
+
+ return JS_TRUE;
+}
+
+GJS_REGISTER_NATIVE_MODULE("_gi", gjs_define_stuff)
diff --git a/modules/lang.js b/modules/lang.js
index b44b0e2..9e5c6c4 100644
--- a/modules/lang.js
+++ b/modules/lang.js
@@ -21,6 +21,8 @@
// Utilities that are "meta-language" things like manipulating object props
+const Gi = imports._gi;
+
function countProperties(obj) {
let count = 0;
for (let property in obj) {
diff --git a/modules/overrides/GObject.js b/modules/overrides/GObject.js
index 760248c..2f692db 100644
--- a/modules/overrides/GObject.js
+++ b/modules/overrides/GObject.js
@@ -19,8 +19,41 @@
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
+const Lang = imports.lang;
+const Gi = imports._gi;
+
let GObject;
+const GObjectMeta = new Lang.Class({
+ Name: 'GObjectClass',
+ Extends: Lang.Class,
+
+ _init: function(params) {
+ if (!params.Extends)
+ params.Extends = GObject.Object;
+
+ if (!this._isValidClass(params.Extends))
+ throw new TypeError('GObject.Class used with invalid base class (is ' + params.Extends.prototype + ')');
+
+ this.parent(params);
+
+ Gi.register_type(params.Extends.prototype, this.prototype, params.Name);
+ },
+
+ _isValidClass: function(klass) {
+ let proto = klass.prototype;
+
+ if (!proto)
+ return false;
+
+ // If proto == GObject.Object.prototype, then
+ // proto.__proto__ is Object, so "proto instanceof GObject.Object"
+ // will return false.
+ return proto == GObject.Object.prototype ||
+ proto instanceof GObject.Object;
+ }
+});
+
function _init() {
GObject = this;
@@ -117,4 +150,13 @@ function _init() {
nick, blurb, flags, default_value);
};
+ this.Class = GObjectMeta;
+ this.Object.prototype.__metaclass__ = this.Class;
+
+ // For compatibility with Lang.Class... we need a _construct
+ // or the Lang.Class constructor will fail.
+ this.Object.prototype._construct = function() {
+ this._init.apply(this, arguments);
+ return this;
+ };
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]