[pygobject] Fix marshalling of C arrays with explicit length in signal arguments



commit b6fefd625b843d4fc3dabc456584a2ad27a48c8c
Author: Martin Pitt <martinpitt gnome org>
Date:   Wed Feb 27 13:41:55 2013 +0100

    Fix marshalling of C arrays with explicit length in signal arguments
    
    We need _pygi_argument_to_array() from both closure marshalling (where we have
    the arguments as GIArgument array) and signal closure marshalling (where we
    have the arguments in a GValue array). Add an alternative "args_values"
    parameter to _pygi_argument_to_array() so that callers can specify one or the
    other depending on which type they have available.
    
    This allows us to pass on the full argument list for signal closures, so that
    _pygi_argument_to_array() can access the explicit length argument for an
    array.
    
    This fixes the GSettings:change-event signal.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=662241

 gi/pygi-argument.c       |   36 ++++++++++++++++++++++++++++--------
 gi/pygi-argument.h       |    1 +
 gi/pygi-closure.c        |    2 +-
 gi/pygi-info.c           |    4 ++--
 gi/pygi-signal-closure.c |    3 ++-
 tests/test_gio.py        |   18 ++++++++++++++++++
 6 files changed, 52 insertions(+), 12 deletions(-)
---
diff --git a/gi/pygi-argument.c b/gi/pygi-argument.c
index 3b65246..8dd7842 100644
--- a/gi/pygi-argument.c
+++ b/gi/pygi-argument.c
@@ -762,8 +762,12 @@ check_number_release:
  * _pygi_argument_to_array
  * @arg: The argument to convert
  * @args: Arguments to method invocation, possibly contaning the array length.
- *        Set to NULL if this is not for a method call
- * @callable_info: Info on the callable, if this a method call; otherwise NULL
+ *        Set to %NULL if this is not for a method call or @args_values is
+ *        specified.
+ * @args_values: GValue Arguments to method invocation, possibly contaning the
+ *               array length. Set to %NULL if this is not for a method call or
+ *               @args is specified.
+ * @callable_info: Info on the callable, if this a method call; otherwise %NULL
  * @type_info: The type info for @arg
  * @out_free_array: A return location for a gboolean that indicates whether
  *                  or not the wrapped GArray should be freed
@@ -781,6 +785,7 @@ check_number_release:
 GArray *
 _pygi_argument_to_array (GIArgument  *arg,
                          GIArgument  *args[],
+                         const GValue *args_values,
                          GICallableInfo *callable_info,                  
                          GITypeInfo  *type_info,
                          gboolean    *out_free_array)
