Commit f1a58305 authored by Xavier Claessens's avatar Xavier Claessens Committed by Philip Chimento

object: Use GISignalInfo to marshal signal arguments

Closes #57.
parent 239f338e
Pipeline #39789 failed with stages
in 2 minutes and 2 seconds
......@@ -190,11 +190,12 @@ gjs_callback_closure(ffi_cif *cif,
{
JSContext *context;
GjsCallbackTrampoline *trampoline;
int i, n_args, n_jsargs, n_outargs, c_args_offset = 0;
int i, n_args, n_jsargs = 0, n_outargs, c_args_offset = 0;
GITypeInfo ret_type;
bool success = false;
bool ret_type_is_void;
auto args = reinterpret_cast<GIArgument **>(ffi_args);
GSignalQuery signal_query = {0};
trampoline = (GjsCallbackTrampoline *) data;
g_assert(trampoline);
......@@ -229,7 +230,10 @@ gjs_callback_closure(ffi_cif *cif,
JSAutoCompartment ac(context, JS_GetFunctionObject(gjs_closure_get_callable(
trampoline->js_function)));
/* If this callable is a signal, there is an extra arg for self */
bool can_throw_gerror = g_callable_info_can_throw_gerror(trampoline->info);
bool is_signal = GI_IS_SIGNAL_INFO(trampoline->info);
n_args = g_callable_info_get_n_args(trampoline->info);
g_assert(n_args >= 0);
......@@ -247,19 +251,39 @@ gjs_callback_closure(ffi_cif *cif,
n_outargs = 0;
JS::AutoValueVector jsargs(context);
if (!jsargs.reserve(n_args))
if (!jsargs.reserve(is_signal ? n_args + 1 : n_args))
g_error("Unable to reserve space for vector");
if (is_signal) {
if (!jsargs.growBy(1))
g_error("Unable to grow vector");
auto* this_gobject = static_cast<GObject*>(args[0]->v_pointer);
JSObject* obj = gjs_object_from_g_object(context, this_gobject);
jsargs[n_jsargs++].setObject(*obj);
args++;
/* Query more info about this signal */
g_assert(trampoline->signal_id != 0);
g_signal_query(trampoline->signal_id, &signal_query);
g_assert(signal_query.n_params == unsigned(n_args));
}
JS::RootedValue rval(context);
for (i = 0, n_jsargs = 0; i < n_args; i++) {
for (i = 0; i < n_args; i++) {
GIArgInfo arg_info;
GITypeInfo type_info;
GjsParamType param_type;
bool should_copy = false;
g_callable_info_load_arg(trampoline->info, i, &arg_info);
g_arg_info_load_type(&arg_info, &type_info);
if (is_signal)
should_copy =
(signal_query.param_types[i] & G_SIGNAL_TYPE_STATIC_SCOPE) == 0;
/* Skip void * arguments */
if (g_type_info_get_tag(&type_info) == GI_TYPE_TAG_VOID)
continue;
......@@ -304,10 +328,9 @@ gjs_callback_closure(ffi_cif *cif,
if (!jsargs.growBy(1))
g_error("Unable to grow vector");
if (!gjs_value_from_g_argument(context, jsargs[n_jsargs++],
&type_info,
args[i + c_args_offset],
false))
if (!gjs_value_from_g_argument(
context, jsargs[n_jsargs++], &type_info,
args[i + c_args_offset], should_copy))
goto out;
break;
case PARAM_CALLBACK:
......@@ -492,7 +515,7 @@ gjs_destroy_notify_callback(gpointer data)
GjsCallbackTrampoline* gjs_callback_trampoline_new(
JSContext* context, JS::HandleFunction function,
GICallableInfo* callable_info, GIScopeType scope,
JS::HandleObject scope_object, bool is_vfunc) {
JS::HandleObject scope_object, bool is_vfunc, unsigned signal_id) {
GjsCallbackTrampoline *trampoline;
int n_args, i;
......@@ -576,11 +599,28 @@ GjsCallbackTrampoline* gjs_callback_trampoline_new(
gjs_callback_closure, trampoline);
trampoline->scope = scope;
trampoline->signal_id = signal_id;
trampoline->is_vfunc = is_vfunc;
return trampoline;
}
GClosure* gjs_signal_closure_new(JSContext* cx, JS::HandleFunction function,
GISignalInfo* signal_info,
unsigned signal_id) {
GjsCallbackTrampoline* trampoline = gjs_callback_trampoline_new(
cx, function, signal_info, GI_SCOPE_TYPE_CALL, nullptr, false,
signal_id);
if (!trampoline)
return nullptr;
return g_cclosure_new(reinterpret_cast<GCallback>(&trampoline->closure),
trampoline, [](void* data, GClosure*) {
gjs_callback_trampoline_unref(
static_cast<GjsCallbackTrampoline*>(data));
});
}
/* an helper function to retrieve array lengths from a GArgument
(letting the compiler generate good instructions in case of
big endian machines) */
......@@ -957,7 +997,7 @@ gjs_invoke_c_function(JSContext *context,
callable_info = (GICallableInfo*) g_type_info_get_interface(&ainfo);
trampoline = gjs_callback_trampoline_new(
context, func, callable_info, scope,
is_object_method ? obj : nullptr, false);
is_object_method ? obj : nullptr, false, 0);
closure = trampoline->closure;
g_base_info_unref(callable_info);
}
......
......@@ -51,15 +51,11 @@ struct GjsCallbackTrampoline {
ffi_cif cif;
ffi_closure *closure;
GIScopeType scope;
unsigned signal_id;
bool is_vfunc;
GjsParamType *param_types;
};
GJS_JSAPI_RETURN_CONVENTION
GjsCallbackTrampoline* gjs_callback_trampoline_new(
JSContext* cx, JS::HandleFunction function, GICallableInfo* callable_info,
GIScopeType scope, JS::HandleObject scope_object, bool is_vfunc);
void gjs_callback_trampoline_unref(GjsCallbackTrampoline *trampoline);
void gjs_callback_trampoline_ref(GjsCallbackTrampoline *trampoline);
......@@ -83,6 +79,16 @@ bool gjs_invoke_constructor_from_c(JSContext *context,
const JS::HandleValueArray& args,
GIArgument *rvalue);
GJS_JSAPI_RETURN_CONVENTION
GClosure* gjs_signal_closure_new(JSContext* cx, JS::HandleFunction function,
GISignalInfo* signal_info, unsigned signal_id);
G_END_DECLS
GJS_JSAPI_RETURN_CONVENTION
GjsCallbackTrampoline* gjs_callback_trampoline_new(
JSContext* cx, JS::HandleFunction function, GICallableInfo* callable_info,
GIScopeType scope, JS::HandleObject scope_object, bool is_vfunc,
unsigned signal_id = 0);
#endif /* __GJS_FUNCTION_H__ */
......@@ -1899,6 +1899,22 @@ bool ObjectBase::connect_after(JSContext* cx, unsigned argc, JS::Value* vp) {
return priv->to_instance()->connect_impl(cx, args, true);
}
/* Return value must be freed */
GJS_USE
static GISignalInfo* lookup_signal(GIObjectInfo* info,
const char* signal_name) {
GISignalInfo* signal_info = g_object_info_find_signal(info, signal_name);
if (!signal_info) {
/* Not found, recurse on parent object info */
GjsAutoObjectInfo parent = g_object_info_get_parent(info);
if (parent)
signal_info = lookup_signal(parent, signal_name);
}
return signal_info;
}
bool
ObjectInstance::connect_impl(JSContext *context,
const JS::CallArgs& args,
......@@ -1933,10 +1949,16 @@ ObjectInstance::connect_impl(JSContext *context,
return false;
}
closure = gjs_closure_new_for_signal(
context, JS_GetObjectFunction(callback), "signal callback", signal_id);
if (closure == NULL)
GjsAutoSignalInfo signal_info =
lookup_signal(info(), g_signal_name(signal_id));
if (!signal_info) {
gjs_throw(context, "No introspection information for signal %s",
g_signal_name(signal_id));
return false;
}
JS::RootedFunction func(context, JS_GetObjectFunction(callback));
closure = gjs_signal_closure_new(context, func, signal_info, signal_id);
associate_closure(context, closure);
id = g_signal_connect_closure_by_id(m_gobj,
......
......@@ -292,17 +292,6 @@ closure_marshal(GClosure *closure,
}
}
GClosure* gjs_closure_new_for_signal(JSContext* context, JSFunction* callable,
const char* description, guint signal_id) {
GClosure *closure;
closure = gjs_closure_new(context, callable, description, false);
g_closure_set_meta_marshal(closure, GUINT_TO_POINTER(signal_id), closure_marshal);
return closure;
}
GClosure* gjs_closure_new_marshaled(JSContext* context, JSFunction* callable,
const char* description) {
GClosure *closure;
......
......@@ -49,10 +49,6 @@ bool gjs_value_from_g_value(JSContext *context,
GJS_USE
GClosure* gjs_closure_new_marshaled(JSContext* cx, JSFunction* callable,
const char* description);
GJS_USE
GClosure* gjs_closure_new_for_signal(JSContext* cx, JSFunction* callable,
const char* description,
unsigned signal_id);
G_END_DECLS
......
......@@ -131,6 +131,7 @@ using GjsAutoFunctionInfo = GjsAutoInfo<GI_INFO_TYPE_FUNCTION>;
using GjsAutoInterfaceInfo = GjsAutoInfo<GI_INFO_TYPE_INTERFACE>;
using GjsAutoObjectInfo = GjsAutoInfo<GI_INFO_TYPE_OBJECT>;
using GjsAutoPropertyInfo = GjsAutoInfo<GI_INFO_TYPE_PROPERTY>;
using GjsAutoSignalInfo = GjsAutoInfo<GI_INFO_TYPE_SIGNAL>;
using GjsAutoStructInfo = GjsAutoInfo<GI_INFO_TYPE_STRUCT>;
using GjsAutoTypeInfo = GjsAutoInfo<GI_INFO_TYPE_TYPE>;
using GjsAutoVFuncInfo = GjsAutoInfo<GI_INFO_TYPE_VFUNC>;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment