summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Feltman <sfeltman@src.gnome.org>2014-08-29 14:18:28 -0700
committerSimon Feltman <sfeltman@src.gnome.org>2014-08-29 14:34:48 -0700
commit28d0337f0e3d4b0e9c4350ce5d6cf0cb68da843f (patch)
treee37578da7b26ffc6d45fdb82340b119d4a5072ae
parent16f8f687eae0caa1e4059fd62bd1f9d4c7f655f7 (diff)
downloadpygobject-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.c41
-rw-r--r--tests/test_overrides_gtk.py24
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(&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 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):