[pygobject] cache refactoring: Move closure setup and marshaling into pygi-closure



commit 2cddba811592fbb990322fbf2dce516ffd7e94cd
Author: Simon Feltman <sfeltman src gnome org>
Date:   Sat Oct 12 12:39:20 2013 -0700

    cache refactoring: Move closure setup and marshaling into pygi-closure
    
    Move closure argument caching and marshaling fragments into
    pygi-closure.c.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=709700

 gi/pygi-cache.c           |  111 ++--------------
 gi/pygi-cache.h           |    9 --
 gi/pygi-closure.c         |  314 ++++++++++++++++++++++++++++++++++++++++++++-
 gi/pygi-closure.h         |   13 ++-
 gi/pygi-marshal-cleanup.c |   14 --
 gi/pygi-marshal-cleanup.h |    5 -
 gi/pygi-marshal-from-py.c |  160 -----------------------
 gi/pygi-marshal-from-py.h |    6 -
 gi/pygi-marshal-to-py.c   |   13 --
 gi/pygi-marshal-to-py.h   |    4 -
 10 files changed, 333 insertions(+), 316 deletions(-)
---
diff --git a/gi/pygi-cache.c b/gi/pygi-cache.c
index d91d8ab..aded025 100644
--- a/gi/pygi-cache.c
+++ b/gi/pygi-cache.c
@@ -31,6 +31,7 @@
 #include "pygi-basictype.h"
 #include "pygi-list.h"
 #include "pygi-array.h"
+#include "pygi-closure.h"
 #include "pygi-error.h"
 
 
@@ -162,17 +163,6 @@ _sequence_cache_free_func (PyGISequenceCache *cache)
     }
 }
 
