GNOME Bugzilla – Bug 637601
Issues with cairo types and signals
Last modified: 2011-08-26 13:49:27 UTC
There seems to be an issue with marshalling arguments for a signal handlers with cairo types. An example is the new "draw" signal of GtkWidget which has a cairo context as argument. Running the cairo-demo.py results in: Traceback (most recent call last):
+ Trace 225191
ctx.set_source_rgb(0, 0, 0)
Note that cairo-demo.py needs to be slightly updated to use the "draw" signal instead of the "expose-event". The problem seems to be related to not properly loading the foreign type. Also please note that I do not exclude at this time the possibility that there is something wrong in my jhbuild, but I tried reinstalling everything and I can't seem to be able to resolve the problem.
*** Bug 637602 has been marked as a duplicate of this bug. ***
I'll look into it more tomorrow but it seem that the cairo foreign types isn't being linked into the final executable.
I was informed that foreign types don't work with signals yet. It is on a list of todo items. We will most likely get to at the hackfest at the end of January. You might be able to do ctx = Gdk.cairo_create(widget.get_window()) as a workaround for now.
I was just informed Gdk.cairo_create inside of the draw handler is undefined so don't use it. I am looking into fixing this.
Maybe as a workaround just to progress for now I could wrap in my py callback the raw object from the wrongly wrapped cairo context, in a correct cairo.Context (where cairo is the foreign module)?
What happens is that the g-i people changed the cairo structs to not be foreign, breaking pygobject. I'm investigating now how we can use the boxed cairo structs with the static bindings, instead of foreign structs.
So only CairoRectangleInt has been unmarked as foreign. It is now a boxed struct that should be managed as any other boxed, it has no methods. CairoSurface and CairoContext are still foreign structs and PyGObject should bridge from the introspected stuff to the static cairo bindings. J5 is right about signals not using introspection information yet, I'll be looking at it during the hackfest.
Any update on this issue?
(In reply to comment #8) > Any update on this issue? Didn't had time to look into it, but both Kamstrup and Nacho have shown interest in working on this.
For the record: <tomeu> nacho: nothing to do with the invoker, signal handlers are invoked from the non-gi side of pygobject <tomeu> nacho: need to do something similar to https://bugzilla.gnome.org/show_bug.cgi?id=620808 <tomeu> but for signals
Created attachment 180846 [details] [review] [GI] Use PyGI type conversion (to fix foreign types) for signal callbacks. First attempt at patch to fix foreign types in signal callbacks. Tests are not implemented yet.
Is there anyway to write tests to check for proper handing of foreign types without depending on cairo? If anyone has any suggestions, please let me know.
by using the drawingarea demo I was able to verify this works from a functional point of view. Passes make check. For a test, please just add one to the overrides tests which shows a window and checks to see if the cairo context comes from the static cairo bindings. You can also call some of the cairo functions in test_everything inside the signal handler. Quit the mainloop at the end of the signal handler. I'm going to review the actual code next but it is looking good so far. BTW I checked in the drawingarea demo if you want to check it out demos/gtk-demo/demos/drawingarea.py
Comment on attachment 180846 [details] [review] [GI] Use PyGI type conversion (to fix foreign types) for signal callbacks. >From b63dd6fa99b1f018ffd59cb21b064a61fc4631e1 Mon Sep 17 00:00:00 2001 >From: Laszlo Pandy <lpandy@src.gnome.org> >Date: Mon, 14 Feb 2011 19:36:27 +0100 >Subject: [PATCH] [GI] Use PyGI type conversion (to fix foreign types) for signal callbacks. > >First attempt at patch to fix foreign types in signal callbacks. >Tests are not implemented yet. > >https://bugzilla.gnome.org/show_bug.cgi?id=637601 >--- > gi/Makefile.am | 2 + > gi/gimodule.c | 1 + > gi/pygi-argument.c | 91 +++++++++++++++++ > gi/pygi-argument.h | 2 + > gi/pygi-private.h | 1 + > gi/pygi-signal-closure.c | 245 ++++++++++++++++++++++++++++++++++++++++++++++ > gi/pygi-signal-closure.h | 46 +++++++++ > gi/pygi.h | 28 +++++ > gobject/pygobject.c | 24 ++++- > 9 files changed, 436 insertions(+), 4 deletions(-) > create mode 100644 gi/pygi-signal-closure.c > create mode 100644 gi/pygi-signal-closure.h > >diff --git a/gi/Makefile.am b/gi/Makefile.am >index a98993b..28825ab 100644 >--- a/gi/Makefile.am >+++ b/gi/Makefile.am >@@ -54,6 +54,8 @@ _gi_la_SOURCES = \ > pygi-private.h \ > pygi-property.c \ > pygi-property.h \ >+ pygi-signal-closure.c \ >+ pygi-signal-closure.h \ > pygobject-external.h \ > gimodule.c > >diff --git a/gi/gimodule.c b/gi/gimodule.c >index f70d0f2..55c9d8b 100644 >--- a/gi/gimodule.c >+++ b/gi/gimodule.c >@@ -367,6 +367,7 @@ static struct PyGI_API CAPI = { > pygi_type_import_by_g_type_real, > pygi_get_property_value_real, > pygi_set_property_value_real, >+ pygi_signal_closure_new_real, > pygi_register_foreign_struct_real, > }; > >diff --git a/gi/pygi-argument.c b/gi/pygi-argument.c >index 8dd728d..9816738 100644 >--- a/gi/pygi-argument.c >+++ b/gi/pygi-argument.c >@@ -1719,6 +1719,97 @@ _pygi_argument_to_object (GIArgument *arg, > return object; > } > >+ >+GIArgument >+_pygi_argument_from_g_value(const GValue *value, >+ GITypeInfo *type_info) >+{ >+ GIArgument arg = { 0, }; >+ >+ GITypeTag type_tag = g_type_info_get_tag (type_info); >+ switch (type_tag) { >+ case GI_TYPE_TAG_BOOLEAN: >+ arg.v_boolean = g_value_get_boolean (value); >+ break; >+ case GI_TYPE_TAG_INT8: >+ case GI_TYPE_TAG_INT16: >+ case GI_TYPE_TAG_INT32: >+ case GI_TYPE_TAG_INT64: >+ arg.v_int = g_value_get_int (value); >+ break; >+ case GI_TYPE_TAG_UINT8: >+ case GI_TYPE_TAG_UINT16: >+ case GI_TYPE_TAG_UINT32: >+ case GI_TYPE_TAG_UINT64: >+ arg.v_uint = g_value_get_uint (value); >+ break; >+ case GI_TYPE_TAG_UNICHAR: >+ arg.v_uint32 = g_value_get_char (value); >+ break; >+ case GI_TYPE_TAG_FLOAT: >+ arg.v_float = g_value_get_float (value); >+ break; >+ case GI_TYPE_TAG_DOUBLE: >+ arg.v_double = g_value_get_double (value); >+ break; >+ case GI_TYPE_TAG_GTYPE: >+ arg.v_long = g_value_get_gtype (value); >+ break; >+ case GI_TYPE_TAG_UTF8: >+ case GI_TYPE_TAG_FILENAME: >+ arg.v_string = g_value_dup_string (value); >+ break; >+ case GI_TYPE_TAG_GLIST: >+ case GI_TYPE_TAG_GSLIST: >+ arg.v_pointer = g_value_get_pointer (value); >+ break; >+ case GI_TYPE_TAG_ARRAY: >+ case GI_TYPE_TAG_GHASH: >+ arg.v_pointer = g_value_get_boxed (value); >+ break; >+ case GI_TYPE_TAG_INTERFACE: >+ { >+ GIBaseInfo *info; >+ GIInfoType info_type; >+ >+ info = g_type_info_get_interface (type_info); >+ info_type = g_base_info_get_type (info); >+ >+ g_base_info_unref (info); >+ >+ switch (info_type) { >+ case GI_INFO_TYPE_FLAGS: >+ case GI_INFO_TYPE_ENUM: >+ arg.v_long = g_value_get_enum (value); >+ break; >+ case GI_INFO_TYPE_INTERFACE: >+ case GI_INFO_TYPE_OBJECT: >+ arg.v_pointer = g_value_get_object (value); >+ break; >+ case GI_INFO_TYPE_BOXED: >+ case GI_INFO_TYPE_STRUCT: >+ case GI_INFO_TYPE_UNION: >+ if (G_VALUE_HOLDS(value, G_TYPE_BOXED)) { >+ arg.v_pointer = g_value_get_boxed (value); >+ } else { >+ arg.v_pointer = g_value_get_pointer (value); >+ } >+ break; >+ default: >+ g_warning("Converting of type '%s' is not implemented", g_info_type_to_string(info_type)); >+ g_assert_not_reached(); >+ } >+ break; >+ } >+ case GI_TYPE_TAG_ERROR: >+ case GI_TYPE_TAG_VOID: >+ g_critical("Converting of type '%s' is not implemented", g_type_tag_to_string(type_tag)); >+ g_assert_not_reached(); >+ } >+ >+ return arg; >+} >+ > void > _pygi_argument_release (GIArgument *arg, > GITypeInfo *type_info, >diff --git a/gi/pygi-argument.h b/gi/pygi-argument.h >index d932e8f..7224c75 100644 >--- a/gi/pygi-argument.h >+++ b/gi/pygi-argument.h >@@ -55,6 +55,8 @@ PyObject* _pygi_argument_to_object (GIArgument *arg, > GITypeInfo *type_info, > GITransfer transfer); > >+GIArgument _pygi_argument_from_g_value(const GValue *value, >+ GITypeInfo *type_info); > > void _pygi_argument_release (GIArgument *arg, > GITypeInfo *type_info, >diff --git a/gi/pygi-private.h b/gi/pygi-private.h >index 3a14bc3..efe62c8 100644 >--- a/gi/pygi-private.h >+++ b/gi/pygi-private.h >@@ -29,6 +29,7 @@ > #include "pygi-callbacks.h" > #include "pygi-invoke.h" > #include "pygi-property.h" >+#include "pygi-signal-closure.h" > > G_BEGIN_DECLS > #if PY_VERSION_HEX >= 0x03000000 >diff --git a/gi/pygi-signal-closure.c b/gi/pygi-signal-closure.c >new file mode 100644 >index 0000000..1482529 >--- /dev/null >+++ b/gi/pygi-signal-closure.c >@@ -0,0 +1,245 @@ >+/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */ >+/* >+ * Copyright (c) 2011 Laszlo Pandy <lpandy@src.gnome.org> >+ * >+ * This library is free software; you can redistribute it and/or >+ * modify it under the terms of the GNU Lesser General Public >+ * License as published by the Free Software Foundation; either >+ * version 2.1 of the License, or (at your option) any later version. >+ * >+ * This library is distributed in the hope that it will be useful, >+ * but WITHOUT ANY WARRANTY; without even the implied warranty of >+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU >+ * Lesser General Public License for more details. >+ * >+ * You should have received a copy of the GNU Lesser General Public >+ * License along with this library; if not, write to the Free Software >+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 >+ * USA >+ */ >+ >+#include "pygi-private.h" >+ >+/* Copied from glib */ >+static void >+canonicalize_key (gchar *key) >+{ >+ gchar *p; >+ >+ for (p = key; *p != 0; p++) >+ { >+ gchar c = *p; >+ >+ if (c != '-' && >+ (c < '0' || c > '9') && >+ (c < 'A' || c > 'Z') && >+ (c < 'a' || c > 'z')) >+ *p = '-'; >+ } >+} >+ >+static GISignalInfo * >+_pygi_lookup_signal_from_g_type (GType g_type, >+ const gchar *signal_name) >+{ >+ GIRepository *repository; >+ GIBaseInfo *info; >+ gssize n_infos; >+ gssize i; >+ GType parent; >+ >+ repository = g_irepository_get_default(); >+ info = g_irepository_find_by_gtype (repository, g_type); >+ if (info != NULL) { >+ n_infos = g_object_info_get_n_signals ( (GIObjectInfo *) info); >+ for (i = 0; i < n_infos; i++) { >+ GISignalInfo *signal_info; >+ >+ signal_info = g_object_info_get_signal ( (GIObjectInfo *) info, i); >+ g_assert (info != NULL); >+ >+ if (strcmp (signal_name, g_base_info_get_name (signal_info)) == 0) { >+ g_base_info_unref (info); >+ return signal_info; >+ } >+ >+ g_base_info_unref (signal_info); >+ } >+ >+ g_base_info_unref (info); >+ } >+ >+ parent = g_type_parent (g_type); >+ if (parent > 0) >+ return _pygi_lookup_signal_from_g_type (parent, signal_name); >+ >+ return NULL; >+} >+ >+static void >+pygi_signal_closure_invalidate(gpointer data, >+ GClosure *closure) >+{ >+ PyGClosure *pc = (PyGClosure *)closure; >+ PyGILState_STATE state; >+ >+ state = PyGILState_Ensure(); >+ Py_XDECREF(pc->callback); >+ Py_XDECREF(pc->extra_args); >+ Py_XDECREF(pc->swap_data); >+ PyGILState_Release(state); >+ >+ pc->callback = NULL; >+ pc->extra_args = NULL; >+ pc->swap_data = NULL; >+ >+ g_base_info_unref (((PyGISignalClosure *) pc)->signal_info); >+ ((PyGISignalClosure *) pc)->signal_info = NULL; >+} >+ >+static void >+pygi_signal_closure_marshal(GClosure *closure, >+ GValue *return_value, >+ guint n_param_values, >+ const GValue *param_values, >+ gpointer invocation_hint, >+ gpointer marshal_data) >+{ >+ PyGILState_STATE state; >+ PyGClosure *pc = (PyGClosure *)closure; >+ PyObject *params, *ret = NULL; >+ guint i; >+ GISignalInfo *signal_info; >+ gint n_sig_info_args; >+ gint sig_info_highest_arg; >+ >+ state = PyGILState_Ensure(); >+ >+ signal_info = ((PyGISignalClosure *)closure)->signal_info; >+ n_sig_info_args = g_callable_info_get_n_args(signal_info); >+ /* the first argument to a signal callback is instance, >+ but instance is not counted in the introspection data */ >+ sig_info_highest_arg = n_sig_info_args + 1; >+ g_assert_cmpint(sig_info_highest_arg, ==, n_param_values); >+ >+ /* construct Python tuple for the parameter values */ >+ params = PyTuple_New(n_param_values); >+ for (i = 0; i < n_param_values; i++) { >+ /* swap in a different initial data for connect_object() */ >+ if (i == 0 && G_CCLOSURE_SWAP_DATA(closure)) { >+ g_return_if_fail(pc->swap_data != NULL); >+ Py_INCREF(pc->swap_data); >+ PyTuple_SetItem(params, 0, pc->swap_data); >+ >+ } else if (i == 0) { >+ PyObject *item = pyg_value_as_pyobject(¶m_values[i], FALSE); >+ >+ if (!item) { >+ goto out; >+ } >+ PyTuple_SetItem(params, i, item); >+ >+ } else if (i < sig_info_highest_arg) { >+ GIArgInfo arg_info; >+ GITypeInfo type_info; >+ GITransfer transfer; >+ GIArgument arg = { 0, }; >+ PyObject *item = NULL; >+ >+ g_callable_info_load_arg(signal_info, i - 1, &arg_info); >+ g_arg_info_load_type(&arg_info, &type_info); >+ transfer = g_arg_info_get_ownership_transfer(&arg_info); >+ >+ arg = _pygi_argument_from_g_value(¶m_values[i], &type_info); >+ item = _pygi_argument_to_object(&arg, &type_info, transfer); >+ >+ if (item == NULL) { >+ goto out; >+ } >+ PyTuple_SetItem(params, i, item); >+ } >+ } >+ /* params passed to function may have extra arguments */ >+ if (pc->extra_args) { >+ PyObject *tuple = params; >+ params = PySequence_Concat(tuple, pc->extra_args); >+ Py_DECREF(tuple); >+ } >+ ret = PyObject_CallObject(pc->callback, params); >+ if (ret == NULL) { >+ if (pc->exception_handler) >+ pc->exception_handler(return_value, n_param_values, param_values); >+ else >+ PyErr_Print(); >+ goto out; >+ } >+ >+ if (return_value && pyg_value_from_pyobject(return_value, ret) != 0) { >+ PyErr_SetString(PyExc_TypeError, >+ "can't convert return value to desired type"); >+ >+ if (pc->exception_handler) >+ pc->exception_handler(return_value, n_param_values, param_values); >+ else >+ PyErr_Print(); >+ } >+ Py_DECREF(ret); >+ >+ out: >+ Py_DECREF(params); >+ PyGILState_Release(state); >+} >+ >+GClosure * >+pygi_signal_closure_new_real (PyGObject *instance, >+ const gchar *sig_name, >+ PyObject *callback, >+ PyObject *extra_args, >+ PyObject *swap_data) >+{ >+ GClosure *closure = NULL; >+ PyGISignalClosure *pygi_closure = NULL; >+ GType g_type; >+ GISignalInfo *signal_info = NULL; >+ char *signal_name = g_strdup (sig_name); >+ >+ g_return_val_if_fail(callback != NULL, NULL); >+ >+ canonicalize_key(signal_name); >+ >+ g_type = pyg_type_from_object ((PyObject *)instance); >+ signal_info = _pygi_lookup_signal_from_g_type (g_type, signal_name); >+ >+ if (signal_info == NULL) >+ goto out; >+ >+ closure = g_closure_new_simple(sizeof(PyGISignalClosure), NULL); >+ g_closure_add_invalidate_notifier(closure, NULL, pygi_signal_closure_invalidate); >+ g_closure_set_marshal(closure, pygi_signal_closure_marshal); >+ >+ pygi_closure = (PyGISignalClosure *)closure; >+ >+ pygi_closure->signal_info = signal_info; >+ Py_INCREF(callback); >+ pygi_closure->pyg_closure.callback = callback; >+ >+ if (extra_args != NULL && extra_args != Py_None) { >+ Py_INCREF(extra_args); >+ if (!PyTuple_Check(extra_args)) { >+ PyObject *tmp = PyTuple_New(1); >+ PyTuple_SetItem(tmp, 0, extra_args); >+ extra_args = tmp; >+ } >+ pygi_closure->pyg_closure.extra_args = extra_args; >+ } >+ if (swap_data) { >+ Py_INCREF(swap_data); >+ pygi_closure->pyg_closure.swap_data = swap_data; >+ closure->derivative_flag = TRUE; >+ } >+ >+out: >+ g_free (signal_name); >+ >+ return closure; >+} >diff --git a/gi/pygi-signal-closure.h b/gi/pygi-signal-closure.h >new file mode 100644 >index 0000000..4687f3f >--- /dev/null >+++ b/gi/pygi-signal-closure.h >@@ -0,0 +1,46 @@ >+/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */ >+/* >+ * Copyright (c) 2011 Laszlo Pandy <lpandy@src.gnome.org> >+ * >+ * Permission is hereby granted, free of charge, to any person obtaining a copy >+ * of this software and associated documentation files (the "Software"), to >+ * deal in the Software without restriction, including without limitation the >+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or >+ * sell copies of the Software, and to permit persons to whom the Software is >+ * furnished to do so, subject to the following conditions: >+ * >+ * The above copyright notice and this permission notice shall be included in >+ * all copies or substantial portions of the Software. >+ * >+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR >+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, >+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE >+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER >+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING >+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS >+ * IN THE SOFTWARE. >+ */ >+ >+#ifndef __PYGI_SIGNAL_CLOSURE_H__ >+#define __PYGI_SIGNAL_CLOSURE_H__ >+ >+#include "pygi.h" >+ >+G_BEGIN_DECLS >+ >+/* Private */ >+typedef struct _PyGISignalClosure >+{ >+ PyGClosure pyg_closure; >+ GISignalInfo *signal_info; >+} PyGISignalClosure; >+ >+GClosure * pygi_signal_closure_new_real (PyGObject *instance, >+ const gchar *sig_name, >+ PyObject *callback, >+ PyObject *extra_args, >+ PyObject *swap_data); >+ >+G_END_DECLS >+ >+#endif /* __PYGI_SIGNAL_CLOSURE_H__ */ >diff --git a/gi/pygi.h b/gi/pygi.h >index 2765b40..274af4d 100644 >--- a/gi/pygi.h >+++ b/gi/pygi.h >@@ -71,6 +71,11 @@ struct PyGI_API { > gint (*set_property_value) (PyGObject *instance, > const gchar *attr_name, > PyObject *value); >+ GClosure * (*signal_closure_new) (PyGObject *instance, >+ const gchar *sig_name, >+ PyObject *callback, >+ PyObject *extra_args, >+ PyObject *swap_data); > void (*register_foreign_struct) (const char* namespace_, > const char* name, > PyGIArgOverrideToGIArgumentFunc to_func, >@@ -128,6 +133,19 @@ pygi_set_property_value (PyGObject *instance, > return PyGI_API->set_property_value(instance, attr_name, value); > } > >+static inline GClosure * >+pygi_signal_closure_new (PyGObject *instance, >+ const gchar *sig_name, >+ PyObject *callback, >+ PyObject *extra_args, >+ PyObject *swap_data) >+{ >+ if (_pygi_import() < 0) { >+ return NULL; >+ } >+ return PyGI_API->signal_closure_new(instance, sig_name, callback, extra_args, swap_data); >+} >+ > static inline PyObject * > pygi_register_foreign_struct (const char* namespace_, > const char* name, >@@ -169,6 +187,16 @@ pygi_set_property_value (PyGObject *instance, > return -1; > } > >+static inline GClosure * >+pygi_signal_closure_new (PyGObject *instance, >+ const gchar *sig_name, >+ PyObject *callback, >+ PyObject *extra_args, >+ PyObject *swap_data) >+{ >+ return NULL; >+} >+ > #endif /* ENABLE_INTROSPECTION */ > > #endif /* __PYGI_H__ */ >diff --git a/gobject/pygobject.c b/gobject/pygobject.c >index 9be644a..0faf221 100644 >--- a/gobject/pygobject.c >+++ b/gobject/pygobject.c >@@ -1524,7 +1524,11 @@ pygobject_connect(PyGObject *self, PyObject *args) > extra_args = PySequence_GetSlice(args, 2, len); > if (extra_args == NULL) > return NULL; >- closure = pyg_closure_new(callback, extra_args, NULL); My biggest worry happens here. I think you are breaking ABI. We should only be calling pygi_signal_closure_new if the object itself is a GI object. Of course you have: if (_pygi_import() < 0) { return NULL; } Is that enough? Doesn't that import the gi module? What about static apps that don't want GI imported. >+ >+ closure = pygi_signal_closure_new(self, name, callback, extra_args, NULL); >+ if (closure == NULL) >+ closure = pyg_closure_new(callback, extra_args, NULL); >+ > pygobject_watch_closure((PyObject *)self, closure); > handlerid = g_signal_connect_closure_by_id(self->obj, sigid, detail, > closure, FALSE); >@@ -1573,7 +1577,11 @@ pygobject_connect_after(PyGObject *self, PyObject *args) > extra_args = PySequence_GetSlice(args, 2, len); > if (extra_args == NULL) > return NULL; >- closure = pyg_closure_new(callback, extra_args, NULL); >+ >+ closure = pygi_signal_closure_new(self, name, callback, extra_args, NULL); >+ if (closure == NULL) >+ closure = pyg_closure_new(callback, extra_args, NULL); >+ > pygobject_watch_closure((PyObject *)self, closure); > handlerid = g_signal_connect_closure_by_id(self->obj, sigid, detail, > closure, TRUE); >@@ -1622,7 +1630,11 @@ pygobject_connect_object(PyGObject *self, PyObject *args) > extra_args = PySequence_GetSlice(args, 3, len); > if (extra_args == NULL) > return NULL; >- closure = pyg_closure_new(callback, extra_args, object); >+ >+ closure = pygi_signal_closure_new(self, name, callback, extra_args, object); >+ if (closure == NULL) >+ closure = pyg_closure_new(callback, extra_args, object); >+ > pygobject_watch_closure((PyObject *)self, closure); > handlerid = g_signal_connect_closure_by_id(self->obj, sigid, detail, > closure, FALSE); >@@ -1671,7 +1683,11 @@ pygobject_connect_object_after(PyGObject *self, PyObject *args) > extra_args = PySequence_GetSlice(args, 3, len); > if (extra_args == NULL) > return NULL; >- closure = pyg_closure_new(callback, extra_args, object); >+ >+ closure = pygi_signal_closure_new(self, name, callback, extra_args, object); >+ if (closure == NULL) >+ closure = pyg_closure_new(callback, extra_args, object); >+ > pygobject_watch_closure((PyObject *)self, closure); > handlerid = g_signal_connect_closure_by_id(self->obj, sigid, detail, > closure, TRUE); >-- >1.7.1
Seeing as we are already doing the wrong thing wrt importing GI and potentially breaking PyGtk static bindings, I have committed this code so we can concentrate on fixing that issue.
in _pygi_argument_from_g_value() you do g_value_dup_string() but all other types are not copied. This looks like a leak, no?
reported this in bug #657442