[gjs/wip/xclaesse/57-should-use-g-i-annotations-for-signal: 243/243] object: Use GISignalInfo to marshal signal arguments



commit 95293e25a1b3668adbf055f069c2779b27fd682a
Author: Xavier Claessens <xclaesse gmail com>
Date:   Thu Aug 25 18:09:00 2011 +0200

    object: Use GISignalInfo to marshal signal arguments
    
    Closes #57.

 gi/function.cpp  | 59 +++++++++++++++++++++++++++++++++++++++++++++++---------
 gi/function.h    |  8 +++++++-
 gi/object.cpp    | 28 ++++++++++++++++++++++++---
 gi/value.cpp     | 11 -----------
 gi/value.h       |  4 ----
 gjs/jsapi-util.h |  1 +
 6 files changed, 83 insertions(+), 28 deletions(-)
---
diff --git a/gi/function.cpp b/gi/function.cpp
index ce04027f..7df9c505 100644
--- a/gi/function.cpp
+++ b/gi/function.cpp
@@ -194,7 +194,7 @@ static void gjs_callback_closure(ffi_cif* cif G_GNUC_UNUSED, void* result,
                                  void** ffi_args, void* data) {
     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;
@@ -233,7 +233,10 @@ static void gjs_callback_closure(ffi_cif* cif G_GNUC_UNUSED, void* result,
     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);
@@ -257,19 +260,41 @@ static void gjs_callback_closure(ffi_cif* cif G_GNUC_UNUSED, void* result,
     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");
 
+    GSignalQuery signal_query = {0};
+    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 = ObjectInstance::wrapper_from_gobject(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;
@@ -314,10 +339,9 @@ static void gjs_callback_closure(ffi_cif* cif G_GNUC_UNUSED, void* result,
                 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:
@@ -505,7 +529,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;
 
@@ -595,11 +619,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) */
@@ -962,7 +1003,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);
                 }
diff --git a/gi/function.h b/gi/function.h
index f9b14254..ba3e0726 100644
--- a/gi/function.h
+++ b/gi/function.h
@@ -49,6 +49,7 @@ struct GjsCallbackTrampoline {
     ffi_cif cif;
     ffi_closure *closure;
     GIScopeType scope;
+    unsigned signal_id;
     bool is_vfunc;
     GjsParamType *param_types;
 };
@@ -56,7 +57,8 @@ struct GjsCallbackTrampoline {
 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);
+    GIScopeType scope, JS::HandleObject scope_object, bool is_vfunc,
+    unsigned signal_id = 0);
 
 void gjs_callback_trampoline_unref(GjsCallbackTrampoline *trampoline);
 void gjs_callback_trampoline_ref(GjsCallbackTrampoline *trampoline);
@@ -81,4 +83,8 @@ 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);
+
 #endif  // GI_FUNCTION_H_
diff --git a/gi/object.cpp b/gi/object.cpp
index 3d0064b5..afdfc3a3 100644
--- a/gi/object.cpp
+++ b/gi/object.cpp
@@ -1751,6 +1751,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,
@@ -1785,10 +1801,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_ptr, signal_id, signal_detail,
diff --git a/gi/value.cpp b/gi/value.cpp
index a375c34a..1141729a 100644
--- a/gi/value.cpp
+++ b/gi/value.cpp
@@ -299,17 +299,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;
diff --git a/gi/value.h b/gi/value.h
index d929c9e3..ac3fe2f1 100644
--- a/gi/value.h
+++ b/gi/value.h
@@ -47,9 +47,5 @@ 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);
 
 #endif  // GI_VALUE_H_
diff --git a/gjs/jsapi-util.h b/gjs/jsapi-util.h
index 06f57b5b..00fe231c 100644
--- a/gjs/jsapi-util.h
+++ b/gjs/jsapi-util.h
@@ -130,6 +130,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>;


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