summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTomeu Vizoso <tomeu@sugarlabs.org>2010-04-18 13:11:11 -0400
committerTomeu Vizoso <tomeu@sugarlabs.org>2010-04-18 13:15:07 -0400
commit8b70faa7a9a32b9ea8862f28a503e38f496cfd89 (patch)
tree139df2373cdc05b308dfd87ea46699eee8999f13
parente239faacb4798fe2d166233ca1a19a843a6225e3 (diff)
downloadpygi-8b70faa7a9a32b9ea8862f28a503e38f496cfd89.tar.gz
pygi-8b70faa7a9a32b9ea8862f28a503e38f496cfd89.tar.xz
pygi-8b70faa7a9a32b9ea8862f28a503e38f496cfd89.zip
Implement vfuncs.
https://bugzilla.gnome.org/show_bug.cgi?id=602736
-rw-r--r--gi/gimodule.c89
-rw-r--r--gi/pygi-argument.c1
-rw-r--r--gi/pygi-callbacks.c3
-rw-r--r--gi/pygi-closure.c4
-rw-r--r--gi/pygi-closure.h2
-rw-r--r--gi/pygi-info.c86
-rw-r--r--gi/pygi-info.h1
-rw-r--r--gi/types.py44
-rw-r--r--tests/test_gi.py18
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):