[gjs] Improve GType detection for unconstrained GValues



commit d2e7143c108e5f6b2fb0223f0c1b9f4ae00feb47
Author: Giovanni Campagna <gcampagna src gnome org>
Date:   Sat Feb 11 15:36:15 2012 +0100

    Improve GType detection for unconstrained GValues
    
    In ebc84492, we added a way to get a GType for a constructor.
    Let's expand this to objects (by way of the JavaScript 'constructor'
    property), and then use this mechanism to improve GType detection
    in GValues. This can be used with APIs like GtkListStore that force
    the user to create a GValue and expect the right type.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=669848

 gi/gtype.c                   |   16 ++++++++++------
 gi/value.c                   |   22 +++++++++++++++++-----
 modules/overrides/GObject.js |    2 ++
 test/js/testGIMarshalling.js |   30 +++++++++++++++++++++++++++++-
 4 files changed, 58 insertions(+), 12 deletions(-)
---
diff --git a/gi/gtype.c b/gi/gtype.c
index d47e16f..a297f9d 100644
--- a/gi/gtype.c
+++ b/gi/gtype.c
@@ -149,7 +149,7 @@ gjs_gtype_get_actual_gtype (JSContext *context,
                             JSObject  *object)
 {
     GType gtype = G_TYPE_INVALID;
-    jsval gtype_val;
+    jsval gtype_val = JSVAL_VOID;
 
     JS_BeginRequest(context);
     if (JS_InstanceOf(context, object, &gjs_gtype_class, NULL)) {
@@ -159,13 +159,17 @@ gjs_gtype_get_actual_gtype (JSContext *context,
 
     /* 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 (!JS_GetProperty(context, object, "$gtype", &gtype_val) ||
+        !JSVAL_IS_OBJECT(gtype_val)) {
 
-    if (!JSVAL_IS_OBJECT(gtype_val))
-        goto out;
+        /* OK, so we're not a class. But maybe we're an instance. Check
+           for "constructor" and recurse on that. */
+        if (!JS_GetProperty(context, object, "constructor", &gtype_val))
+            goto out;
+    }
 
-    gtype = gjs_gtype_get_actual_gtype(context, JSVAL_TO_OBJECT(gtype_val));
+    if (JSVAL_IS_OBJECT(gtype_val))
+        gtype = gjs_gtype_get_actual_gtype(context, JSVAL_TO_OBJECT(gtype_val));
 
  out:
     JS_EndRequest(context);
diff --git a/gi/value.c b/gi/value.c
index 3439132..d7c01da 100644
--- a/gi/value.c
+++ b/gi/value.c
@@ -32,6 +32,7 @@
 #include "object.h"
 #include "boxed.h"
 #include "union.h"
+#include "gtype.h"
 #include <gjs/gjs-module.h>
 #include <gjs/compat.h>
 
@@ -173,7 +174,8 @@ gjs_closure_new_marshaled (JSContext    *context,
 }
 
 static GType
-gjs_value_guess_g_type(jsval value)
+gjs_value_guess_g_type(JSContext *context,
+                       jsval      value)
 {
     if (JSVAL_IS_NULL(value))
         return G_TYPE_POINTER;
@@ -190,9 +192,8 @@ gjs_value_guess_g_type(jsval value)
     if (JSVAL_IS_BOOLEAN(value))
         return G_TYPE_BOOLEAN;
 
-    if (JSVAL_IS_OBJECT(value)) {
-        return G_TYPE_OBJECT;
-    }
+    if (JSVAL_IS_OBJECT(value))
+        return gjs_gtype_get_actual_gtype(context, JSVAL_TO_OBJECT(value));
 
     return G_TYPE_INVALID;
 }
@@ -208,7 +209,7 @@ gjs_value_to_g_value_internal(JSContext    *context,
     gtype = G_VALUE_TYPE(gvalue);
 
     if (gtype == 0) {
-        gtype = gjs_value_guess_g_type(value);
+        gtype = gjs_value_guess_g_type(context, value);
 
         if (gtype == G_TYPE_INVALID) {
             gjs_throw(context, "Could not guess unspecified GValue type");
@@ -475,6 +476,17 @@ gjs_value_to_g_value_internal(JSContext    *context,
         }
 
         g_value_set_param(gvalue, gparam);
+    } else if (g_type_is_a(gtype, G_TYPE_GTYPE)) {
+        GType type;
+
+        if (!JSVAL_IS_OBJECT(value)) {
+            gjs_throw(context, "Wrong type %s; expect a GType object",
+                      gjs_get_type_name(value));
+            return JS_FALSE;
+        }
+
+        type = gjs_gtype_get_actual_gtype(context, JSVAL_TO_OBJECT(value));
+        g_value_set_gtype(gvalue, type);
     } else if (g_type_is_a(gtype, G_TYPE_POINTER)) {
         if (JSVAL_IS_NULL(value)) {
             /* Nothing to do */
diff --git a/modules/overrides/GObject.js b/modules/overrides/GObject.js
index cd728e9..13ae765 100644
--- a/modules/overrides/GObject.js
+++ b/modules/overrides/GObject.js
@@ -164,6 +164,8 @@ function _init() {
     this.TYPE_BOXED = GObject.type_from_name('GBoxed');
     this.TYPE_PARAM = GObject.type_from_name('GParam');
     this.TYPE_OBJECT = GObject.type_from_name('GObject');
+    this.TYPE_GTYPE = GObject.type_from_name('GType');
+    this.TYPE_VARIANT = GObject.type_from_name('GVariant');
     this.TYPE_UNICHAR = this.TYPE_UINT;
 
     this.ParamSpec.char = function(name, nick, blurb, flags, minimum, maximum, default_value) {
diff --git a/test/js/testGIMarshalling.js b/test/js/testGIMarshalling.js
index 15ff5ea..e046e6d 100644
--- a/test/js/testGIMarshalling.js
+++ b/test/js/testGIMarshalling.js
@@ -14,8 +14,9 @@ function assertArrayEquals(expected, got) {
 
 const GIMarshallingTests = imports.gi.GIMarshallingTests;
 
-// We use Gio to have some objects that we know exist
+// We use Gio and GLib to have some objects that we know exist
 const Gio = imports.gi.Gio;
+const GLib = imports.gi.GLib;
 const GObject = imports.gi.GObject;
 const Lang = imports.lang;
 
@@ -230,6 +231,33 @@ function testGType() {
     assertEquals(GObject.TYPE_INT, GIMarshallingTests.gtype_inout(GObject.TYPE_NONE));
 }
 
+function testGValueGType() {
+    // test that inferring the GType for a primitive value or an object works
+
+    // Primitives (and primitive like)
+    GIMarshallingTests.gvalue_in_with_type(42, GObject.TYPE_INT);
+    GIMarshallingTests.gvalue_in_with_type(42.5, GObject.TYPE_DOUBLE);
+    GIMarshallingTests.gvalue_in_with_type('42', GObject.TYPE_STRING);
+    GIMarshallingTests.gvalue_in_with_type(GObject.TYPE_GTYPE, GObject.TYPE_GTYPE)
+
+    // Object and interface
+    GIMarshallingTests.gvalue_in_with_type(new Gio.SimpleAction, Gio.SimpleAction);
+    GIMarshallingTests.gvalue_in_with_type(new Gio.SimpleAction, GObject.Object);
+    GIMarshallingTests.gvalue_in_with_type(new Gio.SimpleAction, GObject.TYPE_OBJECT);
+    GIMarshallingTests.gvalue_in_with_type(new Gio.SimpleAction, Gio.SimpleAction);
+
+    // Boxed and union
+    GIMarshallingTests.gvalue_in_with_type(new GLib.KeyFile, GLib.KeyFile);
+    GIMarshallingTests.gvalue_in_with_type(new GLib.KeyFile, GObject.TYPE_BOXED);
+    GIMarshallingTests.gvalue_in_with_type(GLib.Variant.new('u', 42), GLib.Variant);
+    GIMarshallingTests.gvalue_in_with_type(GLib.Variant.new('u', 42), GObject.TYPE_VARIANT);
+    GIMarshallingTests.gvalue_in_with_type(new GIMarshallingTests.BoxedStruct, GIMarshallingTests.BoxedStruct);
+    GIMarshallingTests.gvalue_in_with_type(GIMarshallingTests.union_returnv(), GIMarshallingTests.Union);
+
+    // Other
+    GIMarshallingTests.gvalue_in_with_type(GObject.ParamSpec.string('my-param', '', '', GObject.ParamFlags.READABLE, ''),
+					   GObject.TYPE_PARAM);
+}
 
 function callback_return_value_only() {
     return 42;



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