-static void
-_callback_cache_free_func (PyGICallbackCache *cache)
-{
-    if (cache != NULL) {
-        if (cache->interface_info != NULL)
-            g_base_info_unref ( (GIBaseInfo *)cache->interface_info);
-
-        g_slice_free (PyGICallbackCache, cache);
-    }
-}
-
 void
 _pygi_callable_cache_free (PyGICallableCache *cache)
 {
@@ -248,28 +238,6 @@ pygi_arg_sequence_setup (PyGISequenceCache  *sc,
     return TRUE;
 }
 
-static PyGICallbackCache *
-_callback_cache_new (GIArgInfo *arg_info,
-                     GIInterfaceInfo *iface_info,
-                     gssize child_offset)
-{
-   PyGICallbackCache *cc;
-
-   cc = g_slice_new0 (PyGICallbackCache);
-   ( (PyGIArgCache *)cc)->destroy_notify = (GDestroyNotify)_callback_cache_free_func;
-
-   cc->user_data_index = g_arg_info_get_closure (arg_info);
-   if (cc->user_data_index != -1)
-       cc->user_data_index += child_offset;
-   cc->destroy_notify_index = g_arg_info_get_destroy (arg_info);
-   if (cc->destroy_notify_index != -1)
-       cc->destroy_notify_index += child_offset;
-   cc->scope = g_arg_info_get_scope (arg_info);
-   g_base_info_ref( (GIBaseInfo *)iface_info);
-   cc->interface_info = iface_info;
-   return cc;
-}
-
 PyGIArgCache *
 _arg_cache_alloc (void)
 {
@@ -335,38 +303,6 @@ _arg_cache_to_py_interface_object_setup (PyGIArgCache *arg_cache,
 }
 
 static void
-_arg_cache_from_py_interface_callback_setup (PyGIArgCache *arg_cache,
-                                             PyGICallableCache *callable_cache)
-{
-    PyGICallbackCache *callback_cache = (PyGICallbackCache *)arg_cache;
-    if (callback_cache->user_data_index >= 0) {
-        PyGIArgCache *user_data_arg_cache = _arg_cache_alloc ();
-        user_data_arg_cache->meta_type = PYGI_META_ARG_TYPE_CHILD_WITH_PYARG;
-        user_data_arg_cache->direction = PYGI_DIRECTION_FROM_PYTHON;
-        user_data_arg_cache->has_default = TRUE; /* always allow user data with a NULL default. */
-        _pygi_callable_cache_set_arg (callable_cache, callback_cache->user_data_index,
-                                      user_data_arg_cache);
-    }
-
-    if (callback_cache->destroy_notify_index >= 0) {
-        PyGIArgCache *destroy_arg_cache = _arg_cache_alloc ();
-        destroy_arg_cache->meta_type = PYGI_META_ARG_TYPE_CHILD;
-        destroy_arg_cache->direction = PYGI_DIRECTION_FROM_PYTHON;
-        _pygi_callable_cache_set_arg (callable_cache, callback_cache->destroy_notify_index,
-                                      destroy_arg_cache);
-    }
-    arg_cache->from_py_marshaller = _pygi_marshal_from_py_interface_callback;
-    arg_cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_interface_callback;
-}
-
-static void
-_arg_cache_to_py_interface_callback_setup (void)
-{
-    PyErr_Format(PyExc_NotImplementedError,
-                 "Callback returns are not supported");
-}
-
-static void
 _arg_cache_from_py_interface_enum_setup (PyGIArgCache *arg_cache,
                                          GITransfer transfer)
 {
@@ -404,45 +340,22 @@ _arg_cache_new_for_interface (GIInterfaceInfo   *iface_info,
                               PyGICallableCache *callable_cache)
 {
     PyGIArgCache *arg_cache = NULL;
-    gssize child_offset = 0;
     GIInfoType info_type;
 
-    if (callable_cache != NULL)
-        child_offset =
-            (callable_cache->function_type == PYGI_FUNCTION_TYPE_METHOD ||
-                 callable_cache->function_type == PYGI_FUNCTION_TYPE_VFUNC) ? 1: 0;
-
     info_type = g_base_info_get_type ( (GIBaseInfo *)iface_info);
 
-    /* Callbacks are special cased */
-    if (info_type == GI_INFO_TYPE_CALLBACK) {
-        PyGICallbackCache *callback_cache;
-
-        if (direction & PYGI_DIRECTION_TO_PYTHON) {
-            _arg_cache_to_py_interface_callback_setup ();
-            return NULL;
+    switch (info_type) {
+        case GI_INFO_TYPE_CALLBACK:
+        {
+            return pygi_arg_callback_new_from_info (type_info,
+                                                    arg_info,
+                                                    transfer,
+                                                    direction,
+                                                    iface_info,
+                                                    callable_cache);
         }
-
-        callback_cache =
-            _callback_cache_new (arg_info,
-                                 iface_info,
-                                 child_offset);
-
-        arg_cache = (PyGIArgCache *)callback_cache;
-        if (arg_cache == NULL)
-            return NULL;
-
-        pygi_arg_base_setup (arg_cache,
-                             type_info,
-                             arg_info,
-                             transfer,
-                             direction);
-
-        if (direction & PYGI_DIRECTION_FROM_PYTHON)
-            _arg_cache_from_py_interface_callback_setup (arg_cache, callable_cache);
-
-        return arg_cache;
-
+        default:
+            ;  /* pass through to old model of setup */
     }
 
     arg_cache = (PyGIArgCache *)_interface_cache_new (iface_info);
diff --git a/gi/pygi-cache.h b/gi/pygi-cache.h
index 0629646..d20cb9f 100644
--- a/gi/pygi-cache.h
+++ b/gi/pygi-cache.h
@@ -155,15 +155,6 @@ typedef struct _PyGIInterfaceCache
     gchar *type_name;
 } PyGIInterfaceCache;
 
-typedef struct _PyGICallbackCache
-{
-    PyGIArgCache arg_cache;
-    gssize user_data_index;
-    gssize destroy_notify_index;
-    GIScopeType scope;
-    GIInterfaceInfo *interface_info;
-} PyGICallbackCache;
-
 struct _PyGICallableCache
 {
     const gchar *name;
diff --git a/gi/pygi-closure.c b/gi/pygi-closure.c
index 5df4713..3dd73da 100644
--- a/gi/pygi-closure.c
+++ b/gi/pygi-closure.c
@@ -14,12 +14,23 @@
  * 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
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #include "pygi-private.h"
+#include "pygi-closure.h"
+
+
+typedef struct _PyGICallbackCache
+{
+    PyGIArgCache arg_cache;
+    gssize user_data_index;
+    gssize destroy_notify_index;
+    GIScopeType scope;
+    GIInterfaceInfo *interface_info;
+} PyGICallbackCache;
+
+static PyGICClosure *global_destroy_notify;
 
 /* This maintains a list of closures which can be free'd whenever
    as they have been called.  We will free them on the next
@@ -669,3 +680,300 @@ _pygi_make_native_closure (GICallableInfo* info,
 
     return closure;
 }
+
+/* _pygi_destroy_notify_dummy:
+ *
+ * Dummy method used in the occasion when a method has a GDestroyNotify
+ * argument without user data.
+ */
+static void
+_pygi_destroy_notify_dummy (gpointer data) {
+}
+
+static void
+_pygi_destroy_notify_callback_closure (ffi_cif *cif,
+                                       void *result,
+                                       void **args,
+                                       void *data)
+{
+    PyGICClosure *info = * (void**) (args[0]);
+
+    g_assert (info);
+
+    _pygi_invoke_closure_free (info);
+}
+
+/* _pygi_destroy_notify_create:
+ *
+ * Method used in the occasion when a method has a GDestroyNotify
+ * argument with user data.
+ */
+static PyGICClosure*
+_pygi_destroy_notify_create (void)
+{
+    if (!global_destroy_notify) {
+
+        PyGICClosure *destroy_notify = g_slice_new0 (PyGICClosure);
+        GIBaseInfo* glib_destroy_notify;
+
+        g_assert (destroy_notify);
+
+        glib_destroy_notify = g_irepository_find_by_name (NULL, "GLib", "DestroyNotify");
+        g_assert (glib_destroy_notify != NULL);
+        g_assert (g_base_info_get_type (glib_destroy_notify) == GI_INFO_TYPE_CALLBACK);
+
+        destroy_notify->closure = g_callable_info_prepare_closure ( (GICallableInfo*) glib_destroy_notify,
+                                                                    &destroy_notify->cif,
+                                                                    _pygi_destroy_notify_callback_closure,
+                                                                    NULL);
+
+        global_destroy_notify = destroy_notify;
+    }
+
+    return global_destroy_notify;
+}
+
+static gboolean
+_pygi_marshal_from_py_interface_callback (PyGIInvokeState   *state,
+                                          PyGICallableCache *callable_cache,
+                                          PyGIArgCache      *arg_cache,
+                                          PyObject          *py_arg,
+                                          GIArgument        *arg,
+                                          gpointer          *cleanup_data)
+{
+    GICallableInfo *callable_info;
+    PyGICClosure *closure;
+    PyGIArgCache *user_data_cache = NULL;
+    PyGIArgCache *destroy_cache = NULL;
+    PyGICallbackCache *callback_cache;
+    PyObject *py_user_data = NULL;
+
+    callback_cache = (PyGICallbackCache *)arg_cache;
+
+    if (callback_cache->user_data_index > 0) {
+        user_data_cache = _pygi_callable_cache_get_arg (callable_cache, callback_cache->user_data_index);
+        if (user_data_cache->py_arg_index < state->n_py_in_args) {
+            /* py_user_data is a borrowed reference. */
+            py_user_data = PyTuple_GetItem (state->py_in_args, user_data_cache->py_arg_index);
+            if (!py_user_data)
+                return FALSE;
+            /* NULL out user_data if it was not supplied and the default arg placeholder
+             * was used instead.
+             */
+            if (py_user_data == _PyGIDefaultArgPlaceholder) {
+                py_user_data = NULL;
+            } else if (callable_cache->user_data_varargs_index < 0) {
+                /* For non-variable length user data, place the user data in a
+                 * single item tuple which is concatenated to the callbacks arguments.
+                 * This allows callback input arg marshaling to always expect a
+                 * tuple for user data. Note the
+                 */
+                py_user_data = Py_BuildValue("(O)", py_user_data, NULL);
+            } else {
+                /* increment the ref borrowed from PyTuple_GetItem above */
+                Py_INCREF (py_user_data);
+            }
+        }
+    }
+
+    if (py_arg == Py_None) {
+        return TRUE;
+    }
+
+    if (!PyCallable_Check (py_arg)) {
+        PyErr_Format (PyExc_TypeError,
+                      "Callback needs to be a function or method not %s",
+                      py_arg->ob_type->tp_name);
+
+        return FALSE;
+    }
+
+    callable_info = (GICallableInfo *)callback_cache->interface_info;
+
+    closure = _pygi_make_native_closure (callable_info, callback_cache->scope, py_arg, py_user_data);
+    arg->v_pointer = closure->closure;
+
+    /* always decref the user data as _pygi_make_native_closure adds its own ref */
+    Py_XDECREF (py_user_data);
+
+    /* The PyGICClosure instance is used as user data passed into the C function.
+     * The return trip to python will marshal this back and pull the python user data out.
+     */
+    if (user_data_cache != NULL) {
+        state->in_args[user_data_cache->c_arg_index].v_pointer = closure;
+    }
+
+    /* Setup a GDestroyNotify callback if this method supports it along with
+     * a user data field. The user data field is a requirement in order
+     * free resources and ref counts associated with this arguments closure.
+     * In case a user data field is not available, show a warning giving
+     * explicit information and setup a dummy notification to avoid a crash
+     * later on in _pygi_destroy_notify_callback_closure.
+     */
+    if (callback_cache->destroy_notify_index > 0) {
+        destroy_cache = _pygi_callable_cache_get_arg (callable_cache, callback_cache->destroy_notify_index);
+    }
+
+    if (destroy_cache) {
+        if (user_data_cache != NULL) {
+            PyGICClosure *destroy_notify = _pygi_destroy_notify_create ();
+            state->in_args[destroy_cache->c_arg_index].v_pointer = destroy_notify->closure;
+        } else {
+            gchar *msg = g_strdup_printf("Callables passed to %s will leak references because "
+                                         "the method does not support a user_data argument. "
+                                         "See: https://bugzilla.gnome.org/show_bug.cgi?id=685598";,
+                                         callable_cache->name);
+            if (PyErr_WarnEx(PyExc_RuntimeWarning, msg, 2)) {
+                g_free(msg);
+                _pygi_invoke_closure_free(closure);
+                return FALSE;
+            }
+            g_free(msg);
+            state->in_args[destroy_cache->c_arg_index].v_pointer = _pygi_destroy_notify_dummy;
+        }
+    }
+
+    /* Use the PyGIClosure as data passed to cleanup for GI_SCOPE_TYPE_CALL. */
+    *cleanup_data = closure;
+
+    return TRUE;
+}
+
+static PyObject *
+_pygi_marshal_to_py_interface_callback (PyGIInvokeState   *state,
+                                        PyGICallableCache *callable_cache,
+                                        PyGIArgCache      *arg_cache,
+                                        GIArgument        *arg)
+{
+    PyObject *py_obj = NULL;
+
+    PyErr_Format (PyExc_NotImplementedError,
+                  "Marshalling a callback to PyObject is not supported");
+    return py_obj;
+}
+
+static void
+_callback_cache_free_func (PyGICallbackCache *cache)
+{
+    if (cache != NULL) {
+        if (cache->interface_info != NULL)
+            g_base_info_unref ( (GIBaseInfo *)cache->interface_info);
+
+        g_slice_free (PyGICallbackCache, cache);
+    }
+}
+
+static void
+_pygi_marshal_cleanup_from_py_interface_callback (PyGIInvokeState *state,
+                                                  PyGIArgCache    *arg_cache,
+                                                  PyObject        *py_arg,
+                                                  gpointer         data,
+                                                  gboolean         was_processed)
+{
+    PyGICallbackCache *callback_cache = (PyGICallbackCache *)arg_cache;
+    if (was_processed && callback_cache->scope == GI_SCOPE_TYPE_CALL) {
+        _pygi_invoke_closure_free (data);
+    }
+}
+
+static void
+_arg_cache_from_py_interface_callback_setup (PyGIArgCache *arg_cache,
+                                             PyGICallableCache *callable_cache)
+{
+    PyGICallbackCache *callback_cache = (PyGICallbackCache *)arg_cache;
+    if (callback_cache->user_data_index >= 0) {
+        PyGIArgCache *user_data_arg_cache = _arg_cache_alloc ();
+        user_data_arg_cache->meta_type = PYGI_META_ARG_TYPE_CHILD_WITH_PYARG;
+        user_data_arg_cache->direction = PYGI_DIRECTION_FROM_PYTHON;
+        user_data_arg_cache->has_default = TRUE; /* always allow user data with a NULL default. */
+        _pygi_callable_cache_set_arg (callable_cache, callback_cache->user_data_index,
+                                      user_data_arg_cache);
+    }
+
+    if (callback_cache->destroy_notify_index >= 0) {
+        PyGIArgCache *destroy_arg_cache = _arg_cache_alloc ();
+        destroy_arg_cache->meta_type = PYGI_META_ARG_TYPE_CHILD;
+        destroy_arg_cache->direction = PYGI_DIRECTION_FROM_PYTHON;
+        _pygi_callable_cache_set_arg (callable_cache, callback_cache->destroy_notify_index,
+                                      destroy_arg_cache);
+    }
+    arg_cache->from_py_marshaller = _pygi_marshal_from_py_interface_callback;
+    arg_cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_interface_callback;
+}
+
+
+static gboolean
+pygi_arg_callback_setup_from_info (PyGICallbackCache  *arg_cache,
+                                   GITypeInfo         *type_info,
+                                   GIArgInfo          *arg_info,   /* may be null */
+                                   GITransfer          transfer,
+                                   PyGIDirection       direction,
+                                   GIInterfaceInfo    *iface_info,
+                                   PyGICallableCache  *callable_cache)
+{
+    gssize child_offset = 0;
+
+    if (!pygi_arg_base_setup ((PyGIArgCache *)arg_cache,
+                              type_info,
+                              arg_info,
+                              transfer,
+                              direction)) {
+        return FALSE;
+    }
+
+    if (direction & PYGI_DIRECTION_TO_PYTHON) {
+        ((PyGIArgCache *)arg_cache)->to_py_marshaller = _pygi_marshal_to_py_interface_callback;
+    }
+
+    if (callable_cache != NULL)
+        child_offset =
+            (callable_cache->function_type == PYGI_FUNCTION_TYPE_METHOD ||
+                 callable_cache->function_type == PYGI_FUNCTION_TYPE_VFUNC) ? 1: 0;
+
+    ( (PyGIArgCache *)arg_cache)->destroy_notify = (GDestroyNotify)_callback_cache_free_func;
+
+    arg_cache->user_data_index = g_arg_info_get_closure (arg_info);
+    if (arg_cache->user_data_index != -1)
+        arg_cache->user_data_index += child_offset;
+    arg_cache->destroy_notify_index = g_arg_info_get_destroy (arg_info);
+    if (arg_cache->destroy_notify_index != -1)
+        arg_cache->destroy_notify_index += child_offset;
+    arg_cache->scope = g_arg_info_get_scope (arg_info);
+    g_base_info_ref( (GIBaseInfo *)iface_info);
+    arg_cache->interface_info = iface_info;
+
+    if (direction & PYGI_DIRECTION_FROM_PYTHON)
+        _arg_cache_from_py_interface_callback_setup ((PyGIArgCache *)arg_cache, callable_cache);
+
+    return TRUE;
+}
+
+PyGIArgCache *
+pygi_arg_callback_new_from_info  (GITypeInfo        *type_info,
+                                  GIArgInfo         *arg_info,   /* may be null */
+                                  GITransfer         transfer,
+                                  PyGIDirection      direction,
+                                  GIInterfaceInfo   *iface_info,
+                                  PyGICallableCache *callable_cache)
+{
+    gboolean res = FALSE;
+    PyGICallbackCache *callback_cache;
+
+    callback_cache = g_slice_new0 (PyGICallbackCache);
+    if (callback_cache == NULL)
+        return NULL;
+
+    res = pygi_arg_callback_setup_from_info (callback_cache,
+                                             type_info,
+                                             arg_info,
+                                             transfer,
+                                             direction,
+                                             iface_info,
+                                             callable_cache);
+    if (res) {
+        return (PyGIArgCache *)callback_cache;
+    } else {
+        _pygi_arg_cache_free ((PyGIArgCache *)callback_cache);
+        return NULL;
+    }
+}
diff --git a/gi/pygi-closure.h b/gi/pygi-closure.h
index 6f98339..0620dc7 100644
--- a/gi/pygi-closure.h
+++ b/gi/pygi-closure.h
@@ -12,9 +12,7 @@
  * 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
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #ifndef __PYGI_CLOSURE_H__
@@ -24,6 +22,8 @@
 #include <girffi.h>
 #include <ffi.h>
 
+#include "pygi-cache.h"
+
 G_BEGIN_DECLS
 
 
@@ -52,6 +52,13 @@ PyGICClosure* _pygi_make_native_closure (GICallableInfo* info,
                                          PyObject *function,
                                          gpointer user_data);
 
+PyGIArgCache *pygi_arg_callback_new_from_info  (GITypeInfo        *type_info,
+                                                GIArgInfo         *arg_info,   /* may be null */
+                                                GITransfer         transfer,
+                                                PyGIDirection      direction,
+                                                GIInterfaceInfo   *iface_info,
+                                                PyGICallableCache *callable_cache);
+
 G_END_DECLS
 
 #endif /* __PYGI_CLOSURE_H__ */
diff --git a/gi/pygi-marshal-cleanup.c b/gi/pygi-marshal-cleanup.c
index a8fa3f6..0376e37 100644
--- a/gi/pygi-marshal-cleanup.c
+++ b/gi/pygi-marshal-cleanup.c
@@ -233,20 +233,6 @@ _pygi_marshal_cleanup_to_py_interface_object (PyGIInvokeState *state,
         g_object_unref (G_OBJECT(data));
 }
 
-
-void
-_pygi_marshal_cleanup_from_py_interface_callback (PyGIInvokeState *state,
-                                                  PyGIArgCache    *arg_cache,
-                                                  PyObject        *py_arg,
-                                                  gpointer         data,
-                                                  gboolean         was_processed)
-{
-    PyGICallbackCache *callback_cache = (PyGICallbackCache *)arg_cache;
-    if (was_processed && callback_cache->scope == GI_SCOPE_TYPE_CALL) {
-        _pygi_invoke_closure_free (data);
-    }
-}
-
 void 
 _pygi_marshal_cleanup_from_py_interface_struct_gvalue (PyGIInvokeState *state,
                                                        PyGIArgCache    *arg_cache,
diff --git a/gi/pygi-marshal-cleanup.h b/gi/pygi-marshal-cleanup.h
index eaacb8d..530f5f3 100644
--- a/gi/pygi-marshal-cleanup.h
+++ b/gi/pygi-marshal-cleanup.h
@@ -65,11 +65,6 @@ void _pygi_marshal_cleanup_to_py_interface_object         (PyGIInvokeState *stat
                                                            PyObject        *dummy,
                                                            gpointer         data,
                                                            gboolean         was_processed);
-void _pygi_marshal_cleanup_from_py_interface_callback     (PyGIInvokeState *state,
-                                                           PyGIArgCache    *arg_cache,
-                                                           PyObject        *py_arg,
-                                                           gpointer         data,
-                                                           gboolean         was_processed);
 G_END_DECLS
 
 #endif /* __PYGI_MARSHAL_CLEANUP_H__ */
diff --git a/gi/pygi-marshal-from-py.c b/gi/pygi-marshal-from-py.c
index c6fe1c2..92c89c8 100644
--- a/gi/pygi-marshal-from-py.c
+++ b/gi/pygi-marshal-from-py.c
@@ -140,166 +140,6 @@ _is_union_member (GIInterfaceInfo *interface_info, PyObject *py_arg) {
     return is_member;
 }
 
-/* _pygi_destroy_notify_dummy:
- *
- * Dummy method used in the occasion when a method has a GDestroyNotify
- * argument without user data.
- */
-static void
-_pygi_destroy_notify_dummy (gpointer data) {
-}
-
-static PyGICClosure *global_destroy_notify;
-
-static void
-_pygi_destroy_notify_callback_closure (ffi_cif *cif,
-                                       void *result,
-                                       void **args,
-                                       void *data)
-{
-    PyGICClosure *info = * (void**) (args[0]);
-
-    g_assert (info);
-
-    _pygi_invoke_closure_free (info);
-}
-
-/* _pygi_destroy_notify_create:
- *
- * Method used in the occasion when a method has a GDestroyNotify
- * argument with user data.
- */
-static PyGICClosure*
-_pygi_destroy_notify_create (void)
-{
-    if (!global_destroy_notify) {
-
-        PyGICClosure *destroy_notify = g_slice_new0 (PyGICClosure);
-        GIBaseInfo* glib_destroy_notify;
-
-        g_assert (destroy_notify);
-
-        glib_destroy_notify = g_irepository_find_by_name (NULL, "GLib", "DestroyNotify");
-        g_assert (glib_destroy_notify != NULL);
-        g_assert (g_base_info_get_type (glib_destroy_notify) == GI_INFO_TYPE_CALLBACK);
-
-        destroy_notify->closure = g_callable_info_prepare_closure ( (GICallableInfo*) glib_destroy_notify,
-                                                                    &destroy_notify->cif,
-                                                                    _pygi_destroy_notify_callback_closure,
-                                                                    NULL);
-
-        global_destroy_notify = destroy_notify;
-    }
-
-    return global_destroy_notify;
-}
-
-gboolean
-_pygi_marshal_from_py_interface_callback (PyGIInvokeState   *state,
-                                          PyGICallableCache *callable_cache,
-                                          PyGIArgCache      *arg_cache,
-                                          PyObject          *py_arg,
-                                          GIArgument        *arg,
-                                          gpointer          *cleanup_data)
-{
-    GICallableInfo *callable_info;
-    PyGICClosure *closure;
-    PyGIArgCache *user_data_cache = NULL;
-    PyGIArgCache *destroy_cache = NULL;
-    PyGICallbackCache *callback_cache;
-    PyObject *py_user_data = NULL;
-
-    callback_cache = (PyGICallbackCache *)arg_cache;
-
-    if (callback_cache->user_data_index > 0) {
-        user_data_cache = _pygi_callable_cache_get_arg (callable_cache, callback_cache->user_data_index);
-        if (user_data_cache->py_arg_index < state->n_py_in_args) {
-            /* py_user_data is a borrowed reference. */
-            py_user_data = PyTuple_GetItem (state->py_in_args, user_data_cache->py_arg_index);
-            if (!py_user_data)
-                return FALSE;
-            /* NULL out user_data if it was not supplied and the default arg placeholder
-             * was used instead.
-             */
-            if (py_user_data == _PyGIDefaultArgPlaceholder) {
-                py_user_data = NULL;
-            } else if (callable_cache->user_data_varargs_index < 0) {
-                /* For non-variable length user data, place the user data in a
-                 * single item tuple which is concatenated to the callbacks arguments.
-                 * This allows callback input arg marshaling to always expect a
-                 * tuple for user data. Note the
-                 */
-                py_user_data = Py_BuildValue("(O)", py_user_data, NULL);
-            } else {
-                /* increment the ref borrowed from PyTuple_GetItem above */
-                Py_INCREF (py_user_data);
-            }
-        }
-    }
-
-    if (py_arg == Py_None) {
-        return TRUE;
-    }
-
-    if (!PyCallable_Check (py_arg)) {
-        PyErr_Format (PyExc_TypeError,
-                      "Callback needs to be a function or method not %s",
-                      py_arg->ob_type->tp_name);
-
-        return FALSE;
-    }
-
-    callable_info = (GICallableInfo *)callback_cache->interface_info;
-
-    closure = _pygi_make_native_closure (callable_info, callback_cache->scope, py_arg, py_user_data);
-    arg->v_pointer = closure->closure;
-
-    /* always decref the user data as _pygi_make_native_closure adds its own ref */
-    Py_XDECREF (py_user_data);
-
-    /* The PyGICClosure instance is used as user data passed into the C function.
-     * The return trip to python will marshal this back and pull the python user data out.
-     */
-    if (user_data_cache != NULL) {
-        state->in_args[user_data_cache->c_arg_index].v_pointer = closure;
-    }
-
-    /* Setup a GDestroyNotify callback if this method supports it along with
-     * a user data field. The user data field is a requirement in order
-     * free resources and ref counts associated with this arguments closure.
-     * In case a user data field is not available, show a warning giving
-     * explicit information and setup a dummy notification to avoid a crash
-     * later on in _pygi_destroy_notify_callback_closure.
-     */
-    if (callback_cache->destroy_notify_index > 0) {
-        destroy_cache = _pygi_callable_cache_get_arg (callable_cache, callback_cache->destroy_notify_index);
-    }
-
-    if (destroy_cache) {
-        if (user_data_cache != NULL) {
-            PyGICClosure *destroy_notify = _pygi_destroy_notify_create ();
-            state->in_args[destroy_cache->c_arg_index].v_pointer = destroy_notify->closure;
-        } else {
-            gchar *msg = g_strdup_printf("Callables passed to %s will leak references because "
-                                         "the method does not support a user_data argument. "
-                                         "See: https://bugzilla.gnome.org/show_bug.cgi?id=685598";,
-                                         callable_cache->name);
-            if (PyErr_WarnEx(PyExc_RuntimeWarning, msg, 2)) {
-                g_free(msg);
-                _pygi_invoke_closure_free(closure);
-                return FALSE;
-            }
-            g_free(msg);
-            state->in_args[destroy_cache->c_arg_index].v_pointer = _pygi_destroy_notify_dummy;
-        }
-    }
-
-    /* Use the PyGIClosure as data passed to cleanup for GI_SCOPE_TYPE_CALL. */
-    *cleanup_data = closure;
-
-    return TRUE;
-}
-
 gboolean
 _pygi_marshal_from_py_interface_enum (PyGIInvokeState   *state,
                                       PyGICallableCache *callable_cache,
diff --git a/gi/pygi-marshal-from-py.h b/gi/pygi-marshal-from-py.h
index a49c179..0172c19 100644
--- a/gi/pygi-marshal-from-py.h
+++ b/gi/pygi-marshal-from-py.h
@@ -33,12 +33,6 @@ G_BEGIN_DECLS
 gboolean _pygi_marshal_from_py_ssize_t     (PyGIArgCache      *arg_cache,
                                             Py_ssize_t         size,
                                             GIArgument        *arg);
-gboolean _pygi_marshal_from_py_interface_callback (PyGIInvokeState   *state,
-                                                   PyGICallableCache *callable_cache,
-                                                   PyGIArgCache      *arg_cache,
-                                                   PyObject          *py_arg,
-                                                   GIArgument        *arg,
-                                                   gpointer          *cleanup_data);
 gboolean _pygi_marshal_from_py_interface_enum     (PyGIInvokeState   *state,
                                                    PyGICallableCache *callable_cache,
                                                    PyGIArgCache      *arg_cache,
diff --git a/gi/pygi-marshal-to-py.c b/gi/pygi-marshal-to-py.c
index e890b1e..69a7c1a 100644
--- a/gi/pygi-marshal-to-py.c
+++ b/gi/pygi-marshal-to-py.c
@@ -75,19 +75,6 @@ gi_argument_to_c_long (GIArgument *arg_in,
 }
 
 PyObject *
-_pygi_marshal_to_py_interface_callback (PyGIInvokeState   *state,
-                                        PyGICallableCache *callable_cache,
-                                        PyGIArgCache      *arg_cache,
-                                        GIArgument        *arg)
-{
-    PyObject *py_obj = NULL;
-
-    PyErr_Format (PyExc_NotImplementedError,
-                  "Marshalling a callback to PyObject is not supported");
-    return py_obj;
-}
-
-PyObject *
 _pygi_marshal_to_py_interface_enum (PyGIInvokeState   *state,
                                     PyGICallableCache *callable_cache,
                                     PyGIArgCache      *arg_cache,
diff --git a/gi/pygi-marshal-to-py.h b/gi/pygi-marshal-to-py.h
index edf1989..de8f85b 100644
--- a/gi/pygi-marshal-to-py.h
+++ b/gi/pygi-marshal-to-py.h
@@ -22,10 +22,6 @@
 #ifndef __PYGI_MARSHAL_TO_PY_H__
 #define __PYGI_MARSHAL_TO_PY_H__
 
-PyObject *_pygi_marshal_to_py_interface_callback(PyGIInvokeState   *state,
-                                                 PyGICallableCache *callable_cache,
-                                                 PyGIArgCache      *arg_cache,
-                                                 GIArgument        *arg);
 PyObject *_pygi_marshal_to_py_interface_enum   (PyGIInvokeState   *state,
                                                 PyGICallableCache *callable_cache,
                                                 PyGIArgCache      *arg_cache,


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