gscript r2 - trunk



Author: alexl
Date: Mon Sep  8 18:10:46 2008
New Revision: 2
URL: http://svn.gnome.org/viewvc/gscript?rev=2&view=rev

Log:
Initial import


Added:
   trunk/MAINTAINERS
   trunk/Makefile
   trunk/gscriptengine.c
   trunk/gscriptengine.h
   trunk/gscriptinternal.c
   trunk/gscriptinternal.h
   trunk/gscriptintrospect.c
   trunk/gscriptvalue.c
   trunk/gscriptvalue.h
   trunk/js-gtk.c

Added: trunk/MAINTAINERS
==============================================================================
--- (empty file)
+++ trunk/MAINTAINERS	Mon Sep  8 18:10:46 2008
@@ -0,0 +1,3 @@
+Alexander Larsson
+E-mail: alexl redhat com
+Userid: alexl

Added: trunk/Makefile
==============================================================================
--- (empty file)
+++ trunk/Makefile	Mon Sep  8 18:10:46 2008
@@ -0,0 +1,20 @@
+# These are set by default for a linux debug build in the "js" subdirectory
+# Change if your setup differs
+JSDIR=js
+JSBUILD=Linux_All_DBG.OBJ
+JSARCH=-DXP_UNIX
+
+JSINCLUDES=-I$(JSDIR)/src -I $(JSDIR)/src/$(JSBUILD)
+INCLUDES=$(JSINCLUDES) $(JSARCH)
+
+GTK_CFLAGS=`pkg-config --libs --cflags gtk+-2.0 gobject-introspection-1.0`
+
+CFLAGS=-g -O -Wall $(GTK_CFLAGS)
+
+SOURCES=gscriptinternal.c  gscriptvalue.c gscriptengine.c gscriptintrospect.c js-gtk.c
+
+js-gtk: $(SOURCES)
+	gcc -g $(CFLAGS) $(INCLUDES) $(SOURCES) $(JSDIR)/src/$(JSBUILD)/libjs.a -o js-gtk
+
+clean:
+	rm -f js-gtk

Added: trunk/gscriptengine.c
==============================================================================
--- (empty file)
+++ trunk/gscriptengine.c	Mon Sep  8 18:10:46 2008
@@ -0,0 +1,172 @@
+#include "gscriptengine.h"
+#include "gscriptinternal.h"
+#include <string.h>
+
+/**
+ * GScriptEngine:
+ * 
+ */
+struct _GScriptEngine
+{
+  GObject parent_instance;
+
+  JSContext *cx;
+  JSObject *global;
+};
+
+G_DEFINE_TYPE (GScriptEngine, g_script_engine, G_TYPE_OBJECT);
+
+static void
+g_script_engine_finalize (GObject *object)
+{
+  GScriptEngine *engine;
+
+  engine = G_SCRIPT_ENGINE (object);
+
+  JS_RemoveRoot (engine->cx, &engine->global);
+  
+  JS_DestroyContext (engine->cx);
+  engine->cx = NULL;
+
+  G_OBJECT_CLASS (g_script_engine_parent_class)->finalize (object);
+}
+
+static void
+g_script_engine_class_init (GScriptEngineClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+  gobject_class->finalize = g_script_engine_finalize;
+}
+
+static void
+error_reporter (JSContext *cx, const char *message, JSErrorReport *report)
+{
+  /* TODO: Better support for error reporting. Emit signal? */
+  fprintf(stderr, "JS error: %s\n", message);
+}
+
+static JSBool
+GC (JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+    JS_GC(cx);
+    return JS_TRUE;
+}
+
+static void
+g_script_engine_init (GScriptEngine *engine)
+{
+  jsval gtype;
+  static JSClass global_class = {
+    "global", JSCLASS_GLOBAL_FLAGS,
+    JS_PropertyStub,JS_PropertyStub,JS_PropertyStub,JS_PropertyStub,
+    JS_EnumerateStub,JS_ResolveStub,JS_ConvertStub,JS_FinalizeStub,
+    JSCLASS_NO_OPTIONAL_MEMBERS
+  };
+
+  static JSFunctionSpec global_functions[] = {
+    {"__gc",              GC,             0,0,0},
+    {NULL,NULL,0,0,0}
+  };
+  
+  
+  engine->cx = JS_NewContext (_g_script_get_runtime (), 8192);
+  JS_SetContextPrivate (engine->cx, engine);
+  
+  JS_SetOptions(engine->cx, JSOPTION_VAROBJFIX);
+  JS_SetVersion(engine->cx, JSVERSION_1_7);
+  
+  engine->global = NULL;
+  JS_AddNamedRoot (engine->cx, &engine->global, "GScriptEngine->global");
+
+  JS_SetErrorReporter(engine->cx, error_reporter);
+
+  engine->global = JS_NewObject (engine->cx, &global_class, NULL, NULL);
+  
+  JS_InitStandardClasses (engine->cx, engine->global);
+
+  gtype = OBJECT_TO_JSVAL (_g_script_get_gtype_object ());
+  if (!JS_SetProperty (engine->cx, engine->global, "GType", &gtype))
+    g_warning ("Failed to create GType global property");
+
+  /* TODO: Move these out of GScriptEngine */
+  JS_DefineFunctions (engine->cx, engine->global, global_functions);
+}
+
+/**
+ * g_script_engine_new:
+ * 
+ * Creates a new script engine
+ *
+ * Returns: a #GScriptEngine.
+ **/
+GScriptEngine *
+g_script_engine_new (void)
+{
+  return g_object_new (G_TYPE_SCRIPT_ENGINE, NULL);
+}
+
+GScriptValue *
+g_script_engine_get_global (GScriptEngine *engine)
+{
+  return _g_script_value_new_from_jsobject (engine->global);
+}
+
+GScriptValue *
+g_script_engine_evaluate_script (GScriptEngine *engine,
+				 const char *script)
+{
+  jsval rval;
+
+  /* TODO:
+     error reporting,
+     utf8-> utf16
+     filenames..
+     roots
+  */
+
+  rval = JSVAL_VOID;
+  JS_EvaluateScript (engine->cx, engine->global, script, strlen(script),
+		     "filename", 0, &rval);
+
+  return _g_script_value_new_from_jsval (rval);
+}
+
+GScriptValue *
+g_script_engine_call (GScriptEngine  *engine,
+		      GScriptValue   *this_object,
+		      GScriptValue   *function,
+		      guint           n_args,
+		      GScriptValue **args)
+{
+  jsval f, ret, *js_args;
+  GScriptValue *ret_val;
+  int i;
+  
+  if (!g_script_value_is_function (function))
+    return g_script_value_new_undefined ();
+
+  if (this_object != NULL && !g_script_value_is_object (function))
+    return g_script_value_new_undefined ();
+  
+  f = _g_script_value_get_jsval (function);
+
+  JS_AddRoot (engine->cx, &ret);
+  js_args = g_new (jsval, n_args);
+  for (i = 0; i < n_args; i++)
+    js_args[i] = _g_script_value_get_jsval (args[i]);
+
+  ret = JSVAL_VOID;
+  if (!JS_CallFunctionValue (engine->cx,
+			     (this_object != NULL) ?
+			       JSVAL_TO_OBJECT (_g_script_value_get_jsval (this_object)) :
+			       engine->global,
+			     f, n_args, 
+			     js_args, &ret))
+    g_warning ("Call failed");
+
+  g_free (js_args);
+  ret_val = _g_script_value_new_from_jsval (ret);
+  
+  return ret_val;
+}

Added: trunk/gscriptengine.h
==============================================================================
--- (empty file)
+++ trunk/gscriptengine.h	Mon Sep  8 18:10:46 2008
@@ -0,0 +1,43 @@
+#ifndef __G_SCRIPT_ENGINE_H__
+#define __G_SCRIPT_ENGINE_H__
+
+#include <glib-object.h>
+#include "gscriptvalue.h"
+
+G_BEGIN_DECLS
+
+#define G_TYPE_SCRIPT_ENGINE         (g_script_engine_get_type ())
+#define G_SCRIPT_ENGINE(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_SCRIPT_ENGINE, GScriptEngine))
+#define G_SCRIPT_ENGINE_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_SCRIPT_ENGINE, GScriptEngineClass))
+#define G_IS_SCRIPT_ENGINE(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_SCRIPT_ENGINE))
+#define G_IS_SCRIPT_ENGINE_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_SCRIPT_ENGINE))
+#define G_SCRIPT_ENGINE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_SCRIPT_ENGINE, GScriptEngineClass))
+
+typedef struct _GScriptEngineClass   GScriptEngineClass;
+typedef struct _GScriptEngine GScriptEngine;
+
+struct _GScriptEngineClass
+{
+  GObjectClass parent_class;
+
+  /* Padding for future expansion */
+  void (*_g_reserved1) (void);
+  void (*_g_reserved2) (void);
+  void (*_g_reserved3) (void);
+  void (*_g_reserved4) (void);
+  void (*_g_reserved5) (void);
+};
+
+GScriptEngine      *g_script_engine_new (void);
+GScriptValue *g_script_engine_get_global (GScriptEngine *engine);
+GScriptValue *g_script_engine_evaluate_script (GScriptEngine *engine,
+					       const char *script);
+GScriptValue *     g_script_engine_call (GScriptEngine  *engine,
+					 GScriptValue   *this_object,
+					 GScriptValue   *function,
+					 guint           n_args,
+					 GScriptValue   **args);
+
+G_END_DECLS
+
+#endif /* __G_SCRIPT_ENGINE_H__ */

