diff options
author | Simon Feltman <sfeltman@src.gnome.org> | 2014-08-29 14:18:28 -0700 |
---|---|---|
committer | Simon Feltman <sfeltman@src.gnome.org> | 2014-08-29 14:34:48 -0700 |
commit | 28d0337f0e3d4b0e9c4350ce5d6cf0cb68da843f (patch) | |
tree | e37578da7b26ffc6d45fdb82340b119d4a5072ae | |
parent | 16f8f687eae0caa1e4059fd62bd1f9d4c7f655f7 (diff) | |
download | pygobject-28d0337f0e3d4b0e9c4350ce5d6cf0cb68da843f.tar.gz |
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
-rw-r--r-- | gi/pygi-signal-closure.c | 41 | ||||
-rw-r--r-- | 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 0c6b9b97..3cf84862 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(¶m_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 ba90fc31..395b1577 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): |