[pygi] Implement vfuncs.



commit 8b70faa7a9a32b9ea8862f28a503e38f496cfd89
Author: Tomeu Vizoso <tomeu sugarlabs org>
Date:   Sun Apr 18 13:11:11 2010 -0400

    Implement vfuncs.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=602736

 gi/gimodule.c       |   89 +++++++++++++++++++++++++++++++++++++++++++++++++++
 gi/pygi-argument.c  |    1 +
 gi/pygi-callbacks.c |    3 +-
 gi/pygi-closure.c   |    4 +-
 gi/pygi-closure.h   |    2 +-
 gi/pygi-info.c      |   86 ++++++++++++++++++++++++++++++++++++++++++++++++-
 gi/pygi-info.h      |    1 +
 gi/types.py         |   44 +++++++++++++++++--------
 tests/test_gi.py    |   18 ++++++++++
 9 files changed, 227 insertions(+), 21 deletions(-)
---
diff --git a/gi/gimodule.c b/gi/gimodule.c
index 8dd8ac5..8650fb3 100644
--- a/gi/gimodule.c
+++ b/gi/gimodule.c
@@ -132,6 +132,94 @@ _wrap_pyg_register_interface_info(PyObject *self, PyObject *args)
     Py_RETURN_NONE;
 }
 
