[pygobject] Use g_vfunc_info_invoke for chaining up in vfuncs



commit da50d5620a42046d4fc905bb28a0890d73533cb1
Author: Tomeu Vizoso <tomeu vizoso collabora co uk>
Date:   Mon Dec 13 18:03:51 2010 +0100

    Use g_vfunc_info_invoke for chaining up in vfuncs
    
    https://bugzilla.gnome.org/show_bug.cgi?id=637165

 gi/pygi-info.c   |    4 +-
 gi/pygi-invoke.c |   72 +++++++++++++++++++++++++++++++++++++++++------------
 gi/pygi-invoke.h |    3 +-
 gi/types.py      |   28 ++++++++++++++++++++-
 tests/test_gi.py |    5 ++-
 5 files changed, 89 insertions(+), 23 deletions(-)
---
diff --git a/gi/pygi-info.c b/gi/pygi-info.c
index 9d15e5e..c753097 100644
--- a/gi/pygi-info.c
+++ b/gi/pygi-info.c
@@ -235,6 +235,7 @@ out:
 PYGLIB_DEFINE_TYPE ("gi.CallableInfo", PyGICallableInfo_Type, PyGIBaseInfo);
 
 static PyMethodDef _PyGICallableInfo_methods[] = {
+    { "invoke", (PyCFunction) _wrap_g_callable_info_invoke, METH_VARARGS | METH_KEYWORDS },
     { NULL, NULL, 0 }
 };
 
@@ -476,7 +477,6 @@ _pygi_g_type_info_size (GITypeInfo *type_info)
 static PyMethodDef _PyGIFunctionInfo_methods[] = {
     { "is_constructor", (PyCFunction) _wrap_g_function_info_is_constructor, METH_NOARGS },
     { "is_method", (PyCFunction) _wrap_g_function_info_is_method, METH_NOARGS },
-    { "invoke", (PyCFunction) _wrap_g_function_info_invoke, METH_VARARGS },
     { NULL, NULL, 0 }
 };
 
@@ -1544,7 +1544,7 @@ _pygi_info_register_types (PyObject *m)
     _PyGI_REGISTER_TYPE (m, PyGIFieldInfo_Type, FieldInfo,
                          PyGIBaseInfo_Type);
     _PyGI_REGISTER_TYPE (m, PyGIVFuncInfo_Type, VFuncInfo,
-                         PyGIBaseInfo_Type);
+                         PyGICallableInfo_Type);
     _PyGI_REGISTER_TYPE (m, PyGIUnionInfo_Type, UnionInfo,
                          PyGIRegisteredTypeInfo_Type);
     _PyGI_REGISTER_TYPE (m, PyGIBoxedInfo_Type, BoxedInfo,
diff --git a/gi/pygi-invoke.c b/gi/pygi-invoke.c
index 3a4fafa..e0b365a 100644
--- a/gi/pygi-invoke.c
+++ b/gi/pygi-invoke.c
@@ -58,19 +58,40 @@ struct invocation_state
     GIArgument *backup_args;
     GIArgument return_arg;
 
-    PyObject *return_value;
+    PyObject  *return_value;
+
+    GType      implementor_gtype;
 };
 
