[gjs] Represent GTypes as a new boxed wrapper type



commit f1dc3188f5e7a3e9d9d5cd26879024441dcb26b4
Author: Jasper St. Pierre <jstpierre mecheye net>
Date:   Thu Jan 19 22:24:17 2012 -0500

    Represent GTypes as a new boxed wrapper type
    
    We can't natively represent a pointer as a regular value in JS (we have at
    most 30-bit integers or doubles), so to store GTypes correctly, we need to
    box them. Create a new native object that simply represents a GType, give
    it a 'g_type_name' wrapper, and fix up the rest of the world so we no longer
    treat a GType as a special integer.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=668427

 Makefile.am                  |    6 +-
 gi/arg.c                     |  105 +++++++++++++++++++-------
 gi/enumeration.c             |    3 +-
 gi/gtype.c                   |  171 ++++++++++++++++++++++++++++++++++++++++++
 gi/gtype.h                   |   50 ++++++++++++
 gi/object.c                  |   31 +-------
 gi/object.h                  |    2 -
 gi/param.c                   |   19 ++++-
 test/js/testGIMarshalling.js |   29 +++++++
 9 files changed, 349 insertions(+), 67 deletions(-)
---
diff --git a/Makefile.am b/Makefile.am
index ddf30d1..83c6ebb 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -50,7 +50,8 @@ nobase_gjs_module_include_HEADERS =	\
 	gi/enumeration.h	\
 	gi/function.h	\
 	gi/keep-alive.h	\
-	gi/interface.h
+	gi/interface.h	\
+	gi/gtype.h
 
 noinst_HEADERS +=		\
 	gjs/jsapi-private.h	\
@@ -133,7 +134,8 @@ libgjs_la_SOURCES += \
         gi/repo.c	\
 	gi/union.c	\
         gi/value.c	\
-	gi/interface.c
+	gi/interface.c	\
+	gi/gtype.c
 
 if ENABLE_DTRACE
 gjs_gi_probes.h: gi/gjs_gi_probes.d
diff --git a/gi/arg.c b/gi/arg.c
index a653d79..5e9d8f8 100644
--- a/gi/arg.c
+++ b/gi/arg.c
@@ -24,6 +24,7 @@
 #include <config.h>
 
 #include "arg.h"
+#include "gtype.h"
 #include "object.h"
 #include "foreign.h"
 #include "boxed.h"
@@ -150,25 +151,6 @@ _gjs_enum_to_int (GIEnumInfo *enum_info,
     return (int)value;
 }
 
-/* The typelib used to have machine-independent types like
- * GI_TYPE_TAG_LONG that had to be converted; now we only
- * handle GType specially here.
- */
-static inline GITypeTag
-replace_gtype(GITypeTag type) {
-    if (type == GI_TYPE_TAG_GTYPE) {
-        /* Constant folding should handle this hopefully */
-        switch (sizeof(GType)) {
-        case 1: return GI_TYPE_TAG_UINT8;
-        case 2: return GI_TYPE_TAG_UINT16;
-        case 4: return GI_TYPE_TAG_UINT32;
-        case 8: return GI_TYPE_TAG_UINT64;
-        default: g_assert_not_reached ();
-        }
-    }
-    return type;
-}
-
 /* Check if an argument of the given needs to be released if we created it
  * from a JS value to pass it into a function and aren't transfering ownership.
  */