+static PyObject *
+_wrap_pyg_hook_up_vfunc_implementation (PyObject *self, PyObject *args)
+{
+    PyGIBaseInfo *py_info;
+    PyObject *py_type;
+    PyObject *py_function;
+    gpointer implementor_class = NULL;
+    GType ancestor_g_type = 0;
+    GType implementor_gtype = 0;
+    gpointer *method_ptr = NULL;
+    int length, i;
+    GIBaseInfo *vfunc_info;
+    GIBaseInfo *ancestor_info;
+    GIStructInfo *struct_info;
+    gboolean is_interface = FALSE;
+    PyGICClosure *closure = NULL;
+
+    if (!PyArg_ParseTuple(args, "O!O!O:hook_up_vfunc_implementation",
+                          &PyGIBaseInfo_Type, &py_info,
+                          &PyGTypeWrapper_Type, &py_type,
+                          &py_function))
+        return NULL;
+
+    implementor_gtype = pyg_type_from_object(py_type);
+    g_assert(G_TYPE_IS_CLASSED(implementor_gtype));
+
+    vfunc_info = py_info->info;
+    ancestor_info = g_base_info_get_container(vfunc_info);
+    is_interface = g_base_info_get_type(ancestor_info) == GI_INFO_TYPE_INTERFACE;
+
+    ancestor_g_type = g_registered_type_info_get_g_type(
+            (GIRegisteredTypeInfo *)ancestor_info);
+
+    implementor_class = g_type_class_ref(implementor_gtype);
+    if (is_interface) {
+        GTypeInstance *implementor_iface_class;
+        implementor_iface_class = g_type_interface_peek(implementor_class,
+                                                        ancestor_g_type);
+        g_type_class_unref (implementor_class);
+        implementor_class = implementor_iface_class;
+
+        struct_info = g_interface_info_get_iface_struct ((GIInterfaceInfo*)ancestor_info);
+    } else
+        struct_info = g_object_info_get_class_struct ((GIObjectInfo*)ancestor_info);
+
+    length = g_struct_info_get_n_fields(struct_info);
+    for (i = 0; i < length; i++) {
+        GIFieldInfo *field_info;
+        GITypeInfo *type_info;
+        GIBaseInfo *interface_info;
+        GICallbackInfo *callback_info;
+        gint offset;
+
+        field_info = g_struct_info_get_field (struct_info, i);
+
+        if (strcmp(g_base_info_get_name((GIBaseInfo*) field_info),
+                   g_base_info_get_name((GIBaseInfo*) vfunc_info)) != 0)
+            continue;
+
+        type_info = g_field_info_get_type (field_info);
+        if (g_type_info_get_tag (type_info) != GI_TYPE_TAG_INTERFACE)
+            continue;
+
+        interface_info = g_type_info_get_interface (type_info);
+        g_assert(g_base_info_get_type(interface_info) == GI_INFO_TYPE_CALLBACK);
+
+        callback_info = (GICallbackInfo*) interface_info;
+        offset = g_field_info_get_offset(field_info);
+        method_ptr = G_STRUCT_MEMBER_P(implementor_class, offset);
+
+        closure = _pygi_make_native_closure((GICallableInfo*)callback_info,
+            GI_SCOPE_TYPE_NOTIFIED, py_function, NULL);
+
+        *method_ptr = closure->closure;
+
+        g_base_info_unref (interface_info);
+        g_base_info_unref (type_info);
+        g_base_info_unref (field_info);
+
+        break;
+    }
+
+    g_base_info_unref (struct_info);
+    g_type_class_unref (implementor_class);
+
+    Py_RETURN_NONE;
+}
+
 
 static PyMethodDef _pygi_functions[] = {
     { "enum_add", (PyCFunction)_wrap_pyg_enum_add, METH_VARARGS | METH_KEYWORDS },
@@ -139,6 +227,7 @@ static PyMethodDef _pygi_functions[] = {
 
     { "set_object_has_new_constructor", (PyCFunction)_wrap_pyg_set_object_has_new_constructor, METH_VARARGS | METH_KEYWORDS },
     { "register_interface_info", (PyCFunction)_wrap_pyg_register_interface_info, METH_VARARGS },
+    { "hook_up_vfunc_implementation", (PyCFunction)_wrap_pyg_hook_up_vfunc_implementation, METH_VARARGS },
     { NULL, NULL, 0 }
 };
 
diff --git a/gi/pygi-argument.c b/gi/pygi-argument.c
index df88a6c..4bedc82 100644
--- a/gi/pygi-argument.c
+++ b/gi/pygi-argument.c
@@ -1518,6 +1518,7 @@ _pygi_argument_to_object (GArgument  *arg,
 
                     break;
                 }
+                case GI_INFO_TYPE_INTERFACE:
                 case GI_INFO_TYPE_OBJECT:
                     if (arg->v_pointer == NULL) {
                         object = Py_None;
diff --git a/gi/pygi-callbacks.c b/gi/pygi-callbacks.c
index cf6ebd9..fb852ff 100644
--- a/gi/pygi-callbacks.c
+++ b/gi/pygi-callbacks.c
@@ -202,10 +202,9 @@ _pygi_create_callback (PyGIBaseInfo  *function_info,
         return FALSE;
     }
 
-
     /** Now actually build the closure **/
     *closure_out = _pygi_make_native_closure((GICallableInfo *)callback_info,
-                                             callback_arg,
+                                             g_arg_info_get_scope(callback_arg),
                                              py_function,
                                              py_user_data);
     
diff --git a/gi/pygi-closure.c b/gi/pygi-closure.c
index 0ad8fef..35373d2 100644
--- a/gi/pygi-closure.c
+++ b/gi/pygi-closure.c
@@ -170,7 +170,7 @@ void _pygi_invoke_closure_free(gpointer data)
 
 PyGICClosure*
 _pygi_make_native_closure (GICallableInfo* info,
-                           GIArgInfo* arg_info,
+                           GIScopeType scope,
                            PyObject *py_function,
                            gpointer py_user_data)
 {
@@ -199,7 +199,7 @@ _pygi_make_native_closure (GICallableInfo* info,
     
     /* Give the closure the information it needs to determine when
        to free itself later */
-    closure->scope = g_arg_info_get_scope(arg_info);
+    closure->scope = scope;
 
     return closure;
 }
diff --git a/gi/pygi-closure.h b/gi/pygi-closure.h
index c03e69d..550bf8a 100644
--- a/gi/pygi-closure.h
+++ b/gi/pygi-closure.h
@@ -48,7 +48,7 @@ void _pygi_closure_handle(ffi_cif *cif, void *result, void
 void _pygi_invoke_closure_free(gpointer user_data);
 
 PyGICClosure* _pygi_make_native_closure (GICallableInfo* info,
-                                         GIArgInfo* arg_info,
+                                         GIScopeType scope,
                                          PyObject *function,
                                          gpointer user_data);
 
diff --git a/gi/pygi-info.c b/gi/pygi-info.c
index 824e579..00d9e4d 100644
--- a/gi/pygi-info.c
+++ b/gi/pygi-info.c
@@ -213,8 +213,8 @@ _pygi_info_new (GIBaseInfo *info)
             PyErr_SetString(PyExc_NotImplementedError, "GISignalInfo bindings not implemented");
             return NULL;
         case GI_INFO_TYPE_VFUNC:
-            PyErr_SetString(PyExc_NotImplementedError, "GIVFuncInfo bindings not implemented");
-            return NULL;
+            type = &PyGIVFuncInfo_Type;
+            break;
         case GI_INFO_TYPE_PROPERTY:
             PyErr_SetString(PyExc_NotImplementedError, "GIPropertyInfo bindings not implemented");
             return NULL;
@@ -1709,12 +1709,49 @@ _wrap_g_object_info_get_constants (PyGIBaseInfo *self)
     return infos;
 }
 
+static PyObject *
+_wrap_g_object_info_get_vfuncs (PyGIBaseInfo *self)
+{
+    gssize n_infos;
+    PyObject *infos;
+    gssize i;
+
+    n_infos = g_object_info_get_n_vfuncs((GIObjectInfo *)self->info);
+
+    infos = PyTuple_New(n_infos);
+    if (infos == NULL) {
+        return NULL;
+    }
+
+    for (i = 0; i < n_infos; i++) {
+        GIBaseInfo *info;
+        PyObject *py_info;
+
+        info = (GIBaseInfo *)g_object_info_get_vfunc((GIObjectInfo *)self->info, i);
+        g_assert(info != NULL);
+
+        py_info = _pygi_info_new(info);
+
+        g_base_info_unref(info);
+
+        if (py_info == NULL) {
+            Py_CLEAR(infos);
+            break;
+        }
+
+        PyTuple_SET_ITEM(infos, i, py_info);
+    }
+
+    return infos;
+}
+
 static PyMethodDef _PyGIObjectInfo_methods[] = {
     { "get_parent", (PyCFunction)_wrap_g_object_info_get_parent, METH_NOARGS },
     { "get_methods", (PyCFunction)_wrap_g_object_info_get_methods, METH_NOARGS },
     { "get_fields", (PyCFunction)_wrap_g_object_info_get_fields, METH_NOARGS },
     { "get_interfaces", (PyCFunction)_wrap_g_object_info_get_interfaces, METH_NOARGS },
     { "get_constants", (PyCFunction)_wrap_g_object_info_get_constants, METH_NOARGS },
+    { "get_vfuncs", (PyCFunction)_wrap_g_object_info_get_vfuncs, METH_NOARGS },
     { NULL, NULL, 0 }
 };
 
@@ -1794,9 +1831,46 @@ _wrap_g_interface_info_get_constants (PyGIBaseInfo *self)
     return infos;
 }
 
+static PyObject *
+_wrap_g_interface_info_get_vfuncs (PyGIBaseInfo *self)
+{
+    gssize n_infos;
+    PyObject *infos;
+    gssize i;
+
+    n_infos = g_interface_info_get_n_vfuncs((GIInterfaceInfo *)self->info);
+
+    infos = PyTuple_New(n_infos);
+    if (infos == NULL) {
+        return NULL;
+    }
+
+    for (i = 0; i < n_infos; i++) {
+        GIBaseInfo *info;
+        PyObject *py_info;
+
+        info = (GIBaseInfo *)g_interface_info_get_vfunc((GIInterfaceInfo *)self->info, i);
+        g_assert(info != NULL);
+
+        py_info = _pygi_info_new(info);
+
+        g_base_info_unref(info);
+
+        if (py_info == NULL) {
+            Py_CLEAR(infos);
+            break;
+        }
+
+        PyTuple_SET_ITEM(infos, i, py_info);
+    }
+
+    return infos;
+}
+
 static PyMethodDef _PyGIInterfaceInfo_methods[] = {
     { "get_methods", (PyCFunction)_wrap_g_interface_info_get_methods, METH_NOARGS },
     { "get_constants", (PyCFunction)_wrap_g_interface_info_get_constants, METH_NOARGS },
+    { "get_vfuncs", (PyCFunction)_wrap_g_interface_info_get_vfuncs, METH_NOARGS },
     { NULL, NULL, 0 }
 };
 
@@ -2102,6 +2176,13 @@ static PyMethodDef _PyGIUnresolvedInfo_methods[] = {
     { NULL, NULL, 0 }
 };
 
+/* GIVFuncInfo */
+_PyGI_DEFINE_INFO_TYPE("VFuncInfo", GIVFuncInfo, PyGIBaseInfo_Type);
+
+static PyMethodDef _PyGIVFuncInfo_methods[] = {
+    { NULL, NULL, 0 }
+};
+
 /* Private */
 
 gchar *
@@ -2151,6 +2232,7 @@ _pygi_info_register_types (PyObject *m)
     _PyGI_REGISTER_TYPE(m, PyGIConstantInfo_Type, "ConstantInfo");
     _PyGI_REGISTER_TYPE(m, PyGIValueInfo_Type, "ValueInfo");
     _PyGI_REGISTER_TYPE(m, PyGIFieldInfo_Type, "FieldInfo");
+    _PyGI_REGISTER_TYPE(m, PyGIVFuncInfo_Type, "VFuncInfo");
 
 #undef _PyGI_REGISTER_TYPE
 }
diff --git a/gi/pygi-info.h b/gi/pygi-info.h
index 437ef9a..fe02d1a 100644
--- a/gi/pygi-info.h
+++ b/gi/pygi-info.h
@@ -45,6 +45,7 @@ extern PyTypeObject PyGIConstantInfo_Type;
 extern PyTypeObject PyGIValueInfo_Type;
 extern PyTypeObject PyGIFieldInfo_Type;
 extern PyTypeObject PyGIUnresolvedInfo_Type;
+extern PyTypeObject PyGIVFuncInfo_Type;
 
 #define PyGIBaseInfo_GET_GI_INFO(object) g_base_info_ref(((PyGIBaseInfo *)object)->info)
 
diff --git a/gi/types.py b/gi/types.py
index b7061bd..cda1e52 100644
--- a/gi/types.py
+++ b/gi/types.py
@@ -30,7 +30,8 @@ from ._gi import \
     ObjectInfo, \
     StructInfo, \
     set_object_has_new_constructor, \
-    register_interface_info
+    register_interface_info, \
+    hook_up_vfunc_implementation
 
 
 def Function(info):
@@ -91,6 +92,22 @@ class MetaClassHelper(object):
             value = constant_info.get_value()
             setattr(cls, name, value)
 
+    def _setup_vfuncs(cls):
+        for base in cls.__bases__:
+            if not hasattr(base, '__info__') or \
+                    not hasattr(base.__info__, 'get_vfuncs'):
+                continue
+            for vfunc_info in base.__info__.get_vfuncs():
+                vfunc = getattr(cls, 'do_' + vfunc_info.get_name(), None)
+                if vfunc is None:
+                    raise TypeError('Class implementing %s.%s should implement '
+                            'the method do_%s()' % (base.__info__.get_namespace(),
+                                                    base.__info__.get_name(),
+                                                    vfunc_info.get_name()))
+                else:
+                    hook_up_vfunc_implementation(vfunc_info, cls.__gtype__,
+                                                 vfunc)
+
 
 class GObjectMeta(gobject.GObjectMeta, MetaClassHelper):
 
@@ -98,19 +115,18 @@ class GObjectMeta(gobject.GObjectMeta, MetaClassHelper):
         super(GObjectMeta, cls).__init__(name, bases, dict_)
 
         # Avoid touching anything else than the base class.
-        if cls.__info__.get_g_type().pytype is not None:
-            return
-
-        cls._setup_methods()
-        cls._setup_constants()
-
-        if isinstance(cls.__info__, ObjectInfo):
-            cls._setup_fields()
-            cls._setup_constructors()
-            set_object_has_new_constructor(cls.__info__.get_g_type())
-        elif isinstance(cls.__info__, InterfaceInfo):
-            register_interface_info(cls.__info__.get_g_type())
-
+        if cls.__info__.get_g_type().pytype is None:
+            cls._setup_methods()
+            cls._setup_constants()
+
+            if isinstance(cls.__info__, ObjectInfo):
+                cls._setup_fields()
+                cls._setup_constructors()
+                set_object_has_new_constructor(cls.__info__.get_g_type())
+            elif isinstance(cls.__info__, InterfaceInfo):
+                register_interface_info(cls.__info__.get_g_type())
+        else:
+            cls._setup_vfuncs()
 
 class StructMeta(type, MetaClassHelper):
 
diff --git a/tests/test_gi.py b/tests/test_gi.py
index b37dce4..9f3c215 100644
--- a/tests/test_gi.py
+++ b/tests/test_gi.py
@@ -1313,10 +1313,17 @@ class TestPythonGObject(unittest.TestCase):
     class Object(GIMarshallingTests.Object):
         __gtype_name__ = "Object"
 
+        def __init__(self, int):
+            GIMarshallingTests.Object.__init__(self)
+            self.val = None
+
         def method(self):
             # Don't call super, which asserts that self.int == 42.
             pass
 
+        def do_method_int8_in(self, int8):
+            self.val = int8
+
     def test_object(self):
         self.assertTrue(issubclass(self.Object, GIMarshallingTests.Object))
 
@@ -1326,6 +1333,11 @@ class TestPythonGObject(unittest.TestCase):
     def test_object_method(self):
         self.Object(int = 0).method()
 
+    def test_object_vfuncs(self):
+        object_ = self.Object(int = 42)
+        object_.method_int8_in(84)
+        self.assertEqual(object_.val, 84)
+
 
 class TestMultiOutputArgs(unittest.TestCase):
 
@@ -1351,12 +1363,18 @@ class TestInterfaces(unittest.TestCase):
             __gtype_name__ = 'TestInterfaceImpl'
             def __init__(self):
                 gobject.GObject.__init__(self)
+                self.val = None
+
+            def do_test_int8_in(self, int8):
+                self.val = int8
 
         self.assertTrue(issubclass(TestInterfaceImpl, GIMarshallingTests.Interface))
 
         instance = TestInterfaceImpl()
         self.assertTrue(isinstance(instance, GIMarshallingTests.Interface))
 
+        GIMarshallingTests.test_interface_test_int8_in(instance, 42)
+        self.assertEquals(instance.val, 42)
 
 class TestOverrides(unittest.TestCase):
 



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