gscript r2 - trunk
- From: alexl svn gnome org
- To: svn-commits-list gnome org
- Subject: gscript r2 - trunk
- Date: Mon, 8 Sep 2008 18:10:46 +0000 (UTC)
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", >ype))
+ 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, >ype);
+
+ gtype = JS_NewObject (cx, >ype_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", >ype))
+ 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),
+ ¶ms[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 (¶ms[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 *)¶m_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]