[gnode] Add trampolines / closures
- From: Jasper St. Pierre <jstpierre src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnode] Add trampolines / closures
- Date: Sat, 28 Nov 2015 05:53:23 +0000 (UTC)
commit 93c19c7cef1f8869c35cf35484e511a0b0417c51
Author: Jasper St. Pierre <jstpierre mecheye net>
Date: Fri Nov 27 16:15:56 2015 -0800
Add trampolines / closures
Trying out various C++ features here, so it's not coherent at all..
src/function.cc | 106 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/function.h | 2 +
src/gobject.cc | 20 ++++++++++
src/value.cc | 21 +++++++++++
src/value.h | 1 +
5 files changed, 150 insertions(+), 0 deletions(-)
---
diff --git a/src/function.cc b/src/function.cc
index 09d588c..e76bc4e 100644
--- a/src/function.cc
+++ b/src/function.cc
@@ -149,4 +149,110 @@ Handle<Function> MakeFunction(GIBaseInfo *info) {
return fn;
}
+class TrampolineInfo {
+ private:
+ ffi_cif cif;
+ ffi_closure *closure;
+ v8::Persistent<v8::Function> func;
+ GICallableInfo *info;
+ GIScopeType scope_type;
+
+ public:
+ TrampolineInfo(v8::Handle<v8::Function> function,
+ GICallableInfo *info,
+ GIScopeType scope_type);
+
+ void Dispose();
+ static void Call(ffi_cif *cif, void *result, void **args, void *data);
+ void *GetClosure();
+};
+
+void TrampolineInfo::Dispose() {
+ func.Dispose ();
+ g_base_info_unref (info);
+ g_callable_info_free_closure (info, closure);
+};
+
+void TrampolineInfo::Call(ffi_cif *cif,
+ void *result,
+ void **args,
+ void *data) {
+ TrampolineInfo *trampoline = (TrampolineInfo *) data;
+
+ int argc = g_callable_info_get_n_args (trampoline->info);
+ Handle<Value> argv[argc];
+
+ for (int i = 0; i < argc; i++) {
+ GIArgInfo arg_info;
+ g_callable_info_load_arg (trampoline->info, i, &arg_info);
+ GITypeInfo type_info;
+ g_arg_info_load_type (&arg_info, &type_info);
+ argv[i] = GIArgumentToV8 (&type_info, (GIArgument *) &args[i]);
+ }
+
+ Handle<Function> func = trampoline->func;
+ /* Provide a bogus "this" function. Any interested callers should
+ * bind their callbacks to what they're intersted in... */
+ Handle<Object> this_obj = func;
+ Handle<Value> return_value = func->Call (this_obj, argc, argv);
+ GITypeInfo type_info;
+ g_callable_info_load_return_type (trampoline->info, &type_info);
+ V8ToGIArgument (&type_info, (GIArgument *) &result, return_value,
+ g_callable_info_may_return_null (trampoline->info));
+}
+
+TrampolineInfo::TrampolineInfo(Handle<Function> function,
+ GICallableInfo *info,
+ GIScopeType scope_type) {
+ this->closure = g_callable_info_prepare_closure (info, &cif, Call, this);
+ this->func = Persistent<Function>::New (function);
+ this->info = g_base_info_ref (info);
+ this->scope_type = scope_type;
+}
+
+struct Closure {
+ GClosure base_;
+ Persistent<Function> func;
+
+ static void Marshal(GClosure *closure,
+ GValue *g_return_value,
+ uint argc, const GValue *g_argv,
+ gpointer invocation_hint,
+ gpointer marshal_data);
+
+ static void Invalidated(gpointer data, GClosure *closure);
+};
+
+void Closure::Marshal(GClosure *base,
+ GValue *g_return_value,
+ uint argc, const GValue *g_argv,
+ gpointer invocation_hint,
+ gpointer marshal_data) {
+ Closure *closure = (Closure *) base;
+ Handle<Function> func = closure->func;
+
+ Handle<Value> argv[argc];
+
+ for (uint i = 0; i < argc; i++)
+ argv[i] = GValueToV8 (&g_argv[i]);
+
+ Handle<Object> this_obj = func;
+ Handle<Value> return_value = func->Call (this_obj, argc, argv);
+ V8ToGValue (g_return_value, return_value);
+}
+
+void Closure::Invalidated(gpointer data, GClosure *base) {
+ Closure *closure = (Closure *) base;
+ closure->func.Dispose();
+}
+
+GClosure *MakeClosure(Handle<Function> function) {
+ Closure *closure = (Closure *) g_closure_new_simple (sizeof (*closure), NULL);
+ closure->func = Persistent<Function>::New (function);
+ GClosure *gclosure = &closure->base_;
+ g_closure_set_marshal (gclosure, Closure::Marshal);
+ g_closure_add_invalidate_notifier (gclosure, NULL, Closure::Invalidated);
+ return gclosure;
+}
+
};
diff --git a/src/function.h b/src/function.h
index fea7903..fc9bced 100644
--- a/src/function.h
+++ b/src/function.h
@@ -24,9 +24,11 @@
#include <node.h>
#include <girepository.h>
+#include <girffi.h>
namespace GNodeJS {
v8::Handle<v8::Function> MakeFunction(GIBaseInfo *base_info);
+GClosure *MakeClosure(v8::Handle<v8::Function> function);
};
diff --git a/src/gobject.cc b/src/gobject.cc
index 68bf554..f54b7ed 100644
--- a/src/gobject.cc
+++ b/src/gobject.cc
@@ -176,9 +176,29 @@ static void DefinePrototypeMethods(Handle<ObjectTemplate> prototype, GIBaseInfo
}
}
+static Handle<Value> SignalConnectInternal(const Arguments &args, bool after) {
+ HandleScope scope;
+ GObject *gobject = GObjectFromWrapper(args.This ());
+
+ String::Utf8Value signal_name (args[0]->ToString ());
+ Handle<Function> callback = Local<Function>::Cast (args[1]->ToObject ());
+ GClosure *gclosure = MakeClosure (callback);
+
+ ulong handler_id = g_signal_connect_closure (gobject, *signal_name, gclosure, after);
+ return scope.Close (Integer::NewFromUnsigned (handler_id));
+}
+
+static Handle<Value> SignalConnect(const Arguments &args) {
+ return SignalConnectInternal (args, false);
+}
+
static Handle<FunctionTemplate> GetBaseClassTemplate() {
Local<FunctionTemplate> tpl = FunctionTemplate::New ();
tpl->InstanceTemplate ()->SetInternalFieldCount (1);
+
+ Handle<ObjectTemplate> proto = tpl->PrototypeTemplate ();
+ proto->Set (String::NewSymbol ("connect"), FunctionTemplate::New (SignalConnect)->GetFunction ());
+
return tpl;
}
diff --git a/src/value.cc b/src/value.cc
index b1bd5d2..16129e5 100644
--- a/src/value.cc
+++ b/src/value.cc
@@ -254,4 +254,25 @@ void V8ToGValue(GValue *gvalue, Handle<Value> value) {
}
}
+Handle<Value> GValueToV8(const GValue *gvalue) {
+ if (G_VALUE_HOLDS_BOOLEAN (gvalue)) {
+ if (g_value_get_boolean (gvalue))
+ return True ();
+ else
+ return False ();
+ } else if (G_VALUE_HOLDS_INT (gvalue)) {
+ return Integer::New (g_value_get_int (gvalue));
+ } else if (G_VALUE_HOLDS_UINT (gvalue)) {
+ return Integer::NewFromUnsigned (g_value_get_uint (gvalue));
+ } else if (G_VALUE_HOLDS_FLOAT (gvalue)) {
+ return Number::New (g_value_get_float (gvalue));
+ } else if (G_VALUE_HOLDS_DOUBLE (gvalue)) {
+ return Number::New (g_value_get_double (gvalue));
+ } else if (G_VALUE_HOLDS_STRING (gvalue)) {
+ return String::New (g_value_get_string (gvalue));
+ } else {
+ g_assert_not_reached ();
+ }
+}
+
};
diff --git a/src/value.h b/src/value.h
index 48dcbb3..6fcd6cd 100644
--- a/src/value.h
+++ b/src/value.h
@@ -32,5 +32,6 @@ void V8ToGIArgument(GITypeInfo *type_info, GIArgument *argument, v8::Handle<v8::
void FreeGIArgument(GITypeInfo *type_info, GIArgument *argument);
void V8ToGValue(GValue *gvalue, v8::Handle<v8::Value> value);
+v8::Handle<v8::Value> GValueToV8(const GValue *gvalue);
};
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]