Added: trunk/gscriptinternal.c
==============================================================================
--- (empty file)
+++ trunk/gscriptinternal.c	Mon Sep  8 18:10:46 2008
@@ -0,0 +1,1521 @@
+#include "gscriptinternal.h"
+#include <girepository.h>
+#include <string.h>
+
+static void finalize_signal_object (JSContext *cx,
+				    JSObject *obj);
+static JSBool lazy_enumerate_object (JSContext *cx, JSObject *obj);
+static JSBool lazy_resolve_object (JSContext *cx, JSObject *obj, jsval id,  uintN flags, JSObject **objp);
+static void jsclass_finalize_gobject (JSContext *cx,
+				      JSObject *obj);
+static JSBool lazy_enumerate_object_prototype (JSContext *cx, JSObject *obj);
+static JSBool lazy_resolve_object_prototype (JSContext *cx, JSObject *obj, jsval id,  uintN flags, JSObject **objp);
+static void jsclass_finalize_gobject_prototype (JSContext *cx,
+						JSObject *obj);
+static JSObject *ensure_class_for_gtype (GType type);
+static JSBool call_signal_object (JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
+
+typedef struct {
+  guint signal_id;
+} SignalPrivate;
+
+typedef struct {
+  GClosure	closure;
+  GScriptEngine *engine;
+  GScriptValue *function;
+} JSClosure;
+
+static JSClass signal_class = {
+  "signal", JSCLASS_HAS_PRIVATE ,
+  JS_PropertyStub,JS_PropertyStub,JS_PropertyStub,JS_PropertyStub,
+  JS_EnumerateStub,JS_ResolveStub, JS_ConvertStub, finalize_signal_object,
+  0,0,
+  call_signal_object
+};
+
+static JSClass gobject_class = {
+  "gobject",
+  JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE | JSCLASS_NEW_RESOLVE_GETS_START,
+  JS_PropertyStub,JS_PropertyStub,JS_PropertyStub,JS_PropertyStub,
+  lazy_enumerate_object,(JSResolveOp)lazy_resolve_object,
+  JS_ConvertStub, jsclass_finalize_gobject,
+};
+
+static JSClass gobject_prototype_class = {
+  "gobject_prototype",
+  JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE | JSCLASS_NEW_RESOLVE_GETS_START,
+  JS_PropertyStub,JS_PropertyStub,JS_PropertyStub,JS_PropertyStub,
+  lazy_enumerate_object_prototype,(JSResolveOp)lazy_resolve_object_prototype,
+  JS_ConvertStub, jsclass_finalize_gobject_prototype,
+};
+
+static JSBool
+throw_error (JSContext *cx, const char *format, ...)
+{
+  void *mark;
+  jsval *args;
+  jsval exc;
+  gchar *buffer;
+  va_list vargs;
+
+  va_start (vargs, format);
+  buffer = g_strdup_vprintf (format, vargs);
+  va_end (vargs);
+  
+  args = JS_PushArguments (cx, &mark, "s", buffer);
+  g_free (buffer);
+  
+  if (args)
+    {
+      if (JS_CallFunctionName (cx, JS_GetGlobalObject (cx),
+			      "Error", 1, args, &exc))
+	JS_SetPendingException (cx, exc);
+      JS_PopArguments (cx, mark);
+    }
+  
+  return JS_FALSE;
+}
+
+GObject *
+_js_object_get_gobject (JSObject *obj)
+{
+  JSContext *cx;
+  
+  cx = _g_script_get_internal_context ();
+  return JS_GetInstancePrivate (cx, obj, &gobject_class, NULL);
+}
+
+static char *
+canonical_property_name_to_js_name (const char *canonical, const char *prefix)
+{
+  char *js_name;
+  char *p;
+  int len, prefix_len;
+  
+  len = strlen (canonical);
+  prefix_len = 0;
+  if (prefix)
+    prefix_len = strlen (prefix);
+  js_name = g_malloc (len + prefix_len + 1);
+  if (prefix)
+    strcpy (js_name, prefix);
+  strcpy (js_name + prefix_len, canonical);
+  
+  for (p = js_name; *p != 0; p++)
+    {
+      if (*p == '-')
+	*p = '_';
+    }
+
+  return js_name;
+}
+
+JSRuntime *
+_g_script_get_runtime (void)
+{
+  static JSRuntime *rt = NULL;
+
+  if (rt == NULL)
+    rt = JS_NewRuntime (0x100000);
+
+  return rt;
+}
+
+static void
+list_children_types (GArray *array, GType parent)
+{
+  GType *children;
+  guint n_children, i;
+  
+  children = g_type_children (parent, &n_children);
+  g_array_append_vals (array, children, n_children);
+
+  for (i = 0; i < n_children; i++)
+    list_children_types (array, children[i]);
+  
+  g_free (children);
+}
+
+typedef struct {
+  GType *types;
+  int n_types;
+  int i;
+} GTypeList;
+
+static JSBool
+lazy_enumerate_gtype (JSContext *cx, JSObject *obj,
+		      JSIterateOp enum_op, jsval *statep, jsid *idp)
+{
+  GArray *array;
+  GTypeList *list;
+  GType t;
+
+  switch (enum_op)
+    {
+    case JSENUMERATE_INIT:
+      array = g_array_new (FALSE, FALSE, sizeof (GType));
+      t = G_TYPE_OBJECT;
+      g_array_append_val (array, t);
+      list_children_types (array, G_TYPE_OBJECT);
+
+      list = g_new (GTypeList, 1);
+      list->n_types = array->len;
+      list->types = (GType *)g_array_free (array, FALSE);
+      list->i = 0;
+
+      *statep = PRIVATE_TO_JSVAL (list);
+      if (idp)
+	*idp = INT_TO_JSVAL(list->n_types);
+      break;
+    case JSENUMERATE_NEXT:
+      list = JSVAL_TO_PRIVATE (*statep);
+      if (list->i < list->n_types)
+	{
+	  JSString *s;
+	  s = JS_NewStringCopyZ (cx, g_type_name (list->types[list->i++]));
+	  JS_ValueToId (cx, STRING_TO_JSVAL(s), idp);
+	}
+      else
+	*statep = JSVAL_NULL; 
+      break;
+    case JSENUMERATE_DESTROY:
+      list = JSVAL_TO_PRIVATE (*statep);
+      g_free (list->types);
+      g_free (list);
+      *statep = JSVAL_NULL; 
+      break;
+    }
+  return JS_TRUE;
+}
+
+static JSBool
+lazy_resolve_gtype (JSContext *cx, JSObject *obj, jsval id)
+{
+  const char *propname;
+  GType type;
+  
+  g_assert (JSVAL_IS_STRING (id));
+  
+  propname = JS_GetStringBytes (JSVAL_TO_STRING (id));
+
+  type = G_TYPE_INVALID;
+  if (propname)
+    type = g_type_from_name (propname);
+
+  if (type)
+    ensure_class_for_gtype (type);
+  
+  return JS_TRUE;
+}
+
+static JSBool
+gtype_import_namespace (JSContext *cx,
+			JSObject *obj,
+			uintN argc,
+			jsval *argv,
+			jsval *rval)
+{
+  const char *ns;
+  int i, n;
+  GIBaseInfo *info;
+  
+  if (!JSVAL_IS_STRING (argv[0]))
+    return JS_FALSE; /* TODO: Set error */
+  
+  ns = JS_GetStringBytes (JSVAL_TO_STRING (argv[0]));
+
+  g_irepository_require (g_irepository_get_default (), ns, NULL);
+
+  n = g_irepository_get_n_infos (g_irepository_get_default (), ns);
+  for (i = 0; i < n; i++)
+    {
+      info = g_irepository_get_info (g_irepository_get_default (), ns, i);
+      if (g_base_info_get_type (info) == GI_INFO_TYPE_OBJECT)
+	{
+	  GType type;
+
+	  type = g_registered_type_info_get_g_type ((GIRegisteredTypeInfo *)info);
+
+	  if (type != 0)
+	    ensure_class_for_gtype (type);
+	}
+    }
+  return JS_TRUE;
+}
+
+JSObject *
+_g_script_get_gtype_object (void)
+{
+  static JSObject *gtype = NULL;
+  static JSClass gtype_class = {
+    "gtype", JSCLASS_NEW_ENUMERATE,
+    JS_PropertyStub,JS_PropertyStub,JS_PropertyStub,JS_PropertyStub,
+    (JSEnumerateOp)lazy_enumerate_gtype, lazy_resolve_gtype,JS_ConvertStub,JS_FinalizeStub,
+    JSCLASS_NO_OPTIONAL_MEMBERS
+  };
+  static JSFunctionSpec gtype_methods[] = {
+    {"import_namespace",  gtype_import_namespace, 1,JSPROP_ENUMERATE,0},
+    {NULL,NULL,0,0,0}
+  };
+  JSContext *cx;
+
+  if (gtype == NULL)
+    {
+      cx = _g_script_get_internal_context ();
+      
+      JS_AddRoot (cx, &gtype);
+      
+      gtype = JS_NewObject (cx, &gtype_class, NULL, NULL);
+
+      JS_DefineFunctions (cx, gtype, gtype_methods);      
+
+    }
+
+  return gtype;
+}
+
+JSContext *
+_g_script_get_internal_context (void)
+{
+  JSRuntime *rt;
+  static JSContext *cx = NULL;
+  JSObject *global;
+  jsval gtype;
+  static JSClass global_class = {
+    "global", JSCLASS_GLOBAL_FLAGS,
+    JS_PropertyStub,JS_PropertyStub,JS_PropertyStub,JS_PropertyStub,
+    JS_EnumerateStub,JS_ResolveStub,JS_ConvertStub,JS_FinalizeStub,
+    JSCLASS_NO_OPTIONAL_MEMBERS
+  };
+
+  if (cx == NULL)
+    {
+      rt = _g_script_get_runtime ();
+      cx = JS_NewContext (rt, 0x1000);
+      global = JS_NewObject (cx, &global_class, NULL, NULL);
+      JS_InitStandardClasses (cx, global);
+
+      gtype = OBJECT_TO_JSVAL (_g_script_get_gtype_object ());
+      if (!JS_SetProperty (cx, global, "GType", &gtype))
+	g_error ("Unable to init GType object");
+    }
+
+  return cx;
+}
+
+static void object_toggle_notify_cb (gpointer      data,
+				     GObject      *object,
+				     gboolean      is_last_ref);
+
+
+static JSBool
+construct_object (JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+  gpointer private;
+  GType type;
+  GObject *gobject;
+  JSObject *o;
+  int i, n_params;
+  GParameter *params;
+  gboolean res;
+  GParamSpec *param_spec;
+  GObjectClass *oclass;
+  const char *propname;
+  GScriptValue *v;
+    
+  private =  JS_GetInstancePrivate (cx, JS_GetPrototype(cx, obj), &gobject_prototype_class, NULL);
+
+  if (private == NULL)
+    return throw_error (cx, "No GType for this constructor");
+
+  type = (GType)private;
+  oclass = g_type_class_peek (type);
+  
+  /* Handle construct properties */
+  
+  params = g_new0 (GParameter, (argc+1) / 2);
+
+  res = TRUE;
+  i = 0;
+  n_params = 0;
+  while (i < argc)
+    {
+      if (!JSVAL_IS_STRING (argv[i]))
+	{
+	  res = throw_error (cx, "expected string for property name");
+	  goto out;
+	}
+      propname = JS_GetStringBytes (JSVAL_TO_STRING (argv[i]));
+      i++;
+      if (i == argc)
+	{
+	  res = throw_error (cx, "no value for property %s", propname);
+	  goto out;
+	}
+
+      param_spec = g_object_class_find_property (oclass, propname);
+      if (param_spec != NULL)
+	{
+	  v = _g_script_value_new_from_jsval (argv[i]);
+	  
+	  if (!g_script_value_to_gvalue (v,
+					 G_PARAM_SPEC_VALUE_TYPE (param_spec),
+					 &params[n_params].value))
+	    {
+	      g_object_unref (v);
+	      res = throw_error (cx, "Argument of wrong type for the property %s", propname);
+	      goto out;
+	    }
+	  params[n_params++].name = propname;
+	  g_object_unref (v);
+	}
+      else
+	{
+	  res = throw_error (cx, "no such property %s", propname);
+	  goto out;
+	}
+
+      i++;
+    }
+  
+  
+  gobject = g_object_newv (type, n_params, params);
+  if (gobject == NULL)
+    {
+      res = throw_error (cx, "GObject construction failed");
+      goto out;
+    }
+
+  g_object_ref_sink (gobject);
+
+  JS_AddRoot (cx, &o);
+  if (wrap_object (gobject, &o))
+    *rval = OBJECT_TO_JSVAL (o);
+  
+  JS_RemoveRoot (cx, &o);
+  
+  g_object_unref (gobject);
+
+ out:
+  
+  for (i = 0; i < n_params; i++)
+    g_value_unset (&params[i].value);
+
+  g_free (params);
+  
+  return res;
+}
+
+static void
+jsclass_finalize_gobject_prototype (JSContext *cx,
+				    JSObject *obj)
+{
+}
+
+
+static void
+jsclass_finalize_gobject (JSContext *cx,
+			  JSObject *obj)
+{
+  GObject *wrapped_object;
+
+  wrapped_object = JS_GetPrivate (cx, obj);
+  
+  if (wrapped_object == NULL)
+    return; /* Really shouldn't happen, but lets be safe */
+
+  //g_print ("Finalizing proxy %p (wrapped object %p)\n", obj, wrapped_object);
+  
+  /* We're finalizing the js proxy object, and we're about to
+   * drop the last ref to the wrapped object, freeing it.
+   * However, its possible that the unref ressurects the
+   * wrapped object, and for that eventuallity we remove the
+   * js proxy pointer first so that it won't be around pointing
+   * to an invalid object.
+   */
+  g_object_set_data_full (wrapped_object,
+			  "js-wrapper",
+			  NULL, NULL);
+  
+  /* Release the wrapped object, freeing it */
+  g_object_remove_toggle_ref (wrapped_object,
+			      object_toggle_notify_cb,
+			      cx);
+  
+  /* At this point the private pointer of the proxy still points to
+   * the dead wrapped object, but the proxy is finalized and won't be
+   * referenced anymore, so it won't be used.
+   */
+}
+
+static JSBool
+object_get_property (JSContext *cx, JSObject *obj, jsval id, jsval *vp)
+{
+  GObject *wrapped_object;
+  char *propname;
+  GValue val = {0};
+  GParamSpec *param_spec;
+  GScriptValue *v;
+
+  g_assert (JSVAL_IS_STRING (id));
+
+  propname = JS_GetStringBytes (JSVAL_TO_STRING (id));
+
+  wrapped_object =  JS_GetInstancePrivate (cx, obj, &gobject_class, NULL);
+  if (wrapped_object == NULL)
+    return JS_TRUE; /* This may be a prototype, we can't get the property value, set to undefined */
+  
+  param_spec = g_object_class_find_property (G_OBJECT_GET_CLASS (wrapped_object),
+					     propname);
+  g_value_init (&val, G_PARAM_SPEC_VALUE_TYPE (param_spec));
+  g_object_get_property (wrapped_object,
+			 propname,
+			 &val);
+  
+  v = g_script_value_new_from_gvalue (&val);
+
+  if (v == NULL)
+    g_warning ("Failed to convert GValue of type %s in property %s", G_VALUE_TYPE_NAME (&val), propname);
+  else
+    {
+      *vp = _g_script_value_get_jsval (v);
+      g_object_unref (v);
+    }
+  
+  g_value_unset (&val);  
+  
+  return JS_TRUE;
+}
+
+static JSBool
+object_set_property (JSContext *cx, JSObject *obj, jsval id, jsval *vp)
+{
+  GObject *wrapped_object;
+  char *propname;
+  GValue val = {0};
+  GParamSpec *param_spec;
+  GScriptValue *v;
+
+  wrapped_object =  JS_GetInstancePrivate (cx, obj, &gobject_class, NULL);
+  if (wrapped_object == NULL)
+    return JS_TRUE; /* Ignore proxies and wrong types */
+  
+  if (!JSVAL_IS_STRING (id))
+    return JS_TRUE; /* Not a string, so not a gobject property */
+  
+  propname = JS_GetStringBytes (JSVAL_TO_STRING (id));
+
+  param_spec = g_object_class_find_property (G_OBJECT_GET_CLASS (wrapped_object),
+					     propname);
+  if (param_spec != NULL)
+    {
+      v = _g_script_value_new_from_jsval (*vp);
+      
+      /* TODO: Convert v to type of param_spec and put in val */
+      if (!g_script_value_to_gvalue (v,
+				     G_PARAM_SPEC_VALUE_TYPE (param_spec),
+				     &val))
+	{
+	  g_object_unref (v);
+	  return throw_error (cx, "Argument of wrong type for the property %s", propname); 
+	}
+      g_object_set_property (wrapped_object,
+			     propname,
+			     &val);
+      g_object_unref (v);
+      g_value_unset (&val);
+    }
+  
+  return JS_TRUE;
+}
+
+static gboolean
+define_property_from_paramspec (JSContext *cx, JSObject *obj, GParamSpec *param_spec)
+{
+  static GQuark qname = 0;
+  guint attrs;
+  char *js_name;
+
+  if (qname == 0)
+    qname = g_quark_from_static_string ("js-defined-property");
+
+  if (g_param_spec_get_qdata (param_spec, qname) != NULL)
+    return FALSE; /* Already defined, ignore request */
+  
+  g_param_spec_set_qdata (param_spec, qname, (gpointer)1);
+  
+  if (param_spec->flags & G_PARAM_CONSTRUCT_ONLY)
+    return FALSE;
+  
+  attrs = JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED;
+  
+  if ((param_spec->flags & G_PARAM_WRITABLE) == 0)
+    attrs |= JSPROP_READONLY;
+
+  js_name = canonical_property_name_to_js_name (param_spec->name, NULL);
+  
+  /* If this fails we just don't find this property, not
+     much we can do. Better luck next time. */
+  JS_DefineProperty (cx, obj,
+		     js_name,
+		     JSVAL_VOID,
+		     object_get_property,
+		     object_set_property,
+		     attrs);
+
+  g_free (js_name);
+  
+  return TRUE;
+}
+
+static void
+finalize_signal_object (JSContext *cx,
+			JSObject *obj)
+{
+  SignalPrivate *private;
+  
+  private = JS_GetPrivate (cx, obj);
+  g_free (private);
+}
+
+static void
+free_js_closure (gpointer	 data,
+		 GClosure	*closure)
+{
+  JSClosure *js_closure = (JSClosure *)closure;
+
+  g_object_unref (js_closure->engine);
+  g_object_unref (js_closure->function);
+}
+
+static void
+signal_closure_marshal_func (GClosure	*closure,
+			     GValue     *return_value,
+			     guint       n_param_values,
+			     const GValue   *param_values,
+			     gpointer    invocation_hint,
+			     gpointer	 marshal_data)
+{
+  JSClosure *js_closure = (JSClosure *)closure;
+  GScriptValue *ret;
+  GScriptValue **args;
+  int i;
+  
+  args = g_new0 (GScriptValue *, n_param_values);
+
+  for (i = 0; i < n_param_values; i++)
+    {
+      args[i] = g_script_value_new_from_gvalue ((GValue *)&param_values[i]);
+      
+      if (args[i] == NULL)
+	{
+	  g_print ("Failed to convert arg %d in signal emission\n", i);
+	  args[i] = g_script_value_new_undefined ();
+	}
+    }
+  
+  ret = g_script_engine_call (js_closure->engine,
+			      args[0],
+			      js_closure->function,
+			      n_param_values - 1,
+			      args+1);
+
+  for (i = 0; i < n_param_values; i++)
+    g_object_unref (args[i]);
+  
+  g_free (args);
+}
+
+static JSBool
+call_signal_object (JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+  JSObject *proxy_object;
+  GObject *wrapped_object;
+  SignalPrivate *private;
+  GScriptValue *v;
+  GValue *args;
+  GValue retv = {0};
+  int i;
+  GSignalQuery query;
+  GType type;
+  gboolean types_ok;
+  JSObject *signal_object;
+
+  /* This is the object that contains the signal, the actual signal
+     object is found at argv[-2] as the Function object */
+  signal_object = JSVAL_TO_OBJECT (argv[-2]);
+
+  private = JS_GetInstancePrivate (cx, signal_object, &signal_class, argv);
+  if (private == NULL)
+    return JS_FALSE;
+
+  proxy_object = JS_GetParent (cx, signal_object); /* TODO: Verify ok (maybe we can set it non-modifiable) */
+  
+  wrapped_object = JS_GetInstancePrivate (cx, proxy_object, &gobject_class, NULL);
+  if (wrapped_object == NULL)
+    return JS_FALSE;
+
+  g_signal_query (private->signal_id, &query);
+
+  if (argc < query.n_params)
+    return throw_error (cx, "Too few arguments to signal %s", query.signal_name); 
+  
+  args = g_new0 (GValue, query.n_params + 1);
+  
+  g_value_init (&args[0], G_OBJECT_TYPE (wrapped_object));
+  g_value_set_object (&args[0], wrapped_object);
+
+  types_ok = TRUE;
+  for (i = 0; types_ok && i < query.n_params; i++)
+    {
+      v = _g_script_value_new_from_jsval (argv[i]);
+      
+      type = query.param_types[i] & ~G_SIGNAL_TYPE_STATIC_SCOPE;
+      
+      if (!g_script_value_to_gvalue (v, type, &args[i+1]))
+	types_ok = FALSE;
+
+      g_object_unref (v);
+    }
+
+  if (types_ok)
+    {
+      type = query.return_type & ~G_SIGNAL_TYPE_STATIC_SCOPE;
+      if (type != G_TYPE_NONE)
+	g_value_init (&retv, type);
+      
+      g_signal_emitv (args, private->signal_id, 0, &retv);
+
+      if (type != G_TYPE_NONE)
+	{
+	  v = g_script_value_new_from_gvalue (&retv);
+	  if (v)
+	    {
+	      *rval = _g_script_value_get_jsval (v);
+	      g_object_unref (v);
+	    }
+	  else
+	    *rval = JSVAL_VOID;
+	  
+	  g_value_unset (&retv);
+	}
+      else
+	*rval = JSVAL_VOID;
+    }
+  else
+    *rval = JSVAL_VOID;
+
+  for (i = 0; i < query.n_params+1; i++)
+    g_value_unset (&args[i]);
+
+  g_free (args);
+      
+  return JS_TRUE;
+}
+
+
+static JSBool
+signal_object_connect (JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+  JSObject *proxy_object;
+  GObject *wrapped_object;
+  SignalPrivate *private;
+  GClosure *closure;
+  gulong res;
+
+  private = JS_GetInstancePrivate (cx, obj, &signal_class, argv);
+  if (private == NULL)
+    return JS_FALSE;
+  
+  if (argv[0] == JSVAL_NULL ||
+      !JSVAL_IS_OBJECT (argv[0]) ||
+      !JS_ObjectIsFunction(cx, JSVAL_TO_OBJECT (argv[0])))
+    return JS_FALSE; /* TODO: Set error */
+  
+  proxy_object = JS_GetParent (cx, obj); /* TODO: Verify ok (maybe we can set it non-modifiable) */
+  
+  wrapped_object = JS_GetInstancePrivate (cx, proxy_object, &gobject_class, NULL);
+  if (wrapped_object == NULL)
+    return JS_FALSE;
+
+  closure = g_closure_new_simple (sizeof (JSClosure), NULL);
+  g_closure_set_marshal (closure, signal_closure_marshal_func);
+  g_closure_add_finalize_notifier (closure, NULL, free_js_closure);
+  ((JSClosure *)closure)->engine = JS_GetContextPrivate (cx);
+  ((JSClosure *)closure)->function = _g_script_value_new_from_jsval (argv[0]);
+  
+  res = g_signal_connect_closure_by_id (wrapped_object,
+					private->signal_id,
+					0 /* detail */,
+					closure,
+					FALSE /* after */);
+
+  return JS_TRUE;
+}
+
+static JSBool
+signal_object_to_string (JSContext *cx,
+			 JSObject *obj,
+			 uintN argc,
+			 jsval *argv,
+			 jsval *rval)
+{
+  SignalPrivate *private;
+  GObject *wrapped_object;
+  char *str;
+  GScriptValue *v;
+  GSignalQuery query;
+  JSObject *proxy_object;
+
+  str = NULL;
+  
+  private =  JS_GetInstancePrivate (cx, obj, &signal_class, NULL);
+  if (private == NULL)
+    return JS_FALSE;
+
+  proxy_object = JS_GetParent (cx, obj); /* TODO: Verify ok (maybe we can set it non-modifiable) */
+  wrapped_object = JS_GetInstancePrivate (cx, proxy_object, &gobject_class, NULL);
+
+  g_signal_query (private->signal_id, &query);
+  str = g_strdup_printf ("[signal %s on %s %p]",
+			 query.signal_name,
+			 g_type_name (G_OBJECT_TYPE (wrapped_object)),
+			 wrapped_object);
+
+  v = g_script_value_new_from_string (str);
+  *rval = _g_script_value_get_jsval (v);
+  g_object_unref (v);
+  g_free (str);
+  
+  return TRUE;
+}
+
+
+static void
+define_property_for_signal (JSContext *cx, JSObject *obj, const char *name, guint signal_id)
+{
+  guint attrs;
+  JSObject *signal_object, *proto;
+  SignalPrivate *private;
+  char *js_name;
+      
+  attrs = JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY;
+
+  /* If this fails we just don't find this property, not
+     much we can do. Better luck next time. */
+
+  js_name = canonical_property_name_to_js_name (name, "on_");
+
+  signal_object = JS_DefineObject (cx, obj, js_name, &signal_class, NULL, attrs);
+  
+  g_free (js_name);
+
+  if (signal_object != NULL)
+    {
+      private = g_new (SignalPrivate, 1);
+      private->signal_id = signal_id;
+      JS_SetPrivate (cx, signal_object, private);
+      
+      proto = JS_GetPrototype (cx, signal_object);
+
+      JS_DefineFunction (cx, proto, 
+			 "connect", signal_object_connect, 1, JSPROP_ENUMERATE);
+      JS_DefineFunction (cx, proto, 
+			 "toString", signal_object_to_string, 1, JSPROP_ENUMERATE);
+    }
+}
+
+static JSBool
+invoke_method (JSContext *cx,
+	       JSObject *obj,
+	       uintN argc,
+	       jsval *argv,
+	       jsval *rval)
+{
+  GObject *wrapped_object;
+  GIFunctionInfo **infop, *info;
+  jsval v;
+  GError *error;
+  GArgument retval;
+  GArgument *in_args;
+  GArgument *out_args;
+  int n_args, n_in_args, n_out_args, i;
+  GIArgInfo *arg_info;
+  GITypeInfo *type_info;
+  GIDirection dir;
+  gboolean result;
+  GScriptValue *script_value;
+  char *err_str;
+
+  wrapped_object =  JS_GetInstancePrivate (cx, obj, &gobject_class, NULL);
+  if (wrapped_object == NULL)
+    return throw_error (cx, "Invoking GObject method on non-GObject");
+
+  if (!JS_GetReservedSlot (cx, JS_GetFunctionObject (JS_ValueToFunction (cx, argv[-2])), 0, &v))
+    return throw_error (cx, "No method info availible for function call");
+
+  infop = JSVAL_TO_PRIVATE (v);
+  info = *infop;
+
+  n_args = g_callable_info_get_n_args ((GICallableInfo *)info);
+  g_assert (argc + 1 >= n_args);
+				 
+  in_args = g_new0 (GArgument, n_args);
+  out_args = g_new0 (GArgument, n_args);
+  n_in_args = 0;
+  n_out_args = 0;
+
+  /* Here we just assume that the first arg is the this pointer, and
+     that it has the right type. That should be OK unless the code
+     does weird stuff.
+     TODO: We could check the type here to avoid weird errors */
+  in_args[n_in_args++].v_pointer = wrapped_object;
+
+  result = TRUE;
+  for (i = 0; result && (i < (n_args - 1)); i++)
+    {
+      arg_info = g_callable_info_get_arg ((GICallableInfo *)info, i+1);
+
+      dir = g_arg_info_get_direction (arg_info);
+      type_info = g_arg_info_get_type (arg_info);
+      
+      if (dir == GI_DIRECTION_IN)
+	{
+	  script_value = _g_script_value_new_from_jsval (argv[i]);
+	  if (_g_script_convert_js_to_arg (script_value,
+					   type_info,
+					   &in_args[n_in_args],
+					   g_arg_info_may_be_null (arg_info),
+					   &err_str))
+	    {
+	      /* converted to in_args */
+	      n_in_args ++;
+	    }
+	  else
+	    {
+	      throw_error (cx, err_str);
+	      result = FALSE;
+	    }
+	  g_object_unref (script_value);
+	}
+      else if (dir == GI_DIRECTION_OUT)
+	{
+	  /* TODO */
+	  throw_error (cx, "Out params not supported");
+	  result = FALSE;
+	}
+      else /* IN_OUT */
+	{
+	  /* TODO */
+	  throw_error (cx, "In/Out params not supported");
+	  result = FALSE;
+	}
+    }
+
+  error = NULL;
+  if (result)
+    {
+      if (g_function_info_invoke (info,
+				  in_args,
+				  n_in_args,
+				  out_args,
+				  n_out_args,
+				  &retval,
+				  &error))
+	{
+	  GScriptValue *grval;
+	  GITransfer caller_owns;
+	  
+	  grval = NULL;
+	  type_info = g_callable_info_get_return_type ((GICallableInfo *)info);
+	  if (g_type_info_get_tag (type_info) == GI_TYPE_TAG_VOID)
+	    {
+	      *rval = JSVAL_VOID;
+	    }
+	  else
+	    {
+	      if (_g_script_convert_arg_to_js (&retval,
+					       type_info,
+					       &grval,
+					       &err_str))
+		{
+		  *rval = _g_script_value_get_jsval (grval);
+		  g_object_unref (grval);
+		}
+	      else
+		{
+		  throw_error (cx, err_str);
+		  result = FALSE;
+		}
+
+	      caller_owns = g_callable_info_get_caller_owns ((GICallableInfo *)info);
+	      if (caller_owns == GI_TRANSFER_CONTAINER)
+		{
+		  /* Free retval shallow */
+		  _g_script_arg_free (&retval, type_info, FALSE);
+		}
+	      else if (caller_owns == GI_TRANSFER_EVERYTHING)
+		{
+		  /* Free retval deep */
+		  _g_script_arg_free (&retval, type_info, TRUE);
+		}
+	    }
+	}
+      else
+	{
+	  throw_error (cx, error->message);
+	  g_error_free (error);
+	  result = FALSE;
+	}
+    }
+
+  for (i = 1; i < n_args; i++)
+    {
+      GITransfer called_owns;
+      
+      arg_info = g_callable_info_get_arg ((GICallableInfo *)info, i);
+      
+      called_owns = g_arg_info_get_ownership_transfer (arg_info);
+      type_info = g_arg_info_get_type (arg_info);
+
+      /* TODO: Check out exactly what these means,
+	 transfer_container can't really mean the called function owns
+	 the contaner but not its contents... really... */
+      if (called_owns == GI_TRANSFER_NOTHING)
+	_g_script_arg_free (&in_args[i], type_info, TRUE /* deep? */);
+      else if (called_owns == GI_TRANSFER_CONTAINER)
+	_g_script_arg_free (&in_args[i], type_info, FALSE /* deep? */);
+      /* GI_TRANSFER_EVERYTHING -> don't free, called_owns */
+	
+    }
+
+  g_free (in_args);
+  
+  /* TODO: Free the out args */
+  
+  g_free (out_args);
+  
+  return result;
+}
+
+static gboolean
+define_property_from_function_info (JSContext *cx,
+				    JSObject *obj,
+				    GIFunctionInfo *info)
+{
+  JSFunction *f;
+  JSObject *f_obj;
+  GIFunctionInfo **infop;
+  GScriptValue *symbol;
+  jsval v;
+  GIFunctionInfoFlags flags;
+  int n_args, i;
+  GIArgInfo *arg_info;
+  GITypeInfo *type_info;
+  GIDirection dir;
+  const char *symbol_name;
+  static const char *hidden_symbols[] = {
+    "g_object_ref",
+    "g_object_ref_sink",
+    "g_object_unref",
+    "gtk_object_ref",
+    "gtk_object_unref",
+    "gtk_object_weakref",
+    "gtk_object_weakunref",
+    "gtk_object_sink",
+    "gtk_object_set",
+    "gtk_object_get",
+    "gtk_object_set_data",
+    "gtk_object_set_data_full",
+    "gtk_object_remove_data",
+    "gtk_object_get_data",
+    "gtk_object_remove_no_notify",
+    "gtk_object_set_user_data",
+    "gtk_object_get_user_data",
+    "gtk_object_set_data_by_id",
+    "gtk_object_set_data_by_id_full",
+    "gtk_object_get_data_by_id",
+    "gtk_object_remove_data_by_id",
+    "gtk_object_remove_no_notify_by_id",
+    "gtk_object_add_arg_type",
+    "gtk_widget_ref",
+    "gtk_widget_unref",
+    "gtk_widget_set",
+    NULL
+  };
+
+  /* Check if we should allow this and if not return FALSE */
+
+  if (g_base_info_is_deprecated ((GIBaseInfo *)info))
+    return FALSE;
+
+  flags = g_function_info_get_flags (info);
+
+  if ((flags & GI_FUNCTION_IS_CONSTRUCTOR) ||
+      (flags & GI_FUNCTION_IS_GETTER) ||
+      (flags & GI_FUNCTION_IS_SETTER))
+    return FALSE;
+
+  n_args = g_callable_info_get_n_args ((GICallableInfo *)info);
+
+  for (i = 1; i < n_args; i++)
+    {
+      arg_info = g_callable_info_get_arg ((GICallableInfo *)info, i);
+
+      dir = g_arg_info_get_direction (arg_info);
+      if (dir == GI_DIRECTION_OUT ||
+	  dir == GI_DIRECTION_INOUT)
+	{
+	  //g_print ("hiding %s (non-in)\n", g_base_info_get_name ((GIBaseInfo *)info));
+	  return FALSE; /* non-in args not yet supported */
+	}
+	  
+      type_info = g_arg_info_get_type (arg_info);
+
+      if (!_g_script_convert_type_supported (type_info))
+	{
+	  //g_print ("hiding %s (arg type) %s\n", g_base_info_get_name ((GIBaseInfo *)info), g_function_info_get_symbol (info));
+	  return FALSE;
+	}
+    }
+
+  symbol_name = g_function_info_get_symbol (info);
+  for (i = 0; hidden_symbols[i] != NULL; i++)
+    {
+      if (strcmp (symbol_name, hidden_symbols[i]) == 0)
+	return FALSE;
+    }
+  
+  f = JS_DefineFunction (cx, obj, g_base_info_get_name ((GIBaseInfo *)info),
+			 invoke_method,
+			 g_callable_info_get_n_args ((GICallableInfo *)info) - 1,
+			 JSPROP_ENUMERATE);
+
+  infop = g_new (GIFunctionInfo *, 1);
+  g_assert (((int)infop) % 2 == 0);
+  *infop = info;
+
+  f_obj = JS_GetFunctionObject (f);
+
+  symbol = g_script_value_new_from_string (symbol_name);
+  v = _g_script_value_get_jsval (symbol);
+  JS_SetProperty (cx, f_obj, "symbol", &v);
+  g_object_unref (symbol);
+  
+  if (!JS_SetReservedSlot (cx, f_obj, 0, PRIVATE_TO_JSVAL (infop)))
+    g_warning ("Unable to set reserved slot of function");
+  
+  return TRUE;
+  
+}
+
+
+static JSBool
+lazy_enumerate_object_prototype (JSContext *cx, JSObject *obj)
+{
+  JSClass *class;
+  GType type;
+  GParamSpec **param_specs;
+  GObjectClass *oclass;
+  guint n, i;
+  gpointer private;
+  GIBaseInfo *info;
+
+  private =  JS_GetInstancePrivate (cx, obj, &gobject_prototype_class, NULL);
+  if (private == NULL)
+    return JS_TRUE;
+
+  class = JS_GetClass (obj);
+  type = (GType)private;
+  oclass = g_type_class_ref (type);
+  
+  param_specs = g_object_class_list_properties (oclass, &n);
+  if (param_specs != NULL)
+    {
+      for (i = 0; i < n; i++)
+	define_property_from_paramspec (cx, obj, param_specs[i]);
+    }
+  
+  g_type_class_unref (oclass);
+
+  info = g_irepository_find_by_gtype (g_irepository_get_default (),
+				      type);
+  if (info != NULL)
+    {
+      GIFunctionInfo *function;
+      int n_methods;
+      
+      g_assert (g_base_info_get_type (info) == GI_INFO_TYPE_OBJECT);
+      
+      n_methods = g_object_info_get_n_methods ((GIObjectInfo *)info);
+      for (i = 0; i < n_methods; i++)
+	{
+	  function = g_object_info_get_method ((GIObjectInfo *)info, i);
+	  define_property_from_function_info (cx, obj, function);
+	}
+    }
+  
+  return JS_TRUE;
+}
+
+static JSBool
+lazy_enumerate_object (JSContext *cx, JSObject *obj)
+{
+  GType type;
+  GObject *wrapped_object;
+  guint n, i;
+  guint *signal_ids;
+  GSignalQuery query;
+
+  wrapped_object =  JS_GetInstancePrivate (cx, obj, &gobject_class, NULL);
+  if (wrapped_object == NULL)
+    return JS_TRUE;
+
+  /* This is a proxy object, not a prototype.
+   * We want to set the properties on the prototypes instead
+   * of the object proxies themselves.
+   * However, the signal objects go on the object itself, due
+   * to the back-reference required for e.g. connect().
+   */
+  type = G_OBJECT_TYPE (wrapped_object);
+  while (type != 0)
+    {
+      signal_ids = g_signal_list_ids (type, &n);
+      for (i = 0; i < n; i++)
+	{
+	  g_signal_query (signal_ids[i], &query);
+	  if (query.signal_id != 0)
+	    define_property_for_signal (cx, obj, query.signal_name, signal_ids[i]);
+	}
+      g_free (signal_ids);
+      type = g_type_parent (type);
+    }
+  
+  return JS_TRUE;
+}
+
+static JSBool
+lazy_resolve_object_prototype (JSContext *cx, JSObject *obj, jsval id,  uintN flags, JSObject **objp)
+{
+  gpointer private;
+  char *propname;
+  GParamSpec *param_spec;
+  GObjectClass *oclass;
+  guint sig_id;
+  GType type;
+  GIBaseInfo *info;
+
+  private = JS_GetInstancePrivate (cx, obj, &gobject_prototype_class, NULL);
+  if (private == NULL)
+    return JS_TRUE;
+  g_assert (JSVAL_IS_STRING (id));
+
+  type = (GType)private;
+
+  /* Look at properties */
+  
+  propname = JS_GetStringBytes (JSVAL_TO_STRING (id));
+
+  oclass = g_type_class_ref (type);
+  
+  param_spec = g_object_class_find_property (oclass, propname);
+
+  if (param_spec != NULL)
+    {
+      define_property_from_paramspec (cx, obj, param_spec);
+      g_type_class_unref (oclass);
+      *objp = obj; /* Signal success */
+      return JS_TRUE;
+    }
+  
+  g_type_class_unref (oclass);
+
+  /* Look at signals */
+
+  sig_id = 0;
+  if (propname[0] == 'o' && propname[1] == 'n' && propname[2] == '_')
+    sig_id = g_signal_lookup (propname+3, type);
+
+  if (sig_id != 0)
+    {
+      /* *objp here is the original object, not the prototype */
+      define_property_for_signal (cx, *objp, propname+3, sig_id);
+      /* No need to set *objp, as its already right */
+      return JS_TRUE;
+    }
+
+  /* Look at methods (via GObject Introspection) */
+
+  info = g_irepository_find_by_gtype (g_irepository_get_default (),
+				      type);
+  if (info != NULL)
+    {
+      GIFunctionInfo *function;
+      
+      g_assert (g_base_info_get_type (info) == GI_INFO_TYPE_OBJECT);
+      
+      function = g_object_info_find_method ((GIObjectInfo *)info, propname);
+
+      if (function &&
+	  define_property_from_function_info (cx, obj, function))
+	{
+	  *objp = obj; /* Signal success */
+	  return JS_TRUE;
+	}
+    }
+  
+  *objp = NULL; /* Signal no such property */
+  return JS_TRUE;
+}
+
+
+static JSBool
+lazy_resolve_object (JSContext *cx, JSObject *obj, jsval id,  uintN flags, JSObject **objp)
+{
+  GObject *wrapped_object;
+
+  wrapped_object =  JS_GetInstancePrivate (cx, obj, &gobject_class, NULL);
+  if (wrapped_object == NULL)
+    {
+      *objp = NULL; /* Signal no such property */
+      return JS_TRUE;
+    }
+  
+  /* This is a proxy object, not a prototype.
+     We want to set the properties on the prototypes instead
+     of the object proxies themselves, so just return */
+  
+  *objp = NULL; /* Signal no such property */
+  
+  return JS_TRUE;
+}
+
+static JSBool
+gobject_to_string (JSContext *cx,
+		   JSObject *obj,
+		   uintN argc,
+		   jsval *argv,
+		   jsval *rval)
+{
+  GObject *wrapped_object;
+  gpointer private;
+  GType type;
+  char *str;
+  GScriptValue *v;
+
+  str = NULL;
+  
+  wrapped_object =  JS_GetInstancePrivate (cx, obj, &gobject_class, NULL);
+  if (wrapped_object != NULL)
+    {
+      str = g_strdup_printf ("[%s %p]",
+			     g_type_name (G_OBJECT_TYPE (wrapped_object)),
+			     wrapped_object);
+    }
+  else
+    {
+      private =  JS_GetInstancePrivate (cx, obj, &gobject_prototype_class, NULL);
+      if (private != NULL)
+	{
+	  type = (GType)private;
+	  str = g_strdup_printf ("[class %s]",
+				 g_type_name (type));
+	}
+    }
+
+  if (str != NULL)
+    {
+      v = g_script_value_new_from_string (str);
+      *rval = _g_script_value_get_jsval (v);
+      g_object_unref (v);
+      g_free (str);
+    }
+  else
+    *rval = JSVAL_VOID;
+  
+  return TRUE;
+}
+
+static JSFunctionSpec gobject_methods[] = {
+  {"toString",  gobject_to_string,             0,JSPROP_ENUMERATE, 0},
+  {NULL,NULL,0,0,0}
+};
+
+
+static JSObject * /* value always rooted by the GType */
+ensure_class_for_gtype (GType type)
+{
+  GType parent;
+  JSContext *cx;
+  JSObject *gtype_object;
+  JSObject *parent_proto;
+  static GQuark qname = 0;
+  JSObject **qdata;
+  const char *old_name;
+
+  if (qname == 0)
+    qname = g_quark_from_static_string ("js-defined-type");
+
+  if ((qdata = g_type_get_qdata (type, qname)) != NULL)
+    {
+      /* We've already created this class... */
+      return *qdata;
+    }
+  
+  cx = _g_script_get_internal_context ();
+  gtype_object = _g_script_get_gtype_object ();
+
+  qdata = g_new0 (JSObject *, 1);
+  if (!JS_AddRoot (cx, qdata))
+    {
+      g_warning ("failed to root type qdata");
+      g_free (qdata);
+      return NULL;
+    }
+
+  parent_proto = NULL;
+  parent = g_type_parent (type);
+  if (parent != 0)
+    {
+      parent_proto = ensure_class_for_gtype (parent);
+      if (parent_proto == NULL)
+	{
+	  g_warning ("failed to root type qdata");
+	  JS_RemoveRoot (cx, qdata);
+	  g_free (qdata);
+	  return NULL;
+	}
+    }
+
+  /* Temporarily set the class name so we create a constructor
+     with the right name. Then change back to the old one. This is
+     not threadsafe, but then we're not using the threadsafe
+     spidermonkey stuff either. */
+  old_name = gobject_prototype_class.name;
+  gobject_prototype_class.name = g_type_name (type);
+  *qdata = JS_InitClass (cx, gtype_object, parent_proto,
+			 &gobject_prototype_class,
+			 construct_object, 0 /* TODO: uintN nargs for constructor */,
+			 NULL, NULL, //JSPropertySpec *ps, JSFunctionSpec *fs,
+			 NULL, NULL //JSPropertySpec *static_ps, JSFunctionSpec *static_fs
+			 );
+
+  if (type == G_TYPE_OBJECT)
+    JS_DefineFunctions (cx, *qdata, gobject_methods);      
+  
+  gobject_prototype_class.name = old_name;
+  
+
+  if (*qdata)
+    JS_SetPrivate (cx, *qdata, (gpointer)type);
+
+  g_type_set_qdata (type, qname, qdata);
+
+  return *qdata;
+}
+
+static void
+object_toggle_notify_cb (gpointer      data,
+			 GObject      *object,
+			 gboolean      is_last_ref)
+{
+  JSObject **user_data;
+  JSContext *cx;
+  
+  user_data = g_object_get_data (object, "js-wrapper");
+
+  //g_print ("toggle notify is_last_ref=%d for wrapped object %p (proxy %p)\n", is_last_ref, object, *user_data);
+
+  
+  /* TODO: How do we know the context is still around?? (and not in use elsewhere?) */
+  cx = data;
+  
+  if (is_last_ref)
+    {
+      /* By now the only ref to the wrapped object is the js proxy.
+       * We drop the root for that to allow it to be collected when
+       * the last ref to the proxy goes away on the JS side.
+       * When this happens we free the wrapped object.
+       */
+      JS_RemoveRoot (cx, user_data);
+    }
+  else
+    {
+      /* Oh, but before the above happened the object got another ref, so
+       * we root the proxy again to keep it alive for as long as the wrapped
+       * object lives, to ensure we keep around any important data stored
+       * on the proxy object
+       */
+      JS_AddRoot (cx, user_data);
+    }
+
+}
+
+gboolean
+wrap_object (GObject *object,
+	     JSObject **res /* Should be rooted */
+	     )
+{
+  GType type;
+  JSObject *class_prototype;
+  JSObject **user_data;
+  JSContext *cx;
+
+  /* check if already wrapped */
+  user_data = g_object_get_data (object, "js-wrapper");
+  if (user_data != NULL)
+    {
+      *res = *user_data;
+      return TRUE;
+    }
+
+  cx = _g_script_get_internal_context ();
+  
+  type = G_OBJECT_TYPE (object);
+
+  class_prototype = ensure_class_for_gtype (type);
+  
+  /* No need for gc roots, as the class_property lives with the gtype */
+  if (class_prototype == NULL)
+    return FALSE;
+
+  user_data = g_new0 (JSObject *, 1);
+  
+  if (!JS_AddRoot (cx, user_data))
+    {
+      g_free (user_data);
+      return FALSE;
+    }
+
+  g_object_set_data_full (object,
+			  "js-wrapper",
+			  user_data, g_free);
+  
+  *user_data = JS_NewObject (cx, &gobject_class, class_prototype, NULL);
+  
+  if (*user_data == NULL ||
+      !JS_SetPrivate (cx, *user_data, object))
+    {
+      g_object_set_data (object,
+			 "js-wrapper",
+			 NULL);
+      JS_RemoveRoot (cx, user_data);
+      g_free (user_data);
+      return FALSE;
+    }
+
+  /* We succeeded in wrapping the object, now ref it with a toggle ref */
+  
+  g_object_add_toggle_ref (object,
+			   object_toggle_notify_cb,
+			   cx /* TODO: How to ensure lifetime of the cx object? */
+			   ); 
+
+  /* We now have a strong ref in both ways, and both objects
+     point to each other. In the toggle ref callback we drop the
+     GC root to the proxy object if there is only the toggle ref
+     to ensure we can collect the two objects */
+
+  *res = *user_data;
+  return TRUE;
+}

Added: trunk/gscriptinternal.h
==============================================================================
--- (empty file)
+++ trunk/gscriptinternal.h	Mon Sep  8 18:10:46 2008
@@ -0,0 +1,37 @@
+#ifndef __G_SCRIPT_INTERNAL_H__
+#define __G_SCRIPT_INTERNAL_H__
+
+#include <jsapi.h>
+#include "gscriptvalue.h"
+#include "gscriptengine.h"
+#include <girepository.h>
+
+JSRuntime *_g_script_get_runtime (void);
+JSContext *_g_script_get_internal_context (void);
+JSObject *_g_script_get_gtype_object (void);
+jsval _g_script_value_get_jsval (GScriptValue *value);
+GScriptValue * _g_script_value_new_from_jsval (jsval value);
+GScriptValue * _g_script_value_new_from_jsobject (JSObject *obj);
+GObject * _js_object_get_gobject (JSObject *obj);
+
+gboolean wrap_object (GObject *object,
+		      JSObject **res /* Should be rooted */
+		      );
+
+/* Introspection arg conversion: */
+gboolean _g_script_convert_type_supported (GITypeInfo *type_info);
+gboolean _g_script_convert_js_to_arg (GScriptValue *value,
+				      GITypeInfo *type_info,
+				      GArgument *arg,
+				      gboolean may_be_null,
+				      char **error);
+gboolean _g_script_convert_arg_to_js (GArgument *arg,
+				      GITypeInfo *type_info,
+				      GScriptValue **value,
+				      char **error);
+void     _g_script_arg_free          (GArgument *arg,
+				      GITypeInfo *type_info,
+				      gboolean free_deep);
+
+
+#endif /* __G_SCRIPT_INTERNAL_H__ */

Added: trunk/gscriptintrospect.c
==============================================================================
--- (empty file)
+++ trunk/gscriptintrospect.c	Mon Sep  8 18:10:46 2008
@@ -0,0 +1,477 @@
+#include "gscriptinternal.h"
+
+gboolean
+_g_script_convert_type_supported (GITypeInfo *type_info)
+{
+  GITypeTag type_tag;
+
+  type_tag = g_type_info_get_tag (type_info);
+
+  switch (type_tag)
+    {
+    case GI_TYPE_TAG_VOID:
+    case GI_TYPE_TAG_BOOLEAN:
+    case GI_TYPE_TAG_INT8:
+    case GI_TYPE_TAG_UINT8:
+    case GI_TYPE_TAG_INT16:
+    case GI_TYPE_TAG_UINT16:
+    case GI_TYPE_TAG_INT32:
+    case GI_TYPE_TAG_UINT32:
+    case GI_TYPE_TAG_INT64:
+    case GI_TYPE_TAG_UINT64:
+    case GI_TYPE_TAG_INT:
+    case GI_TYPE_TAG_UINT:
+    case GI_TYPE_TAG_LONG:
+    case GI_TYPE_TAG_ULONG:
+    case GI_TYPE_TAG_SSIZE:
+    case GI_TYPE_TAG_SIZE:
+    case GI_TYPE_TAG_FLOAT:
+    case GI_TYPE_TAG_DOUBLE:
+    case GI_TYPE_TAG_UTF8:
+      return TRUE;
+      
+    case GI_TYPE_TAG_FILENAME:
+    case GI_TYPE_TAG_ARRAY:
+    case GI_TYPE_TAG_GLIST:
+    case GI_TYPE_TAG_GSLIST:
+    case GI_TYPE_TAG_GHASH:
+    case GI_TYPE_TAG_ERROR:
+      return FALSE;
+      
+    case GI_TYPE_TAG_INTERFACE:
+      {
+	GIBaseInfo *interface;
+	GIInfoType interface_type;
+	
+	interface = g_type_info_get_interface (type_info);
+	interface_type = g_base_info_get_type (interface);
+
+	if (interface_type == GI_INFO_TYPE_OBJECT)
+	  return TRUE;
+	
+	return FALSE;
+      }
+    }
+  
+  return FALSE;
+}
+
+gboolean
+_g_script_convert_js_to_arg (GScriptValue *value,
+			     GITypeInfo *type_info,
+			     GArgument *arg,
+			     gboolean may_be_null,
+			     char **error)
+{
+  GITypeTag type_tag;
+
+  type_tag = g_type_info_get_tag (type_info);
+
+  switch (type_tag)
+    {
+    case GI_TYPE_TAG_VOID:
+      if (!g_script_value_is_undefined (value))
+	{
+	  *error = "Invalid argument type, expected undefined";
+	  return FALSE;
+	}
+      break;
+    case GI_TYPE_TAG_BOOLEAN:
+      if (!g_script_value_is_boolean (value))
+	{
+	  *error = "Invalid argument type, expected boolean";
+	  return FALSE;
+	}
+      arg->v_boolean = g_script_value_to_boolean (value);
+      break;
+    case GI_TYPE_TAG_INT8:
+      if (!g_script_value_is_number (value))
+	{
+	  *error = "Invalid argument type, expected number";
+	  return FALSE;
+	}
+      arg->v_int8 = g_script_value_to_int32 (value);
+      break;
+    case GI_TYPE_TAG_UINT8:
+      if (!g_script_value_is_number (value))
+	{
+	  *error = "Invalid argument type, expected number";
+	  return FALSE;
+	}
+      arg->v_uint8 = g_script_value_to_uint32 (value);
+      break;
+    case GI_TYPE_TAG_INT16:
+      if (!g_script_value_is_number (value))
+	{
+	  *error = "Invalid argument type, expected number";
+	  return FALSE;
+	}
+      arg->v_int16 = g_script_value_to_int32 (value);
+      break;
+    case GI_TYPE_TAG_UINT16:
+      if (!g_script_value_is_number (value))
+	{
+	  *error = "Invalid argument type, expected number";
+	  return FALSE;
+	}
+      arg->v_uint16 = g_script_value_to_uint32 (value);
+      break;
+    case GI_TYPE_TAG_INT32:
+      if (!g_script_value_is_number (value))
+	{
+	  *error = "Invalid argument type, expected number";
+	  return FALSE;
+	}
+      arg->v_int32 = g_script_value_to_int32 (value);
+      break;
+    case GI_TYPE_TAG_UINT32:
+      if (!g_script_value_is_number (value))
+	{
+	  *error = "Invalid argument type, expected number";
+	  return FALSE;
+	}
+      arg->v_uint32 = g_script_value_to_uint32 (value);
+      break;
+    case GI_TYPE_TAG_INT64:
+      if (!g_script_value_is_number (value))
+	{
+	  *error = "Invalid argument type, expected number";
+	  return FALSE;
+	}
+      arg->v_int64 = (gint64)g_script_value_to_double (value);
+      break;
+    case GI_TYPE_TAG_UINT64:
+      if (!g_script_value_is_number (value))
+	{
+	  *error = "Invalid argument type, expected number";
+	  return FALSE;
+	}
+      arg->v_uint64 = (gint64)g_script_value_to_double (value);
+      break;
+    case GI_TYPE_TAG_INT:
+      if (!g_script_value_is_number (value))
+	{
+	  *error = "Invalid argument type, expected number";
+	  return FALSE;
+	}
+      arg->v_int = g_script_value_to_int32 (value);
+      break;
+    case GI_TYPE_TAG_UINT:
+      if (!g_script_value_is_number (value))
+	{
+	  *error = "Invalid argument type, expected number";
+	  return FALSE;
+	}
+      arg->v_uint = g_script_value_to_uint32 (value);
+      break;
+    case GI_TYPE_TAG_LONG:
+      if (!g_script_value_is_number (value))
+	{
+	  *error = "Invalid argument type, expected number";
+	  return FALSE;
+	}
+      arg->v_long = (long)g_script_value_to_double (value);
+      break;
+    case GI_TYPE_TAG_ULONG:
+      if (!g_script_value_is_number (value))
+	{
+	  *error = "Invalid argument type, expected number";
+	  return FALSE;
+	}
+      arg->v_ulong = (gulong)g_script_value_to_double (value);
+      break;
+    case GI_TYPE_TAG_SSIZE:
+      if (!g_script_value_is_number (value))
+	{
+	  *error = "Invalid argument type, expected number";
+	  return FALSE;
+	}
+      arg->v_ssize = (gssize)g_script_value_to_double (value);
+      break;
+    case GI_TYPE_TAG_SIZE:
+      if (!g_script_value_is_number (value))
+	{
+	  *error = "Invalid argument type, expected number";
+	  return FALSE;
+	}
+      arg->v_size = (gsize)g_script_value_to_double (value);
+      break;
+    case GI_TYPE_TAG_FLOAT:
+      if (!g_script_value_is_number (value))
+	{
+	  *error = "Invalid argument type, expected number";
+	  return FALSE;
+	}
+      arg->v_float = (float)g_script_value_to_double (value);
+      break;
+    case GI_TYPE_TAG_DOUBLE:
+      if (!g_script_value_is_number (value))
+	{
+	  *error = "Invalid argument type, expected number";
+	  return FALSE;
+	}
+      arg->v_double = g_script_value_to_double (value);
+      break;
+    case GI_TYPE_TAG_UTF8:
+      if (may_be_null && g_script_value_is_null (value))
+	{
+	  arg->v_string = NULL;
+	  break;
+	}
+      if (!g_script_value_is_string (value))
+	{
+	  *error = "Invalid argument type, expected number";
+	  return FALSE;
+	}
+      arg->v_string = g_script_value_to_string (value);
+      break;
+    case GI_TYPE_TAG_FILENAME:
+      *error = "filename arguments not yet supported";
+      return FALSE;
+      break;
+    case GI_TYPE_TAG_ARRAY:
+      *error = "array arguments not yet supported";
+      return FALSE;
+      break;
+    case GI_TYPE_TAG_INTERFACE:
+      {
+	GIBaseInfo *interface;
+	GIInfoType interface_type;
+	GType required_gtype;
+	GObject *gobject;
+	
+	interface = g_type_info_get_interface (type_info);
+	interface_type = g_base_info_get_type (interface);
+
+	arg->v_pointer = NULL;
+	
+	if (interface_type == GI_INFO_TYPE_OBJECT)
+	  {
+	    if (may_be_null && g_script_value_is_null (value))
+	      {
+		arg->v_pointer = NULL;
+		break;
+	      }
+	    
+	    if (!g_script_value_is_gobject (value))
+	      {
+		*error = "Invalid argument type, expected GObject";
+		return FALSE;
+	      }
+	    
+	    gobject = g_script_value_to_gobject (value);
+	    required_gtype = g_registered_type_info_get_g_type ((GIRegisteredTypeInfo *)interface);
+	    if (!g_type_is_a (G_OBJECT_TYPE (gobject), required_gtype))
+	      {
+		*error = "Invalid argument type, not right GType";
+		return FALSE;
+	      }
+	    arg->v_pointer = g_object_ref (gobject);
+	    break;
+	  }
+	else
+	  {
+	    g_print ("Unhandled interface type: %d\n", interface_type);
+	  }
+	
+	*error = "interface arguments of not yet supported type";
+	return FALSE;
+      }
+      *error = "interface arguments not yet supported";
+      return FALSE;
+      break;
+    case GI_TYPE_TAG_GLIST:
+      *error = "glist arguments not yet supported";
+      return FALSE;
+      break;
+    case GI_TYPE_TAG_GSLIST:
+      *error = "gslist arguments not yet supported";
+      return FALSE;
+      break;
+    case GI_TYPE_TAG_GHASH:
+      *error = "ghash arguments not yet supported";
+      return FALSE;
+      break;
+    case GI_TYPE_TAG_ERROR:
+      *error = "error arguments not yet supported";
+      return FALSE;
+      break;
+    }
+  
+  return TRUE;
+}
+
+gboolean
+_g_script_convert_arg_to_js (GArgument *arg,
+			     GITypeInfo *type_info,
+			     GScriptValue **value,
+			     char **error)
+{
+  GITypeTag type_tag;
+
+  type_tag = g_type_info_get_tag (type_info);
+
+  switch (type_tag)
+    {
+    case GI_TYPE_TAG_VOID:
+      *value = g_script_value_new_undefined ();
+      break;
+    case GI_TYPE_TAG_BOOLEAN:
+      *value = g_script_value_new_from_boolean (arg->v_boolean);
+      break;
+    case GI_TYPE_TAG_INT8:
+      *value = g_script_value_new_from_int32 (arg->v_int8);
+      break;
+    case GI_TYPE_TAG_UINT8:
+      *value = g_script_value_new_from_uint32 (arg->v_uint8);
+      break;
+    case GI_TYPE_TAG_INT16:
+      *value = g_script_value_new_from_int32 (arg->v_int16);
+      break;
+    case GI_TYPE_TAG_UINT16:
+      *value = g_script_value_new_from_uint32 (arg->v_uint16);
+      break;
+    case GI_TYPE_TAG_INT32:
+      *value = g_script_value_new_from_int32 (arg->v_int32);
+      break;
+    case GI_TYPE_TAG_UINT32:
+      *value = g_script_value_new_from_uint32 (arg->v_uint32);
+      break;
+    case GI_TYPE_TAG_INT64:
+      *value = g_script_value_new_from_double (arg->v_int64);
+      break;
+    case GI_TYPE_TAG_UINT64:
+      *value = g_script_value_new_from_double (arg->v_uint64);
+      break;
+    case GI_TYPE_TAG_INT:
+      *value = g_script_value_new_from_int32 (arg->v_int32);
+      break;
+    case GI_TYPE_TAG_UINT:
+      *value = g_script_value_new_from_uint32 (arg->v_uint32);
+      break;
+    case GI_TYPE_TAG_LONG:
+      *value = g_script_value_new_from_double (arg->v_long);
+      break;
+    case GI_TYPE_TAG_ULONG:
+      *value = g_script_value_new_from_double (arg->v_ulong);
+      break;
+    case GI_TYPE_TAG_SSIZE:
+      *value = g_script_value_new_from_double (arg->v_ssize);
+      break;
+    case GI_TYPE_TAG_SIZE:
+      *value = g_script_value_new_from_double (arg->v_size);
+      break;
+    case GI_TYPE_TAG_FLOAT:
+      *value = g_script_value_new_from_double (arg->v_float);
+      break;
+    case GI_TYPE_TAG_DOUBLE:
+      *value = g_script_value_new_from_double (arg->v_double);
+      break;
+    case GI_TYPE_TAG_UTF8:
+      *value = g_script_value_new_from_string (arg->v_string);
+      break;
+    case GI_TYPE_TAG_FILENAME:
+      *error = "filename return values not yet supported";
+      return FALSE;
+      break;
+    case GI_TYPE_TAG_ARRAY:
+      *error = "array return values not yet supported";
+      return FALSE;
+      break;
+    case GI_TYPE_TAG_INTERFACE:
+      {
+	GIBaseInfo *interface;
+	GIInfoType interface_type;
+	
+	interface = g_type_info_get_interface (type_info);
+	interface_type = g_base_info_get_type (interface);
+	
+	if (interface_type == GI_INFO_TYPE_OBJECT)
+	  {
+	    *value = g_script_value_new_from_gobject (arg->v_pointer);
+	    break;
+	  }
+	else
+	  {
+	    g_print ("Unhandled interface type: %d\n", interface_type);
+	  }
+	
+	*error = "interface return values of not yet supported type";
+	return FALSE;
+      }
+      break;
+    case GI_TYPE_TAG_GLIST:
+      *error = "glist return values not yet supported";
+      return FALSE;
+      break;
+    case GI_TYPE_TAG_GSLIST:
+      *error = "gslist return values not yet supported";
+      return FALSE;
+      break;
+    case GI_TYPE_TAG_GHASH:
+      *error = "ghash return values not yet supported";
+      return FALSE;
+      break;
+    case GI_TYPE_TAG_ERROR:
+      *error = "error return values not yet supported";
+      return FALSE;
+      break;
+    }
+
+  return TRUE;
+}
+
+void
+_g_script_arg_free (GArgument *arg,
+		    GITypeInfo *type_info,
+		    gboolean free_deep)
+{
+  GITypeTag type_tag;
+
+  type_tag = g_type_info_get_tag (type_info);
+
+  switch (type_tag)
+    {
+    case GI_TYPE_TAG_UTF8:
+      g_free (arg->v_string);
+      break;
+    case GI_TYPE_TAG_FILENAME:
+      g_free (arg->v_string);
+      break;
+    case GI_TYPE_TAG_ARRAY:
+      g_warning ("TODO");
+      break;
+    case GI_TYPE_TAG_INTERFACE:
+      {
+	GIBaseInfo *interface;
+	GIInfoType interface_type;
+	
+	interface = g_type_info_get_interface (type_info);
+	interface_type = g_base_info_get_type (interface);
+	
+	if (interface_type == GI_INFO_TYPE_OBJECT)
+	  {
+	    if (arg->v_pointer)
+	      g_object_unref (arg->v_pointer);
+	    break;
+	  }
+	else
+	  g_warning ("TODO");
+      }
+      break;
+    case GI_TYPE_TAG_GLIST:
+      g_warning ("TODO");
+      break;
+    case GI_TYPE_TAG_GSLIST:
+      g_warning ("TODO");
+      break;
+    case GI_TYPE_TAG_GHASH:
+      g_warning ("TODO");
+      break;
+    case GI_TYPE_TAG_ERROR:
+      g_warning ("TODO");
+      break;
+    default:
+      break;
+    }
+}

Added: trunk/gscriptvalue.c
==============================================================================
--- (empty file)
+++ trunk/gscriptvalue.c	Mon Sep  8 18:10:46 2008
@@ -0,0 +1,752 @@
+#include "gscriptvalue.h"
+#include "gscriptinternal.h"
+
+/**
+ * GScriptValue:
+ * 
+ */
+struct _GScriptValue
+{
+  GObject parent_instance;
+
+  jsval value;
+};
+
+G_DEFINE_TYPE (GScriptValue, g_script_value, G_TYPE_OBJECT);
+
+static void
+g_script_value_finalize (GObject *object)
+{
+  GScriptValue *value;
+  JSContext *cx;
+
+  value = G_SCRIPT_VALUE (object);
+
+  cx = _g_script_get_internal_context ();
+  
+  JS_RemoveRoot (cx, &value->value);
+
+  G_OBJECT_CLASS (g_script_value_parent_class)->finalize (object);
+}
+
+static void
+g_script_value_class_init (GScriptValueClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+  gobject_class->finalize = g_script_value_finalize;
+}
+
+static void
+g_script_value_init (GScriptValue *value)
+{
+  JSContext *cx;
+  gboolean ok;
+
+  cx = _g_script_get_internal_context ();
+
+  value->value = JSVAL_VOID;
+
+  ok = JS_AddNamedRoot (cx, &value->value, "GScriptValue");
+
+  if (!ok)
+    {
+      /* TODO: What to do here? make the object not working? */
+    }
+}
+
+jsval
+_g_script_value_get_jsval (GScriptValue *value)
+{
+  return value->value;
+}
+
+/**
+ * g_script_value_new:
+ * 
+ * Creates a new script value of type undefined
+ *
+ * Returns: a #GScriptValue.
+ **/
+GScriptValue *
+g_script_value_new (void)
+{
+  JSContext *cx = _g_script_get_internal_context ();
+  GScriptValue *value;
+
+  value = g_object_new (G_TYPE_SCRIPT_VALUE, NULL);
+
+  value->value = OBJECT_TO_JSVAL (JS_NewObject (cx, NULL, NULL, NULL));
+  
+  return value;
+}
+
+GScriptValue *
+g_script_value_new_undefined (void)
+{
+  return g_object_new (G_TYPE_SCRIPT_VALUE, NULL);
+}
+
+GScriptValue *
+_g_script_value_new_from_jsval (jsval js_value)
+{
+  GScriptValue *value;
+
+  value = g_object_new (G_TYPE_SCRIPT_VALUE, NULL);
+  value->value = js_value;
+  return value;
+}
+
+GScriptValue *
+_g_script_value_new_from_jsobject (JSObject *obj)
+{
+  return _g_script_value_new_from_jsval (OBJECT_TO_JSVAL (obj));
+}
+
+
+GScriptValue  *
+g_script_value_new_from_gvalue (GValue *gvalue)
+{
+  GScriptValue *value;
+
+  if (!G_IS_VALUE (gvalue))
+    return g_object_new (G_TYPE_SCRIPT_VALUE, NULL);
+  
+  switch (G_VALUE_TYPE (gvalue))
+    {
+    case G_TYPE_BOOLEAN:
+      value = g_script_value_new_from_boolean (g_value_get_boolean (gvalue));
+      break;
+
+    case G_TYPE_CHAR:
+      value = g_script_value_new_from_int32 (g_value_get_char (gvalue));
+      break;
+      
+    case G_TYPE_UCHAR:
+      value = g_script_value_new_from_uint32 (g_value_get_uchar (gvalue));
+      break;
+      
+    case G_TYPE_INT:
+      value = g_script_value_new_from_int32 (g_value_get_int (gvalue));
+      break;
+      
+    case G_TYPE_UINT:
+      value = g_script_value_new_from_uint32 (g_value_get_uint (gvalue));
+      break;
+      
+    case G_TYPE_LONG:
+      value = g_script_value_new_from_double ((double)g_value_get_long (gvalue));
+      break;
+      
+    case G_TYPE_ULONG:
+      value = g_script_value_new_from_double ((double)g_value_get_ulong (gvalue));
+      break;
+      
+    case G_TYPE_INT64:
+      value = g_script_value_new_from_double ((double)g_value_get_int64 (gvalue));
+      break;
+      
+    case G_TYPE_UINT64:
+      value = g_script_value_new_from_double ((double)g_value_get_uint64 (gvalue));
+      break;
+      
+    case G_TYPE_FLOAT:
+      value = g_script_value_new_from_double ((double)g_value_get_float (gvalue));
+      break;
+      
+    case G_TYPE_DOUBLE:
+      value = g_script_value_new_from_double ((double)g_value_get_double (gvalue));
+      break;
+      
+    case G_TYPE_STRING:
+      value = g_script_value_new_from_string (g_value_get_string (gvalue));
+      break;
+
+    default:
+      value = NULL;
+    }
+
+  if (value == NULL)
+    {
+      if (g_type_is_a (G_VALUE_TYPE (gvalue),G_TYPE_ENUM))
+	value = g_script_value_new_from_double ((double)gvalue->data[0].v_long);
+      else if (g_type_is_a (G_VALUE_TYPE (gvalue),G_TYPE_FLAGS))
+	value = g_script_value_new_from_double ((double)gvalue->data[0].v_ulong);
+      else if (g_type_is_a (G_VALUE_TYPE (gvalue),G_TYPE_OBJECT))
+	{
+	  JSContext *cx = _g_script_get_internal_context ();
+	  JSObject *js_obj;
+	  GObject *gobject;
+	  
+	  /* TODO: This creates the classes in the internal contexts global,
+	     not in the callers global. Does this matter? */
+	  
+	  js_obj = JSVAL_NULL;
+	  if (JS_AddRoot (cx, &js_obj))
+	    {
+	      gobject = g_value_get_object (gvalue);
+	      if (gobject == NULL)
+		{
+		  value = g_object_new (G_TYPE_SCRIPT_VALUE, NULL);
+		  value->value = JSVAL_NULL;
+		}
+	      else if (wrap_object (gobject, &js_obj))
+		{
+		  value = g_object_new (G_TYPE_SCRIPT_VALUE, NULL);
+		  value->value = OBJECT_TO_JSVAL(js_obj);
+		}
+	      JS_RemoveRoot (cx, &js_obj);
+	    }
+	}
+    }
+      
+  return value; /* can be NULL on failed convert */
+}
+
+GScriptValue *
+g_script_value_new_from_double (double v)
+{
+  GScriptValue *value;
+  JSContext *cx = _g_script_get_internal_context ();
+
+  value = g_object_new (G_TYPE_SCRIPT_VALUE, NULL);
+
+  if (!JS_NewNumberValue (cx, (double)v, &value->value))
+    value->value = JSVAL_VOID;
+  
+  return value;
+}
+
+GScriptValue *
+g_script_value_new_from_boolean (gboolean v)
+{
+  GScriptValue *value;
+
+  value = g_object_new (G_TYPE_SCRIPT_VALUE, NULL);
+
+  value->value = BOOLEAN_TO_JSVAL (v);
+  
+  return value;
+}
+
+
+GScriptValue *
+g_script_value_new_from_int32 (gint32 v)
+{
+  GScriptValue *value;
+
+  value = g_object_new (G_TYPE_SCRIPT_VALUE, NULL);
+
+  if (INT_FITS_IN_JSVAL (v))
+    value->value = INT_TO_JSVAL (v);
+  else
+    {
+      JSContext *cx = _g_script_get_internal_context ();
+
+      if (!JS_NewNumberValue (cx, (double)v, &value->value))
+	value->value = JSVAL_VOID;
+    }
+  
+  return value;
+}
+
+GScriptValue *
+g_script_value_new_from_uint32 (guint32 v)
+{
+  GScriptValue *value;
+
+  value = g_object_new (G_TYPE_SCRIPT_VALUE, NULL);
+
+  if (((gint32)v) >= 0 &&
+      INT_FITS_IN_JSVAL ((gint32)v))
+    value->value = INT_TO_JSVAL ((gint32)v);
+  else
+    {
+      JSContext *cx = _g_script_get_internal_context ();
+
+      if (!JS_NewNumberValue (cx, (double)v, &value->value))
+	value->value = JSVAL_VOID;
+    }
+  
+  return value;
+}
+
+GScriptValue *
+g_script_value_new_from_string (const char *str)
+{
+  JSContext *cx = _g_script_get_internal_context ();
+  GScriptValue *value;
+  jschar *str2;
+  JSString *js_str;
+
+  value = g_object_new (G_TYPE_SCRIPT_VALUE, NULL);
+  str2 = g_utf8_to_utf16 (str, -1, NULL, NULL, NULL);
+  if (str2)
+    {
+      js_str = JS_NewUCStringCopyZ (cx, (const jschar *)str2);
+      value->value = STRING_TO_JSVAL(js_str);
+      g_free (str2);
+    }
+      
+  return value;
+}
+
+GScriptValue *
+g_script_value_new_from_gobject (GObject *object)
+{
+  GScriptValue *value;
+  JSObject *js_object;
+
+  value = NULL;
+  
+  js_object = NULL;
+  if (wrap_object (object, &js_object))
+    {
+      value = g_object_new (G_TYPE_SCRIPT_VALUE, NULL);
+      value->value = OBJECT_TO_JSVAL (js_object);
+    }
+  else
+    g_warning ("Couldn't wrap object");
+  
+  return value;
+}
+
+static JSBool
+call_native_function (JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+  GScriptValue *ret;
+  GScriptValue **gargs;
+  GScriptNativeFunction native, *nativep;
+  jsval v;
+  int i;
+  
+  if (!JS_GetReservedSlot (cx, JS_GetFunctionObject (JS_ValueToFunction (cx, argv[-2])), 0, &v))
+    return JS_FALSE;
+
+  nativep = JSVAL_TO_PRIVATE (v);
+  native = *nativep;
+
+  gargs = g_new (GScriptValue *, argc);
+  for (i = 0; i < argc; i++)
+    gargs[i] = _g_script_value_new_from_jsval (argv[i]);
+  
+  ret = native (argc, gargs);
+
+  if (ret)
+    {
+      *rval = ret->value;
+      g_object_unref (ret);
+    }
+  else
+    *rval = JSVAL_VOID;
+
+  for (i = 0; i < argc; i++)
+    g_object_unref (gargs[i]);
+  
+  g_free (gargs);
+
+  return JS_TRUE;
+}
+
+GScriptValue *
+g_script_value_new_from_function (GScriptNativeFunction function, int n_args)
+{
+  GScriptValue *new_value;
+  JSContext *cx = _g_script_get_internal_context ();
+  JSFunction *func;
+  JSObject *object;
+  GScriptNativeFunction *nativep;
+  
+  new_value = g_object_new (G_TYPE_SCRIPT_VALUE, NULL);
+  func = JS_NewFunction (cx, call_native_function, n_args, 0, NULL, NULL);
+
+  object = JS_GetFunctionObject (func);
+  new_value->value = OBJECT_TO_JSVAL (object);
+
+  nativep = g_new (GScriptNativeFunction, 1);
+  g_assert (((int)nativep) % 2 == 0);
+  *nativep = function;
+
+  if (!JS_SetReservedSlot (cx, object, 0, PRIVATE_TO_JSVAL (nativep)))
+    g_warning ("Unable to set reserved slot of function");
+  
+  return new_value;
+}
+
+GScriptValue *
+g_script_value_dup (GScriptValue *value)
+{
+  GScriptValue *new_value;
+
+  new_value = g_object_new (G_TYPE_SCRIPT_VALUE, NULL);
+
+  new_value->value = value->value;
+  
+  return new_value;
+}
+
+gboolean
+g_script_value_is_null (GScriptValue *value)
+{
+  return JSVAL_IS_NULL (value->value);
+}
+
+gboolean
+g_script_value_is_undefined (GScriptValue *value)
+{
+  return JSVAL_IS_VOID (value->value);
+}
+
+gboolean
+g_script_value_is_boolean (GScriptValue *value)
+{
+  return JSVAL_IS_BOOLEAN (value->value);
+}
+
+gboolean
+g_script_value_is_number (GScriptValue *value)
+{
+  return JSVAL_IS_NUMBER (value->value);
+}
+
+gboolean
+g_script_value_is_string (GScriptValue *value)
+{
+  return JSVAL_IS_STRING (value->value);
+}
+
+gboolean
+g_script_value_is_object (GScriptValue *value)
+{
+  return
+    JSVAL_IS_OBJECT (value->value) &&
+    value->value != JSVAL_NULL;
+}
+
+gboolean
+g_script_value_is_function (GScriptValue *value)
+{
+  JSContext *cx = _g_script_get_internal_context ();
+  return
+    JSVAL_IS_OBJECT (value->value) &&
+    value->value != JSVAL_NULL &&
+    JS_ObjectIsFunction(cx, JSVAL_TO_OBJECT (value->value));
+}
+
+gboolean
+g_script_value_is_gobject (GScriptValue *value)
+{
+  GObject *gobject;
+  
+  if (!JSVAL_IS_OBJECT (value->value) ||
+      value->value == JSVAL_NULL)
+    return FALSE;
+
+  gobject = _js_object_get_gobject (JSVAL_TO_OBJECT (value->value));
+  
+  return gobject != NULL;
+}
+
+gboolean
+g_script_value_to_boolean (GScriptValue *value)
+{
+  JSContext *cx = _g_script_get_internal_context ();
+  JSBool v;
+
+  if (JS_ValueToBoolean (cx, value->value, &v))
+    return v;
+  return FALSE;
+}
+
+gint32
+g_script_value_to_int32 (GScriptValue *value)
+{
+  JSContext *cx = _g_script_get_internal_context ();
+  gint32 v;
+
+  if (JS_ValueToECMAInt32 (cx, value->value, &v))
+    return v;
+  return 0;
+}
+
+guint32
+g_script_value_to_uint32 (GScriptValue *value)
+{
+  JSContext *cx = _g_script_get_internal_context ();
+  guint32 v;
+
+  if (JS_ValueToECMAUint32 (cx, value->value, &v))
+    return v;
+  return 0;
+}
+
+double
+g_script_value_to_double (GScriptValue *value)
+{
+  JSContext *cx = _g_script_get_internal_context ();
+  jsdouble v;
+
+  if (JS_ValueToNumber (cx, value->value, &v))
+    return v;
+  return 0;
+}
+
+char *
+g_script_value_to_string (GScriptValue *value)
+{
+  JSContext *cx = _g_script_get_internal_context ();
+  JSString *str;
+  jschar *chars;
+  size_t len;
+  char *res;
+
+  str = JS_ValueToString (cx, value->value);
+
+  if (str == NULL)
+    return NULL;
+  
+  chars = JS_GetStringChars (str);
+  len = JS_GetStringLength (str);
+  
+  res = g_utf16_to_utf8 (chars, len, NULL, NULL, NULL);
+  return res;
+}
+
+GScriptValue *
+g_script_value_to_object (GScriptValue *value)
+{
+  JSContext *cx = _g_script_get_internal_context ();
+  GScriptValue *new_value;
+  JSObject *object;
+
+  new_value = g_object_new (G_TYPE_SCRIPT_VALUE, NULL);
+
+  if (!JS_ValueToObject (cx, value->value, &object))
+    new_value->value = OBJECT_TO_JSVAL(object);
+
+  return new_value;
+}
+
+GObject *
+g_script_value_to_gobject (GScriptValue *value)
+{
+  GObject *gobject;
+  
+  if (!JSVAL_IS_OBJECT (value->value) ||
+      value->value == JSVAL_NULL)
+    return FALSE;
+
+  gobject = _js_object_get_gobject (JSVAL_TO_OBJECT (value->value));
+  
+  return gobject;
+}
+
+gboolean
+g_script_value_to_gvalue (GScriptValue *value,
+			  GType enforce_type,
+			  GValue *gvalue)
+{
+  switch (enforce_type)
+    {
+    case G_TYPE_BOOLEAN:
+      {
+	gboolean v;
+	
+	if (!g_script_value_is_boolean (value))
+	  return FALSE;
+	
+	g_value_init (gvalue, G_TYPE_BOOLEAN);
+	v = g_script_value_to_boolean (value);
+	g_value_set_boolean (gvalue, v);
+	return TRUE;
+      }
+    case G_TYPE_INT:
+      {
+	gint32 v;
+	
+	if (!g_script_value_is_number (value))
+	  return FALSE;
+	
+	g_value_init (gvalue, G_TYPE_INT);
+	v = g_script_value_to_int32 (value);
+	g_value_set_int (gvalue, v);
+	return TRUE;
+      }
+    case G_TYPE_UINT:
+      {
+	guint32 v;
+	
+	if (!g_script_value_is_number (value))
+	  return FALSE;
+	
+	g_value_init (gvalue, G_TYPE_INT);
+	v = g_script_value_to_int32 (value);
+	g_value_set_int (gvalue, v);
+	return TRUE;
+      }
+    case G_TYPE_CHAR:
+      {
+	gint32 v;
+	
+	if (!g_script_value_is_number (value))
+	  return FALSE;
+
+	g_value_init (gvalue, G_TYPE_INT);
+	v = g_script_value_to_int32 (value);
+
+	if (v < G_MININT8 || v > G_MAXINT8)
+	  return FALSE;
+	
+	g_value_set_char (gvalue, v);
+	return TRUE;
+      }
+    case G_TYPE_UCHAR:
+      {
+	gint32 v;
+	
+	if (!g_script_value_is_number (value))
+	  return FALSE;
+
+	g_value_init (gvalue, G_TYPE_INT);
+	v = g_script_value_to_int32 (value);
+
+	if (v < 0 || v > G_MAXUINT8)
+	  return FALSE;
+	
+	g_value_set_uchar (gvalue, v);
+	return TRUE;
+      }
+    case G_TYPE_LONG:
+    case G_TYPE_ULONG:
+    case G_TYPE_INT64:
+    case G_TYPE_UINT64:
+    case G_TYPE_FLOAT:
+    case G_TYPE_DOUBLE:
+      {
+	double v;
+	
+	if (!g_script_value_is_number (value))
+	  return FALSE;
+	
+	v = g_script_value_to_double (value);
+	
+	g_value_init (gvalue, enforce_type);
+
+	/* TODO: Range checking */
+	
+	switch (enforce_type)
+	  {
+	  case G_TYPE_LONG:
+	    g_value_set_long (gvalue, (long)v);
+	    break;
+	  case G_TYPE_ULONG:
+	    g_value_set_ulong (gvalue, (ulong)v);
+	    break;
+	  case G_TYPE_INT64:
+	    g_value_set_int64 (gvalue, (gint64)v);
+	    break;
+	  case G_TYPE_UINT64:
+	    g_value_set_uint64 (gvalue, (guint64)v);
+	    break;
+	  case G_TYPE_FLOAT:
+	    g_value_set_float (gvalue, v);
+	    break;
+	  case G_TYPE_DOUBLE:
+	    g_value_set_double (gvalue, v);
+	    break;
+	  }
+		
+	return TRUE;
+      }
+    case G_TYPE_STRING:
+      {
+	char *s;
+	
+	if (!g_script_value_is_string (value))
+	  return FALSE;
+	
+	s = g_script_value_to_string (value);
+	g_value_init (gvalue, enforce_type);
+	g_value_take_string (gvalue, s);
+		
+	return TRUE;
+      }
+    default:
+      
+      break;
+    }
+
+  if (g_type_is_a (enforce_type, G_TYPE_ENUM) &&
+      g_script_value_is_number (value))
+    {
+      gint32 v;
+
+      v = g_script_value_to_int32 (value);
+      g_value_init (gvalue, enforce_type);
+      gvalue->data[0].v_long = v;
+      return TRUE;
+    }
+  else if (g_type_is_a (enforce_type, G_TYPE_FLAGS) &&
+      g_script_value_is_number (value))
+    {
+      guint32 v;
+
+      v = g_script_value_to_uint32 (value);
+      g_value_init (gvalue, enforce_type);
+      gvalue->data[0].v_ulong = v;
+      return TRUE;
+    }
+  else if (g_type_is_a (enforce_type, G_TYPE_OBJECT) &&
+	   (g_script_value_is_null (value) ||
+	    g_script_value_is_gobject (value)))
+    {
+      GObject *o;
+
+      o = g_script_value_to_gobject (value);
+
+      if (o == NULL ||
+	  g_type_is_a (G_OBJECT_TYPE (o), enforce_type))
+	{
+	  g_value_init (gvalue, enforce_type);
+	  g_value_set_object (gvalue, o);
+	  return TRUE;
+	}
+      
+      g_object_unref (o);
+    }
+
+  return FALSE;
+}
+
+
+GScriptValue *
+g_script_value_get_property (GScriptValue *value,
+			     const char *name)
+{
+  JSContext *cx = _g_script_get_internal_context ();
+  GScriptValue *prop_value;
+
+  prop_value = g_object_new (G_TYPE_SCRIPT_VALUE, NULL);
+  if (g_script_value_is_object (value))
+    {
+      JS_GetProperty(cx, JSVAL_TO_OBJECT (value->value),
+		     name, &prop_value->value);
+    }
+	  
+  return prop_value;
+}
+
+void
+g_script_value_set_property (GScriptValue *value,
+			     const char *name,
+			     GScriptValue *prop_val)
+{
+  JSContext *cx = _g_script_get_internal_context ();
+
+  /* TODO: Check error? */
+  if (g_script_value_is_object (value))
+    {
+      JS_SetProperty (cx, JSVAL_TO_OBJECT (value->value),
+		      name, &prop_val->value);
+    }
+}

Added: trunk/gscriptvalue.h
==============================================================================
--- (empty file)
+++ trunk/gscriptvalue.h	Mon Sep  8 18:10:46 2008
@@ -0,0 +1,74 @@
+#ifndef __G_SCRIPT_VALUE_H__
+#define __G_SCRIPT_VALUE_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define G_TYPE_SCRIPT_VALUE         (g_script_value_get_type ())
+#define G_SCRIPT_VALUE(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_SCRIPT_VALUE, GScriptValue))
+#define G_SCRIPT_VALUE_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_SCRIPT_VALUE, GScriptValueClass))
+#define G_IS_SCRIPT_VALUE(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_SCRIPT_VALUE))
+#define G_IS_SCRIPT_VALUE_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_SCRIPT_VALUE))
+#define G_SCRIPT_VALUE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_SCRIPT_VALUE, GScriptValueClass))
+
+typedef struct _GScriptValueClass   GScriptValueClass;
+typedef struct _GScriptValue GScriptValue;
+
+struct _GScriptValueClass
+{
+  GObjectClass parent_class;
+
+  /* Padding for future expansion */
+  void (*_g_reserved1) (void);
+  void (*_g_reserved2) (void);
+  void (*_g_reserved3) (void);
+  void (*_g_reserved4) (void);
+  void (*_g_reserved5) (void);
+};
+
+typedef GScriptValue * (*GScriptNativeFunction) (int n_args, GScriptValue **args);
+
+GScriptValue      *g_script_value_new (void);
+GScriptValue      *g_script_value_new_undefined (void);
+GScriptValue      *g_script_value_new_from_gvalue (GValue *value);
+GScriptValue      *g_script_value_new_from_boolean (gboolean v);
+GScriptValue      *g_script_value_new_from_double (double v);
+GScriptValue      *g_script_value_new_from_int32 (gint32 v);
+GScriptValue      *g_script_value_new_from_uint32 (guint32 v);
+GScriptValue      *g_script_value_new_from_string (const char *str);
+GScriptValue      *g_script_value_new_from_gobject (GObject *object);
+GScriptValue      *g_script_value_new_from_function (GScriptNativeFunction function, int n_args);
+GScriptValue      *g_script_value_dup (GScriptValue *value);
+
+gboolean           g_script_value_is_null (GScriptValue *value);
+gboolean           g_script_value_is_undefined (GScriptValue *value);
+gboolean           g_script_value_is_boolean (GScriptValue *value);
+gboolean           g_script_value_is_number (GScriptValue *value);
+gboolean           g_script_value_is_string (GScriptValue *value);
+gboolean           g_script_value_is_object (GScriptValue *value);
+gboolean           g_script_value_is_function (GScriptValue *value);
+gboolean           g_script_value_is_gobject (GScriptValue *value);
+
+gboolean           g_script_value_to_boolean (GScriptValue *value);
+gint32             g_script_value_to_int32 (GScriptValue *value);
+guint32            g_script_value_to_uint32 (GScriptValue *value);
+double             g_script_value_to_double (GScriptValue *value);
+char *             g_script_value_to_string (GScriptValue *value);
+GScriptValue *     g_script_value_to_object (GScriptValue *value);
+GObject *          g_script_value_to_gobject (GScriptValue *value);
+
+gboolean           g_script_value_to_gvalue (GScriptValue *value,
+					     GType enforce_type,
+					     GValue *gvalue);
+
+GScriptValue *     g_script_value_get_property (GScriptValue *value,
+						const char *name);
+void               g_script_value_set_property (GScriptValue *value,
+						const char *name,
+						GScriptValue *prop_val);
+
+/* remove property? */
+G_END_DECLS
+
+#endif /* __G_SCRIPT_VALUE_H__ */

Added: trunk/js-gtk.c
==============================================================================
--- (empty file)
+++ trunk/js-gtk.c	Mon Sep  8 18:10:46 2008
@@ -0,0 +1,172 @@
+/* Compile with:
+gcc -g -I . -I ./Linux_All_DBG.OBJ `pkg-config --libs --cflags gtk+-2.0 gobject-introspection-1.0` -DXP_UNIX -O -Wall js-gtk.c Linux_All_DBG.OBJ/libjs.a -o js-gtk
+*/
+#include <girepository.h>
+#include "gscriptinternal.h"
+#include "gscriptengine.h"
+#include <jsapi.h>
+#include <gtk/gtk.h>
+#include <glib.h>
+#include <string.h>
+
+GScriptEngine *engine;
+GtkTextBuffer *text_buffer;
+GtkWidget *textview;
+
+static void
+print (const char *s)
+{
+  GtkTextIter iter;
+  GtkTextMark *mark;
+  
+  gtk_text_buffer_get_end_iter (text_buffer, &iter);
+  gtk_text_buffer_insert (text_buffer, &iter, s, -1);
+  gtk_text_buffer_get_end_iter (text_buffer, &iter);
+  gtk_text_buffer_insert (text_buffer, &iter, "\n", -1);
+
+  mark = gtk_text_buffer_get_insert  (text_buffer);
+  gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (textview), mark, 0.0, FALSE, 0.0, 0.0);
+}
+
+static void
+activate_entry (GtkEntry *entry)
+{
+  GScriptValue *res;
+  const char *text;
+  char *s;
+
+  text = gtk_entry_get_text (entry);
+
+  s = g_strdup_printf ("%s :", text);
+  print (s);
+  g_free (s);
+  res = g_script_engine_evaluate_script (engine, text);
+  s = g_strdup_printf ("-> %s", g_script_value_to_string (res));
+  print (s);
+  g_object_unref (res);
+  g_free (s);
+
+  gtk_entry_set_text (entry, "");
+}
+
+static void
+setup_shell (void)
+{
+  GtkWidget *window, *vbox, *entry, *sw;
+
+  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+
+  vbox = gtk_vbox_new (FALSE, 1);
+  gtk_container_add (GTK_CONTAINER (window), vbox);
+
+  sw = gtk_scrolled_window_new (NULL, NULL);
+  gtk_widget_set_size_request (sw, 400, 600);
+  gtk_box_pack_start (GTK_BOX (vbox),
+		      sw,
+		      TRUE, TRUE, 0);  
+
+  textview = gtk_text_view_new ();
+  text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (textview));
+  gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (textview), FALSE);
+  gtk_text_view_set_editable (GTK_TEXT_VIEW (textview), FALSE);
+
+  gtk_container_add (GTK_CONTAINER (sw), textview);
+  
+  entry = gtk_entry_new ();
+  g_signal_connect (entry, "activate", G_CALLBACK (activate_entry), NULL);
+  
+  gtk_box_pack_start (GTK_BOX (vbox),
+		      entry,
+		      FALSE, FALSE, 0);  
+
+  gtk_widget_show_all (window);
+  gtk_widget_grab_focus (entry);  
+}
+
+
+static GScriptValue *
+print_cb (int n_args, GScriptValue **args)
+{
+  char *s;
+
+  s = g_script_value_to_string (args[0]);
+  if (s != NULL)
+    {
+      print (s);
+      g_free (s);
+    }
+  
+  return NULL;
+}
+
+int
+main(int argc, char *argv[])
+{
+  const gchar *ns;
+  GScriptValue *wrapped, *f;
+  GScriptValue *res;
+  GScriptValue *global;
+  GtkWidget *label;
+  
+  gtk_init(&argc, &argv);
+
+  ns = g_irepository_require (g_irepository_get_default (),
+			      "Gtk", NULL);
+  ns = g_irepository_require (g_irepository_get_default (),
+			      "GObject", NULL);
+
+
+  engine = g_script_engine_new ();
+
+  label = gtk_label_new ("Text of label");
+  g_object_ref_sink (label);
+  
+  wrapped = g_script_value_new_from_gobject (G_OBJECT (label));
+  global = g_script_engine_get_global (engine);
+  g_script_value_set_property (global,
+			       "label",
+			       wrapped);
+  
+  g_object_unref (label); /* Now label is only owned by the proxy object */
+  
+  setup_shell ();
+
+  wrapped = g_script_value_new_from_gobject (G_OBJECT (textview));
+  global = g_script_engine_get_global (engine);
+  g_script_value_set_property (global,
+			       "tv",
+			       wrapped);
+
+  f = g_script_value_new_from_function (print_cb, 1);
+  g_script_value_set_property (global,
+			       "print",
+			       f);
+  g_object_unref (f);
+  
+  if (1)
+    {
+      print ("Running script");
+      print ("---------------------");
+      
+      
+      res = g_script_engine_evaluate_script (engine,
+					     "print (label.move_cursor);"
+					     "print (label.move_cursor.connect);"
+					     "label.move_cursor.connect( function (x, y, z) {print (this);print(x);print(y);print(z)});"
+					     "print (label.label);"
+					     "print (label.style);"
+					     "print (label.wrap);"
+					     "print (label.nonexist);"
+					     );
+      
+      print ("---------------------");
+      print ("script result:");
+      print (g_script_value_to_string (res));
+      
+      g_signal_emit_by_name (label, "move_cursor", 0, 0, FALSE);
+    }
+
+  gtk_main ();
+  
+  return 0;
+}



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