diff options
Diffstat (limited to 'gi/pygi-info.c')
-rw-r--r-- | gi/pygi-info.c | 2093 |
1 files changed, 2093 insertions, 0 deletions
diff --git a/gi/pygi-info.c b/gi/pygi-info.c new file mode 100644 index 0000000..5f4a174 --- /dev/null +++ b/gi/pygi-info.c @@ -0,0 +1,2093 @@ +/* -*- Mode: C; c-basic-offset: 4 -*- + * vim: tabstop=4 shiftwidth=4 expandtab + * + * Copyright (C) 2005-2009 Johan Dahlin <johan@gnome.org> + * + * pygi-info.c: GI.*Info wrappers. + * + * 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" + +#include <pygobject.h> + +#define _PyGI_DEFINE_INFO_TYPE(name, cname, base) \ +static PyMethodDef _Py##cname##_methods[]; \ +PyTypeObject Py##cname##_Type = { \ + PyObject_HEAD_INIT(NULL) \ + 0, \ + "gi." name, /* tp_name */ \ + sizeof(PyGIBaseInfo), /* tp_basicsize */ \ + 0, /* tp_itemsize */ \ + (destructor)NULL, /* tp_dealloc */ \ + (printfunc)NULL, /* tp_print */ \ + (getattrfunc)NULL, /* tp_getattr */ \ + (setattrfunc)NULL, /* tp_setattr */ \ + (cmpfunc)NULL, /* tp_compare */ \ + (reprfunc)NULL, /* tp_repr */ \ + NULL, /* tp_as_number */ \ + NULL, /* tp_as_sequence */ \ + NULL, /* tp_as_mapping */ \ + (hashfunc)NULL, /* tp_hash */ \ + (ternaryfunc)NULL, /* tp_call */ \ + (reprfunc)NULL, /* tp_str */ \ + (getattrofunc)NULL, /* tp_getattro */ \ + (setattrofunc)NULL, /* tp_setattro */ \ + NULL, /* tp_as_buffer */ \ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ \ + NULL, /* tp_doc */ \ + (traverseproc)NULL, /* tp_traverse */ \ + (inquiry)NULL, /* tp_clear */ \ + (richcmpfunc)NULL, /* tp_richcompare */ \ + offsetof(PyGIBaseInfo, inst_weakreflist), /* tp_weaklistoffset */ \ + (getiterfunc)NULL, /* tp_iter */ \ + (iternextfunc)NULL, /* tp_iternext */ \ + _Py##cname##_methods, /* tp_methods */ \ + NULL, /* tp_members */ \ + NULL, /* tp_getset */ \ + &base /* tp_base */ \ +} + + +/* BaseInfo */ + +static void +_base_info_dealloc (PyGIBaseInfo *self) +{ + PyObject_GC_UnTrack((PyObject *)self); + + PyObject_ClearWeakRefs((PyObject *)self); + + g_base_info_unref(self->info); + + self->ob_type->tp_free((PyObject *)self); +} + +static int +_base_info_traverse (PyGIBaseInfo *self, + visitproc visit, + void *arg) +{ + return 0; +} + +static PyObject * +_base_info_repr (PyGIBaseInfo *self) +{ + return PyString_FromFormat("<%s object (%s) at 0x%p>", + self->ob_type->tp_name, g_base_info_get_name(self->info), (void *)self); +} + +static PyMethodDef _PyGIBaseInfo_methods[]; + +PyTypeObject PyGIBaseInfo_Type = { + PyObject_HEAD_INIT(NULL) + 0, + "gi.BaseInfo", /* tp_name */ + sizeof(PyGIBaseInfo), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)_base_info_dealloc, /* tp_dealloc */ + (printfunc)NULL, /* tp_print */ + (getattrfunc)NULL, /* tp_getattr */ + (setattrfunc)NULL, /* tp_setattr */ + (cmpfunc)NULL, /* tp_compare */ + (reprfunc)_base_info_repr, /* tp_repr */ + NULL, /* tp_as_number */ + NULL, /* tp_as_sequence */ + NULL, /* tp_as_mapping */ + (hashfunc)NULL, /* tp_hash */ + (ternaryfunc)NULL, /* tp_call */ + (reprfunc)NULL, /* tp_str */ + (getattrofunc)NULL, /* tp_getattro */ + (setattrofunc)NULL, /* tp_setattro */ + NULL, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_HAVE_GC, /* tp_flags */ + NULL, /* tp_doc */ + (traverseproc)_base_info_traverse, /* tp_traverse */ + (inquiry)NULL, /* tp_clear */ + (richcmpfunc)NULL, /* tp_richcompare */ + offsetof(PyGIBaseInfo, inst_weakreflist), /* tp_weaklistoffset */ + (getiterfunc)NULL, /* tp_iter */ + (iternextfunc)NULL, /* tp_iternext */ + _PyGIBaseInfo_methods, /* tp_methods */ +}; + +static PyObject * +_wrap_g_base_info_get_name (PyGIBaseInfo *self) +{ + return PyString_FromString(g_base_info_get_name(self->info)); +} + +static PyObject * +_wrap_g_base_info_get_namespace (PyGIBaseInfo *self) +{ + return PyString_FromString(g_base_info_get_namespace(self->info)); +} + +static PyObject * +_wrap_g_base_info_get_container (PyGIBaseInfo *self) +{ + GIBaseInfo *info; + + info = g_base_info_get_container(self->info); + + if (info == NULL) { + Py_RETURN_NONE; + } + + return _pygi_info_new(info); +} + + +static PyMethodDef _PyGIBaseInfo_methods[] = { + { "get_name", (PyCFunction)_wrap_g_base_info_get_name, METH_NOARGS }, + { "get_namespace", (PyCFunction)_wrap_g_base_info_get_namespace, METH_NOARGS }, + { "get_container", (PyCFunction)_wrap_g_base_info_get_container, METH_NOARGS }, + { NULL, NULL, 0 } +}; + +PyObject * +_pygi_info_new (GIBaseInfo *info) +{ + GIInfoType info_type; + PyTypeObject *type = NULL; + PyGIBaseInfo *self; + + info_type = g_base_info_get_type(info); + + switch (info_type) + { + case GI_INFO_TYPE_INVALID: + PyErr_SetString(PyExc_RuntimeError, "Invalid info type"); + return NULL; + case GI_INFO_TYPE_FUNCTION: + type = &PyGIFunctionInfo_Type; + break; + case GI_INFO_TYPE_CALLBACK: + PyErr_SetString(PyExc_NotImplementedError, "GICallbackInfo bindings not implemented"); + return NULL; + case GI_INFO_TYPE_STRUCT: + type = &PyGIStructInfo_Type; + break; + case GI_INFO_TYPE_BOXED: + PyErr_SetString(PyExc_NotImplementedError, "GIBoxedInfo bindings not implemented"); + return NULL; + case GI_INFO_TYPE_ENUM: + case GI_INFO_TYPE_FLAGS: + type = &PyGIEnumInfo_Type; + break; + case GI_INFO_TYPE_OBJECT: + type = &PyGIObjectInfo_Type; + break; + case GI_INFO_TYPE_INTERFACE: + type = &PyGIInterfaceInfo_Type; + break; + case GI_INFO_TYPE_CONSTANT: + type = &PyGIConstantInfo_Type; + break; + case GI_INFO_TYPE_ERROR_DOMAIN: + PyErr_SetString(PyExc_NotImplementedError, "GIErrorDomainInfo bindings not implemented"); + return NULL; + case GI_INFO_TYPE_UNION: + PyErr_SetString(PyExc_NotImplementedError, "GIUnionInfo bindings not implemented"); + return NULL; + case GI_INFO_TYPE_VALUE: + type = &PyGIValueInfo_Type; + break; + case GI_INFO_TYPE_SIGNAL: + 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; + case GI_INFO_TYPE_PROPERTY: + PyErr_SetString(PyExc_NotImplementedError, "GIPropertyInfo bindings not implemented"); + return NULL; + case GI_INFO_TYPE_FIELD: + type = &PyGIFieldInfo_Type; + break; + case GI_INFO_TYPE_ARG: + PyErr_SetString(PyExc_NotImplementedError, "GIArgInfo bindings not implemented"); + return NULL; + case GI_INFO_TYPE_TYPE: + PyErr_SetString(PyExc_NotImplementedError, "GITypeInfo bindings not implemented"); + return NULL; + case GI_INFO_TYPE_UNRESOLVED: + type = &PyGIUnresolvedInfo_Type; + break; + } + + self = (PyGIBaseInfo *)type->tp_alloc(type, 0); + if (self == NULL) { + return NULL; + } + + self->info = g_base_info_ref(info); + + return (PyObject *)self; +} + +GIBaseInfo * +_pygi_object_get_gi_info (PyObject *object, + PyTypeObject *type) +{ + PyObject *py_info; + GIBaseInfo *info = NULL; + + py_info = PyObject_GetAttrString(object, "__info__"); + if (py_info == NULL) { + return NULL; + } + if (!PyObject_TypeCheck(py_info, type)) { + PyErr_Format(PyExc_TypeError, "attribute '__info__' must be %s, not %s", + type->tp_name, py_info->ob_type->tp_name); + goto out; + } + + info = ((PyGIBaseInfo *)py_info)->info; + g_base_info_ref(info); + +out: + Py_DECREF(py_info); + + return info; +} + + +/* CallableInfo */ +_PyGI_DEFINE_INFO_TYPE("CallableInfo", GICallableInfo, PyGIBaseInfo_Type); + +static PyMethodDef _PyGICallableInfo_methods[] = { + { NULL, NULL, 0 } +}; + + +/* FunctionInfo */ +_PyGI_DEFINE_INFO_TYPE("FunctionInfo", GIFunctionInfo, PyGICallableInfo_Type); + +static PyObject * +_wrap_g_function_info_is_constructor (PyGIBaseInfo *self) +{ + GIFunctionInfoFlags flags; + gboolean is_constructor; + + flags = g_function_info_get_flags((GIFunctionInfo*)self->info); + is_constructor = flags & GI_FUNCTION_IS_CONSTRUCTOR; + + return PyBool_FromLong(is_constructor); +} + +static PyObject * +_wrap_g_function_info_is_method (PyGIBaseInfo *self) +{ + GIFunctionInfoFlags flags; + gboolean is_method; + + flags = g_function_info_get_flags((GIFunctionInfo*)self->info); + is_method = flags & GI_FUNCTION_IS_METHOD; + + return PyBool_FromLong(is_method); +} + +gsize +_pygi_g_type_tag_size (GITypeTag type_tag) +{ + gsize size = 0; + + switch(type_tag) { + case GI_TYPE_TAG_BOOLEAN: + size = sizeof(gboolean); + break; + case GI_TYPE_TAG_INT8: + case GI_TYPE_TAG_UINT8: + size = sizeof(gint8); + break; + case GI_TYPE_TAG_INT16: + case GI_TYPE_TAG_UINT16: + size = sizeof(gint16); + break; + case GI_TYPE_TAG_INT32: + case GI_TYPE_TAG_UINT32: + size = sizeof(gint32); + break; + case GI_TYPE_TAG_INT64: + case GI_TYPE_TAG_UINT64: + size = sizeof(gint64); + break; + case GI_TYPE_TAG_SHORT: + case GI_TYPE_TAG_USHORT: + size = sizeof(gshort); + break; + case GI_TYPE_TAG_INT: + case GI_TYPE_TAG_UINT: + size = sizeof(gint); + break; + case GI_TYPE_TAG_LONG: + case GI_TYPE_TAG_ULONG: + size = sizeof(glong); + break; + case GI_TYPE_TAG_SIZE: + case GI_TYPE_TAG_SSIZE: + size = sizeof(gsize); + break; + case GI_TYPE_TAG_FLOAT: + size = sizeof(gfloat); + break; + case GI_TYPE_TAG_DOUBLE: + size = sizeof(gdouble); + break; + case GI_TYPE_TAG_TIME_T: + size = sizeof(time_t); + break; + case GI_TYPE_TAG_GTYPE: + size = sizeof(GType); + break; + case GI_TYPE_TAG_VOID: + case GI_TYPE_TAG_UTF8: + case GI_TYPE_TAG_FILENAME: + case GI_TYPE_TAG_ARRAY: + case GI_TYPE_TAG_INTERFACE: + case GI_TYPE_TAG_GLIST: + case GI_TYPE_TAG_GSLIST: + case GI_TYPE_TAG_GHASH: + case GI_TYPE_TAG_ERROR: + PyErr_Format(PyExc_TypeError, + "Unable to know the size (assuming %s is not a pointer)", + g_type_tag_to_string(type_tag)); + break; + } + + return size; +} + +gsize +_pygi_g_type_info_size (GITypeInfo *type_info) +{ + gsize size = 0; + gboolean is_pointer; + + is_pointer = g_type_info_is_pointer(type_info); + + if (is_pointer) { + size = sizeof(gpointer); + } else { + GITypeTag type_tag; + + type_tag = g_type_info_get_tag(type_info); + switch(type_tag) { + case GI_TYPE_TAG_BOOLEAN: + case GI_TYPE_TAG_INT8: + case GI_TYPE_TAG_UINT8: + case GI_TYPE_TAG_INT16: + case GI_TYPE_TAG_UINT16: + case GI_TYPE_TAG_INT32: + case GI_TYPE_TAG_UINT32: + case GI_TYPE_TAG_INT64: + case GI_TYPE_TAG_UINT64: + case GI_TYPE_TAG_SHORT: + case GI_TYPE_TAG_USHORT: + case GI_TYPE_TAG_INT: + case GI_TYPE_TAG_UINT: + case GI_TYPE_TAG_LONG: + case GI_TYPE_TAG_ULONG: + case GI_TYPE_TAG_SIZE: + case GI_TYPE_TAG_SSIZE: + case GI_TYPE_TAG_FLOAT: + case GI_TYPE_TAG_DOUBLE: + case GI_TYPE_TAG_TIME_T: + case GI_TYPE_TAG_GTYPE: + size = _pygi_g_type_tag_size(type_tag); + g_assert(size > 0); + 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); + + switch (info_type) { + case GI_INFO_TYPE_STRUCT: + size = g_struct_info_get_size((GIStructInfo *)info); + break; + case GI_INFO_TYPE_UNION: + size = g_union_info_get_size((GIUnionInfo *)info); + break; + case GI_INFO_TYPE_ENUM: + case GI_INFO_TYPE_FLAGS: + { + GITypeTag type_tag; + + type_tag = g_enum_info_get_storage_type((GIEnumInfo *)info); + size = _pygi_g_type_tag_size(type_tag); + break; + } + case GI_INFO_TYPE_BOXED: + case GI_INFO_TYPE_OBJECT: + case GI_INFO_TYPE_INTERFACE: + case GI_INFO_TYPE_CALLBACK: + /* Should have been catched by is_pointer above. */ + case GI_INFO_TYPE_VFUNC: + case GI_INFO_TYPE_INVALID: + case GI_INFO_TYPE_FUNCTION: + case GI_INFO_TYPE_CONSTANT: + case GI_INFO_TYPE_ERROR_DOMAIN: + case GI_INFO_TYPE_VALUE: + case GI_INFO_TYPE_SIGNAL: + case GI_INFO_TYPE_PROPERTY: + case GI_INFO_TYPE_FIELD: + case GI_INFO_TYPE_ARG: + case GI_INFO_TYPE_TYPE: + case GI_INFO_TYPE_UNRESOLVED: + g_assert_not_reached(); + break; + } + + g_base_info_unref(info); + break; + } + case GI_TYPE_TAG_ARRAY: + case GI_TYPE_TAG_VOID: + case GI_TYPE_TAG_UTF8: + case GI_TYPE_TAG_FILENAME: + case GI_TYPE_TAG_GLIST: + case GI_TYPE_TAG_GSLIST: + case GI_TYPE_TAG_GHASH: + case GI_TYPE_TAG_ERROR: + /* Should have been catched by is_pointer above. */ + g_assert_not_reached(); + break; + } + } + + return size; +} + + +static PyObject * +_wrap_g_function_info_invoke (PyGIBaseInfo *self, + PyObject *py_args) +{ + gboolean is_method; + gboolean is_constructor; + + gsize n_args; + gsize n_in_args; + gsize n_out_args; + gsize n_backup_args; + Py_ssize_t n_py_args; + gsize n_aux_in_args; + gsize n_aux_out_args; + gsize n_return_values; + + glong error_arg_pos; + + GIArgInfo **arg_infos; + GITypeInfo **arg_type_infos; + GITypeInfo *return_type_info; + GITypeTag return_type_tag; + + GArgument **args; + gboolean *args_is_auxiliary; + + GArgument *in_args; + GArgument *out_args; + GArgument *out_values; + GArgument *backup_args; + GArgument return_arg; + + PyObject *return_value = NULL; + + gsize i; + + { + GIFunctionInfoFlags flags; + + flags = g_function_info_get_flags((GIFunctionInfo *)self->info); + is_method = (flags & GI_FUNCTION_IS_METHOD) != 0; + is_constructor = (flags & GI_FUNCTION_IS_CONSTRUCTOR) != 0; + } + + /* Count arguments. */ + n_args = g_callable_info_get_n_args((GICallableInfo *)self->info); + n_in_args = 0; + n_out_args = 0; + n_backup_args = 0; + n_aux_in_args = 0; + n_aux_out_args = 0; + + error_arg_pos = -1; + + arg_infos = g_newa(GIArgInfo *, n_args); + arg_type_infos = g_newa(GITypeInfo *, n_args); + + args_is_auxiliary = g_newa(gboolean, n_args); + memset(args_is_auxiliary, 0, sizeof(args_is_auxiliary) * n_args); + + if (is_method) { + /* The first argument is the instance. */ + n_in_args += 1; + } + + for (i = 0; i < n_args; i++) { + GIDirection direction; + GITransfer transfer; + GITypeTag arg_type_tag; + + arg_infos[i] = g_callable_info_get_arg((GICallableInfo *)self->info, i); + arg_type_infos[i] = g_arg_info_get_type(arg_infos[i]); + + direction = g_arg_info_get_direction(arg_infos[i]); + transfer = g_arg_info_get_ownership_transfer(arg_infos[i]); + arg_type_tag = g_type_info_get_tag(arg_type_infos[i]); + + if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT) { + n_in_args += 1; + if (transfer == GI_TRANSFER_CONTAINER) { + n_backup_args += 1; + } + } + if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT) { + n_out_args += 1; + } + + if (direction == GI_DIRECTION_INOUT && transfer == GI_TRANSFER_NOTHING) { + n_backup_args += 1; + } + + switch (arg_type_tag) { + case GI_TYPE_TAG_ARRAY: + { + gint length_arg_pos; + + length_arg_pos = g_type_info_get_array_length(arg_type_infos[i]); + if (length_arg_pos < 0) { + break; + } + + g_assert(length_arg_pos < n_args); + args_is_auxiliary[length_arg_pos] = TRUE; + + if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT) { + n_aux_in_args += 1; + } + if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT) { + n_aux_out_args += 1; + } + + break; + } + case GI_TYPE_TAG_ERROR: + g_warn_if_fail(error_arg_pos < 0); + error_arg_pos = i; + break; + default: + break; + } + } + + return_type_info = g_callable_info_get_return_type((GICallableInfo *)self->info); + return_type_tag = g_type_info_get_tag(return_type_info); + + if (return_type_tag == GI_TYPE_TAG_ARRAY) { + gint length_arg_pos; + length_arg_pos = g_type_info_get_array_length(return_type_info); + if (length_arg_pos >= 0) { + g_assert(length_arg_pos < n_args); + args_is_auxiliary[length_arg_pos] = TRUE; + n_aux_out_args += 1; + } + } + + n_return_values = n_out_args - n_aux_out_args; + if (return_type_tag != GI_TYPE_TAG_VOID) { + n_return_values += 1; + } + + { + gsize n_py_args_expected; + Py_ssize_t py_args_pos; + + /* Check the argument count. */ + n_py_args = PyTuple_Size(py_args); + g_assert(n_py_args >= 0); + + n_py_args_expected = n_in_args + + (is_constructor ? 1 : 0) + - n_aux_in_args + - (error_arg_pos >= 0 ? 1 : 0); + + if (n_py_args != n_py_args_expected) { + PyErr_Format(PyExc_TypeError, + "takes exactly %zd argument(s) (%zd given)", + n_py_args_expected, n_py_args); + goto out; + } + + /* Check argument types. */ + py_args_pos = 0; + if (is_constructor || is_method) { + py_args_pos += 1; + } + + for (i = 0; i < n_args; i++) { + GIDirection direction; + GITypeTag type_tag; + gboolean may_be_null; + PyObject *py_arg; + gint retval; + + direction = g_arg_info_get_direction(arg_infos[i]); + type_tag = g_type_info_get_tag(arg_type_infos[i]); + + if (direction == GI_DIRECTION_OUT + || args_is_auxiliary[i] + || type_tag == GI_TYPE_TAG_ERROR) { + continue; + } + + g_assert(py_args_pos < n_py_args); + py_arg = PyTuple_GET_ITEM(py_args, py_args_pos); + + may_be_null = g_arg_info_may_be_null(arg_infos[i]); + + retval = _pygi_g_type_info_check_object(arg_type_infos[i], + may_be_null, py_arg); + + if (retval < 0) { + goto out; + } else if (!retval) { + _PyGI_ERROR_PREFIX("argument %zd: ", py_args_pos); + goto out; + } + + py_args_pos += 1; + } + + g_assert(py_args_pos == n_py_args); + } + + args = g_newa(GArgument *, n_args); + in_args = g_newa(GArgument, n_in_args); + out_args = g_newa(GArgument, n_out_args); + out_values = g_newa(GArgument, n_out_args); + backup_args = g_newa(GArgument, n_backup_args); + + /* Bind args so we can use an unique index. */ + { + gsize in_args_pos; + gsize out_args_pos; + + in_args_pos = is_method ? 1 : 0; + out_args_pos = 0; + + for (i = 0; i < n_args; i++) { + GIDirection direction; + + direction = g_arg_info_get_direction(arg_infos[i]); + + switch (direction) { + case GI_DIRECTION_IN: + g_assert(in_args_pos < n_in_args); + args[i] = &in_args[in_args_pos]; + in_args_pos += 1; + break; + case GI_DIRECTION_INOUT: + g_assert(in_args_pos < n_in_args); + g_assert(out_args_pos < n_out_args); + in_args[in_args_pos].v_pointer = &out_values[out_args_pos]; + in_args_pos += 1; + case GI_DIRECTION_OUT: + g_assert(out_args_pos < n_out_args); + out_args[out_args_pos].v_pointer = &out_values[out_args_pos]; + args[i] = &out_values[out_args_pos]; + out_args_pos += 1; + } + } + + g_assert(in_args_pos == n_in_args); + g_assert(out_args_pos == n_out_args); + } + + /* Convert the input arguments. */ + { + Py_ssize_t py_args_pos; + gsize backup_args_pos; + + py_args_pos = 0; + backup_args_pos = 0; + + if (is_constructor) { + /* Skip the first argument. */ + py_args_pos += 1; + } else if (is_method) { + /* Get the instance. */ + GIBaseInfo *container_info; + GIInfoType container_info_type; + PyObject *py_arg; + + container_info = g_base_info_get_container(self->info); + container_info_type = g_base_info_get_type(container_info); + + g_assert(py_args_pos < n_py_args); + py_arg = PyTuple_GET_ITEM(py_args, py_args_pos); + + switch(container_info_type) { + case GI_INFO_TYPE_UNION: + PyErr_SetString(PyExc_NotImplementedError, "calling methods on unions is not supported yet."); + goto out; + break; + case GI_INFO_TYPE_STRUCT: + { + GType type; + + type = g_registered_type_info_get_g_type((GIRegisteredTypeInfo *)container_info); + + if (g_type_is_a(type, G_TYPE_BOXED)) { + g_assert(n_in_args > 0); + in_args[0].v_pointer = pyg_boxed_get(py_arg, void); + } else if (g_type_is_a(type, G_TYPE_POINTER) || type == G_TYPE_NONE) { + g_assert(n_in_args > 0); + in_args[0].v_pointer = pyg_pointer_get(py_arg, void); + } else { + PyErr_Format(PyExc_TypeError, "unable to convert an instance of '%s'", g_type_name(type)); + goto out; + } + + break; + } + case GI_INFO_TYPE_OBJECT: + case GI_INFO_TYPE_INTERFACE: + g_assert(n_in_args > 0); + in_args[0].v_pointer = pygobject_get(py_arg); + break; + default: + /* Other types don't have methods. */ + g_assert_not_reached(); + } + + py_args_pos += 1; + } + + for (i = 0; i < n_args; i++) { + GIDirection direction; + + if (args_is_auxiliary[i]) { + continue; + } + + direction = g_arg_info_get_direction(arg_infos[i]); + + if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT) { + PyObject *py_arg; + GITypeTag arg_type_tag; + GITransfer transfer; + + arg_type_tag = g_type_info_get_tag(arg_type_infos[i]); + + if (arg_type_tag == GI_TYPE_TAG_ERROR) { + GError **error; + + error = g_slice_new(GError *); + *error = NULL; + + args[i]->v_pointer = error; + continue; + } + + transfer = g_arg_info_get_ownership_transfer(arg_infos[i]); + + g_assert(py_args_pos < n_py_args); + py_arg = PyTuple_GET_ITEM(py_args, py_args_pos); + + *args[i] = _pygi_argument_from_object(py_arg, arg_type_infos[i], transfer); + + if (PyErr_Occurred()) { + /* TODO: release previous input arguments. */ + goto out; + } + + if (direction == GI_DIRECTION_INOUT && transfer == GI_TRANSFER_NOTHING) { + /* We need to keep a copy of the argument to be able to release it later. */ + g_assert(backup_args_pos < n_backup_args); + backup_args[backup_args_pos] = *args[i]; + backup_args_pos += 1; + } else if (transfer == GI_TRANSFER_CONTAINER) { + /* We need to keep a copy of the items to be able to release them later. */ + switch (arg_type_tag) { + case GI_TYPE_TAG_ARRAY: + { + GArray *array; + gsize item_size; + GArray *new_array; + + array = args[i]->v_pointer; + + item_size = g_array_get_element_size(array); + + new_array = g_array_sized_new(FALSE, FALSE, item_size, array->len); + g_array_append_vals(new_array, array->data, array->len); + + g_assert(backup_args_pos < n_backup_args); + backup_args[backup_args_pos].v_pointer = new_array; + + break; + } + case GI_TYPE_TAG_GLIST: + g_assert(backup_args_pos < n_backup_args); + backup_args[backup_args_pos].v_pointer = g_list_copy(args[i]->v_pointer); + break; + case GI_TYPE_TAG_GSLIST: + g_assert(backup_args_pos < n_backup_args); + backup_args[backup_args_pos].v_pointer = g_slist_copy(args[i]->v_pointer); + break; + case GI_TYPE_TAG_GHASH: + { + GHashTable *hash_table; + GList *keys; + GList *values; + + hash_table = args[i]->v_pointer; + + keys = g_hash_table_get_keys(hash_table); + values = g_hash_table_get_values(hash_table); + + g_assert(backup_args_pos < n_backup_args); + backup_args[backup_args_pos].v_pointer = g_list_concat(keys, values); + + break; + } + default: + g_warn_if_reached(); + } + + backup_args_pos += 1; + } + + if (arg_type_tag == GI_TYPE_TAG_ARRAY) { + GArray *array; + gssize length_arg_pos; + + array = args[i]->v_pointer; + + length_arg_pos = g_type_info_get_array_length(arg_type_infos[i]); + if (length_arg_pos >= 0) { + /* Set the auxiliary argument holding the length. */ + args[length_arg_pos]->v_size = array->len; + } + + /* Get rid of the GArray. */ + args[i]->v_pointer = array->data; + + if (direction != GI_DIRECTION_INOUT || transfer != GI_TRANSFER_NOTHING) { + /* The array hasn't been referenced anywhere, so free it to avoid losing memory. */ + g_array_free(array, FALSE); + } + } + + py_args_pos += 1; + } + } + + g_assert(py_args_pos == n_py_args); + g_assert(backup_args_pos == n_backup_args); + } + + /* Invoke the callable. */ + { + GError *error; + gint retval; + + error = NULL; + + retval = g_function_info_invoke((GIFunctionInfo *)self->info, + in_args, n_in_args, out_args, n_out_args, &return_arg, &error); + if (!retval) { + g_assert(error != NULL); + /* TODO: raise the right error, out of the error domain. */ + PyErr_SetString(PyExc_RuntimeError, error->message); + g_error_free(error); + + /* TODO: release input arguments. */ + + goto out; + } + } + + if (error_arg_pos >= 0) { + GError **error; + + error = args[error_arg_pos]->v_pointer; + + if (*error != NULL) { + /* TODO: raise the right error, out of the error domain, if applicable. */ + PyErr_SetString(PyExc_Exception, (*error)->message); + g_error_free(*error); + + /* TODO: release input arguments. */ + + goto out; + } + } + + /* Convert the return value. */ + if (is_constructor) { + PyTypeObject *py_type; + GIBaseInfo *info; + GIInfoType info_type; + GITransfer transfer; + + g_assert(n_py_args > 0); + py_type = (PyTypeObject *)PyTuple_GET_ITEM(py_args, 0); + + info = g_type_info_get_interface(return_type_info); + g_assert(info != NULL); + + info_type = g_base_info_get_type(info); + + transfer = g_callable_info_get_caller_owns((GICallableInfo *)self->info); + + switch (info_type) { + case GI_INFO_TYPE_UNION: + /* TODO */ + PyErr_SetString(PyExc_NotImplementedError, "creating unions is not supported yet"); + g_base_info_unref(info); + goto out; + case GI_INFO_TYPE_STRUCT: + { + GType type; + + type = g_registered_type_info_get_g_type((GIRegisteredTypeInfo *)info); + + if (g_type_is_a(type, G_TYPE_BOXED)) { + if (return_arg.v_pointer == NULL) { + PyErr_SetString(PyExc_TypeError, "constructor returned NULL"); + break; + } + g_warn_if_fail(transfer == GI_TRANSFER_EVERYTHING); + return_value = pyg_boxed_new(type, return_arg.v_pointer, FALSE, transfer == GI_TRANSFER_EVERYTHING); + } else if (g_type_is_a(type, G_TYPE_POINTER) || type == G_TYPE_NONE) { + if (return_arg.v_pointer == NULL) { + PyErr_SetString(PyExc_TypeError, "constructor returned NULL"); + break; + } + g_warn_if_fail(transfer == GI_TRANSFER_NOTHING); + return_value = _pygi_struct_new(py_type, return_arg.v_pointer, transfer == GI_TRANSFER_EVERYTHING); + } else { + PyErr_Format(PyExc_TypeError, "cannot create '%s' instances", py_type->tp_name); + g_base_info_unref(info); + goto out; + } + + break; + } + case GI_INFO_TYPE_OBJECT: + if (return_arg.v_pointer == NULL) { + PyErr_SetString(PyExc_TypeError, "constructor returned NULL"); + break; + } + return_value = pygobject_new(return_arg.v_pointer); + if (transfer == GI_TRANSFER_EVERYTHING) { + /* The new wrapper increased the reference count, so decrease it. */ + g_object_unref (return_arg.v_pointer); + } + break; + default: + /* Other types don't have neither methods nor constructors. */ + g_assert_not_reached(); + } + + g_base_info_unref(info); + + if (return_value == NULL) { + /* TODO: release arguments. */ + goto out; + } + } else { + GITransfer transfer; + + if (return_type_tag == GI_TYPE_TAG_ARRAY) { + /* Create a #GArray. */ + return_arg.v_pointer = _pygi_argument_to_array(&return_arg, args, return_type_info); + } + + transfer = g_callable_info_get_caller_owns((GICallableInfo *)self->info); + + return_value = _pygi_argument_to_object(&return_arg, return_type_info, transfer); + if (return_value == NULL) { + /* TODO: release argument. */ + goto out; + } + + _pygi_argument_release(&return_arg, return_type_info, transfer, GI_DIRECTION_OUT); + + if (return_type_tag == GI_TYPE_TAG_ARRAY + && transfer == GI_TRANSFER_NOTHING) { + /* We created a #GArray, so free it. */ + return_arg.v_pointer = g_array_free(return_arg.v_pointer, FALSE); + } + } + + /* Convert output arguments and release arguments. */ + { + gsize backup_args_pos; + gsize return_values_pos; + + backup_args_pos = 0; + return_values_pos = 0; + + if (n_return_values > 1) { + /* Return a tuple. */ + PyObject *return_values; + + return_values = PyTuple_New(n_return_values); + if (return_values == NULL) { + /* TODO: release arguments. */ + goto out; + } + + if (return_type_tag == GI_TYPE_TAG_VOID) { + /* The current return value is None. */ + Py_DECREF(return_value); + } else { + /* Put the return value first. */ + g_assert(return_value != NULL); + PyTuple_SET_ITEM(return_values, return_values_pos, return_value); + return_values_pos += 1; + } + + return_value = return_values; + } + + for (i = 0; i < n_args; i++) { + GIDirection direction; + GITypeTag type_tag; + GITransfer transfer; + + if (args_is_auxiliary[i]) { + /* Auxiliary arguments are handled at the same time as their relatives. */ + continue; + } + + direction = g_arg_info_get_direction(arg_infos[i]); + transfer = g_arg_info_get_ownership_transfer(arg_infos[i]); + + type_tag = g_type_info_get_tag(arg_type_infos[i]); + + if (type_tag == GI_TYPE_TAG_ARRAY + && (direction != GI_DIRECTION_IN || transfer == GI_TRANSFER_NOTHING)) { + /* Create a #GArray. */ + args[i]->v_pointer = _pygi_argument_to_array(args[i], args, arg_type_infos[i]); + } + + if (direction == GI_DIRECTION_INOUT || direction == GI_DIRECTION_OUT) { + /* Convert the argument. */ + PyObject *obj; + + obj = _pygi_argument_to_object(args[i], arg_type_infos[i], transfer); + if (obj == NULL) { + /* TODO: release arguments. */ + goto out; + } + + g_assert(return_values_pos < n_return_values); + + if (n_return_values > 1) { + PyTuple_SET_ITEM(return_value, return_values_pos, obj); + } else { + /* The current return value is None. */ + Py_DECREF(return_value); + return_value = obj; + } + + return_values_pos += 1; + } + + /* Release the argument. */ + + if ((direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT) + && transfer == GI_TRANSFER_CONTAINER) { + /* Release the items we kept in another container. */ + switch (type_tag) { + case GI_TYPE_TAG_ARRAY: + case GI_TYPE_TAG_GLIST: + case GI_TYPE_TAG_GSLIST: + g_assert(backup_args_pos < n_backup_args); + _pygi_argument_release(&backup_args[backup_args_pos], arg_type_infos[i], + transfer, GI_DIRECTION_IN); + break; + case GI_TYPE_TAG_GHASH: + { + GITypeInfo *key_type_info; + GITypeInfo *value_type_info; + GList *item; + gsize length; + gsize j; + + key_type_info = g_type_info_get_param_type(arg_type_infos[i], 0); + value_type_info = g_type_info_get_param_type(arg_type_infos[i], 1); + + g_assert(backup_args_pos < n_backup_args); + item = backup_args[backup_args_pos].v_pointer; + + length = g_list_length(item) / 2; + + for (j = 0; j < length; j++, item = g_list_next(item)) { + _pygi_argument_release((GArgument *)&item->data, key_type_info, + GI_TRANSFER_NOTHING, GI_DIRECTION_IN); + } + + for (j = 0; j < length; j++, item = g_list_next(item)) { + _pygi_argument_release((GArgument *)&item->data, value_type_info, + GI_TRANSFER_NOTHING, GI_DIRECTION_IN); + } + + g_list_free(backup_args[backup_args_pos].v_pointer); + + break; + } + default: + g_warn_if_reached(); + } + + if (direction == GI_DIRECTION_INOUT) { + /* Release the output argument. */ + _pygi_argument_release(args[i], arg_type_infos[i], GI_TRANSFER_CONTAINER, + GI_DIRECTION_OUT); + } + + backup_args_pos += 1; + } else if (direction == GI_DIRECTION_INOUT) { + if (transfer == GI_TRANSFER_NOTHING) { + g_assert(backup_args_pos < n_backup_args); + _pygi_argument_release(&backup_args[backup_args_pos], arg_type_infos[i], + GI_TRANSFER_NOTHING, GI_DIRECTION_IN); + backup_args_pos += 1; + } + + _pygi_argument_release(args[i], arg_type_infos[i], transfer, + GI_DIRECTION_OUT); + } else { + _pygi_argument_release(args[i], arg_type_infos[i], transfer, direction); + } + + if (type_tag == GI_TYPE_TAG_ARRAY + && (direction != GI_DIRECTION_IN && transfer == GI_TRANSFER_NOTHING)) { + /* We created a #GArray and it has not been released above, so free it. */ + args[i]->v_pointer = g_array_free(args[i]->v_pointer, FALSE); + } + } + + g_assert(n_return_values <= 1 || return_values_pos == n_return_values); + g_assert(backup_args_pos == n_backup_args); + } + +out: + g_base_info_unref((GIBaseInfo *)return_type_info); + + for (i = 0; i < n_args; i++) { + g_base_info_unref((GIBaseInfo *)arg_type_infos[i]); + g_base_info_unref((GIBaseInfo *)arg_infos[i]); + } + + if (PyErr_Occurred()) { + Py_CLEAR(return_value); + } + + return return_value; +} + +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 } +}; + + +/* RegisteredTypeInfo */ +_PyGI_DEFINE_INFO_TYPE("RegisteredTypeInfo", GIRegisteredTypeInfo, PyGIBaseInfo_Type); + +static PyObject * +_wrap_g_registered_type_info_get_g_type (PyGIBaseInfo *self) +{ + GType type; + + type = g_registered_type_info_get_g_type((GIRegisteredTypeInfo *)self->info); + + return pyg_type_wrapper_new(type); +} + +static PyMethodDef _PyGIRegisteredTypeInfo_methods[] = { + { "get_g_type", (PyCFunction)_wrap_g_registered_type_info_get_g_type, METH_NOARGS }, + { NULL, NULL, 0 } +}; + + +/* GIStructInfo */ +_PyGI_DEFINE_INFO_TYPE("StructInfo", GIStructInfo, PyGIRegisteredTypeInfo_Type); + +static PyObject * +_wrap_g_struct_info_get_fields (PyGIBaseInfo *self) +{ + gssize n_infos; + PyObject *infos; + gssize i; + + n_infos = g_struct_info_get_n_fields((GIStructInfo *)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_struct_info_get_field((GIStructInfo *)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 PyObject * +_wrap_g_struct_info_get_methods (PyGIBaseInfo *self) +{ + gssize n_infos; + PyObject *infos; + gssize i; + + n_infos = g_struct_info_get_n_methods((GIStructInfo *)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_struct_info_get_method((GIStructInfo *)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 _PyGIStructInfo_methods[] = { + { "get_fields", (PyCFunction)_wrap_g_struct_info_get_fields, METH_NOARGS }, + { "get_methods", (PyCFunction)_wrap_g_struct_info_get_methods, METH_NOARGS }, + { NULL, NULL, 0 } +}; + +gboolean +pygi_g_struct_info_is_simple (GIStructInfo *struct_info) +{ + gboolean is_simple; + gsize n_field_infos; + gsize i; + + is_simple = TRUE; + + n_field_infos = g_struct_info_get_n_fields(struct_info); + + for (i = 0; i < n_field_infos && is_simple; i++) { + GIFieldInfo *field_info; + GITypeInfo *field_type_info; + gboolean is_pointer; + + field_info = g_struct_info_get_field(struct_info, i); + field_type_info = g_field_info_get_type(field_info); + is_pointer = g_type_info_is_pointer(field_type_info); + + if (is_pointer) { + is_simple = FALSE; + } else { + GITypeTag field_type_tag; + + field_type_tag = g_type_info_get_tag(field_type_info); + + switch (field_type_tag) { + case GI_TYPE_TAG_BOOLEAN: + case GI_TYPE_TAG_INT8: + case GI_TYPE_TAG_UINT8: + case GI_TYPE_TAG_INT16: + case GI_TYPE_TAG_UINT16: + case GI_TYPE_TAG_INT32: + case GI_TYPE_TAG_UINT32: + case GI_TYPE_TAG_SHORT: + case GI_TYPE_TAG_USHORT: + case GI_TYPE_TAG_INT: + case GI_TYPE_TAG_UINT: + case GI_TYPE_TAG_INT64: + case GI_TYPE_TAG_UINT64: + case GI_TYPE_TAG_LONG: + case GI_TYPE_TAG_ULONG: + case GI_TYPE_TAG_SSIZE: + case GI_TYPE_TAG_SIZE: + case GI_TYPE_TAG_FLOAT: + case GI_TYPE_TAG_DOUBLE: + case GI_TYPE_TAG_TIME_T: + break; + case GI_TYPE_TAG_VOID: + case GI_TYPE_TAG_GTYPE: + case GI_TYPE_TAG_ERROR: + case GI_TYPE_TAG_UTF8: + case GI_TYPE_TAG_FILENAME: + case GI_TYPE_TAG_ARRAY: + case GI_TYPE_TAG_GLIST: + case GI_TYPE_TAG_GSLIST: + case GI_TYPE_TAG_GHASH: + /* Should have been catched by is_pointer above. */ + g_assert_not_reached(); + break; + case GI_TYPE_TAG_INTERFACE: + { + GIBaseInfo *info; + GIInfoType info_type; + + info = g_type_info_get_interface(field_type_info); + info_type = g_base_info_get_type(info); + + switch (info_type) { + case GI_INFO_TYPE_BOXED: + case GI_INFO_TYPE_STRUCT: + is_simple = pygi_g_struct_info_is_simple((GIStructInfo *)info); + break; + case GI_INFO_TYPE_UNION: + /* TODO */ + is_simple = FALSE; + break; + case GI_INFO_TYPE_ENUM: + case GI_INFO_TYPE_FLAGS: + break; + case GI_INFO_TYPE_OBJECT: + case GI_INFO_TYPE_VFUNC: + case GI_INFO_TYPE_CALLBACK: + case GI_INFO_TYPE_INVALID: + case GI_INFO_TYPE_INTERFACE: + case GI_INFO_TYPE_FUNCTION: + case GI_INFO_TYPE_CONSTANT: + case GI_INFO_TYPE_ERROR_DOMAIN: + case GI_INFO_TYPE_VALUE: + case GI_INFO_TYPE_SIGNAL: + case GI_INFO_TYPE_PROPERTY: + case GI_INFO_TYPE_FIELD: + case GI_INFO_TYPE_ARG: + case GI_INFO_TYPE_TYPE: + case GI_INFO_TYPE_UNRESOLVED: + is_simple = FALSE; + break; + } + + g_base_info_unref(info); + break; + } + } + } + + g_base_info_unref((GIBaseInfo *)field_type_info); + g_base_info_unref((GIBaseInfo *)field_info); + } + + return is_simple; +} + + +/* EnumInfo */ +_PyGI_DEFINE_INFO_TYPE("EnumInfo", GIEnumInfo, PyGIRegisteredTypeInfo_Type); + +static PyObject * +_wrap_g_enum_info_get_values (PyGIBaseInfo *self) +{ + gssize n_infos; + PyObject *infos; + gssize i; + + n_infos = g_enum_info_get_n_values((GIEnumInfo *)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_enum_info_get_value((GIEnumInfo *)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 _PyGIEnumInfo_methods[] = { + { "get_values", (PyCFunction)_wrap_g_enum_info_get_values, METH_NOARGS }, + { NULL, NULL, 0 } +}; + + +/* ObjectInfo */ +_PyGI_DEFINE_INFO_TYPE("ObjectInfo", GIObjectInfo, PyGIRegisteredTypeInfo_Type); + +static PyObject * +_wrap_g_object_info_get_parent (PyGIBaseInfo *self) +{ + GIBaseInfo *info; + PyObject *py_info; + + info = (GIBaseInfo *)g_object_info_get_parent((GIObjectInfo*)self->info); + + if (info == NULL) { + Py_RETURN_NONE; + } + + py_info = _pygi_info_new(info); + + g_base_info_unref(info); + + return py_info; +} + +static PyObject * +_wrap_g_object_info_get_methods (PyGIBaseInfo *self) +{ + gssize n_infos; + PyObject *infos; + gssize i; + + n_infos = g_object_info_get_n_methods((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_method((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 PyObject * +_wrap_g_object_info_get_fields (PyGIBaseInfo *self) +{ + gssize n_infos; + PyObject *infos; + gssize i; + + n_infos = g_object_info_get_n_fields((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_field((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 PyObject * +_wrap_g_object_info_get_interfaces (PyGIBaseInfo *self) +{ + gssize n_infos; + PyObject *infos; + gssize i; + + n_infos = g_object_info_get_n_interfaces((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_interface((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 PyObject * +_wrap_g_object_info_get_constants (PyGIBaseInfo *self) +{ + gssize n_infos; + PyObject *infos; + gssize i; + + n_infos = g_object_info_get_n_constants((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_constant((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 }, + { NULL, NULL, 0 } +}; + + +/* GIInterfaceInfo */ +_PyGI_DEFINE_INFO_TYPE("InterfaceInfo", GIInterfaceInfo, PyGIRegisteredTypeInfo_Type); + +static PyObject * +_wrap_g_interface_info_get_methods (PyGIBaseInfo *self) +{ + gssize n_infos; + PyObject *infos; + gssize i; + + n_infos = g_interface_info_get_n_methods((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_method((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 PyObject * +_wrap_g_interface_info_get_constants (PyGIBaseInfo *self) +{ + gssize n_infos; + PyObject *infos; + gssize i; + + n_infos = g_interface_info_get_n_constants((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_constant((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 }, + { NULL, NULL, 0 } +}; + +/* GIConstantInfo */ +_PyGI_DEFINE_INFO_TYPE("ConstantInfo", GIConstantInfo, PyGIBaseInfo_Type); + +static PyObject * +_wrap_g_constant_info_get_value (PyGIBaseInfo *self) +{ + GITypeInfo *type_info; + GArgument value; + PyObject *py_value; + + if (g_constant_info_get_value((GIConstantInfo *)self->info, &value) < 0) { + PyErr_SetString(PyExc_RuntimeError, "unable to get value"); + return NULL; + } + + type_info = g_constant_info_get_type((GIConstantInfo *)self->info); + + py_value = _pygi_argument_to_object(&value, type_info, GI_TRANSFER_NOTHING); + + g_base_info_unref((GIBaseInfo *)type_info); + + return py_value; +} + +static PyMethodDef _PyGIConstantInfo_methods[] = { + { "get_value", (PyCFunction)_wrap_g_constant_info_get_value, METH_NOARGS }, + { NULL, NULL, 0 } +}; + +/* GIValueInfo */ +_PyGI_DEFINE_INFO_TYPE("ValueInfo", GIValueInfo, PyGIBaseInfo_Type); + +static PyObject * +_wrap_g_value_info_get_value (PyGIBaseInfo *self) +{ + glong value; + + value = g_value_info_get_value((GIValueInfo *)self->info); + + return PyInt_FromLong(value); +} + + +static PyMethodDef _PyGIValueInfo_methods[] = { + { "get_value", (PyCFunction)_wrap_g_value_info_get_value, METH_NOARGS }, + { NULL, NULL, 0 } +}; + + +/* GIFieldInfo */ +_PyGI_DEFINE_INFO_TYPE("FieldInfo", GIFieldInfo, PyGIBaseInfo_Type); + +static PyObject * +_wrap_g_field_info_get_value (PyGIBaseInfo *self, + PyObject *args) +{ + PyObject *instance; + GIBaseInfo *container_info; + GIInfoType container_info_type; + gpointer pointer; + GITypeInfo *field_type_info; + GArgument value; + PyObject *py_value = NULL; + + if (!PyArg_ParseTuple(args, "O:FieldInfo.get_value", &instance)) { + return NULL; + } + + container_info = g_base_info_get_container(self->info); + g_assert(container_info != NULL); + + /* Check the instance. */ + if (!_pygi_g_registered_type_info_check_object((GIRegisteredTypeInfo *)container_info, TRUE, instance)) { + _PyGI_ERROR_PREFIX("argument 1: "); + return NULL; + } + + /* Get the pointer to the container. */ + container_info_type = g_base_info_get_type(container_info); + switch (container_info_type) { + case GI_INFO_TYPE_UNION: + PyErr_SetString(PyExc_NotImplementedError, "getting a field from an union is not supported yet"); + return NULL; + case GI_INFO_TYPE_STRUCT: + pointer = pyg_boxed_get(instance, void); + break; + case GI_INFO_TYPE_OBJECT: + pointer = pygobject_get(instance); + break; + default: + /* Other types don't have fields. */ + g_assert_not_reached(); + } + + /* Get the field's value. */ + field_type_info = g_field_info_get_type((GIFieldInfo *)self->info); + + /* A few types are not handled by g_field_info_get_field, so do it here. */ + if (!g_type_info_is_pointer(field_type_info) + && g_type_info_get_tag(field_type_info) == GI_TYPE_TAG_INTERFACE) { + GIBaseInfo *info; + GIInfoType info_type; + + if (!(g_field_info_get_flags((GIFieldInfo *)self->info) & GI_FIELD_IS_READABLE)) { + PyErr_SetString(PyExc_RuntimeError, "field is not readable"); + goto out; + } + + info = g_type_info_get_interface(field_type_info); + + info_type = g_base_info_get_type(info); + + g_base_info_unref(info); + + switch(info_type) { + case GI_INFO_TYPE_UNION: + PyErr_SetString(PyExc_NotImplementedError, "getting an union is not supported yet"); + goto out; + case GI_INFO_TYPE_STRUCT: + { + gsize offset; + + offset = g_field_info_get_offset((GIFieldInfo *)self->info); + + value.v_pointer = pointer + offset; + + goto argument_to_object; + } + default: + /* Fallback. */ + break; + } + } + + if (!g_field_info_get_field((GIFieldInfo *)self->info, pointer, &value)) { + PyErr_SetString(PyExc_RuntimeError, "unable to get the value"); + goto out; + } + +argument_to_object: + py_value = _pygi_argument_to_object(&value, field_type_info, GI_TRANSFER_NOTHING); + +out: + g_base_info_unref((GIBaseInfo *)field_type_info); + + return py_value; +} + +static PyObject * +_wrap_g_field_info_set_value (PyGIBaseInfo *self, + PyObject *args) +{ + PyObject *instance; + PyObject *py_value; + GIBaseInfo *container_info; + GIInfoType container_info_type; + gpointer pointer; + GITypeInfo *field_type_info; + GArgument value; + PyObject *retval = NULL; + + if (!PyArg_ParseTuple(args, "OO:FieldInfo.set_value", &instance, &py_value)) { + return NULL; + } + + container_info = g_base_info_get_container(self->info); + g_assert(container_info != NULL); + + /* Check the instance. */ + if (!_pygi_g_registered_type_info_check_object((GIRegisteredTypeInfo *)container_info, TRUE, instance)) { + _PyGI_ERROR_PREFIX("argument 1: "); + return NULL; + } + + /* Get the pointer to the container. */ + container_info_type = g_base_info_get_type(container_info); + switch (container_info_type) { + case GI_INFO_TYPE_UNION: + PyErr_SetString(PyExc_NotImplementedError, "setting a field in an union is not supported yet"); + return NULL; + case GI_INFO_TYPE_STRUCT: + pointer = pyg_boxed_get(instance, void); + break; + case GI_INFO_TYPE_OBJECT: + pointer = pygobject_get(instance); + break; + default: + /* Other types don't have fields. */ + g_assert_not_reached(); + } + + field_type_info = g_field_info_get_type((GIFieldInfo *)self->info); + + /* Check the value. */ + { + gboolean retval; + + retval = _pygi_g_type_info_check_object(field_type_info, TRUE, py_value); + if (retval < 0) { + goto out; + } + + if (!retval) { + _PyGI_ERROR_PREFIX("argument 2: "); + goto out; + } + } + + /* Set the field's value. */ + /* A few types are not handled by g_field_info_set_field, so do it here. */ + if (!g_type_info_is_pointer(field_type_info) + && g_type_info_get_tag(field_type_info) == GI_TYPE_TAG_INTERFACE) { + GIBaseInfo *info; + GIInfoType info_type; + + if (!(g_field_info_get_flags((GIFieldInfo *)self->info) & GI_FIELD_IS_WRITABLE)) { + PyErr_SetString(PyExc_RuntimeError, "field is not writable"); + goto out; + } + + info = g_type_info_get_interface(field_type_info); + + info_type = g_base_info_get_type(info); + + switch (info_type) { + case GI_INFO_TYPE_UNION: + PyErr_SetString(PyExc_NotImplementedError, "setting an union is not supported yet"); + goto out; + case GI_INFO_TYPE_STRUCT: + { + gboolean is_simple; + gsize offset; + gssize size; + + is_simple = pygi_g_struct_info_is_simple((GIStructInfo *)info); + + if (!is_simple) { + PyErr_SetString(PyExc_TypeError, + "cannot set a structure which has no well-defined ownership transfer rules"); + g_base_info_unref(info); + goto out; + } + + value = _pygi_argument_from_object(py_value, field_type_info, GI_TRANSFER_NOTHING); + if (PyErr_Occurred()) { + g_base_info_unref(info); + goto out; + } + + offset = g_field_info_get_offset((GIFieldInfo *)self->info); + size = g_struct_info_get_size((GIStructInfo *)info); + g_assert(size > 0); + + g_memmove(pointer + offset, value.v_pointer, size); + + g_base_info_unref(info); + + retval = Py_None; + goto out; + } + default: + /* Fallback. */ + break; + } + + g_base_info_unref(info); + } + + value = _pygi_argument_from_object(py_value, field_type_info, GI_TRANSFER_EVERYTHING); + if (PyErr_Occurred()) { + goto out; + } + + if (!g_field_info_set_field((GIFieldInfo *)self->info, pointer, &value)) { + _pygi_argument_release(&value, field_type_info, GI_TRANSFER_NOTHING, GI_DIRECTION_IN); + PyErr_SetString(PyExc_RuntimeError, "unable to set value for field"); + goto out; + } + + retval = Py_None; + +out: + g_base_info_unref((GIBaseInfo *)field_type_info); + + Py_XINCREF(retval); + return retval; +} + +static PyMethodDef _PyGIFieldInfo_methods[] = { + { "get_value", (PyCFunction)_wrap_g_field_info_get_value, METH_VARARGS }, + { "set_value", (PyCFunction)_wrap_g_field_info_set_value, METH_VARARGS }, + { NULL, NULL, 0 } +}; + + +/* GIUnresolvedInfo */ +_PyGI_DEFINE_INFO_TYPE("UnresolvedInfo", GIUnresolvedInfo, PyGIBaseInfo_Type); + +static PyMethodDef _PyGIUnresolvedInfo_methods[] = { + { NULL, NULL, 0 } +}; + +/* Private */ + +gchar * +_pygi_g_base_info_get_fullname (GIBaseInfo *info) +{ + GIBaseInfo *container_info; + gchar *fullname; + + container_info = g_base_info_get_container(info); + if (container_info != NULL) { + fullname = g_strdup_printf("%s.%s.%s", + g_base_info_get_namespace(container_info), + g_base_info_get_name(container_info), + g_base_info_get_name(info)); + } else { + fullname = g_strdup_printf("%s.%s", + g_base_info_get_namespace(info), + g_base_info_get_name(info)); + } + + if (fullname == NULL) { + PyErr_NoMemory(); + } + + return fullname; +} + +void +_pygi_info_register_types (PyObject *m) +{ +#define _PyGI_REGISTER_TYPE(m, type, name) \ + type.ob_type = &PyType_Type; \ + if (PyType_Ready(&type)) \ + return; \ + if (PyModule_AddObject(m, name, (PyObject *)&type)) \ + return + + _PyGI_REGISTER_TYPE(m, PyGIBaseInfo_Type, "BaseInfo"); + _PyGI_REGISTER_TYPE(m, PyGIUnresolvedInfo_Type, "UnresolvedInfo"); + _PyGI_REGISTER_TYPE(m, PyGICallableInfo_Type, "CallableInfo"); + _PyGI_REGISTER_TYPE(m, PyGIFunctionInfo_Type, "FunctionInfo"); + _PyGI_REGISTER_TYPE(m, PyGIRegisteredTypeInfo_Type, "RegisteredTypeInfo"); + _PyGI_REGISTER_TYPE(m, PyGIStructInfo_Type, "StructInfo"); + _PyGI_REGISTER_TYPE(m, PyGIEnumInfo_Type, "EnumInfo"); + _PyGI_REGISTER_TYPE(m, PyGIObjectInfo_Type, "ObjectInfo"); + _PyGI_REGISTER_TYPE(m, PyGIInterfaceInfo_Type, "InterfaceInfo"); + _PyGI_REGISTER_TYPE(m, PyGIConstantInfo_Type, "ConstantInfo"); + _PyGI_REGISTER_TYPE(m, PyGIValueInfo_Type, "ValueInfo"); + _PyGI_REGISTER_TYPE(m, PyGIFieldInfo_Type, "FieldInfo"); + +#undef _PyGI_REGISTER_TYPE +} |