seed r226 - in trunk: examples extensions libseed tests
- From: racarr svn gnome org
- To: svn-commits-list gnome org
- Subject: seed r226 - in trunk: examples extensions libseed tests
- Date: Mon, 10 Nov 2008 13:00:08 +0000 (UTC)
Author: racarr
Date: Mon Nov 10 13:00:08 2008
New Revision: 226
URL: http://svn.gnome.org/viewvc/seed?rev=226&view=rev
Log:
Implement the ability to define new signals on objects, add
GObject.TYPE_* through an import-hook js. Add return values from signals.
Add signal.emit().
Added:
trunk/extensions/GObject.js
trunk/tests/gtype-signal.js (contents, props changed)
trunk/tests/gtype-signal2.js (contents, props changed)
Modified:
trunk/examples/pango.js
trunk/extensions/Makefile.am
trunk/libseed/seed-closure.h
trunk/libseed/seed-gtype.c
trunk/libseed/seed-signals.c
trunk/tests/Makefile.am
Modified: trunk/examples/pango.js
==============================================================================
--- trunk/examples/pango.js (original)
+++ trunk/examples/pango.js Mon Nov 10 13:00:08 2008
@@ -107,7 +107,7 @@
dy = evt.get_y() - actor.y;
select_actor(actor);
-
+
dragging = true;
return true;
Added: trunk/extensions/GObject.js
==============================================================================
--- (empty file)
+++ trunk/extensions/GObject.js Mon Nov 10 13:00:08 2008
@@ -0,0 +1,30 @@
+(function()
+ {
+ var types = [{name:"NONE", fundamental: 1},
+ {name:"INTERFACE", fundamental: 2},
+ {name:"CHAR", fundamental: 3},
+ {name:"UCHAR", fundamental: 4},
+ {name:"BOOLEAN", fundamental: 5},
+ {name:"INT", fundamental: 6},
+ {name:"UINT", fundamental: 7},
+ {name:"LONG", fundamental: 8},
+ {name:"ULONG", fundamental: 9},
+ {name:"INT64", fundamental: 10},
+ {name:"UINT64", fundamental: 11},
+ {name:"ENUM", fundamental: 12},
+ {name:"FLAGS", fundamental: 13},
+ {name:"FLOAT", fundamental: 14},
+ {name:"DOUBLE", fundamental: 15},
+ {name:"STRING", fundamental: 16},
+ {name:"POINTER", fundamental: 17},
+ {name:"BOXED", fundamental: 18},
+ {name:"PARAM", fundamental: 19},
+ {name:"OBJECT", fundamental: 20}];
+
+ for (var i = 0; i < types.length; i++)
+ {
+
+ GObject["TYPE_"+types[i].name] = types[i].fundamental << 2;
+ }
+
+ }).apply();
Modified: trunk/extensions/Makefile.am
==============================================================================
--- trunk/extensions/Makefile.am (original)
+++ trunk/extensions/Makefile.am Mon Nov 10 13:00:08 2008
@@ -1,4 +1,4 @@
-EXTRA_DIST= Gio.js Seed.js Gtk.js
+EXTRA_DIST= Gio.js Seed.js Gtk.js GObject.js
extensiondir=$(datadir)/seed
-extension_DATA = Gio.js Seed.js Gtk.js
+extension_DATA = Gio.js Seed.js Gtk.js GObject.js
Modified: trunk/libseed/seed-closure.h
==============================================================================
--- trunk/libseed/seed-closure.h (original)
+++ trunk/libseed/seed-closure.h Mon Nov 10 13:00:08 2008
@@ -30,6 +30,8 @@
JSObjectRef this;
JSValueRef user_data;
+
+ GType return_type;
} SeedClosure;
typedef struct _SeedNativeClosure {
Modified: trunk/libseed/seed-gtype.c
==============================================================================
--- trunk/libseed/seed-gtype.c (original)
+++ trunk/libseed/seed-gtype.c Mon Nov 10 13:00:08 2008
@@ -24,6 +24,292 @@
JSClassRef seed_gtype_class;
+/* From pygobject */
+static ffi_type *
+g_value_to_ffi_type (const GValue *gvalue, gpointer *value)
+{
+ ffi_type *rettype = NULL;
+ GType type = g_type_fundamental (G_VALUE_TYPE (gvalue));
+ g_assert (type != G_TYPE_INVALID);
+
+ switch (type) {
+ case G_TYPE_BOOLEAN:
+ case G_TYPE_CHAR:
+ case G_TYPE_INT:
+ rettype = &ffi_type_sint;
+ *value = (gpointer)&(gvalue->data[0].v_int);
+ break;
+ case G_TYPE_UCHAR:
+ case G_TYPE_UINT:
+ rettype = &ffi_type_uint;
+ *value = (gpointer)&(gvalue->data[0].v_uint);
+ break;
+ case G_TYPE_STRING:
+ case G_TYPE_OBJECT:
+ case G_TYPE_BOXED:
+ case G_TYPE_POINTER:
+ rettype = &ffi_type_pointer;
+ *value = (gpointer)&(gvalue->data[0].v_pointer);
+ break;
+ case G_TYPE_FLOAT:
+ rettype = &ffi_type_float;
+ *value = (gpointer)&(gvalue->data[0].v_float);
+ break;
+ case G_TYPE_DOUBLE:
+ rettype = &ffi_type_double;
+ *value = (gpointer)&(gvalue->data[0].v_double);
+ break;
+ case G_TYPE_LONG:
+ rettype = &ffi_type_slong;
+ *value = (gpointer)&(gvalue->data[0].v_long);
+ break;
+ case G_TYPE_ULONG:
+ rettype = &ffi_type_ulong;
+ *value = (gpointer)&(gvalue->data[0].v_ulong);
+ break;
+ case G_TYPE_INT64:
+ rettype = &ffi_type_sint64;
+ *value = (gpointer)&(gvalue->data[0].v_int64);
+ break;
+ case G_TYPE_UINT64:
+ rettype = &ffi_type_uint64;
+ *value = (gpointer)&(gvalue->data[0].v_uint64);
+ break;
+ default:
+ rettype = &ffi_type_pointer;
+ *value = NULL;
+ g_warning ("Unsupported fundamental type: %s", g_type_name (type));
+ break;
+ }
+ return rettype;
+}
+
+/* From pygobject */
+static void
+g_value_from_ffi_type (GValue *gvalue, gpointer *value)
+{
+ switch (g_type_fundamental (G_VALUE_TYPE (gvalue))) {
+ case G_TYPE_INT:
+ g_value_set_int (gvalue, *(gint*)value);
+ break;
+ case G_TYPE_FLOAT:
+ g_value_set_float (gvalue, *(gfloat*)value);
+ break;
+ case G_TYPE_DOUBLE:
+ g_value_set_double (gvalue, *(gdouble*)value);
+ break;
+ case G_TYPE_BOOLEAN:
+ g_value_set_boolean (gvalue, *(gboolean*)value);
+ break;
+ case G_TYPE_STRING:
+ g_value_set_string (gvalue, *(gchar**)value);
+ break;
+ case G_TYPE_CHAR:
+ g_value_set_char (gvalue, *(gchar*)value);
+ break;
+ case G_TYPE_UCHAR:
+ g_value_set_uchar (gvalue, *(guchar*)value);
+ break;
+ case G_TYPE_UINT:
+ g_value_set_uint (gvalue, *(guint*)value);
+ break;
+ case G_TYPE_POINTER:
+ g_value_set_pointer (gvalue, *(gpointer*)value);
+ break;
+ case G_TYPE_LONG:
+ g_value_set_long (gvalue, *(glong*)value);
+ break;
+ case G_TYPE_ULONG:
+ g_value_set_ulong (gvalue, *(gulong*)value);
+ break;
+ case G_TYPE_INT64:
+ g_value_set_int64 (gvalue, *(gint64*)value);
+ break;
+ case G_TYPE_UINT64:
+ g_value_set_uint64 (gvalue, *(guint64*)value);
+ break;
+ case G_TYPE_BOXED:
+ g_value_set_boxed (gvalue, *(gpointer*)value);
+ break;
+ default:
+ g_warning ("Unsupported fundamental type: %s",
+ g_type_name (g_type_fundamental (G_VALUE_TYPE (gvalue))));
+ }
+
+}
+
+/* from pygobject */
+void
+g_cclosure_marshal_generic_ffi (GClosure *closure,
+ GValue *return_gvalue,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint,
+ gpointer marshal_data)
+{
+ ffi_type *rtype;
+ void *rvalue;
+ int n_args;
+ ffi_type **atypes;
+ void **args;
+ int i;
+ ffi_cif cif;
+ GCClosure *cc = (GCClosure*) closure;
+
+ if (return_gvalue && G_VALUE_TYPE (return_gvalue))
+ {
+ rtype = g_value_to_ffi_type (return_gvalue, &rvalue);
+ }
+ else
+ {
+ rtype = &ffi_type_void;
+ }
+
+ rvalue = g_alloca (MAX (rtype->size, sizeof (ffi_arg)));
+
+ n_args = n_param_values + 1;
+ atypes = g_alloca (sizeof (ffi_type *) * n_args);
+ args = g_alloca (sizeof (gpointer) * n_args);
+
+ if (G_CCLOSURE_SWAP_DATA (closure))
+ {
+ atypes[n_args-1] = g_value_to_ffi_type (param_values + 0,
+ &args[n_args-1]);
+ atypes[0] = &ffi_type_pointer;
+ args[0] = &closure->data;
+ }
+ else
+ {
+ atypes[0] = g_value_to_ffi_type (param_values + 0, &args[0]);
+ atypes[n_args-1] = &ffi_type_pointer;
+ args[n_args-1] = &closure->data;
+ }
+
+ for (i = 1; i < n_args - 1; i++)
+ atypes[i] = g_value_to_ffi_type (param_values + i, &args[i]);
+
+ if (ffi_prep_cif (&cif, FFI_DEFAULT_ABI, n_args, rtype, atypes) != FFI_OK)
+ return;
+
+ ffi_call (&cif, marshal_data ? marshal_data : cc->callback, rvalue, args);
+
+ if (return_gvalue && G_VALUE_TYPE (return_gvalue))
+ g_value_from_ffi_type (return_gvalue, rvalue);
+}
+
+static JSValueRef
+seed_gsignal_method_invoked(JSContextRef ctx,
+ JSObjectRef function,
+ JSObjectRef thisObject,
+ size_t argumentCount,
+ const JSValueRef arguments[],
+ JSValueRef * exception)
+{
+ // TODO: class_closure, and accumlator. Not useful until we have structs.
+ JSValueRef jsname, jstype, jsflags, jsreturn_type, jsparams, ret;
+ GType itype, return_type;
+ guint n_params = 0;
+ GType * param_types = 0;
+ gchar * name;
+ guint signal_id;
+ GSignalFlags flags;
+
+ /* Sanity check */
+ if (argumentCount != 1)
+ {
+ gchar * mes = g_strdup_printf("Signal constructor expected 1 argument",
+ " got %d \n", argumentCount);
+ seed_make_exception(exception, "ArgumentError", mes);
+ g_free(mes);
+ return (JSObjectRef)JSValueMakeNull(eng->context);
+ }
+ if (JSValueIsNull(eng->context, arguments[0]) ||
+ !JSValueIsObject(eng->context, arguments[0]))
+ {
+ seed_make_exception(exception, "ArgumentError",
+ "Signal constructor expected object"
+ " as first argument");
+ return (JSObjectRef)JSValueMakeNull(eng->context);
+ }
+
+
+ /* Signal name */
+ jsname = seed_value_get_property((JSObjectRef)arguments[0], "name");
+ /* seed_value_to_string can handle non strings, however the kind
+ * of strings we want as a signal name are rather small, so make sure
+ * we have an actual string */
+ if (JSValueIsNull(eng->context, jsname) ||
+ !JSValueIsString(eng->context, jsname))
+ {
+ seed_make_exception(exception, "ArgumentError",
+ "Signal definition needs name property");
+ return (JSObjectRef)JSValueMakeNull(eng->context);
+ }
+ name = seed_value_to_string(jsname, exception);
+
+ /* Type to install on. Comes from class. */
+ jstype = seed_value_get_property(thisObject, "type");
+ itype = seed_value_to_int(jstype, exception);
+
+ /* Signal flags */
+ jsflags = seed_value_get_property((JSObjectRef)arguments[0], "flags");
+ if (JSValueIsNull(eng->context, jsflags) ||
+ !JSValueIsNumber(eng->context, jsflags))
+ flags = G_SIGNAL_RUN_FIRST;
+ else
+ flags = seed_value_to_long(jsflags, exception);
+
+
+ /* Return type */
+ jsreturn_type = seed_value_get_property((JSObjectRef)arguments[0],
+ "return_type");
+ if (JSValueIsNull(eng->context, jsreturn_type) ||
+ !JSValueIsNumber(eng->context, jsreturn_type))
+ return_type = G_TYPE_NONE;
+ else
+ return_type = seed_value_to_int(jsreturn_type, exception);
+
+ /* Number of params and types */
+ jsparams = seed_value_get_property((JSObjectRef)arguments[0],
+ "parameters");
+ if (!JSValueIsNull(eng->context, jsparams) &&
+ JSValueIsObject(eng->context, jsparams))
+ {
+ n_params = seed_value_to_int
+ (seed_value_get_property(jsparams, "length"), exception);
+ if (n_params > 0)
+ {
+ guint i;
+
+ param_types = g_new0(GType, n_params);
+ for (i = 0; i < n_params; i++)
+ {
+ JSValueRef ptype =
+ JSObjectGetPropertyAtIndex(eng->context,
+ (JSObjectRef)jsparams,
+ i,
+ exception);
+
+ param_types[i] = seed_value_to_int(ptype, exception);
+ }
+ }
+ }
+
+ signal_id = g_signal_newv(name, itype,
+ flags, 0, 0, 0,
+ g_cclosure_marshal_generic_ffi,
+ return_type,
+ n_params,
+ param_types);
+
+ g_free(name);
+ g_free(param_types);
+
+ return (JSValueRef)seed_value_from_uint(signal_id, exception);
+}
+
+
+
static void
seed_handle_class_init_closure(ffi_cif * cif,
void *result, void **args, void *userdata)
@@ -37,6 +323,14 @@
jsargs[0] = seed_make_struct(*(gpointer *) args[0], 0);
jsargs[1] = seed_gobject_get_prototype_for_gtype(type);
+ // TODO:
+ // Should probably have a custom type for class, and have it auto convert.
+ seed_value_set_property((JSObjectRef)jsargs[0],
+ "type", seed_value_from_int(type, 0));
+ seed_create_function("install_signal",
+ &seed_gsignal_method_invoked,
+ (JSObjectRef)jsargs[0]);
+
JSObjectCallAsFunction(eng->context, function, 0, 2, jsargs, 0);
if (exception)
{
@@ -211,15 +505,14 @@
void seed_gtype_init(void)
{
- JSClassDefinition def = kJSClassDefinitionEmpty;
+ JSClassDefinition gtype_def = kJSClassDefinitionEmpty;
JSObjectRef gtype_constructor;
- def.callAsConstructor = seed_gtype_constructor_invoked;
- seed_gtype_class = JSClassCreate(&def);
+ gtype_def.callAsConstructor = seed_gtype_constructor_invoked;
+ seed_gtype_class = JSClassCreate(>ype_def);
JSClassRetain(seed_gtype_class);
gtype_constructor = JSObjectMake(eng->context, seed_gtype_class, 0);
seed_value_set_property(eng->global, "GType", gtype_constructor);
-
}
Modified: trunk/libseed/seed-signals.c
==============================================================================
--- trunk/libseed/seed-signals.c (original)
+++ trunk/libseed/seed-signals.c Mon Nov 10 13:00:08 2008
@@ -111,6 +111,7 @@
{
SeedClosure *seed_closure = (SeedClosure *) closure;
JSValueRef *args, exception = 0;
+ JSValueRef ret = 0;
gint i;
args = g_newa(JSValueRef, n_param_values + 1);
@@ -131,10 +132,16 @@
else
args[i] = JSValueMakeNull(eng->context);
- JSObjectCallAsFunction(eng->context, seed_closure->function,
+ ret = JSObjectCallAsFunction(eng->context, seed_closure->function,
seed_closure->this,
n_param_values + 1, args, &exception);
+ if (ret)
+ {
+ seed_gvalue_from_seed_value(ret, seed_closure->return_type,
+ return_value, &exception);
+
+ }
if (exception)
{
gchar *mes = seed_exception_to_string(exception);
@@ -145,6 +152,61 @@
}
static JSValueRef
+seed_gobject_signal_emit(JSContextRef ctx,
+ JSObjectRef function,
+ JSObjectRef thisObject,
+ size_t argumentCount,
+ const JSValueRef arguments[],
+ JSValueRef * exception)
+{
+ JSValueRef ret;
+ GValue * params;
+ GValue ret_value = {0};
+ GSignalQuery query;
+
+ signal_privates * privates;
+ guint i;
+
+ privates = JSObjectGetPrivate(thisObject);
+
+ g_signal_query(privates->signal_id,
+ &query);
+
+ if (argumentCount != query.n_params)
+ {
+ gchar * mes = g_strdup_printf("Signal: %s for type %s expected %d "
+ "arguments, got %d",
+ query.signal_name,
+ g_type_name(query.itype),
+ query.n_params,
+ argumentCount);
+ seed_make_exception(exception, "ArgumentError", mes);
+ g_free(mes);
+ return JSValueMakeNull(eng->context);
+ }
+
+
+ params = g_new0(GValue, argumentCount+1);
+
+ g_value_init(¶ms[0], G_TYPE_OBJECT);
+ g_value_set_object(¶ms[0], privates->object);
+ for (i = 0; i < argumentCount; i++)
+ seed_gvalue_from_seed_value(arguments[i],
+ query.param_types[i],
+ ¶ms[i+1], exception);
+
+ g_signal_emitv(params, privates->signal_id, 0, &ret_value);
+
+ for (i = 0; i < argumentCount; i++)
+ g_value_unset(¶ms[i]);
+ g_free(params);
+
+ ret = seed_value_from_gvalue(&ret_value, exception);
+
+ return ret;
+}
+
+static JSValueRef
seed_gobject_signal_connect(JSContextRef ctx,
JSObjectRef function,
JSObjectRef thisObject,
@@ -152,6 +214,7 @@
const JSValueRef arguments[],
JSValueRef * exception)
{
+ GSignalQuery query;
signal_privates *privates;
GClosure *closure;
@@ -170,6 +233,8 @@
g_free(mes);
return JSValueMakeNull(eng->context);
}
+
+ g_signal_query(privates->signal_id, &query);
closure = g_closure_new_simple(sizeof(SeedClosure), 0);
g_closure_set_marshal(closure, seed_signal_marshal_func);
@@ -177,6 +242,7 @@
((SeedClosure *) closure)->function = (JSObjectRef) arguments[0];
((SeedClosure *) closure)->object =
g_object_get_data(privates->object, "js-ref");
+ ((SeedClosure *) closure)->return_type = query.return_type;
if (argumentCount >= 2 && !JSValueIsNull(eng->context, arguments[1]))
{
JSValueProtect(eng->context, (JSObjectRef) arguments[1]);
@@ -199,9 +265,9 @@
}
JSStaticFunction signal_static_functions[] =
- { {"connect", seed_gobject_signal_connect, 0}
-,
-{0, 0, 0}
+{ {"connect", seed_gobject_signal_connect, 0},
+ {"emit", seed_gobject_signal_emit, 0},
+ {0, 0, 0}
};
JSClassDefinition gobject_signal_def = {
Modified: trunk/tests/Makefile.am
==============================================================================
--- trunk/tests/Makefile.am (original)
+++ trunk/tests/Makefile.am Mon Nov 10 13:00:08 2008
@@ -3,8 +3,11 @@
compare.js \
constructor-args.js \
signal-this.js \
+ gtype-signal.js \
signal-userdata.js \
+ gtype-signal-exception.js \
out-test.js \
+ gtype-signal2.js \
signal-expects.js \
gtype.js \
json.js \
Added: trunk/tests/gtype-signal.js
==============================================================================
--- (empty file)
+++ trunk/tests/gtype-signal.js Mon Nov 10 13:00:08 2008
@@ -0,0 +1,34 @@
+#!/usr/bin/env seed
+// Returns: 0
+// STDIN:
+// STDOUT:Hello\nGoodbye
+// STDERR:
+
+Seed.import_namespace("Gtk");
+Gtk.init(null, null);
+
+HelloWindowType = {
+ parent: Gtk.Window,
+ name: "HelloWindow",
+ class_init: function(klass, prototype)
+ {
+ var HelloSignalDefinition = {name: "hello"};
+ var GoodbyeSignalDefinition = {name: "goodbye"};
+
+
+ hello_signal_id = klass.install_signal(HelloSignalDefinition);
+ goodbye_signal_id = klass.install_signal(GoodbyeSignalDefinition);
+ },
+ instance_init: function(klass)
+ {
+ }};
+
+HelloWindow = new GType(HelloWindowType);
+w = new HelloWindow();
+
+w.signal.hello.connect(function(){Seed.print("Hello")});
+w.signal.goodbye.connect(function(){Seed.print("Goodbye")});
+
+w.signal.hello.emit();
+w.signal.goodbye.emit();
+
Added: trunk/tests/gtype-signal2.js
==============================================================================
--- (empty file)
+++ trunk/tests/gtype-signal2.js Mon Nov 10 13:00:08 2008
@@ -0,0 +1,32 @@
+#!/usr/bin/env seed
+// Returns: 0
+// STDIN:
+// STDOUT:2 Weathermen
+// STDERR:
+
+Seed.import_namespace("GObject");
+Seed.import_namespace("Gtk");
+Gtk.init(null, null);
+
+HelloWindowType = {
+ parent: Gtk.Window,
+ name: "HelloWindow",
+ class_init: function(klass, prototype)
+ {
+ var HelloSignalDefinition = {name: "hello",
+ parameters: [GObject.TYPE_INT,
+ GObject.TYPE_STRING]};
+
+ hello_signal_id = klass.install_signal(HelloSignalDefinition);
+
+ },
+}
+
+HelloWindow = new GType(HelloWindowType);
+w = new HelloWindow();
+
+w.signal.hello.connect(function(object, number, string)
+ {Seed.print(number+ " " + string)});
+
+w.signal.hello.emit(2, "Weathermen");
+
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]