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



commit e026b36cdaf1c392a0d6a9e603289d1b9ada4e75
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 | 52 ++++++++++++++++++++++++++++++++++++++++++++++------
 gi/function.h   |  6 ++++++
 gi/object.cpp   | 24 ++++++++++++++++++++++--
 gi/value.cpp    | 15 ---------------
 gi/value.h      |  4 ----
 5 files changed, 74 insertions(+), 27 deletions(-)
---
diff --git a/gi/function.cpp b/gi/function.cpp
index 21699b8d..a43a99b1 100644
--- a/gi/function.cpp
+++ b/gi/function.cpp
@@ -173,11 +173,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);
@@ -205,7 +206,10 @@ gjs_callback_closure(ffi_cif *cif,
     JSAutoCompartment ac(context,
                          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);
@@ -223,19 +227,38 @@ 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;
@@ -283,7 +306,7 @@ gjs_callback_closure(ffi_cif *cif,
                 if (!gjs_value_from_g_argument(context, jsargs[n_jsargs++],
                                                &type_info,
                                                args[i + c_args_offset],
-                                               false))
+                                               should_copy))
                     goto out;
                 break;
             case PARAM_CALLBACK:
@@ -472,7 +495,8 @@ gjs_callback_trampoline_new(JSContext       *context,
                             GICallableInfo  *callable_info,
                             GIScopeType      scope,
                             JS::HandleObject scope_object,
-                            bool             is_vfunc)
+                            bool             is_vfunc,
+                            unsigned         signal_id)
 {
     GjsCallbackTrampoline *trampoline;
     int n_args, i;
@@ -562,11 +586,27 @@ gjs_callback_trampoline_new(JSContext       *context,
                                                           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::HandleValue 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);
+    return g_cclosure_new(reinterpret_cast<GCallback>(&trampoline->closure),
+                          trampoline,
+                          reinterpret_cast<GClosureNotify>(&gjs_callback_trampoline_unref));
+}
+
 /* an helper function to retrieve array lengths from a GArgument
    (letting the compiler generate good instructions in case of
    big endian machines) */
@@ -934,7 +974,7 @@ gjs_invoke_c_function(JSContext                             *context,
                                                              callable_info,
                                                              scope,
                                                              is_object_method ? obj : nullptr,
-                                                             false);
+                                                             false, 0);
                     closure = trampoline->closure;
                     g_base_info_unref(callable_info);
                 }
diff --git a/gi/function.h b/gi/function.h
index 9d3283a4..ffeb7ec4 100644
--- a/gi/function.h
+++ b/gi/function.h
@@ -50,6 +50,7 @@ struct GjsCallbackTrampoline {
     ffi_cif cif;
     ffi_closure *closure;
     GIScopeType scope;
+    unsigned signal_id;
     bool is_vfunc;
     GjsParamType *param_types;
 };
@@ -81,6 +82,11 @@ bool gjs_invoke_constructor_from_c(JSContext                  *context,
                                    const JS::HandleValueArray& args,
                                    GIArgument                 *rvalue);
 
+GClosure *gjs_signal_closure_new(JSContext      *cx,
+                                 JS::HandleValue function,
+                                 GISignalInfo   *signal_info,
+                                 unsigned        signal_id);
+
 G_END_DECLS
 
 #endif  /* __GJS_FUNCTION_H__ */
diff --git a/gi/object.cpp b/gi/object.cpp
index 3567ff57..13f48f61 100644
--- a/gi/object.cpp
+++ b/gi/object.cpp
@@ -1631,6 +1631,24 @@ gjs_lookup_object_prototype(JSContext *context,
     return proto;
 }
 
+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 */
+        GIObjectInfo *parent = g_object_info_get_parent(info);
+        if (parent) {
+            signal_info = lookup_signal(parent, signal_name);
+            g_base_info_unref(parent);
+        }
+    }
+
+    return signal_info;
+}
+
 static void
 do_associate_closure(ObjectInstance *priv,
                      GClosure       *closure)
@@ -1697,9 +1715,11 @@ real_connect_func(JSContext *context,
         return false;
     }
 
-    closure = gjs_closure_new_for_signal(context, &argv[1].toObject(), "signal callback", signal_id);
-    if (closure == NULL)
+    GISignalInfo *signal_info = lookup_signal(priv->info, g_signal_name(signal_id));
+    if (!signal_info)
         return false;
+
+    closure = gjs_signal_closure_new(context, argv[1], signal_info, signal_id);
     do_associate_closure(priv, closure);
 
     id = g_signal_connect_closure_by_id(priv->gobj,
diff --git a/gi/value.cpp b/gi/value.cpp
index b264cc71..5c2a508a 100644
--- a/gi/value.cpp
+++ b/gi/value.cpp
@@ -286,21 +286,6 @@ closure_marshal(GClosure        *closure,
     }
 }
 
-GClosure*
-gjs_closure_new_for_signal(JSContext  *context,
-                           JSObject   *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,
                            JSObject     *callable,
diff --git a/gi/value.h b/gi/value.h
index 1ad411df..a4fe7ed5 100644
--- a/gi/value.h
+++ b/gi/value.h
@@ -44,10 +44,6 @@ bool gjs_value_from_g_value(JSContext             *context,
 GClosure*  gjs_closure_new_marshaled    (JSContext    *context,
                                          JSObject     *callable,
                                          const char   *description);
-GClosure*  gjs_closure_new_for_signal   (JSContext    *context,
-                                         JSObject     *callable,
-                                         const char   *description,
-                                         guint         signal_id);
 
 G_END_DECLS
 


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