After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 637601 - Issues with cairo types and signals
Issues with cairo types and signals
Status: RESOLVED FIXED
Product: pygobject
Classification: Bindings
Component: introspection
unspecified
Other Linux
: Normal normal
: ---
Assigned To: Nobody's working on this now (help wanted and appreciated)
Python bindings maintainers
: 637602 (view as bug list)
Depends on:
Blocks:
 
 
Reported: 2010-12-19 20:30 UTC by jessevdk@gmail.com
Modified: 2011-08-26 13:49 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
[GI] Use PyGI type conversion (to fix foreign types) for signal callbacks. (19.88 KB, patch)
2011-02-14 18:44 UTC, Laszlo Pandy
committed Details | Review

Description jessevdk@gmail.com 2010-12-19 20:30:51 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):
  • File "examples/cairo-demo.py", line 83 in draw
    ctx.set_source_rgb(0, 0, 0)
AttributeError: 'Context' object has no attribute 'set_source_rgb'

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.
Comment 1 johnp 2010-12-19 21:02:25 UTC
*** Bug 637602 has been marked as a duplicate of this bug. ***
Comment 2 johnp 2010-12-19 22:16:23 UTC
I'll look into it more tomorrow but it seem that the cairo foreign types isn't being linked into the final executable.
Comment 3 johnp 2010-12-20 17:14:46 UTC
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.
Comment 4 johnp 2010-12-20 18:26:07 UTC
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.
Comment 5 jessevdk@gmail.com 2010-12-20 22:31:10 UTC
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)?
Comment 6 Tomeu Vizoso 2011-01-18 08:48:51 UTC
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.
Comment 7 Tomeu Vizoso 2011-01-18 09:26:30 UTC
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.
Comment 8 jessevdk@gmail.com 2011-01-22 19:24:53 UTC
Any update on this issue?
Comment 9 Tomeu Vizoso 2011-01-22 21:18:04 UTC
(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.
Comment 10 Ignacio Casal Quinteiro (nacho) 2011-01-22 21:22:18 UTC
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
Comment 11 Laszlo Pandy 2011-02-14 18:44:29 UTC
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.
Comment 12 Laszlo Pandy 2011-02-14 19:14:08 UTC
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.
Comment 13 johnp 2011-02-14 21:58:00 UTC
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 14 johnp 2011-02-14 22:13:54 UTC
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(&param_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(&param_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
Comment 15 johnp 2011-02-14 23:21:56 UTC
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.
Comment 16 Xavier Claessens 2011-08-26 13:40:43 UTC
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?
Comment 17 Xavier Claessens 2011-08-26 13:49:27 UTC
reported this in bug #657442