[pygobject] Special case signal output arguments which are structs as pass-by-reference



commit 28d0337f0e3d4b0e9c4350ce5d6cf0cb68da843f
Author: Simon Feltman <sfeltman src gnome org>
Date:   Fri Aug 29 14:18:28 2014 -0700

    Special case signal output arguments which are structs as pass-by-reference
    
    Add a special case which avoids copying of struct arguments marked as output
    to signals. Since we don't currently support output arguments, users have
    come to rely on a pass-by-reference bug which was fixed and caused this to
    regress (bug 722899). Add unittest which is currently failing due to a number
    of issues with emit() not supporting type annotations or output arguments
    (bug 735693).
    
    https://bugzilla.gnome.org/show_bug.cgi?id=735486

 gi/pygi-signal-closure.c    |   41 +++++++++++++++++++++++++++++++++++------
 tests/test_overrides_gtk.py |   24 ++++++++++++++++++++++++
 2 files changed, 59 insertions(+), 6 deletions(-)
---
diff --git a/gi/pygi-signal-closure.c b/gi/pygi-signal-closure.c
index 0c6b9b9..3cf8486 100644
--- a/gi/pygi-signal-closure.c
+++ b/gi/pygi-signal-closure.c
@@ -109,16 +109,19 @@ pygi_signal_closure_marshal(GClosure *closure,
         } else if (i < sig_info_highest_arg) {
             GIArgInfo arg_info;
             GITypeInfo type_info;
+            GITypeTag type_tag;
             GIArgument arg = { 0, };
             PyObject *item = NULL;
             gboolean free_array = FALSE;
+            gboolean pass_struct_by_ref = FALSE;
 
             g_callable_info_load_arg(signal_info, i - 1, &arg_info);
             g_arg_info_load_type(&arg_info, &type_info);
 
             arg = _pygi_argument_from_g_value(&param_values[i], &type_info);
-            
-            if (g_type_info_get_tag (&type_info) == GI_TYPE_TAG_ARRAY) {
+
+            type_tag = g_type_info_get_tag (&type_info);
+            if (type_tag == GI_TYPE_TAG_ARRAY) {
                 /* Skip the self argument of param_values */
                 arg.v_pointer = _pygi_argument_to_array (&arg,
                                                          _pygi_argument_array_length_marshal,
@@ -127,13 +130,39 @@ pygi_signal_closure_marshal(GClosure *closure,
                                                          &type_info,
                                                          &free_array);
             }
-            
-            item = _pygi_argument_to_object (&arg, &type_info, GI_TRANSFER_NOTHING);
-            
+
+            /* Hack to ensure struct output args are passed-by-reference allowing
+             * callback implementors to modify the struct values. This is needed
+             * for keeping backwards compatibility and should be removed in future
+             * versions which support signal output arguments as return values.
+             * See: https://bugzilla.gnome.org/show_bug.cgi?id=735486
+             */
+            if (type_tag == GI_TYPE_TAG_INTERFACE &&
+                    g_arg_info_get_direction (&arg_info) == GI_DIRECTION_OUT) {
+                GIBaseInfo *info = g_type_info_get_interface (&type_info);
+                GIInfoType info_type = g_base_info_get_type (info);
+
+                if (info_type == GI_INFO_TYPE_STRUCT) {
+                    GType gtype = g_registered_type_info_get_g_type ((GIRegisteredTypeInfo *) info);
+                    if (g_type_is_a (gtype, G_TYPE_BOXED)) {
+                        pass_struct_by_ref = TRUE;
+                    }
+                }
+
+                g_base_info_unref (info);
+            }
+
+            if (pass_struct_by_ref) {
+                item = _pygi_argument_to_object (&arg, &type_info, GI_TRANSFER_EVERYTHING);
+                ((PyGBoxed *)item)->free_on_dealloc = FALSE;
+
+            } else {
+                item = _pygi_argument_to_object (&arg, &type_info, GI_TRANSFER_NOTHING);
+            }
+
             if (free_array) {
                 g_array_free (arg.v_pointer, FALSE);
             }
-            
 
             if (item == NULL) {
                 goto out;
diff --git a/tests/test_overrides_gtk.py b/tests/test_overrides_gtk.py
index ba90fc3..395b157 100644
--- a/tests/test_overrides_gtk.py
+++ b/tests/test_overrides_gtk.py
@@ -701,6 +701,30 @@ class TestSignals(unittest.TestCase):
             self.assertIsInstance(win._alloc_value, Gdk.Rectangle)
             self.assertTrue(win._alloc_error is None, win._alloc_error)
 
+    @unittest.expectedFailure  # https://bugzilla.gnome.org/show_bug.cgi?id=735693
+    def test_overlay_child_position(self):
+        def get_child_position(overlay, widget, rect, user_data=None):
+            rect.x = 1
+            rect.y = 2
+            rect.width = 3
+            rect.height = 4
+            return True
+
+        overlay = Gtk.Overlay()
+        overlay.connect('get-child-position', get_child_position)
+
+        rect = Gdk.Rectangle()
+        rect.x = -1
+        rect.y = -1
+        rect.width = -1
+        rect.height = -1
+
+        overlay.emit('get-child-position', None, rect)
+        self.assertEqual(rect.x, 1)
+        self.assertEqual(rect.y, 2)
+        self.assertEqual(rect.width, 3)
+        self.assertEqual(rect.height, 4)
+
 
 @unittest.skipUnless(Gtk, 'Gtk not available')
 class TestBuilder(unittest.TestCase):


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