[gjs] GI: handle G_SIGNAL_TYPE_STATIC_SCOPE in JS signal handlers



commit 9eabf87ff79a25f0b6c2aabe79ca5f8c43b078c9
Author: Johan Bilien <jobi litl com>
Date:   Tue Mar 24 15:20:56 2009 +0000

    GI: handle G_SIGNAL_TYPE_STATIC_SCOPE in JS signal handlers
    
    gi/value.[ch]:
      . allow converting C -> JS boxed without copy
      . add a gjs_closure_new_for_signal for signal closures,
        which will not copy when G_SIGNAL_TYPE_STATIC_SCOPE is set
    gi/object.c:
      . use the new gjs_closure_new_for_signal
---
 gi/object.c |   10 +++-----
 gi/value.c  |   71 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
 gi/value.h  |    4 +++
 3 files changed, 73 insertions(+), 12 deletions(-)

diff --git a/gi/object.c b/gi/object.c
index 07bfca3..b4ee367 100644
--- a/gi/object.c
+++ b/gi/object.c
@@ -917,13 +917,8 @@ real_connect_func(JSContext *context,
         return JS_FALSE;
     }
 
-    closure = gjs_closure_new_marshaled(context, JSVAL_TO_OBJECT(argv[1]), "signal callback");
-    if (closure == NULL)
-        return JS_FALSE;
-
     signal_name = gjs_string_get_ascii_checked(context, argv[0]);
     if (signal_name == NULL) {
-        g_closure_sink(closure);
         return JS_FALSE;
     }
 
@@ -932,10 +927,13 @@ real_connect_func(JSContext *context,
         gjs_throw(context, "No signal %s on object of type %s",
                   signal_name,
                   g_base_info_get_name((GIBaseInfo*) priv->info));
-        g_closure_sink(closure);
         return JS_FALSE;
     }
 
+    closure = gjs_closure_new_for_signal(context, JSVAL_TO_OBJECT(argv[1]), "signal callback", signal_id);
+    if (closure == NULL)
+        return JS_FALSE;
+
     id = g_signal_connect_closure(priv->gobj,
                                   signal_name,
                                   closure,
diff --git a/gi/value.c b/gi/value.c
index d7f6499..590da8a 100644
--- a/gi/value.c
+++ b/gi/value.c
@@ -36,6 +36,11 @@
 
 #include <girepository.h>
 
+static JSBool gjs_value_from_g_value_internal(JSContext    *context,
+                                              jsval        *value_p,
+                                              const GValue *gvalue,
+                                              gboolean      no_copy);
+
 static void
 closure_marshal(GClosure        *closure,
                 GValue          *return_value,
@@ -49,6 +54,7 @@ closure_marshal(GClosure        *closure,
     jsval *argv;
     jsval rval;
     int i;
+    GSignalQuery signal_query = { 0, };
 
     gjs_debug_marshal(GJS_DEBUG_GCLOSURE,
                       "Marshal closure %p",
@@ -68,9 +74,38 @@ closure_marshal(GClosure        *closure,
     gjs_root_value_locations(context, argv, argc);
     JS_AddRoot(context, &rval);
 
+    if (marshal_data) {
+        /* we are used for a signal handler */
+        guint signal_id;
+
+        signal_id = GPOINTER_TO_UINT(marshal_data);
+
+        g_signal_query(signal_id, &signal_query);
+
+        if (!signal_query.signal_id) {
+            gjs_debug(GJS_DEBUG_GCLOSURE,
+                      "Signal handler being called on invalid signal");
+            goto cleanup;
+        }
+
+        if (signal_query.n_params + 1 != n_param_values) {
+            gjs_debug(GJS_DEBUG_GCLOSURE,
+                      "Signal handler being called with wrong number of parameters");
+            goto cleanup;
+        }
+    }
+
     for (i = 0; i < argc; ++i) {
         const GValue *gval = &param_values[i];
-        if (!gjs_value_from_g_value(context, &argv[i], gval)) {
+        gboolean no_copy;
+
+        no_copy = FALSE;
+
+        if (i >= 1 && signal_query.signal_id) {
+            no_copy = signal_query.param_types[i - 1] & G_SIGNAL_TYPE_STATIC_SCOPE;
+        }
+
+        if (!gjs_value_from_g_value_internal(context, &argv[i], gval, no_copy)) {
             gjs_debug(GJS_DEBUG_GCLOSURE,
                       "Unable to convert arg %d in order to invoke closure",
                       i);
@@ -101,6 +136,21 @@ 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);
+
+    g_closure_set_meta_marshal(closure, GUINT_TO_POINTER(signal_id), closure_marshal);
+
+    return closure;
+}
+
+GClosure*
 gjs_closure_new_marshaled (JSContext    *context,
                            JSObject     *callable,
                            const char   *description)
@@ -429,10 +479,11 @@ gjs_value_to_g_value(JSContext    *context,
     return JS_TRUE;
 }
 
-JSBool
-gjs_value_from_g_value(JSContext    *context,
-                       jsval        *value_p,
-                       const GValue *gvalue)
+static JSBool
+gjs_value_from_g_value_internal(JSContext    *context,
+                                jsval        *value_p,
+                                const GValue *gvalue,
+                                gboolean      no_copy)
 {
     GType gtype;
 
@@ -510,7 +561,7 @@ gjs_value_from_g_value(JSContext    *context,
         switch (g_base_info_get_type(info)) {
         case GI_INFO_TYPE_BOXED:
         case GI_INFO_TYPE_STRUCT:
-            obj = gjs_boxed_from_c_struct(context, (GIStructInfo *)info, gboxed, FALSE);
+            obj = gjs_boxed_from_c_struct(context, (GIStructInfo *)info, gboxed, no_copy);
             break;
         case GI_INFO_TYPE_UNION:
             obj = gjs_union_from_c_union(context, (GIUnionInfo *)info, gboxed);
@@ -570,3 +621,11 @@ gjs_value_from_g_value(JSContext    *context,
 
     return JS_TRUE;
 }
+
+JSBool
+gjs_value_from_g_value(JSContext    *context,
+                       jsval        *value_p,
+                       const GValue *gvalue)
+{
+    return gjs_value_from_g_value_internal(context, value_p, gvalue, FALSE);
+}
diff --git a/gi/value.h b/gi/value.h
index da76b6b..460c5ed 100644
--- a/gi/value.h
+++ b/gi/value.h
@@ -39,6 +39,10 @@ JSBool     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]