@@ -815,7 +820,7 @@ _pygi_argument_to_array (GIArgument  *arg,
                     GIArgInfo length_arg_info;
                     GITypeInfo length_type_info;
 
-                    if (G_UNLIKELY (args == NULL)) {
+                    if (G_UNLIKELY (args == NULL && args_values == NULL)) {
                         g_critical ("Unable to determine array length for %p",
                                     arg->v_pointer);
                         g_array = g_array_new (is_zero_terminated, FALSE, item_size);
@@ -828,10 +833,21 @@ _pygi_argument_to_array (GIArgument  *arg,
                     g_assert (callable_info);
                     g_callable_info_load_arg (callable_info, length_arg_pos, &length_arg_info);
                     g_arg_info_load_type (&length_arg_info, &length_type_info);
-                    if (!gi_argument_to_gssize (args[length_arg_pos],
-                                                g_type_info_get_tag (&length_type_info),
-                                                &length))
-                        return NULL;
+
+                    if (args != NULL) {
+                        if (!gi_argument_to_gssize (args[length_arg_pos],
+                                                    g_type_info_get_tag (&length_type_info),
+                                                    &length))
+                            return NULL;
+                    } else {
+                        /* get it from args_values */
+                        GIArgument length_arg = _pygi_argument_from_g_value (&(args_values[length_arg_pos]),
+                                &length_type_info);
+                        if (!gi_argument_to_gssize (&length_arg,
+                                                    g_type_info_get_tag (&length_type_info),
+                                                    &length))
+                            return NULL;
+                    }
                 }
             }
 
@@ -2047,7 +2063,11 @@ _pygi_argument_from_g_value(const GValue *value,
             break;
         case GI_TYPE_TAG_ARRAY:
         case GI_TYPE_TAG_GHASH:
-            arg.v_pointer = g_value_get_boxed (value);
+            if (G_VALUE_HOLDS_BOXED (value))
+                arg.v_pointer = g_value_get_boxed (value);
+            else
+                /* e. g. GSettings::change-event */
+                arg.v_pointer = g_value_get_pointer (value);
             break;
         case GI_TYPE_TAG_INTERFACE:
         {
diff --git a/gi/pygi-argument.h b/gi/pygi-argument.h
index a1420ee..ed88214 100644
--- a/gi/pygi-argument.h
+++ b/gi/pygi-argument.h
@@ -50,6 +50,7 @@ gint _pygi_g_registered_type_info_check_object (GIRegisteredTypeInfo *info,
 
 GArray* _pygi_argument_to_array (GIArgument  *arg,
                                  GIArgument  *args[],
+                                 const GValue *args_values,
                                  GICallableInfo *callable_info,
                                  GITypeInfo  *type_info,
                                  gboolean    *out_free_array);
diff --git a/gi/pygi-closure.c b/gi/pygi-closure.c
index aa9cb78..f49f8e2 100644
--- a/gi/pygi-closure.c
+++ b/gi/pygi-closure.c
@@ -353,7 +353,7 @@ _pygi_closure_convert_arguments (GICallableInfo *callable_info, void **args,
                     arg = (GIArgument*) g_args[i].v_pointer;
                 
                 if (g_type_info_get_tag (&arg_type) == GI_TYPE_TAG_ARRAY)
-                    arg->v_pointer = _pygi_argument_to_array (arg, (GIArgument **) args, 
+                    arg->v_pointer = _pygi_argument_to_array (arg, (GIArgument **) args, NULL,
                                                               callable_info, &arg_type, &free_array);
 
                 value = _pygi_argument_to_object (arg, &arg_type, transfer);
diff --git a/gi/pygi-info.c b/gi/pygi-info.c
index 4d5b9bb..362e7cd 100644
--- a/gi/pygi-info.c
+++ b/gi/pygi-info.c
@@ -1245,7 +1245,7 @@ _wrap_g_constant_info_get_value (PyGIBaseInfo *self)
     type_info = g_constant_info_get_type ( (GIConstantInfo *) self->info);
 
     if (g_type_info_get_tag (type_info) == GI_TYPE_TAG_ARRAY) {
-        value.v_pointer = _pygi_argument_to_array (&value, NULL, NULL,
+        value.v_pointer = _pygi_argument_to_array (&value, NULL, NULL, NULL,
                                                    type_info, &free_array);
     }
 
@@ -1378,7 +1378,7 @@ _wrap_g_field_info_get_value (PyGIBaseInfo *self,
     }
 
     if (g_type_info_get_tag (field_type_info) == GI_TYPE_TAG_ARRAY) {
-        value.v_pointer = _pygi_argument_to_array (&value, NULL, NULL,
+        value.v_pointer = _pygi_argument_to_array (&value, NULL, NULL, NULL,
                                                    field_type_info, &free_array);
     }
 
diff --git a/gi/pygi-signal-closure.c b/gi/pygi-signal-closure.c
index 36ea168..6e026de 100644
--- a/gi/pygi-signal-closure.c
+++ b/gi/pygi-signal-closure.c
@@ -141,7 +141,8 @@ pygi_signal_closure_marshal(GClosure *closure,
             arg = _pygi_argument_from_g_value(&param_values[i], &type_info);
             
             if (g_type_info_get_tag (&type_info) == GI_TYPE_TAG_ARRAY) {
-                arg.v_pointer = _pygi_argument_to_array (&arg, NULL, NULL,
+                /* Skip the self argument of param_values */
+                arg.v_pointer = _pygi_argument_to_array (&arg, NULL, param_values + 1, signal_info,
                                                          &type_info, &free_array);
             }
             
diff --git a/tests/test_gio.py b/tests/test_gio.py
index 942ee00..57ab013 100644
--- a/tests/test_gio.py
+++ b/tests/test_gio.py
@@ -120,6 +120,24 @@ class TestGSettings(unittest.TestCase):
         self.assertEqual(bool(empty), True)
         self.assertEqual(empty.keys(), [])
 
+    def test_change_event(self):
+        changed_log = []
+        change_event_log = []
+
+        def on_changed(settings, key):
+            changed_log.append((settings, key))
+
+        def on_change_event(settings, keys, n_keys):
+            change_event_log.append((settings, keys, n_keys))
+
+        self.settings.connect('changed', on_changed)
+        self.settings.connect('change-event', on_change_event)
+        self.settings['test-string'] = 'Moo'
+        self.assertEqual(changed_log, [(self.settings, 'test-string')])
+        self.assertEqual(change_event_log, [(self.settings,
+                                             [GLib.quark_from_static_string('test-string')],
+                                             1)])
+
 
 class TestGFile(unittest.TestCase):
     def setUp(self):


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