-static void
+static gboolean
 _initialize_invocation_state (struct invocation_state *state,
                               GIFunctionInfo *info,
-                              PyObject *py_args)
+                              PyObject *py_args,
+                              PyObject *kwargs)
 {
-    GIFunctionInfoFlags flags;
+    if (g_base_info_get_type (info) == GI_INFO_TYPE_FUNCTION) {
+        GIFunctionInfoFlags flags = g_function_info_get_flags (info);
+
+        state->is_method = (flags & GI_FUNCTION_IS_METHOD) != 0;
+        state->is_constructor = (flags & GI_FUNCTION_IS_CONSTRUCTOR) != 0;
+        state->implementor_gtype = 0;
+    } else {
+        PyObject *obj;
+
+        state->is_method = TRUE;
+        state->is_constructor = FALSE;
+
+        obj = PyDict_GetItemString (kwargs, "gtype");
+        if (obj == NULL) {
+            PyErr_SetString (PyExc_TypeError,
+                             "need the GType of the implementor class");
+            return FALSE;
+        }
 
-    flags = g_function_info_get_flags (info);
-    state->is_method = (flags & GI_FUNCTION_IS_METHOD) != 0;
-    state->is_constructor = (flags & GI_FUNCTION_IS_CONSTRUCTOR) != 0;
+        state->implementor_gtype = pyg_type_from_object (obj);
+        if (state->implementor_gtype == 0)
+            return FALSE;
+    }
 
     /* Count arguments. */
     state->n_args = g_callable_info_get_n_args ( (GICallableInfo *) info);
@@ -98,6 +119,8 @@ _initialize_invocation_state (struct invocation_state *state,
     state->out_args = NULL;
     state->out_values = NULL;
     state->backup_args = NULL;
+
+    return TRUE;
 }
 
 static gboolean
@@ -552,7 +575,7 @@ _prepare_invocation_state (struct invocation_state *state,
 
 static gboolean
 _invoke_function (struct invocation_state *state,
-                  GIFunctionInfo *function_info, PyObject *py_args)
+                  GICallableInfo *callable_info, PyObject *py_args)
 {
     GError *error;
     gint retval;
@@ -560,13 +583,24 @@ _invoke_function (struct invocation_state *state,
     error = NULL;
 
     pyg_begin_allow_threads;
-    retval = g_function_info_invoke ( (GIFunctionInfo *) function_info,
-                                      state->in_args,
-                                      state->n_in_args,
-                                      state->out_args,
-                                      state->n_out_args,
-                                      &state->return_arg,
-                                      &error);
+    if (g_base_info_get_type (callable_info) == GI_INFO_TYPE_FUNCTION) {
+        retval = g_function_info_invoke ( (GIFunctionInfo *) callable_info,
+                                          state->in_args,
+                                          state->n_in_args,
+                                          state->out_args,
+                                          state->n_out_args,
+                                          &state->return_arg,
+                                          &error);
+    } else {
+        retval = g_vfunc_info_invoke ( (GIVFuncInfo *) callable_info,
+                                       state->implementor_gtype,
+                                       state->in_args,
+                                       state->n_in_args,
+                                       state->out_args,
+                                       state->n_out_args,
+                                       &state->return_arg,
+                                       &error);
+    }
     pyg_end_allow_threads;
 
     if (!retval) {
@@ -916,11 +950,15 @@ _free_invocation_state (struct invocation_state *state)
 
 
 PyObject *
-_wrap_g_function_info_invoke (PyGIBaseInfo *self, PyObject *py_args)
+_wrap_g_callable_info_invoke (PyGIBaseInfo *self, PyObject *py_args,
+                              PyObject *kwargs)
 {
     struct invocation_state state = { 0, };
 
-    _initialize_invocation_state (&state, self->info, py_args);
+    if (!_initialize_invocation_state (&state, self->info, py_args, kwargs)) {
+        _free_invocation_state (&state);
+        return NULL;
+    }
 
     if (!_prepare_invocation_state (&state, self->info, py_args)) {
         _free_invocation_state (&state);
diff --git a/gi/pygi-invoke.h b/gi/pygi-invoke.h
index 0d07b21..dc1ce18 100644
--- a/gi/pygi-invoke.h
+++ b/gi/pygi-invoke.h
@@ -30,7 +30,8 @@
 
 G_BEGIN_DECLS
 
-PyObject *_wrap_g_function_info_invoke (PyGIBaseInfo *self, PyObject *py_args);
+PyObject *_wrap_g_callable_info_invoke (PyGIBaseInfo *self, PyObject *py_args,
+                                        PyObject *kwargs);
 
 G_END_DECLS
 
diff --git a/gi/types.py b/gi/types.py
index cc43d02..4f7094e 100644
--- a/gi/types.py
+++ b/gi/types.py
@@ -45,6 +45,16 @@ def Function(info):
     return function
 
 
+def NativeVFunc(info, cls):
+
+    def native_vfunc(*args):
+        return info.invoke(*args, gtype=cls.__gtype__)
+    native_vfunc.__info__ = info
+    native_vfunc.__name__ = info.get_name()
+    native_vfunc.__module__ = info.get_namespace()
+
+    return native_vfunc
+
 def Constructor(info):
 
     def constructor(cls, *args):
@@ -125,6 +135,21 @@ class MetaClassHelper(object):
 
             base._setup_vfuncs(impl)
 
+    def _setup_native_vfuncs(cls, impl):
+        for base in cls.__bases__ + (cls,):
+            if not hasattr(base, '__info__') or \
+                    not hasattr(base.__info__, 'get_vfuncs') or \
+                    isinstance(base.__info__, InterfaceInfo):
+                continue
+            for vfunc_info in base.__info__.get_vfuncs():
+                name = 'do_%s' % vfunc_info.get_name()
+                value = NativeVFunc(vfunc_info, impl)
+                setattr(impl, name, value)
+
+            if base != cls:
+                base._setup_native_vfuncs(impl)
+
+
 def find_vfunc_conflict_in_bases(vfunc, bases):
     for klass in bases:
         if not hasattr(klass, '__info__') or \
@@ -153,7 +178,6 @@ class GObjectMeta(gobject.GObjectMeta, MetaClassHelper):
 
     def __init__(cls, name, bases, dict_):
         super(GObjectMeta, cls).__init__(name, bases, dict_)
-
         is_gi_defined = False
         if cls.__module__ == 'gi.repository.' + cls.__info__.get_namespace():
             is_gi_defined = True
@@ -167,6 +191,7 @@ class GObjectMeta(gobject.GObjectMeta, MetaClassHelper):
         elif is_gi_defined:
             cls._setup_methods()
             cls._setup_constants()
+            cls._setup_native_vfuncs(cls)
 
             if isinstance(cls.__info__, ObjectInfo):
                 cls._setup_fields()
@@ -175,6 +200,7 @@ class GObjectMeta(gobject.GObjectMeta, MetaClassHelper):
             elif isinstance(cls.__info__, InterfaceInfo):
                 register_interface_info(cls.__info__.get_g_type())
 
+
 class StructMeta(type, MetaClassHelper):
 
     def __init__(cls, name, bases, dict_):
diff --git a/tests/test_gi.py b/tests/test_gi.py
index d1566c6..e19b7fd 100644
--- a/tests/test_gi.py
+++ b/tests/test_gi.py
@@ -1372,7 +1372,8 @@ class TestPythonGObject(unittest.TestCase):
             return 42
 
         def do_method_with_default_implementation(self, int8):
-            self.props.int = int8 * 2
+            GIMarshallingTests.Object.do_method_with_default_implementation(self, int8)
+            self.props.int += int8
 
     class SubObject(GIMarshallingTests.SubObject):
         __gtype_name__ = "SubObject"
@@ -1400,7 +1401,7 @@ class TestPythonGObject(unittest.TestCase):
         self.assertEqual(object_.method_int8_out(), 42)
 
         object_.method_with_default_implementation(42)
-        self.assertEqual(object_.val, 84)
+        self.assertEqual(object_.props.int, 84)
 
         class ObjectWithoutVFunc(GIMarshallingTests.Object):
             __gtype_name__ = 'ObjectWithoutVFunc'



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