@@ -537,7 +519,6 @@ gjs_string_to_intarray(JSContext   *context,
     guint16 *result16;
 
     element_type = g_type_info_get_tag(param_info);
-    element_type = replace_gtype(element_type);
 
     switch (element_type) {
     case GI_TYPE_TAG_INT8:
@@ -624,6 +605,46 @@ gjs_array_to_intarray(JSContext   *context,
 }
 
 static JSBool
+gjs_gtypearray_to_array(JSContext   *context,
+                        jsval        array_value,
+                        unsigned int length,
+                        void       **arr_p)
+{
+    GType *result;
+    unsigned i;
+
+    /* add one so we're always zero terminated */
+    result = g_malloc0((length+1) * sizeof(GType));
+
+    for (i = 0; i < length; ++i) {
+        jsval elem;
+        GType gtype;
+
+        elem = JSVAL_VOID;
+        if (!JS_GetElement(context, JSVAL_TO_OBJECT(array_value),
+                           i, &elem)) {
+            g_free(result);
+            gjs_throw(context, "Missing array element %u", i);
+            return JS_FALSE;
+        }
+
+        gtype = gjs_gtype_get_actual_gtype(context, JSVAL_TO_OBJECT(elem));
+
+        if (gtype == G_TYPE_INVALID) {
+            g_free(result);
+            gjs_throw(context, "Invalid element in GType array");
+            return JS_FALSE;
+        }
+
+        result[i] = gtype;
+    }
+
+    *arr_p = result;
+
+    return JS_TRUE;
+}
+
+static JSBool
 gjs_array_to_floatarray(JSContext   *context,
                         jsval        array_value,
                         unsigned int length,
@@ -854,7 +875,6 @@ gjs_array_to_array(JSContext   *context,
     GITypeTag element_type;
 
     element_type = g_type_info_get_tag(param_info);
-    element_type = replace_gtype(element_type);
 
     /* Special case for GValue "flat arrays" */
     if (is_gvalue_flat_array(param_info, element_type))
@@ -895,6 +915,9 @@ gjs_array_to_array(JSContext   *context,
     case GI_TYPE_TAG_DOUBLE:
         return gjs_array_to_floatarray
             (context, array_value, length, arr_p, TRUE);
+    case GI_TYPE_TAG_GTYPE:
+        return gjs_gtypearray_to_array
+            (context, array_value, length, arr_p);
 
     /* Everything else is a pointer type */
     case GI_TYPE_TAG_INTERFACE:
@@ -924,7 +947,6 @@ gjs_g_array_new_for_type(JSContext    *context,
     guint element_size;
 
     element_type = g_type_info_get_tag(param_info);
-    element_type = replace_gtype(element_type);
 
     if (element_type == GI_TYPE_TAG_INTERFACE) {
         GIInterfaceInfo *interface_info = g_type_info_get_interface(param_info);
@@ -960,6 +982,9 @@ gjs_g_array_new_for_type(JSContext    *context,
     case GI_TYPE_TAG_DOUBLE:
       element_size = sizeof(gdouble);
       break;
+    case GI_TYPE_TAG_GTYPE:
+      element_size = sizeof(GType);
+      break;
     case GI_TYPE_TAG_INTERFACE:
     case GI_TYPE_TAG_UTF8:
     case GI_TYPE_TAG_FILENAME:
@@ -1085,7 +1110,6 @@ gjs_value_to_g_argument(JSContext      *context,
     gboolean nullable_type;
 
     type_tag = g_type_info_get_tag( (GITypeInfo*) type_info);
-    type_tag = replace_gtype(type_tag);
 
     gjs_debug_marshal(GJS_DEBUG_GFUNCTION,
                       "Converting jsval to GArgument %s",
@@ -1206,6 +1230,19 @@ gjs_value_to_g_argument(JSContext      *context,
         }
         break;
 
+    case GI_TYPE_TAG_GTYPE:
+        if (JSVAL_IS_OBJECT(value)) {
+            GType gtype;
+            gtype = gjs_gtype_get_actual_gtype(context, JSVAL_TO_OBJECT(value));
+            if (gtype == G_TYPE_INVALID)
+                wrong = TRUE;
+            arg->v_ssize = gtype;
+        } else {
+            wrong = TRUE;
+            report_type_mismatch = TRUE;
+        }
+        break;
+
     case GI_TYPE_TAG_FILENAME:
         nullable_type = TRUE;
         if (JSVAL_IS_NULL(value)) {
@@ -1643,7 +1680,6 @@ gjs_g_argument_init_default(JSContext      *context,
     GITypeTag type_tag;
 
     type_tag = g_type_info_get_tag( (GITypeInfo*) type_info);
-    type_tag = replace_gtype(type_tag);
 
     switch (type_tag) {
     case GI_TYPE_TAG_VOID:
@@ -1694,6 +1730,10 @@ gjs_g_argument_init_default(JSContext      *context,
         arg->v_double = 0.0;
         break;
 
+    case GI_TYPE_TAG_GTYPE:
+        arg->v_ssize = 0;
+        break;
+
     case GI_TYPE_TAG_FILENAME:
     case GI_TYPE_TAG_UTF8:
     case GI_TYPE_TAG_GLIST:
@@ -1869,7 +1909,6 @@ gjs_array_from_carray_internal (JSContext  *context,
     guint i;
 
     element_type = g_type_info_get_tag(param_info);
-    element_type = replace_gtype(element_type);
 
     if (is_gvalue_flat_array(param_info, element_type))
         return gjs_array_from_flat_gvalue_array(context, array, length, value_p);
@@ -1938,6 +1977,7 @@ gjs_array_from_carray_internal (JSContext  *context,
         case GI_TYPE_TAG_DOUBLE:
           ITERATE(double);
           break;
+        case GI_TYPE_TAG_GTYPE:
         case GI_TYPE_TAG_UTF8:
         case GI_TYPE_TAG_FILENAME:
         case GI_TYPE_TAG_ARRAY:
@@ -2050,7 +2090,6 @@ gjs_array_from_zero_terminated_c_array (JSContext  *context,
     guint i;
 
     element_type = g_type_info_get_tag(param_info);
-    element_type = replace_gtype(element_type);
 
     /* Special case array(guint8) */
     if (element_type == GI_TYPE_TAG_UINT8) {
@@ -2119,6 +2158,7 @@ gjs_array_from_zero_terminated_c_array (JSContext  *context,
         case GI_TYPE_TAG_DOUBLE:
           ITERATE(double);
           break;
+        case GI_TYPE_TAG_GTYPE:
         case GI_TYPE_TAG_UTF8:
         case GI_TYPE_TAG_FILENAME:
         case GI_TYPE_TAG_ARRAY:
@@ -2230,7 +2270,6 @@ gjs_value_from_g_argument (JSContext  *context,
     GITypeTag type_tag;
 
     type_tag = g_type_info_get_tag( (GITypeInfo*) type_info);
-    type_tag = replace_gtype(type_tag);
 
     gjs_debug_marshal(GJS_DEBUG_GFUNCTION,
                       "Converting GArgument %s to jsval",
@@ -2277,6 +2316,14 @@ gjs_value_from_g_argument (JSContext  *context,
     case GI_TYPE_TAG_DOUBLE:
         return JS_NewNumberValue(context, arg->v_double, value_p);
 
+    case GI_TYPE_TAG_GTYPE:
+        {
+            JSObject *obj;
+            obj = gjs_gtype_create_gtype_wrapper(context, arg->v_ssize);
+            *value_p = OBJECT_TO_JSVAL(obj);
+        }
+        break;
+
     case GI_TYPE_TAG_UNICHAR:
         {
             char utf8[7];
@@ -2722,7 +2769,6 @@ gjs_g_arg_release_internal(JSContext  *context,
 
             param_info = g_type_info_get_param_type(type_info, 0);
             element_type = g_type_info_get_tag(param_info);
-            element_type = replace_gtype(element_type);
 
             if (transfer != GI_TRANSFER_CONTAINER && is_gvalue_flat_array(param_info, element_type)) {
                 g_free(arg->v_pointer);
@@ -2744,6 +2790,7 @@ gjs_g_arg_release_internal(JSContext  *context,
             case GI_TYPE_TAG_INT8:
             case GI_TYPE_TAG_INT16:
             case GI_TYPE_TAG_INT32:
+            case GI_TYPE_TAG_GTYPE:
                 g_free (arg->v_pointer);
                 break;
 
@@ -2804,7 +2851,6 @@ gjs_g_arg_release_internal(JSContext  *context,
 
             param_info = g_type_info_get_param_type(type_info, 0);
             element_type = g_type_info_get_tag(param_info);
-            element_type = replace_gtype(element_type);
 
             switch (element_type) {
             case GI_TYPE_TAG_UINT8:
@@ -2815,6 +2861,7 @@ gjs_g_arg_release_internal(JSContext  *context,
             case GI_TYPE_TAG_INT16:
             case GI_TYPE_TAG_INT32:
             case GI_TYPE_TAG_INT64:
+            case GI_TYPE_TAG_GTYPE:
                 g_array_free((GArray*) arg->v_pointer, TRUE);
                 break;
 
diff --git a/gi/enumeration.c b/gi/enumeration.c
index c7734b4..fac9854 100644
--- a/gi/enumeration.c
+++ b/gi/enumeration.c
@@ -28,6 +28,7 @@
 #include <gjs/gjs-module.h>
 #include <gjs/compat.h>
 #include "repo.h"
+#include "gtype.h"
 
 #include <util/log.h>
 
@@ -167,7 +168,7 @@ gjs_define_enumeration(JSContext    *context,
     }
 
     gtype = g_registered_type_info_get_g_type((GIRegisteredTypeInfo*)info);
-    value = INT_TO_JSVAL(gtype);
+    value = OBJECT_TO_JSVAL(gjs_gtype_create_gtype_wrapper(context, gtype));
     JS_DefineProperty(context, enum_obj, "$gtype", value,
                       NULL, NULL, JSPROP_PERMANENT);
 
diff --git a/gi/gtype.c b/gi/gtype.c
new file mode 100644
index 0000000..501903a
--- /dev/null
+++ b/gi/gtype.c
@@ -0,0 +1,171 @@
+/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
+/*
+ * Copyright (c) 2008  litl, LLC
+ * Copyright (c) 2012  Red Hat, Inc.
+ *
+ * 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 "gtype.h"
+
+#include <gjs/gjs-module.h>
+#include <gjs/compat.h>
+#include <util/log.h>
+
+#include <jsapi.h>
+#include <girepository.h>
+
+GJS_DEFINE_PROTO_ABSTRACT("GIRepositoryGType", gtype);
+
+/* priv_from_js adds a "*", so this returns "void *" */
+GJS_DEFINE_PRIV_FROM_JS(void, gjs_gtype_class);
+
+static GQuark
+gjs_get_gtype_wrapper_quark(void)
+{
+    static gsize once_init = 0;
+    static GQuark value = 0;
+    if (g_once_init_enter(&once_init)) {
+        value = g_quark_from_string("gjs-gtype-wrapper");
+        g_once_init_leave(&once_init, 1);
+    }
+    return value;
+}
+
+static void
+gjs_gtype_finalize(JSContext *context,
+                   JSObject  *obj)
+{
+    GType gtype = GPOINTER_TO_SIZE(priv_from_js(context, obj));
+
+    /* proto doesn't have a private set */
+    if (G_UNLIKELY(gtype == 0))
+        return;
+
+    g_type_set_qdata(gtype, gjs_get_gtype_wrapper_quark(), NULL);
+}
+
+static JSBool
+to_string_func(JSContext *context,
+               uintN      argc,
+               jsval     *vp)
+{
+    JSObject *obj = JS_THIS_OBJECT(context, vp);
+    GType gtype;
+    gchar *strval;
+    JSBool ret;
+    jsval retval;
+    
+    gtype = GPOINTER_TO_SIZE(priv_from_js(context, obj));
+
+    strval = g_strdup_printf("[object GType for '%s']",
+                             g_type_name(gtype));
+    ret = gjs_string_from_utf8(context, strval, -1, &retval);
+    if (ret)
+        JS_SET_RVAL(context, vp, retval);
+    g_free(strval);
+    return ret;
+}
+
+static JSBool
+get_name_func (JSContext *context,
+               JSObject  *obj,
+               jsid       id,
+               jsval     *vp)
+{
+    GType gtype;
+    JSBool ret;
+    jsval retval;
+
+    gtype = GPOINTER_TO_SIZE(priv_from_js(context, obj));
+
+    ret = gjs_string_from_utf8(context, g_type_name(gtype), -1, &retval);
+    if (ret)
+        JS_SET_RVAL(context, vp, retval);
+    return ret;
+}
+
+/* Properties */
+static JSPropertySpec gjs_gtype_proto_props[] = {
+    { "name", 0, JSPROP_READONLY | JSPROP_PERMANENT | JSPROP_SHARED, (JSPropertyOp)get_name_func, NULL }
+};
+
+/* Functions */
+static JSFunctionSpec gjs_gtype_proto_funcs[] = {
+    { "toString", (JSNative)to_string_func, 0, 0 }
+};
+
+JSObject *
+gjs_gtype_create_gtype_wrapper (JSContext *context,
+                                GType      gtype)
+{
+    JSObject *object;
+    JSObject *global;
+
+    JS_BeginRequest(context);
+
+    /* put constructor for GIRepositoryGType() in the global namespace */
+    global = gjs_get_import_global(context);
+    gjs_gtype_create_proto(context, global, "GIRepositoryGType", NULL);
+
+    object = g_type_get_qdata(gtype, gjs_get_gtype_wrapper_quark());
+    if (object != NULL)
+        goto out;
+
+    object = JS_NewObject(context, &gjs_gtype_class, NULL, NULL);
+    if (object == NULL)
+        goto out;
+
+    JS_SetPrivate(context, object, GSIZE_TO_POINTER(gtype));
+    g_type_set_qdata(gtype, gjs_get_gtype_wrapper_quark(), object);
+
+ out:
+    JS_EndRequest(context);
+    return object;
+}
+
+GType
+gjs_gtype_get_actual_gtype (JSContext *context,
+                            JSObject  *object)
+{
+    GType gtype = G_TYPE_INVALID;
+    jsval gtype_val;
+
+    JS_BeginRequest(context);
+    if (JS_InstanceOf(context, object, &gjs_gtype_class, NULL)) {
+        gtype = GPOINTER_TO_SIZE(priv_from_js(context, object));
+        goto out;
+    }
+
+    /* OK, we don't have a GType wrapper object -- grab the "$gtype"
+     * property on that and hope it's a GType wrapper object */
+    if (!JS_GetProperty(context, object, "$gtype", &gtype_val))
+        goto out;
+
+    if (!JSVAL_IS_OBJECT(gtype_val))
+        goto out;
+
+    gtype = gjs_gtype_get_actual_gtype(context, JSVAL_TO_OBJECT(gtype_val));
+
+ out:
+    JS_EndRequest(context);
+    return gtype;
+}
diff --git a/gi/gtype.h b/gi/gtype.h
new file mode 100644
index 0000000..645d6f5
--- /dev/null
+++ b/gi/gtype.h
@@ -0,0 +1,50 @@
+/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
+/*
+ * Copyright (c) 2008  litl, LLC
+ * Copyright (c) 2012  Red Hat, Inc.
+ *
+ * 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_GTYPE_H__
+#define __GJS_GTYPE_H__
+
+#include <glib.h>
+
+#include <jsapi.h>
+
+#include <girepository.h>
+
+G_BEGIN_DECLS
+
+jsval      gjs_gtype_create_proto         (JSContext       *context,
+                                           JSObject        *module,
+                                           const char      *proto_name,
+                                           JSObject        *parent);
+
+JSObject * gjs_gtype_create_gtype_wrapper (JSContext *context,
+                                           GType      gtype);
+
+GType      gjs_gtype_get_actual_gtype (JSContext *context,
+                                       JSObject  *object);
+
+
+G_END_DECLS
+
+#endif  /* __GJS_INTERFACE_H__ */
diff --git a/gi/object.c b/gi/object.c
index adb11f8..effc6d5 100644
--- a/gi/object.c
+++ b/gi/object.c
@@ -26,6 +26,7 @@
 #include <string.h>
 
 #include "object.h"
+#include "gtype.h"
 #include "arg.h"
 #include "repo.h"
 #include "function.h"
@@ -1395,7 +1396,7 @@ gjs_define_object_class(JSContext     *context,
        gjs_define_static_methods(context, constructor, info);
     }
 
-    value = INT_TO_JSVAL(gtype);
+    value = OBJECT_TO_JSVAL(gjs_gtype_create_gtype_wrapper(context, gtype));
     JS_DefineProperty(context, constructor, "$gtype", value,
                       NULL, NULL, JSPROP_PERMANENT);
 
@@ -1551,31 +1552,3 @@ gjs_g_object_from_object(JSContext    *context,
 
     return priv->gobj;
 }
-
-GType
-gjs_gtype_from_value(JSContext *context,
-                     jsval      val)
-{
-    GType gtype = G_TYPE_NONE;
-
-    if (JSVAL_IS_INT(val))
-        return JSVAL_TO_INT(val);
-
-    if (JSVAL_IS_OBJECT(val)) {
-        JS_BeginRequest(context);
-
-        JSObject *obj = JSVAL_TO_OBJECT(val);
-        jsval gtype_val;
-        if (!JS_GetProperty(context, obj, "$gtype", &gtype_val))
-            goto out;
-
-        if (!JSVAL_IS_INT(gtype_val))
-            goto out;
-
-        gtype = JSVAL_TO_INT(gtype_val);
-    }
-
- out:
-    JS_EndRequest(context);
-    return gtype;
-}
diff --git a/gi/object.h b/gi/object.h
index d6b9375..e0dc3a4 100644
--- a/gi/object.h
+++ b/gi/object.h
@@ -44,8 +44,6 @@ JSObject* gjs_object_from_g_object      (JSContext     *context,
                                          GObject       *gobj);
 GObject*  gjs_g_object_from_object      (JSContext     *context,
                                          JSObject      *obj);
-GType     gjs_gtype_from_value         (JSContext     *context,
-                                        jsval          value);
 
 G_END_DECLS
 
diff --git a/gi/param.c b/gi/param.c
index 9535499..fd61665 100644
--- a/gi/param.c
+++ b/gi/param.c
@@ -29,6 +29,7 @@
 #include "arg.h"
 #include "object.h"
 #include "repo.h"
+#include "gtype.h"
 #include <gjs/gjs-module.h>
 #include <gjs/compat.h>
 
@@ -189,14 +190,14 @@ param_new_internal(JSContext *cx,
         return JS_FALSE;
 
     if (!JSVAL_IS_STRING(argv[0]) ||
-        !JSVAL_IS_INT(argv[1]) ||
+        !JSVAL_IS_OBJECT(argv[1]) ||
         !JSVAL_IS_STRING(argv[2]) ||
         !JSVAL_IS_STRING(argv[3]) ||
         !JSVAL_IS_INT(argv[4]))
         return JS_FALSE;
 
     prop_name = gjs_string_get_ascii(cx, argv[0]);
-    prop_gtype = JSVAL_TO_INT(argv[1]);
+    prop_gtype = gjs_gtype_get_actual_gtype(cx, JSVAL_TO_OBJECT(argv[1]));
     prop_type = G_TYPE_FUNDAMENTAL(prop_gtype);
     nick = gjs_string_get_ascii(cx, argv[2]);
     blurb = gjs_string_get_ascii(cx, argv[3]);
@@ -298,7 +299,12 @@ param_new_internal(JSContext *cx,
             GIEnumInfo *info;
             gint64 default_value;
 
-            gtype = gjs_gtype_from_value(cx, argv[0]);
+            if (!JSVAL_IS_OBJECT(argv[0])) {
+                gjs_throw(cx, "Passed invalid GType to GParamSpecEnum constructor");
+                goto out;
+            }
+
+            gtype = gjs_gtype_get_actual_gtype(cx, JSVAL_TO_OBJECT(argv[0]));
             if (gtype == G_TYPE_NONE) {
                 gjs_throw(cx, "Passed invalid GType to GParamSpecEnum constructor");
                 goto out;
@@ -321,7 +327,12 @@ param_new_internal(JSContext *cx,
             GType gtype;
             gint64 default_value;
 
-            gtype = gjs_gtype_from_value(cx, argv[0]);
+            if (!JSVAL_IS_OBJECT(argv[0])) {
+                gjs_throw(cx, "Passed invalid GType to GParamSpecFlags constructor");
+                goto out;
+            }
+
+            gtype = gjs_gtype_get_actual_gtype(cx, JSVAL_TO_OBJECT(argv[0]));
             if (gtype == G_TYPE_NONE) {
                 gjs_throw(cx, "Passed invalid GType to GParamSpecFlags constructor");
                 goto out;
diff --git a/test/js/testGIMarshalling.js b/test/js/testGIMarshalling.js
index 5b10c3c..57dcbfc 100644
--- a/test/js/testGIMarshalling.js
+++ b/test/js/testGIMarshalling.js
@@ -16,6 +16,7 @@ const GIMarshallingTests = imports.gi.GIMarshallingTests;
 
 // We use Gio to have some objects that we know exist
 const Gio = imports.gi.Gio;
+const GObject = imports.gi.GObject;
 const Lang = imports.lang;
 
 function testCArray() {
@@ -201,4 +202,32 @@ function testGValue() {
     assertArrayEquals([42, "42", true], thing);
 }
 
+function testGType() {
+    assertEquals("void", GObject.TYPE_NONE.name);
+    assertEquals("gchararray", GObject.TYPE_STRING.name);
+
+    // Make sure "name" is readonly
+    GObject.TYPE_STRING.name = "foo";
+    assertEquals("gchararray", GObject.TYPE_STRING.name);
+
+    // Make sure "name" is permanent
+    assertFalse((delete GObject.TYPE_STRING.name));
+
+    // Make sure "toString" works
+    assertEquals("[object GType for 'void']", GObject.TYPE_NONE.toString());
+    assertEquals("[object GType for 'gchararray']", GObject.TYPE_STRING.toString());
+
+    // Marshalling tests
+    assertEquals(GObject.TYPE_NONE, GIMarshallingTests.gtype_return());
+    assertEquals(GObject.TYPE_STRING, GIMarshallingTests.gtype_string_return());
+
+    GIMarshallingTests.gtype_in(GObject.TYPE_NONE);
+    GIMarshallingTests.gtype_string_in(GObject.TYPE_STRING);
+
+    assertEquals(GObject.TYPE_NONE, GIMarshallingTests.gtype_out());
+    assertEquals(GObject.TYPE_STRING, GIMarshallingTests.gtype_string_out());
+
+    assertEquals(GObject.TYPE_INT, GIMarshallingTests.gtype_inout(GObject.TYPE_NONE));
+}
+
 gjstestRun();



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