[gjs] gi: add fundamental type support
- From: Lionel Landwerlin <llandwerlin src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gjs] gi: add fundamental type support
- Date: Mon, 24 Feb 2014 00:14:02 +0000 (UTC)
commit 400f43ee76c62d25d9ea44bcabb6198b41bcc510
Author: Lionel Landwerlin <llandwerlin gmail com>
Date: Mon Dec 9 17:00:08 2013 +0000
gi: add fundamental type support
This work in largely based on previous work from Johan Dahlin.
https://bugzilla.gnome.org/show_bug.cgi?id=621716
Makefile-insttest.am | 1 +
Makefile.am | 2 +
gi/arg.cpp | 80 +++-
gi/function.cpp | 19 +-
gi/fundamental.cpp | 984 +++++++++++++++++++++++++++++++++
gi/fundamental.h | 61 ++
gi/repo.cpp | 8 +
gi/value.cpp | 10 +
gjs/mem.cpp | 2 +
gjs/mem.h | 1 +
installed-tests/js/testFundamental.js | 16 +
util/log.cpp | 3 +
util/log.h | 1 +
13 files changed, 1175 insertions(+), 13 deletions(-)
---
diff --git a/Makefile-insttest.am b/Makefile-insttest.am
index 263201c..61627ff 100644
--- a/Makefile-insttest.am
+++ b/Makefile-insttest.am
@@ -106,6 +106,7 @@ dist_jstests_DATA += \
installed-tests/js/testEverythingBasic.js \
installed-tests/js/testEverythingEncapsulated.js \
installed-tests/js/testFormat.js \
+ installed-tests/js/testFundamental.js \
installed-tests/js/testGIMarshalling.js \
installed-tests/js/testGObjectClass.js \
installed-tests/js/testJS1_8.js \
diff --git a/Makefile.am b/Makefile.am
index 7a56bde..f87125e 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -40,6 +40,7 @@ nobase_gjs_module_include_HEADERS = \
gi/ns.h \
gi/object.h \
gi/foreign.h \
+ gi/fundamental.h \
gi/param.h \
gi/repo.h \
gi/union.h \
@@ -141,6 +142,7 @@ libgjs_la_SOURCES += \
gi/ns.cpp \
gi/object.cpp \
gi/foreign.cpp \
+ gi/fundamental.cpp \
gi/param.cpp \
gi/proxyutils.cpp \
gi/repo.cpp \
diff --git a/gi/arg.cpp b/gi/arg.cpp
index e654856..c2373ca 100644
--- a/gi/arg.cpp
+++ b/gi/arg.cpp
@@ -27,6 +27,7 @@
#include "gtype.h"
#include "object.h"
#include "foreign.h"
+#include "fundamental.h"
#include "boxed.h"
#include "union.h"
#include "param.h"
@@ -38,6 +39,26 @@
#include <util/log.h>
+static gboolean
+_gjs_gtype_interface_requires_object (GType interface_type)
+{
+ guint i, n_prerequisites;
+ GType *prerequisites = g_type_interface_prerequisites (interface_type,
+ &n_prerequisites);
+
+ for (i = 0; i < n_prerequisites; i++) {
+ if (g_type_is_a (prerequisites[i], G_TYPE_INTERFACE)) {
+ if (_gjs_gtype_interface_requires_object(prerequisites[i]))
+ return TRUE;
+ } else if (g_type_is_a (prerequisites[i], G_TYPE_OBJECT))
+ return TRUE;
+ }
+
+ g_free (prerequisites);
+
+ return FALSE;
+}
+
JSBool
_gjs_flags_value_is_valid(JSContext *context,
GType gtype,
@@ -1483,12 +1504,18 @@ gjs_value_to_g_argument(JSContext *context,
} else if (gtype != G_TYPE_NONE) {
if (g_type_is_a(gtype, G_TYPE_OBJECT) || g_type_is_a(gtype, G_TYPE_INTERFACE)) {
if (gjs_typecheck_object(context, JSVAL_TO_OBJECT(value),
- gtype, JS_TRUE)) {
+ gtype, JS_FALSE)) {
arg->v_pointer = gjs_g_object_from_object(context,
JSVAL_TO_OBJECT(value));
if (transfer != GI_TRANSFER_NOTHING)
g_object_ref(G_OBJECT(arg->v_pointer));
+ } else if (gjs_typecheck_fundamental(context, JSVAL_TO_OBJECT(value), gtype,
JS_FALSE)) {
+ arg->v_pointer = gjs_g_fundamental_from_object(context,
+ JSVAL_TO_OBJECT(value));
+
+ if (transfer != GI_TRANSFER_NOTHING)
+ gjs_fundamental_ref(context, arg->v_pointer);
} else {
arg->v_pointer = NULL;
wrong = TRUE;
@@ -1507,9 +1534,17 @@ gjs_value_to_g_argument(JSContext *context,
g_type_name(gtype),
interface_type);
}
+ } else if (gjs_typecheck_fundamental(context, JSVAL_TO_OBJECT(value), gtype, JS_FALSE)) {
+ arg->v_pointer = gjs_g_fundamental_from_object(context,
+ JSVAL_TO_OBJECT(value));
+
+ if (transfer != GI_TRANSFER_NOTHING)
+ gjs_fundamental_ref(context, arg->v_pointer);
} else {
gjs_throw(context, "Unhandled GType %s unpacking GArgument from Object",
g_type_name(gtype));
+ arg->v_pointer = NULL;
+ wrong = TRUE;
}
} else {
gjs_throw(context, "Unexpected unregistered type unpacking GArgument from Object");
@@ -2505,6 +2540,7 @@ gjs_value_from_g_argument (JSContext *context,
GIBaseInfo* interface_info;
GIInfoType interface_type;
GType gtype;
+ gboolean gtype_is_object, gtype_is_interface;
interface_info = g_type_info_get_interface(type_info);
g_assert(interface_info != NULL);
@@ -2609,11 +2645,21 @@ gjs_value_from_g_argument (JSContext *context,
goto out;
}
- if (g_type_is_a(gtype, G_TYPE_OBJECT) || g_type_is_a(gtype, G_TYPE_INTERFACE)) {
- JSObject *obj;
- obj = gjs_object_from_g_object(context, G_OBJECT(arg->v_pointer));
- if (obj)
- value = OBJECT_TO_JSVAL(obj);
+
+ gtype_is_object = g_type_is_a(gtype, G_TYPE_OBJECT);
+ gtype_is_interface = g_type_is_a(gtype, G_TYPE_INTERFACE);
+ if (gtype_is_object || gtype_is_interface) {
+ if (gtype_is_object || (gtype_is_interface && _gjs_gtype_interface_requires_object(gtype))) {
+ JSObject *obj;
+ obj = gjs_object_from_g_object(context, G_OBJECT(arg->v_pointer));
+ if (obj)
+ value = OBJECT_TO_JSVAL(obj);
+ } else {
+ JSObject *obj;
+ obj = gjs_object_from_g_fundamental(context, (GIObjectInfo *)interface_info,
arg->v_pointer);
+ if (obj)
+ value = OBJECT_TO_JSVAL(obj);
+ }
} else if (g_type_is_a(gtype, G_TYPE_BOXED) ||
g_type_is_a(gtype, G_TYPE_ENUM) ||
g_type_is_a(gtype, G_TYPE_FLAGS)) {
@@ -2630,6 +2676,11 @@ gjs_value_from_g_argument (JSContext *context,
value = OBJECT_TO_JSVAL(obj);
} else if (gtype == G_TYPE_NONE) {
gjs_throw(context, "Unexpected unregistered type packing GArgument into jsval");
+ } else if (G_TYPE_IS_INSTANTIATABLE(gtype)) {
+ JSObject *obj;
+ obj = gjs_object_from_g_fundamental(context, (GIObjectInfo *)interface_info,
arg->v_pointer);
+ if (obj)
+ value = OBJECT_TO_JSVAL(obj);
} else {
gjs_throw(context, "Unhandled GType %s packing GArgument into jsval",
g_type_name(gtype));
@@ -2838,6 +2889,7 @@ gjs_g_arg_release_internal(JSContext *context,
GIBaseInfo* interface_info;
GIInfoType interface_type;
GType gtype;
+ gboolean gtype_is_object, gtype_is_interface;
interface_info = g_type_info_get_interface(type_info);
g_assert(interface_info != NULL);
@@ -2866,9 +2918,16 @@ gjs_g_arg_release_internal(JSContext *context,
* don't have to worry about it.
*/
- if (g_type_is_a(gtype, G_TYPE_OBJECT) || g_type_is_a(gtype, G_TYPE_INTERFACE)) {
- if (transfer != TRANSFER_IN_NOTHING)
- g_object_unref(G_OBJECT(arg->v_pointer));
+ gtype_is_object = g_type_is_a(gtype, G_TYPE_OBJECT);
+ gtype_is_interface = g_type_is_a(gtype, G_TYPE_INTERFACE);
+ if (gtype_is_object || gtype_is_interface) {
+ if (gtype_is_object) {
+ if (transfer != TRANSFER_IN_NOTHING)
+ g_object_unref(G_OBJECT(arg->v_pointer));
+ } else {
+ if (transfer != TRANSFER_IN_NOTHING)
+ gjs_fundamental_unref(context, arg->v_pointer);
+ }
} else if (g_type_is_a(gtype, G_TYPE_CLOSURE)) {
g_closure_unref((GClosure *) arg->v_pointer);
} else if (g_type_is_a(gtype, G_TYPE_VALUE)) {
@@ -2888,6 +2947,9 @@ gjs_g_arg_release_internal(JSContext *context,
gjs_throw(context, "Don't know how to release GArgument: not an object or boxed type");
failed = JS_TRUE;
}
+ } else if (G_TYPE_IS_INSTANTIATABLE(gtype)) {
+ if (transfer != TRANSFER_IN_NOTHING)
+ gjs_fundamental_unref(context, arg->v_pointer);
} else {
gjs_throw(context, "Unhandled GType %s releasing GArgument",
g_type_name(gtype));
diff --git a/gi/function.cpp b/gi/function.cpp
index a588a81..8d2fe77 100644
--- a/gi/function.cpp
+++ b/gi/function.cpp
@@ -26,6 +26,7 @@
#include "function.h"
#include "arg.h"
#include "object.h"
+#include "fundamental.h"
#include "boxed.h"
#include "union.h"
#include "gerror.h"
@@ -549,11 +550,21 @@ gjs_fill_method_instance (JSContext *context,
case GI_INFO_TYPE_OBJECT:
case GI_INFO_TYPE_INTERFACE:
- if (!gjs_typecheck_object(context, obj,
- gtype, JS_TRUE))
+ if (gjs_typecheck_is_object(context, obj, JS_FALSE)) {
+ if (!gjs_typecheck_object(context, obj, gtype, JS_TRUE))
+ return JS_FALSE;
+ out_arg->v_pointer = gjs_g_object_from_object(context, obj);
+ } else if (gjs_typecheck_is_fundamental(context, obj, JS_FALSE)) {
+ if (!gjs_typecheck_fundamental(context, obj, gtype, JS_TRUE))
+ return JS_FALSE;
+ out_arg->v_pointer = gjs_g_fundamental_from_object(context, obj);
+ } else {
+ gjs_throw_custom(context, "TypeError",
+ "%s.%s is not an object instance neither a fundamental instance of a supported
type",
+ g_base_info_get_namespace(container),
+ g_base_info_get_name(container));
return JS_FALSE;
-
- out_arg->v_pointer = gjs_g_object_from_object(context, obj);
+ }
break;
default:
diff --git a/gi/fundamental.cpp b/gi/fundamental.cpp
new file mode 100644
index 0000000..442514e
--- /dev/null
+++ b/gi/fundamental.cpp
@@ -0,0 +1,984 @@
+/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
+/*
+ * Copyright (c) 2013 Intel Corporation
+ * Copyright (c) 2008-2010 litl, LLC
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <config.h>
+
+#include <string.h>
+
+#include <gjs/gi.h>
+
+#include "fundamental.h"
+#include "arg.h"
+#include "object.h"
+#include "boxed.h"
+#include "repo.h"
+#include "function.h"
+#include "gtype.h"
+#include "proxyutils.h"
+
+#include <gjs/gjs.h>
+
+#include <util/log.h>
+
+#include <jsapi.h>
+
+#include <girepository.h>
+
+/*
+ * Structure allocated for prototypes.
+ */
+typedef struct _Fundamental {
+ /* instance info */
+ void *gfundamental;
+ struct _Fundamental *prototype; /* NULL if prototype */
+
+ /* prototype info */
+ GIObjectInfo *info;
+ GType gtype;
+ GIObjectInfoRefFunction ref_function;
+ GIObjectInfoUnrefFunction unref_function;
+ GIObjectInfoGetValueFunction get_value_function;
+ GIObjectInfoSetValueFunction set_value_function;
+
+ jsid constructor_name;
+ GICallableInfo *constructor_info;
+} Fundamental;
+
+/*
+ * Structure allocated for instances.
+ */
+typedef struct {
+ void *gfundamental;
+ struct _Fundamental *prototype;
+} FundamentalInstance;
+
+extern struct JSClass gjs_fundamental_instance_class;
+
+GJS_DEFINE_PRIV_FROM_JS(FundamentalInstance, gjs_fundamental_instance_class)
+
+static GQuark
+gjs_fundamental_table_quark (void)
+{
+ static GQuark val = 0;
+ if (!val)
+ val = g_quark_from_static_string("gjs::fundamental-table");
+
+ return val;
+}
+
+static GHashTable *
+_ensure_mapping_table(GjsContext *context)
+{
+ GHashTable *table =
+ (GHashTable *) g_object_get_qdata ((GObject *) context,
+ gjs_fundamental_table_quark());
+
+ if (G_UNLIKELY(table == NULL)) {
+ table = g_hash_table_new_full(g_direct_hash,
+ g_direct_equal,
+ NULL,
+ NULL);
+ g_object_set_qdata_full((GObject *) context,
+ gjs_fundamental_table_quark(),
+ table,
+ (GDestroyNotify) g_hash_table_unref);
+ }
+
+ return table;
+}
+
+static void
+_fundamental_add_object(void *native_object, JSObject *js_object)
+{
+ GHashTable *table = _ensure_mapping_table(gjs_context_get_current());
+
+ g_hash_table_insert(table, native_object, js_object);
+}
+
+static void
+_fundamental_remove_object(void *native_object)
+{
+ GHashTable *table = _ensure_mapping_table(gjs_context_get_current());
+
+ g_hash_table_remove(table, native_object);
+}
+
+static JSObject *
+_fundamental_lookup_object(void *native_object)
+{
+ GHashTable *table = _ensure_mapping_table(gjs_context_get_current());
+
+ return (JSObject *) g_hash_table_lookup(table, native_object);
+}
+
+/**/
+
+static inline Fundamental *
+proto_priv_from_js(JSContext *context,
+ JSObject *obj)
+{
+ JSObject *proto;
+ JS_GetPrototype(context, obj, &proto);
+ return (Fundamental*) priv_from_js(context, proto);
+}
+
+static FundamentalInstance *
+init_fundamental_instance(JSContext *context,
+ JSObject *object)
+{
+ Fundamental *proto_priv;
+ FundamentalInstance *priv;
+
+ JS_BeginRequest(context);
+
+ priv = g_slice_new0(FundamentalInstance);
+
+ GJS_INC_COUNTER(fundamental);
+
+ g_assert(priv_from_js(context, object) == NULL);
+ JS_SetPrivate(object, priv);
+
+ gjs_debug_lifecycle(GJS_DEBUG_GFUNDAMENTAL,
+ "fundamental instance constructor, obj %p priv %p proto %p ",
+ object, priv, JS_GetPrototype (object));
+
+ proto_priv = proto_priv_from_js(context, object);
+ g_assert(proto_priv != NULL);
+
+ priv->prototype = proto_priv;
+
+ JS_EndRequest(context);
+
+ return priv;
+}
+
+static void
+associate_js_instance_to_fundamental(JSContext *context,
+ JSObject *object,
+ void *gfundamental,
+ gboolean owned_ref)
+{
+ FundamentalInstance *priv;
+
+ priv = priv_from_js(context, object);
+ priv->gfundamental = gfundamental;
+
+ g_assert(_fundamental_lookup_object(gfundamental) == NULL);
+ _fundamental_add_object(gfundamental, object);
+
+ gjs_debug_lifecycle(GJS_DEBUG_GFUNDAMENTAL,
+ "associated JSObject %p with fundamental %p",
+ object, gfundamental);
+
+ if (!owned_ref)
+ priv->prototype->ref_function(gfundamental);
+}
+
+/**/
+
+/* Find the first constructor */
+static GIFunctionInfo *
+find_fundamental_constructor(JSContext *context,
+ GIObjectInfo *info,
+ jsid *constructor_name)
+{
+ int i, n_methods;
+
+ n_methods = g_object_info_get_n_methods(info);
+
+ for (i = 0; i < n_methods; ++i) {
+ GIFunctionInfo *func_info;
+ GIFunctionInfoFlags flags;
+
+ func_info = g_object_info_get_method(info, i);
+
+ flags = g_function_info_get_flags(func_info);
+ if ((flags & GI_FUNCTION_IS_CONSTRUCTOR) != 0) {
+ const char *name;
+
+ name = g_base_info_get_name((GIBaseInfo *) func_info);
+ *constructor_name = gjs_intern_string_to_id(context, name);
+
+ return func_info;
+ }
+
+ g_base_info_unref((GIBaseInfo *) func_info);
+ }
+
+ return NULL;
+}
+
+/**/
+
+static JSBool
+gjs_define_static_methods(JSContext *context,
+ JSObject *constructor,
+ GType gtype,
+ GIObjectInfo *object_info)
+{
+ int i;
+ int n_methods;
+
+ n_methods = g_object_info_get_n_methods(object_info);
+
+ for (i = 0; i < n_methods; i++) {
+ GIFunctionInfo *meth_info;
+ GIFunctionInfoFlags flags;
+
+ meth_info = g_object_info_get_method(object_info, i);
+ flags = g_function_info_get_flags(meth_info);
+
+ /* Anything that isn't a method we put on the prototype of the
+ * constructor. This includes <constructor> introspection
+ * methods, as well as the forthcoming "static methods"
+ * support. We may want to change this to use
+ * GI_FUNCTION_IS_CONSTRUCTOR and GI_FUNCTION_IS_STATIC or the
+ * like in the near future.
+ */
+ if (!(flags & GI_FUNCTION_IS_METHOD)) {
+ gjs_define_function(context, constructor, gtype,
+ (GICallableInfo *)meth_info);
+ }
+
+ g_base_info_unref((GIBaseInfo *) meth_info);
+ }
+ return JS_TRUE;
+}
+
+static JSBool
+fundamental_instance_new_resolve_interface(JSContext *context,
+ JSObject *obj,
+ JSObject **objp,
+ Fundamental *proto_priv,
+ char *name)
+{
+ GIFunctionInfo *method_info;
+ JSBool ret;
+ GType *interfaces;
+ guint n_interfaces;
+ guint i;
+
+ ret = JS_TRUE;
+ interfaces = g_type_interfaces(proto_priv->gtype, &n_interfaces);
+ for (i = 0; i < n_interfaces; i++) {
+ GIBaseInfo *base_info;
+ GIInterfaceInfo *iface_info;
+
+ base_info = g_irepository_find_by_gtype(g_irepository_get_default(),
+ interfaces[i]);
+
+ if (base_info == NULL)
+ continue;
+
+ /* An interface GType ought to have interface introspection info */
+ g_assert(g_base_info_get_type(base_info) == GI_INFO_TYPE_INTERFACE);
+
+ iface_info = (GIInterfaceInfo *) base_info;
+
+ method_info = g_interface_info_find_method(iface_info, name);
+
+ g_base_info_unref(base_info);
+
+
+ if (method_info != NULL) {
+ if (gjs_define_function(context, obj,
+ proto_priv->gtype,
+ (GICallableInfo *) method_info)) {
+ *objp = obj;
+ } else {
+ ret = JS_FALSE;
+ }
+
+ g_base_info_unref((GIBaseInfo *) method_info);
+ }
+ }
+
+ g_free(interfaces);
+ return ret;
+}
+
+/*
+ * Like JSResolveOp, but flags provide contextual information as follows:
+ *
+ * JSRESOLVE_QUALIFIED a qualified property id: obj.id or obj[id], not id
+ * JSRESOLVE_ASSIGNING obj[id] is on the left-hand side of an assignment
+ * JSRESOLVE_DETECTING 'if (o.p)...' or similar detection opcode sequence
+ * JSRESOLVE_DECLARING var, const, or fundamental prolog declaration opcode
+ * JSRESOLVE_CLASSNAME class name used when constructing
+ *
+ * The *objp out parameter, on success, should be null to indicate that id
+ * was not resolved; and non-null, referring to obj or one of its prototypes,
+ * if id was resolved.
+ */
+static JSBool
+fundamental_instance_new_resolve(JSContext *context,
+ JSObject **obj,
+ jsid *id,
+ unsigned flags,
+ JSObject **objp)
+{
+ FundamentalInstance *priv;
+ char *name;
+ JSBool ret = JS_FALSE;
+
+ *objp = NULL;
+
+ if (!gjs_get_string_id(context, *id, &name))
+ return JS_TRUE; /* not resolved, but no error */
+
+ priv = priv_from_js(context, *obj);
+ gjs_debug_jsprop(GJS_DEBUG_GFUNDAMENTAL, "Resolve prop '%s' hook obj %p priv %p", name, *obj, priv);
+
+ if (priv == NULL)
+ goto out; /* wrong class */
+
+ if (priv->prototype == NULL) {
+ /* We are the prototype, so look for methods and other class properties */
+ Fundamental *proto_priv = (Fundamental *) priv;
+ GIFunctionInfo *method_info;
+
+ method_info = g_object_info_find_method((GIStructInfo*) proto_priv->info,
+ name);
+
+ if (method_info != NULL) {
+ const char *method_name;
+
+#if GJS_VERBOSE_ENABLE_GI_USAGE
+ _gjs_log_info_usage((GIBaseInfo *) method_info);
+#endif
+
+ method_name = g_base_info_get_name((GIBaseInfo *) method_info);
+
+ /* we do not define deprecated methods in the prototype */
+ if (g_base_info_is_deprecated((GIBaseInfo *) method_info)) {
+ gjs_debug(GJS_DEBUG_GFUNDAMENTAL,
+ "Ignoring definition of deprecated method %s in prototype %s.%s",
+ method_name,
+ g_base_info_get_namespace((GIBaseInfo *) proto_priv->info),
+ g_base_info_get_name((GIBaseInfo *) proto_priv->info));
+ g_base_info_unref((GIBaseInfo *) method_info);
+ ret = JS_TRUE;
+ goto out;
+ }
+
+ gjs_debug(GJS_DEBUG_GFUNDAMENTAL,
+ "Defining method %s in prototype for %s.%s",
+ method_name,
+ g_base_info_get_namespace((GIBaseInfo *) proto_priv->info),
+ g_base_info_get_name((GIBaseInfo *) proto_priv->info));
+
+ if (gjs_define_function(context, *obj, proto_priv->gtype,
+ method_info) == NULL) {
+ g_base_info_unref((GIBaseInfo *) method_info);
+ goto out;
+ }
+
+ *objp = *obj;
+
+ g_base_info_unref((GIBaseInfo *) method_info);
+ }
+
+ ret = fundamental_instance_new_resolve_interface(context, *obj, objp,
+ proto_priv, name);
+ } else {
+ /* We are an instance, not a prototype, so look for
+ * per-instance props that we want to define on the
+ * JSObject. Generally we do not want to cache these in JS, we
+ * want to always pull them from the C object, or JS would not
+ * see any changes made from C. So we use the get/set prop
+ * hooks, not this resolve hook.
+ */
+ }
+
+ ret = JS_TRUE;
+ out:
+ g_free(name);
+ return ret;
+}
+
+static JSBool
+fundamental_invoke_constructor(FundamentalInstance *priv,
+ JSContext *context,
+ JSObject *obj,
+ unsigned argc,
+ jsval *argv,
+ GArgument *rvalue)
+{
+ jsval js_constructor, js_constructor_func;
+ jsid constructor_const;
+ JSBool ret = JS_FALSE;
+
+ constructor_const = gjs_context_get_const_string(context, GJS_STRING_CONSTRUCTOR);
+ if (!gjs_object_require_property(context, obj, NULL,
+ constructor_const, &js_constructor) ||
+ priv->prototype->constructor_name == JSID_VOID) {
+ gjs_throw (context,
+ "Couldn't find a constructor for type %s.%s",
+ g_base_info_get_namespace((GIBaseInfo*) priv->prototype->info),
+ g_base_info_get_name((GIBaseInfo*) priv->prototype->info));
+ goto end;
+ }
+
+ if (!gjs_object_require_property(context, JSVAL_TO_OBJECT(js_constructor), NULL,
+ priv->prototype->constructor_name, &js_constructor_func)) {
+ gjs_throw (context,
+ "Couldn't find a constructor for type %s.%s",
+ g_base_info_get_namespace((GIBaseInfo*) priv->prototype->info),
+ g_base_info_get_name((GIBaseInfo*) priv->prototype->info));
+ goto end;
+ }
+
+ ret = gjs_invoke_constructor_from_c(context, JSVAL_TO_OBJECT(js_constructor_func), obj, argc, argv,
rvalue);
+
+ end:
+ return ret;
+}
+
+/* If we set JSCLASS_CONSTRUCT_PROTOTYPE flag, then this is called on
+ * the prototype in addition to on each instance. When called on the
+ * prototype, "obj" is the prototype, and "retval" is the prototype
+ * also, but can be replaced with another object to use instead as the
+ * prototype. If we don't set JSCLASS_CONSTRUCT_PROTOTYPE we can
+ * identify the prototype as an object of our class with NULL private
+ * data.
+ */
+GJS_NATIVE_CONSTRUCTOR_DECLARE(fundamental_instance)
+{
+ GJS_NATIVE_CONSTRUCTOR_VARIABLES(fundamental_instance)
+ FundamentalInstance *priv;
+ GArgument ret_value;
+ GITypeInfo return_info;
+
+ GJS_NATIVE_CONSTRUCTOR_PRELUDE(fundamental_instance);
+
+ priv = init_fundamental_instance(context, object);
+
+ gjs_debug_lifecycle(GJS_DEBUG_GFUNDAMENTAL,
+ "fundamental constructor, obj %p priv %p",
+ object, priv);
+
+ if (!fundamental_invoke_constructor(priv, context, object, argc, argv, &ret_value))
+ return JS_FALSE;
+
+ associate_js_instance_to_fundamental(context, object, ret_value.v_pointer, FALSE);
+
+ g_callable_info_load_return_type((GICallableInfo*) priv->prototype->constructor_info, &return_info);
+
+ if (!gjs_g_argument_release (context,
+ g_callable_info_get_caller_owns((GICallableInfo*)
priv->prototype->constructor_info),
+ &return_info,
+ &ret_value))
+ return JS_FALSE;
+
+ GJS_NATIVE_CONSTRUCTOR_FINISH(fundamental_instance);
+
+ return JS_TRUE;
+}
+
+static void
+fundamental_finalize(JSFreeOp *fop,
+ JSObject *obj)
+{
+ FundamentalInstance *priv;
+
+ priv = (FundamentalInstance *) JS_GetPrivate(obj);
+
+ gjs_debug_lifecycle(GJS_DEBUG_GFUNDAMENTAL,
+ "finalize, obj %p priv %p", obj, priv);
+ if (priv == NULL)
+ return; /* wrong class? */
+
+ if (priv->prototype) {
+ if (priv->gfundamental) {
+ _fundamental_remove_object(priv->gfundamental);
+ priv->prototype->unref_function(priv->gfundamental);
+ priv->gfundamental = NULL;
+ }
+
+ g_slice_free(FundamentalInstance, priv);
+ GJS_DEC_COUNTER(fundamental);
+ } else {
+ Fundamental *proto_priv = (Fundamental *) priv;
+
+ /* Only unref infos when freeing the prototype */
+ if (proto_priv->constructor_info)
+ g_base_info_unref (proto_priv->constructor_info);
+ proto_priv->constructor_info = NULL;
+ if (proto_priv->info)
+ g_base_info_unref((GIBaseInfo *) proto_priv->info);
+ proto_priv->info = NULL;
+
+ g_slice_free(Fundamental, proto_priv);
+ }
+}
+
+static JSBool
+to_string_func(JSContext *context,
+ unsigned argc,
+ jsval *vp)
+{
+ JSObject *obj = JS_THIS_OBJECT(context, vp);
+ FundamentalInstance *priv;
+ JSBool ret = JS_FALSE;
+ jsval retval;
+
+ if (!priv_from_js_with_typecheck(context, obj, &priv))
+ goto out;
+
+ if (!priv->prototype) {
+ Fundamental *proto_priv = (Fundamental *) priv;
+
+ if (!_gjs_proxy_to_string_func(context, obj, "fundamental",
+ (GIBaseInfo *) proto_priv->info,
+ proto_priv->gtype,
+ proto_priv->gfundamental,
+ &retval))
+ goto out;
+ } else {
+ if (!_gjs_proxy_to_string_func(context, obj, "fundamental",
+ (GIBaseInfo *) priv->prototype->info,
+ priv->prototype->gtype,
+ priv->gfundamental,
+ &retval))
+ goto out;
+ }
+
+ ret = JS_TRUE;
+ JS_SET_RVAL(context, vp, retval);
+ out:
+ return ret;
+}
+
+/* The bizarre thing about this vtable is that it applies to both
+ * instances of the object, and to the prototype that instances of the
+ * class have.
+ *
+ * Also, there's a constructor field in here, but as far as I can
+ * tell, it would only be used if no constructor were provided to
+ * JS_InitClass. The constructor from JS_InitClass is not applied to
+ * the prototype unless JSCLASS_CONSTRUCT_PROTOTYPE is in flags.
+ *
+ * We allocate 1 reserved slot; this is typically unused, but if the
+ * fundamental is for a nested structure inside a parent structure, the
+ * reserved slot is used to hold onto the parent Javascript object and
+ * make sure it doesn't get freed.
+ */
+struct JSClass gjs_fundamental_instance_class = {
+ "GFundamental_Object",
+ JSCLASS_HAS_PRIVATE |
+ JSCLASS_NEW_RESOLVE,
+ JS_PropertyStub,
+ JS_DeletePropertyStub,
+ JS_PropertyStub,
+ JS_StrictPropertyStub,
+ JS_EnumerateStub,
+ (JSResolveOp) fundamental_instance_new_resolve, /* needs cast since it's the new resolve signature */
+ JS_ConvertStub,
+ fundamental_finalize,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
+static JSPropertySpec gjs_fundamental_instance_proto_props[] = {
+ { NULL }
+};
+
+static JSFunctionSpec gjs_fundamental_instance_proto_funcs[] = {
+ { "toString", JSOP_WRAPPER((JSNative)to_string_func), 0, 0 },
+ { NULL }
+};
+
+static JSObject *
+gjs_lookup_fundamental_prototype(JSContext *context,
+ GIObjectInfo *info,
+ GType gtype)
+{
+ JSObject *in_object;
+ JSObject *constructor;
+ const char *constructor_name;
+ jsval value;
+
+ if (info) {
+ in_object = gjs_lookup_namespace_object(context, (GIBaseInfo*) info);
+ constructor_name = g_base_info_get_name((GIBaseInfo*) info);
+ } else {
+ in_object = gjs_lookup_private_namespace(context);
+ constructor_name = g_type_name(gtype);
+ }
+
+ if (G_UNLIKELY (!in_object))
+ return NULL;
+
+ if (!JS_GetProperty(context, in_object, constructor_name, &value))
+ return NULL;
+
+ if (JSVAL_IS_VOID(value)) {
+ /* In case we're looking for a private type, and we don't find it,
+ we need to define it first.
+ */
+ gjs_define_fundamental_class(context, in_object, info, &constructor, NULL);
+ } else {
+ if (G_UNLIKELY (!JSVAL_IS_OBJECT(value) || JSVAL_IS_NULL(value)))
+ return NULL;
+
+ constructor = JSVAL_TO_OBJECT(value);
+ }
+
+ g_assert(constructor != NULL);
+
+ if (!gjs_object_get_property_const(context, constructor,
+ GJS_STRING_PROTOTYPE, &value))
+ return NULL;
+
+ if (G_UNLIKELY (!JSVAL_IS_OBJECT(value)))
+ return NULL;
+
+ return JSVAL_TO_OBJECT(value);
+}
+
+static JSObject*
+gjs_lookup_fundamental_prototype_from_gtype(JSContext *context,
+ GType gtype)
+{
+ GIObjectInfo *info;
+ JSObject *proto;
+
+ info = (GIObjectInfo *) g_irepository_find_by_gtype(g_irepository_get_default(),
+ gtype);
+ proto = gjs_lookup_fundamental_prototype(context, info, gtype);
+ if (info)
+ g_base_info_unref((GIBaseInfo*)info);
+
+ return proto;
+}
+
+JSBool
+gjs_define_fundamental_class(JSContext *context,
+ JSObject *in_object,
+ GIObjectInfo *info,
+ JSObject **constructor_p,
+ JSObject **prototype_p)
+{
+ const char *constructor_name;
+ JSObject *prototype;
+ jsval value;
+ jsid js_constructor_name = JSID_VOID;
+ JSObject *parent_proto;
+ Fundamental *priv;
+ JSObject *constructor;
+ GType parent_gtype;
+ GType gtype;
+ GIFunctionInfo *constructor_info;
+ /* See the comment in gjs_define_object_class() for an explanation
+ * of how this all works; Fundamental is pretty much the same as
+ * Object.
+ */
+
+ constructor_name = g_base_info_get_name((GIBaseInfo *) info);
+ constructor_info = find_fundamental_constructor(context, info,
+ &js_constructor_name);
+
+ gtype = g_registered_type_info_get_g_type (info);
+ parent_gtype = g_type_parent(gtype);
+ parent_proto = NULL;
+ if (parent_gtype != G_TYPE_INVALID)
+ parent_proto = gjs_lookup_fundamental_prototype_from_gtype(context,
+ parent_gtype);
+
+ if (!gjs_init_class_dynamic(context, in_object,
+ /* parent prototype JSObject* for
+ * prototype; NULL for
+ * Object.prototype
+ */
+ parent_proto,
+ g_base_info_get_namespace((GIBaseInfo *) info),
+ constructor_name,
+ &gjs_fundamental_instance_class,
+ gjs_fundamental_instance_constructor,
+ /* number of constructor args (less can be passed) */
+ constructor_info != NULL ? g_callable_info_get_n_args((GICallableInfo *)
constructor_info) : 0,
+ /* props of prototype */
+ parent_proto ? NULL : &gjs_fundamental_instance_proto_props[0],
+ /* funcs of prototype */
+ parent_proto ? NULL : &gjs_fundamental_instance_proto_funcs[0],
+ /* props of constructor, MyConstructor.myprop */
+ NULL,
+ /* funcs of constructor, MyConstructor.myfunc() */
+ NULL,
+ &prototype,
+ &constructor)) {
+ gjs_log_exception(context);
+ g_error("Can't init class %s", constructor_name);
+ }
+
+ /* Put the info in the prototype */
+ priv = g_slice_new0(Fundamental);
+ g_assert(priv != NULL);
+ g_assert(priv->info == NULL);
+ priv->info = g_base_info_ref((GIBaseInfo *) info);
+ priv->gtype = gtype;
+ priv->constructor_name = js_constructor_name;
+ priv->constructor_info = constructor_info;
+ priv->ref_function = g_object_info_get_ref_function_pointer(info);
+ g_assert(priv->ref_function != NULL);
+ priv->unref_function = g_object_info_get_unref_function_pointer(info);
+ g_assert(priv->unref_function != NULL);
+ priv->set_value_function = g_object_info_get_set_value_function_pointer(info);
+ g_assert(priv->set_value_function != NULL);
+ priv->get_value_function = g_object_info_get_get_value_function_pointer(info);
+ g_assert(priv->get_value_function != NULL);
+ JS_SetPrivate(prototype, priv);
+
+ gjs_debug(GJS_DEBUG_GFUNDAMENTAL,
+ "Defined class %s prototype is %p class %p in object %p constructor %s.%s.%s",
+ constructor_name, prototype, JS_GetClass(prototype),
+ in_object,
+ constructor_info != NULL ? g_base_info_get_namespace(constructor_info) : "unknown",
+ constructor_info != NULL ? g_base_info_get_name(g_base_info_get_container(constructor_info)) :
"unknown",
+ constructor_info != NULL ? g_base_info_get_name(constructor_info) : "unknown");
+
+ if (g_object_info_get_n_fields(priv->info) > 0) {
+ gjs_debug(GJS_DEBUG_GFUNDAMENTAL,
+ "Fundamental type '%s.%s' apparently has accessible fields. "
+ "Gjs has no support for this yet, ignoring these.",
+ g_base_info_get_namespace((GIBaseInfo *)priv->info),
+ g_base_info_get_name ((GIBaseInfo *)priv->info));
+ }
+
+ gjs_define_static_methods(context, constructor, gtype, info);
+
+ value = OBJECT_TO_JSVAL(gjs_gtype_create_gtype_wrapper(context, gtype));
+ JS_DefineProperty(context, constructor, "$gtype", value,
+ NULL, NULL, JSPROP_PERMANENT);
+
+ if (constructor_p)
+ *constructor_p = constructor;
+ if (prototype_p)
+ *prototype_p = prototype;
+
+ return JS_TRUE;
+}
+
+JSObject*
+gjs_object_from_g_fundamental(JSContext *context,
+ GIObjectInfo *info,
+ void *gfundamental)
+{
+ JSObject *proto;
+ JSObject *object;
+
+ if (gfundamental == NULL)
+ return NULL;
+
+ object = _fundamental_lookup_object(gfundamental);
+ if (object)
+ return object;
+
+ gjs_debug_marshal(GJS_DEBUG_GFUNDAMENTAL,
+ "Wrapping fundamental %s.%s %p with JSObject",
+ g_base_info_get_namespace((GIBaseInfo *) info),
+ g_base_info_get_name((GIBaseInfo *) info),
+ gfundamental);
+
+ proto = gjs_lookup_fundamental_prototype_from_gtype(context,
+ G_TYPE_FROM_INSTANCE(gfundamental));
+
+ object = JS_NewObjectWithGivenProto(context,
+ JS_GetClass(proto), proto,
+ gjs_get_import_global(context));
+
+ if (object == NULL)
+ goto out;
+
+ init_fundamental_instance(context, object);
+
+ associate_js_instance_to_fundamental(context, object, gfundamental, FALSE);
+
+ out:
+ return object;
+}
+
+JSObject *
+gjs_fundamental_from_g_value(JSContext *context,
+ const GValue *value,
+ GType gtype)
+{
+ JSObject *proto;
+ Fundamental *proto_priv;
+ void *fobj;
+
+ proto = gjs_lookup_fundamental_prototype_from_gtype(context, gtype);
+ if (!proto)
+ return NULL;
+
+ proto_priv = (Fundamental *) priv_from_js(context, proto);
+
+ fobj = proto_priv->get_value_function(value);
+ if (!fobj) {
+ gjs_throw(context,
+ "Failed to convert GValue to a fundamental instance");
+ return NULL;
+ }
+
+ return gjs_object_from_g_fundamental(context, proto_priv->info, fobj);
+}
+
+void*
+gjs_g_fundamental_from_object(JSContext *context,
+ JSObject *obj)
+{
+ FundamentalInstance *priv;
+
+ if (obj == NULL)
+ return NULL;
+
+ priv = priv_from_js(context, obj);
+
+ if (priv == NULL) {
+ gjs_throw(context,
+ "No introspection information for %p", obj);
+ return NULL;
+ }
+
+ if (priv->gfundamental == NULL) {
+ gjs_throw(context,
+ "Object is %s.%s.prototype, not an object instance - cannot convert to a fundamental
instance",
+ g_base_info_get_namespace((GIBaseInfo *) priv->prototype->info),
+ g_base_info_get_name((GIBaseInfo *) priv->prototype->info));
+ return NULL;
+ }
+
+ return priv->gfundamental;
+}
+
+JSBool
+gjs_typecheck_is_fundamental(JSContext *context,
+ JSObject *object,
+ JSBool throw_error)
+{
+ if (do_base_typecheck(context, object, throw_error)) {
+ FundamentalInstance *priv = priv_from_js(context, object);
+
+ if (priv)
+ return JS_TRUE;
+ }
+
+ if (throw_error)
+ gjs_throw(context,
+ "Object instance or prototype is not a fundamental");
+
+ return JS_FALSE;
+}
+
+JSBool
+gjs_typecheck_fundamental(JSContext *context,
+ JSObject *object,
+ GType expected_gtype,
+ JSBool throw_error)
+{
+ FundamentalInstance *priv;
+ JSBool result;
+
+ if (!do_base_typecheck(context, object, throw_error))
+ return JS_FALSE;
+
+ priv = priv_from_js(context, object);
+
+ if (priv == NULL) {
+ if (throw_error) {
+ gjs_throw(context,
+ "Fundamental instance or prototype has not been properly initialized yet. "
+ "Did you forget to chain-up from _init()?");
+ }
+
+ return JS_FALSE;
+ }
+
+ if (priv->gfundamental == NULL) {
+ if (throw_error) {
+ Fundamental *proto_priv = (Fundamental *) priv;
+ gjs_throw(context,
+ "Object is %s.%s.prototype, not an fundamental instance - cannot convert to void*",
+ proto_priv->info ? g_base_info_get_namespace((GIBaseInfo *) proto_priv->info) : "",
+ proto_priv->info ? g_base_info_get_name((GIBaseInfo *) proto_priv->info) :
g_type_name(proto_priv->gtype));
+ }
+
+ return JS_FALSE;
+ }
+
+ if (expected_gtype != G_TYPE_NONE)
+ result = g_type_is_a(priv->prototype->gtype, expected_gtype);
+ else
+ result = JS_TRUE;
+
+ if (!result && throw_error) {
+ if (priv->prototype->info) {
+ gjs_throw_custom(context, "TypeError",
+ "Object is of type %s.%s - cannot convert to %s",
+ g_base_info_get_namespace((GIBaseInfo *) priv->prototype->info),
+ g_base_info_get_name((GIBaseInfo *) priv->prototype->info),
+ g_type_name(expected_gtype));
+ } else {
+ gjs_throw_custom(context, "TypeError",
+ "Object is of type %s - cannot convert to %s",
+ g_type_name(priv->prototype->gtype),
+ g_type_name(expected_gtype));
+ }
+ }
+
+ return result;
+}
+
+void *
+gjs_fundamental_ref(JSContext *context,
+ void *gfundamental)
+{
+ JSObject *proto;
+ Fundamental *proto_priv;
+
+ proto = gjs_lookup_fundamental_prototype_from_gtype(context,
+ G_TYPE_FROM_INSTANCE(gfundamental));
+
+ proto_priv = (Fundamental *) priv_from_js(context, proto);
+
+ return proto_priv->ref_function(gfundamental);
+}
+
+void
+gjs_fundamental_unref(JSContext *context,
+ void *gfundamental)
+{
+ JSObject *proto;
+ Fundamental *proto_priv;
+
+ proto = gjs_lookup_fundamental_prototype_from_gtype(context,
+ G_TYPE_FROM_INSTANCE(gfundamental));
+
+ proto_priv = (Fundamental *) priv_from_js(context, proto);
+
+ proto_priv->unref_function(gfundamental);
+}
diff --git a/gi/fundamental.h b/gi/fundamental.h
new file mode 100644
index 0000000..50e1086
--- /dev/null
+++ b/gi/fundamental.h
@@ -0,0 +1,61 @@
+/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
+/*
+ * Copyright (c) 2013 Intel Corporation
+ * Copyright (c) 2008-2010 litl, LLC
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef __GJS_FUNDAMENTAL_H__
+#define __GJS_FUNDAMENTAL_H__
+
+#include <glib.h>
+#include <girepository.h>
+#include "gjs/jsapi-util.h"
+
+G_BEGIN_DECLS
+
+JSBool gjs_define_fundamental_class (JSContext *context,
+ JSObject *in_object,
+ GIObjectInfo *info,
+ JSObject **constructor_p,
+ JSObject **prototype_p);
+JSObject* gjs_object_from_g_fundamental (JSContext *context,
+ GIObjectInfo *info,
+ void *fobj);
+void* gjs_g_fundamental_from_object (JSContext *context,
+ JSObject *obj);
+JSObject *gjs_fundamental_from_g_value (JSContext *context,
+ const GValue *value,
+ GType gtype);
+JSBool gjs_typecheck_fundamental (JSContext *context,
+ JSObject *object,
+ GType expected_gtype,
+ JSBool throw_error);
+JSBool gjs_typecheck_is_fundamental (JSContext *context,
+ JSObject *object,
+ JSBool throw_error);
+void* gjs_fundamental_ref (JSContext *context,
+ void *fobj);
+void gjs_fundamental_unref (JSContext *context,
+ void *fobj);
+
+G_END_DECLS
+
+#endif /* __GJS_FUNDAMENTAL_H__ */
diff --git a/gi/repo.cpp b/gi/repo.cpp
index fef7eae..ab8f38e 100644
--- a/gi/repo.cpp
+++ b/gi/repo.cpp
@@ -33,6 +33,7 @@
#include "enumeration.h"
#include "arg.h"
#include "foreign.h"
+#include "fundamental.h"
#include "interface.h"
#include "gerror.h"
@@ -475,6 +476,13 @@ gjs_define_info(JSContext *context,
gjs_define_param_class(context, in_object);
} else if (g_type_is_a (gtype, G_TYPE_OBJECT)) {
gjs_define_object_class(context, in_object, (GIObjectInfo*) info, gtype, NULL);
+ } else if (G_TYPE_IS_INSTANTIATABLE(gtype)) {
+ if (!gjs_define_fundamental_class(context, in_object, (GIObjectInfo*)info, NULL, NULL)) {
+ gjs_throw (context,
+ "Unsupported fundamental class creation for type %s",
+ g_type_name(gtype));
+ return JS_FALSE;
+ }
} else {
gjs_throw (context,
"Unsupported type %s, deriving from fundamental %s",
diff --git a/gi/value.cpp b/gi/value.cpp
index 5d16ea9..828a259 100644
--- a/gi/value.cpp
+++ b/gi/value.cpp
@@ -31,6 +31,7 @@
#include "arg.h"
#include "param.h"
#include "object.h"
+#include "fundamental.h"
#include "boxed.h"
#include "union.h"
#include "gtype.h"
@@ -858,6 +859,15 @@ gjs_value_from_g_value_internal(JSContext *context,
g_value_transform(gvalue, &int_value);
v = g_value_get_int(&int_value);
return JS_NewNumberValue(context, v, value_p);
+ } else if (G_TYPE_IS_INSTANTIATABLE(gtype)) {
+ /* The gtype is none of the above, it should be a custom
+ fundamental type. */
+ JSObject *obj;
+ obj = gjs_fundamental_from_g_value(context, (const GValue*)gvalue, gtype);
+ if (obj == NULL)
+ return JS_FALSE;
+ else
+ *value_p = OBJECT_TO_JSVAL(obj);
} else {
gjs_throw(context,
"Don't know how to convert GType %s to JavaScript object",
diff --git a/gjs/mem.cpp b/gjs/mem.cpp
index 6d99967..68a31e1 100644
--- a/gjs/mem.cpp
+++ b/gjs/mem.cpp
@@ -40,6 +40,7 @@ GJS_DEFINE_COUNTER(gerror)
GJS_DEFINE_COUNTER(closure)
GJS_DEFINE_COUNTER(database)
GJS_DEFINE_COUNTER(function)
+GJS_DEFINE_COUNTER(fundamental)
GJS_DEFINE_COUNTER(importer)
GJS_DEFINE_COUNTER(ns)
GJS_DEFINE_COUNTER(object)
@@ -58,6 +59,7 @@ static GjsMemCounter* counters[] = {
GJS_LIST_COUNTER(closure),
GJS_LIST_COUNTER(database),
GJS_LIST_COUNTER(function),
+ GJS_LIST_COUNTER(fundamental),
GJS_LIST_COUNTER(importer),
GJS_LIST_COUNTER(ns),
GJS_LIST_COUNTER(object),
diff --git a/gjs/mem.h b/gjs/mem.h
index 1ee2604..6eea42c 100644
--- a/gjs/mem.h
+++ b/gjs/mem.h
@@ -48,6 +48,7 @@ GJS_DECLARE_COUNTER(gerror)
GJS_DECLARE_COUNTER(closure)
GJS_DECLARE_COUNTER(database)
GJS_DECLARE_COUNTER(function)
+GJS_DECLARE_COUNTER(fundamental)
GJS_DECLARE_COUNTER(importer)
GJS_DECLARE_COUNTER(ns)
GJS_DECLARE_COUNTER(object)
diff --git a/installed-tests/js/testFundamental.js b/installed-tests/js/testFundamental.js
new file mode 100644
index 0000000..24031ca
--- /dev/null
+++ b/installed-tests/js/testFundamental.js
@@ -0,0 +1,16 @@
+// application/javascript;version=1.8
+
+const JSUnit = imports.jsUnit;
+const Everything = imports.gi.Regress;
+const WarnLib = imports.gi.WarnLib;
+
+const GLib = imports.gi.GLib;
+const Gio = imports.gi.Gio;
+const GObject = imports.gi.GObject;
+const Lang = imports.lang;
+
+function testFundamental() {
+ let f = new Everything.TestFundamentalSubObject('plop');
+}
+
+JSUnit.gjstestRun(this, JSUnit.setUp, JSUnit.tearDown);
diff --git a/util/log.cpp b/util/log.cpp
index 7e00c51..ed6ca18 100644
--- a/util/log.cpp
+++ b/util/log.cpp
@@ -199,6 +199,9 @@ gjs_debug(GjsDebugTopic topic,
case GJS_DEBUG_GFUNCTION:
prefix = "JS G FUNC";
break;
+ case GJS_DEBUG_GFUNDAMENTAL:
+ prefix = "JS G FNDMTL";
+ break;
case GJS_DEBUG_GCLOSURE:
prefix = "JS G CLSR";
break;
diff --git a/util/log.h b/util/log.h
index 83f0338..2a9b596 100644
--- a/util/log.h
+++ b/util/log.h
@@ -58,6 +58,7 @@ typedef enum {
GJS_DEBUG_HTTP,
GJS_DEBUG_BYTE_ARRAY,
GJS_DEBUG_GERROR,
+ GJS_DEBUG_GFUNDAMENTAL,
} GjsDebugTopic;
/* These defines are because we have some pretty expensive and
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]