diff options
author | Simon van der Linden <simon.vanderlinden@student.uclouvain.be> | 2009-05-28 17:45:11 +0200 |
---|---|---|
committer | Simon van der Linden <simon.vanderlinden@student.uclouvain.be> | 2009-06-08 19:08:17 +0200 |
commit | e4f2a5ef8734cf40cf8345d442612db1f6c62d5a (patch) | |
tree | 45a694e46204e770e184aa4fcaaf8e23075235be /girepository | |
parent | f5ab5046fe9b67ec5e8fc64679e1a3d01787af7e (diff) | |
download | pygobject-e4f2a5ef8734cf40cf8345d442612db1f6c62d5a.tar.gz pygobject-e4f2a5ef8734cf40cf8345d442612db1f6c62d5a.tar.xz pygobject-e4f2a5ef8734cf40cf8345d442612db1f6c62d5a.zip |
Introduces the girepository module from the former PyBank.
Diffstat (limited to 'girepository')
-rw-r--r-- | girepository/Makefile.am | 52 | ||||
-rw-r--r-- | girepository/__init__.py | 24 | ||||
-rw-r--r-- | girepository/bank-argument.c | 379 | ||||
-rw-r--r-- | girepository/bank-info.c | 1194 | ||||
-rw-r--r-- | girepository/bank-repository.c | 237 | ||||
-rw-r--r-- | girepository/bank.c | 155 | ||||
-rw-r--r-- | girepository/bank.h | 80 | ||||
-rw-r--r-- | girepository/btypes.py | 300 | ||||
-rw-r--r-- | girepository/importer.py | 52 | ||||
-rw-r--r-- | girepository/module.py | 224 | ||||
-rw-r--r-- | girepository/repository.py | 51 |
11 files changed, 2748 insertions, 0 deletions
diff --git a/girepository/Makefile.am b/girepository/Makefile.am new file mode 100644 index 0000000..656795d --- /dev/null +++ b/girepository/Makefile.am @@ -0,0 +1,52 @@ +AUTOMAKE_OPTIONS = 1.7 +PLATFORM_VERSION = 2.0 + +INCLUDES = \ + -I$(top_srcdir)/gobject \ + $(PYTHON_INCLUDES) \ + $(PYGOBJECT_CFLAGS) \ + $(GOBJECT_INTROSPECTION_CFLAGS) + +pkginclude_HEADERS = bank.h + +# girepository extension modules +pkgpyexecdir = $(pyexecdir)/gtk-2.0/girepository + +# girepository python scripts +pygirepositorydir = $(pkgpyexecdir) +pygirepository_PYTHON = \ + __init__.py \ + importer.py \ + module.py \ + repository.py \ + btypes.py + +# linker flags +common_ldflags = -module -avoid-version +if PLATFORM_WIN32 +common_ldflags += -no-undefined +endif + +CLEANFILES = +EXTRA_DIST = + +# repo module +repo_la_CFLAGS = -O0 +repo_la_LDFLAGS = $(common_ldflags) -export-symbols-regex initrepo +repo_la_LIBADD = $(GOBJECT_INTROSPECTION_LIBS) +repo_la_SOURCES = \ + bank-repository.c \ + bank-argument.c \ + bank-info.c \ + bank.c \ + bank.h + +if BUILD_GOBJECT_INTROSPECTION +pygirepository_LTLIBRARIES = repo.la + +all: $(pygirepository_LTLIBRARIES:.la=.so) +clean-local: + rm -f $(pygirepository_LTLIBRARIES:.la=.so) +.la.so: + $(LN_S) .libs/$@ $@ || true +endif diff --git a/girepository/__init__.py b/girepository/__init__.py new file mode 100644 index 0000000..f2e58bf --- /dev/null +++ b/girepository/__init__.py @@ -0,0 +1,24 @@ +# -*- Mode: Python; py-indent-offset: 4 -*- +# +# Copyright (C) 2005, 2007 Johan Dahlin <johan@gnome.org> +# +# 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 St, Fifth Floor, Boston, MA 02110-1301 USA +# + +from .importer import install_importhook + +install_importhook() + +del install_importhook diff --git a/girepository/bank-argument.c b/girepository/bank-argument.c new file mode 100644 index 0000000..9ac28cd --- /dev/null +++ b/girepository/bank-argument.c @@ -0,0 +1,379 @@ +/* -*- Mode: C; c-basic-offset: 4 -*- + * vim: set ts=8 sts=4 sw=4 noet ai cindent : + * + * Copyright (C) 2005 Johan Dahlin <johan@gnome.org> + * + * 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 St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "bank.h" +#include <pygobject.h> + +GArgument +pyg_argument_from_pyobject(PyObject *object, GITypeInfo *type_info) +{ + GArgument arg; + GITypeTag type_tag; + GIBaseInfo* interface_info; + GIInfoType interface_type; + + type_tag = g_type_info_get_tag((GITypeInfo*)type_info); + switch (type_tag) { + case GI_TYPE_TAG_VOID: + /* Nothing to do */ + break; + case GI_TYPE_TAG_UTF8: + if (object == Py_None) + arg.v_pointer = NULL; + else + arg.v_pointer = PyString_AsString(object); + break; + case GI_TYPE_TAG_UINT8: + arg.v_uint8 = PyInt_AsLong(object); + break; + case GI_TYPE_TAG_UINT: + arg.v_uint = PyInt_AsLong(object); + break; + case GI_TYPE_TAG_UINT16: + arg.v_uint16 = PyInt_AsLong(object); + break; + case GI_TYPE_TAG_UINT32: + arg.v_uint32 = PyLong_AsLongLong(object); + break; + case GI_TYPE_TAG_UINT64: + if (PyInt_Check(object)) { + PyObject *long_obj = PyNumber_Long(object); + arg.v_uint64 = PyLong_AsUnsignedLongLong(long_obj); + Py_DECREF(long_obj); + } else + arg.v_uint64 = PyLong_AsUnsignedLongLong(object); + break; + case GI_TYPE_TAG_INT8: + arg.v_int8 = PyInt_AsLong(object); + break; + case GI_TYPE_TAG_INT: + arg.v_int = PyInt_AsLong(object); + break; + case GI_TYPE_TAG_LONG: + arg.v_long = PyInt_AsLong(object); + break; + case GI_TYPE_TAG_ULONG: + arg.v_ulong = PyInt_AsLong(object); + break; + case GI_TYPE_TAG_BOOLEAN: + arg.v_boolean = PyInt_AsLong(object); + break; + case GI_TYPE_TAG_INT16: + arg.v_int16 = PyInt_AsLong(object); + break; + case GI_TYPE_TAG_INT32: + arg.v_int32 = PyInt_AsLong(object); + break; + case GI_TYPE_TAG_INT64: + arg.v_int64 = PyLong_AsLongLong(object); + break; + case GI_TYPE_TAG_FLOAT: + arg.v_float = (float)PyFloat_AsDouble(object); + break; + case GI_TYPE_TAG_DOUBLE: + arg.v_double = PyFloat_AsDouble(object); + break; + case GI_TYPE_TAG_INTERFACE: + interface_info = g_type_info_get_interface(type_info); + interface_type = g_base_info_get_type(interface_info); + if (interface_type == GI_INFO_TYPE_ENUM) { + arg.v_int = PyInt_AsLong(object); + } else if (object == Py_None) + arg.v_pointer = NULL; + else + arg.v_pointer = pygobject_get(object); + break; + case GI_TYPE_TAG_ARRAY: + arg.v_pointer = NULL; + break; + case GI_TYPE_TAG_ERROR: + /* Allow NULL GError, otherwise fall through */ + if (object == Py_None) { + arg.v_pointer = NULL; + break; + } + default: + g_print("<PyO->GArg> GITypeTag %s is unhandled\n", + g_type_tag_to_string(type_tag)); + break; + } + + return arg; +} + +static PyObject * +glist_to_pyobject(GITypeTag list_tag, GITypeInfo *type_info, GList *list, GSList *slist) +{ + PyObject *py_list; + int i; + GArgument arg; + PyObject *child_obj; + + if ((py_list = PyList_New(0)) == NULL) { + g_list_free(list); + return NULL; + } + i = 0; + if (list_tag == GI_TYPE_TAG_GLIST) { + for ( ; list != NULL; list = list->next) { + arg.v_pointer = list->data; + + child_obj = pyg_argument_to_pyobject(&arg, type_info); + + if (child_obj == NULL) { + g_list_free(list); + Py_DECREF(py_list); + return NULL; + } + PyList_Append(py_list, child_obj); + Py_DECREF(child_obj); + + ++i; + } + } else { + for ( ; slist != NULL; slist = slist->next) { + arg.v_pointer = slist->data; + + child_obj = pyg_argument_to_pyobject(&arg, type_info); + + if (child_obj == NULL) { + g_list_free(list); + Py_DECREF(py_list); + return NULL; + } + PyList_Append(py_list, child_obj); + Py_DECREF(child_obj); + + ++i; + } + } + g_list_free(list); + return py_list; +} + +PyObject * +pyarray_to_pyobject(gpointer array, int length, GITypeInfo *type_info) +{ + PyObject *py_list; + PyObject *child_obj; + GITypeInfo *element_type = g_type_info_get_param_type (type_info, 0); + GITypeTag type_tag = g_type_info_get_tag(element_type); + gsize size; + char buf[256]; + int i; + + if (array == NULL) + return Py_None; + + // FIXME: Doesn't seem right to have this here: + switch (type_tag) { + case GI_TYPE_TAG_INT: + size = sizeof(int); + break; + case GI_TYPE_TAG_INTERFACE: + size = sizeof(gpointer); + break; + default: + snprintf(buf, sizeof(buf), "Unimplemented type: %s\n", g_type_tag_to_string(type_tag)); + PyErr_SetString(PyExc_TypeError, buf); + return NULL; + } + + if ((py_list = PyList_New(0)) == NULL) { + return NULL; + } + + for( i = 0; i < length; i++ ) { + gpointer current_element = array + i * size; + + child_obj = pyg_argument_to_pyobject((GArgument *)¤t_element, element_type); + if (child_obj == NULL) { + Py_DECREF(py_list); + return NULL; + } + PyList_Append(py_list, child_obj); + Py_DECREF(child_obj); + } + + return py_list; +} + +PyObject * +pyg_argument_to_pyobject(GArgument *arg, GITypeInfo *type_info) +{ + GITypeTag type_tag; + PyObject *obj; + GIBaseInfo* interface_info; + GIInfoType interface_type; + GITypeInfo *param_info; + + g_return_val_if_fail(type_info != NULL, NULL); + type_tag = g_type_info_get_tag(type_info); + + switch (type_tag) { + case GI_TYPE_TAG_VOID: + // TODO: Should we take this as a buffer? + g_warning("pybank doesn't know what to do with void types"); + obj = Py_None; + break; + case GI_TYPE_TAG_GLIST: + case GI_TYPE_TAG_GSLIST: + param_info = g_type_info_get_param_type(type_info, 0); + g_assert(param_info != NULL); + obj = glist_to_pyobject(type_tag, + param_info, + type_tag == GI_TYPE_TAG_GLIST ? arg->v_pointer : NULL, + type_tag == GI_TYPE_TAG_GSLIST ? arg->v_pointer : NULL); + break; + case GI_TYPE_TAG_BOOLEAN: + obj = PyBool_FromLong(arg->v_boolean); + break; + case GI_TYPE_TAG_UINT8: + obj = PyInt_FromLong(arg->v_uint8); + break; + case GI_TYPE_TAG_UINT: + obj = PyInt_FromLong(arg->v_uint); + break; + case GI_TYPE_TAG_UINT16: + obj = PyInt_FromLong(arg->v_uint16); + break; + case GI_TYPE_TAG_UINT32: + obj = PyLong_FromLongLong(arg->v_uint32); + break; + case GI_TYPE_TAG_UINT64: + obj = PyLong_FromUnsignedLongLong(arg->v_uint64); + break; + case GI_TYPE_TAG_INT: + obj = PyInt_FromLong(arg->v_int); + break; + case GI_TYPE_TAG_LONG: + obj = PyInt_FromLong(arg->v_long); + break; + case GI_TYPE_TAG_ULONG: + obj = PyInt_FromLong(arg->v_ulong); + break; + case GI_TYPE_TAG_INT8: + obj = PyInt_FromLong(arg->v_int8); + break; + case GI_TYPE_TAG_INT16: + obj = PyInt_FromLong(arg->v_int16); + break; + case GI_TYPE_TAG_INT32: + obj = PyInt_FromLong(arg->v_int32); + break; + case GI_TYPE_TAG_INT64: + obj = PyLong_FromLongLong(arg->v_int64); + break; + case GI_TYPE_TAG_FLOAT: + obj = PyFloat_FromDouble(arg->v_float); + break; + case GI_TYPE_TAG_DOUBLE: + obj = PyFloat_FromDouble(arg->v_double); + break; + case GI_TYPE_TAG_UTF8: + if (arg->v_string == NULL) + obj = Py_None; + else + obj = PyString_FromString(arg->v_string); + break; + case GI_TYPE_TAG_INTERFACE: + interface_info = g_type_info_get_interface(type_info); + interface_type = g_base_info_get_type(interface_info); + + if (interface_type == GI_INFO_TYPE_STRUCT || interface_type == GI_INFO_TYPE_BOXED) { + // Create new struct based on arg->v_pointer + const gchar *module_name = g_base_info_get_namespace(interface_info); + const gchar *type_name = g_base_info_get_name(interface_info); + PyObject *module = PyImport_ImportModule(module_name); + PyObject *tp = PyObject_GetAttrString(module, type_name); + gsize size; + PyObject *buffer; + PyObject **dict; + + if (tp == NULL) { + char buf[256]; + snprintf(buf, sizeof(buf), "Type %s.%s not defined", module_name, type_name); + PyErr_SetString(PyExc_TypeError, buf); + return NULL; + } + + obj = PyObject_GC_New(PyObject, (PyTypeObject *) tp); + if (obj == NULL) + return NULL; + + // FIXME: Any better way to initialize the dict pointer? + dict = (PyObject **) ((char *)obj + ((PyTypeObject *) tp)->tp_dictoffset); + *dict = NULL; + + size = g_struct_info_get_size ((GIStructInfo*)interface_info); + buffer = PyBuffer_FromReadWriteMemory(arg->v_pointer, size); + if (buffer == NULL) + return NULL; + + PyObject_SetAttrString(obj, "__buffer__", buffer); + + } else if (interface_type == GI_INFO_TYPE_ENUM) { + obj = PyInt_FromLong(arg->v_int); + } else if ( arg->v_pointer == NULL ) { + obj = Py_None; + } else { + GValue value; + GObject* gobj = arg->v_pointer; + GType gtype = G_OBJECT_TYPE(gobj); + GIRepository *repo = g_irepository_get_default(); + GIBaseInfo *object_info = g_irepository_find_by_gtype(repo, gtype); + const gchar *module_name; + const gchar *type_name; + + if (object_info != NULL) { + // It's a pybank class, we should make sure it is initialized. + + module_name = g_base_info_get_namespace(object_info); + type_name = g_base_info_get_name(object_info); + + // This will make sure the wrapper class is registered. + char buf[250]; + snprintf(buf, sizeof(buf), "%s.%s", module_name, type_name); + PyRun_SimpleString(buf); + } + + value.g_type = gtype; + value.data[0].v_pointer = gobj; + obj = pyg_value_as_pyobject(&value, FALSE); + } + break; + case GI_TYPE_TAG_ARRAY: + g_warning("pyg_argument_to_pyobject: use pyarray_to_pyobject instead for arrays"); + obj = Py_None; + break; + default: + g_print("<GArg->PyO> GITypeTag %s is unhandled\n", + g_type_tag_to_string(type_tag)); + obj = PyString_FromString("<unhandled return value!>"); /* */ + break; + } + + if (obj != NULL) + Py_INCREF(obj); + + return obj; +} + + diff --git a/girepository/bank-info.c b/girepository/bank-info.c new file mode 100644 index 0000000..974d586 --- /dev/null +++ b/girepository/bank-info.c @@ -0,0 +1,1194 @@ +/* -*- Mode: C; c-basic-offset: 4 -*- + * vim: set ts=8 sts=4 sw=4 noet ai cindent : + * + * Copyright (C) 2005 Johan Dahlin <johan@gnome.org> + * + * 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 St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "bank.h" +#include <pygobject.h> + +static void pyg_base_info_dealloc(PyGIBaseInfo *self); +static void pyg_base_info_free(PyObject *op); +static PyObject* pyg_base_info_repr(PyGIBaseInfo *self); +static int pyg_base_info_traverse(PyGIBaseInfo *self, + visitproc visit, + void *arg); +static void pyg_base_info_clear(PyGIBaseInfo *self); + +static PyObject * +_wrap_g_object_info_get_methods(PyGIBaseInfo *self); + +#define NEW_CLASS(name, cname) \ +static PyMethodDef _Py##cname##_methods[]; \ +PyTypeObject Py##cname##_Type = { \ + PyObject_HEAD_INIT(NULL) \ + 0, \ + "bank." name, \ + sizeof(PyGIBaseInfo), \ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, \ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, \ + NULL, 0, 0, 0, \ + offsetof(PyGIBaseInfo, weakreflist), \ + 0, 0, \ + _Py##cname##_methods, \ + 0, 0, NULL, NULL, 0, 0, \ + offsetof(PyGIBaseInfo, instance_dict) \ +} + +static PyMethodDef _PyGIBaseInfo_methods[]; +static PyGetSetDef _PyGIBaseInfo_getsets[]; + +PyTypeObject PyGIBaseInfo_Type = { + PyObject_HEAD_INIT(NULL) + 0, + "bank.BaseInfo", + sizeof(PyGIBaseInfo), + 0, + /* methods */ + (destructor)pyg_base_info_dealloc, + (printfunc)0, + (getattrfunc)0, + (setattrfunc)0, + (cmpfunc)0, + (reprfunc)pyg_base_info_repr, + 0, + 0, + 0, + (hashfunc)0, + (ternaryfunc)0, + (reprfunc)0, + (getattrofunc)0, + (setattrofunc)0, + 0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_HAVE_GC, + NULL, + (traverseproc)pyg_base_info_traverse, + (inquiry)pyg_base_info_clear, + (richcmpfunc)0, + offsetof(PyGIBaseInfo, weakreflist), + (getiterfunc)0, + (iternextfunc)0, + _PyGIBaseInfo_methods, + 0, + _PyGIBaseInfo_getsets, + NULL, + NULL, + (descrgetfunc)0, + (descrsetfunc)0, + offsetof(PyGIBaseInfo, instance_dict), + (initproc)0, + (allocfunc)0, /* tp_alloc */ + (newfunc)0, /* tp_new */ + (freefunc)pyg_base_info_free, /* tp_free */ + (inquiry)0, /* tp_is_gc */ + (PyObject *)0, /* tp_bases */ +}; + +static PyObject * +pyg_base_info_repr(PyGIBaseInfo *self) +{ + gchar buf[256]; + + g_snprintf(buf, sizeof(buf), + "<%s object (%s) at 0x%lx>", + self->ob_type->tp_name, + g_base_info_get_name(self->info), (long)self); + return PyString_FromString(buf); +} + +static void +pyg_base_info_dealloc(PyGIBaseInfo *self) +{ + PyObject_ClearWeakRefs((PyObject *)self); + pyg_base_info_clear(self); +} + +static int +pyg_base_info_traverse(PyGIBaseInfo *self, + visitproc visit, + void *arg) +{ + int ret = 0; + + if (self->instance_dict) + ret = visit(self->instance_dict, arg); + + if (ret != 0) + return ret; + + return 0; + +} + +static void +pyg_base_info_clear(PyGIBaseInfo *self) +{ + PyObject_GC_UnTrack((PyObject *)self); + + Py_CLEAR(self->instance_dict); + + if (self->info) { + g_base_info_unref(self->info); + self->info = NULL; + } + + PyObject_GC_Del(self); +} + +static void +pyg_base_info_free(PyObject *op) +{ + PyObject_GC_Del(op); +} + + +static PyObject * +pyg_base_info_get_dict(PyGIBaseInfo *self, void *closure) +{ + if (self->instance_dict == NULL) { + self->instance_dict = PyDict_New(); + if (self->instance_dict == NULL) + return NULL; + } + Py_INCREF(self->instance_dict); + return self->instance_dict; +} + +static PyGetSetDef _PyGIBaseInfo_getsets[] = { + { "__dict__", (getter)pyg_base_info_get_dict, (setter)0 }, + { NULL, 0, 0 } +}; + +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_type(PyGIBaseInfo *self) +{ + return PyInt_FromLong(g_base_info_get_type(self->info)); +} + +PyObject * +pyg_info_new(void *info) +{ + PyGIBaseInfo *self; + GIInfoType type_info; + PyTypeObject *tp; + + if (info == NULL) { + PyErr_SetString(PyExc_TypeError, "NULL value sent to pyg_info_new"); + return NULL; + } + + type_info = g_base_info_get_type((GIBaseInfo*)info); + + switch (type_info) + { + case GI_INFO_TYPE_OBJECT: + tp = &PyGIObjectInfo_Type; + break; + case GI_INFO_TYPE_BOXED: + tp = &PyGIBoxedInfo_Type; + break; + case GI_INFO_TYPE_STRUCT: + tp = &PyGIStructInfo_Type; + break; + case GI_INFO_TYPE_FUNCTION: + tp = &PyGIFunctionInfo_Type; + break; + case GI_INFO_TYPE_ENUM: + case GI_INFO_TYPE_FLAGS: + tp = &PyGIEnumInfo_Type; + break; + case GI_INFO_TYPE_ARG: + tp = &PyGIArgInfo_Type; + break; + case GI_INFO_TYPE_TYPE: + tp = &PyGITypeInfo_Type; + break; + case GI_INFO_TYPE_INTERFACE: + tp = &PyGIInterfaceInfo_Type; + break; + case GI_INFO_TYPE_UNRESOLVED: + tp = &PyGIUnresolvedInfo_Type; + break; + case GI_INFO_TYPE_VALUE: + tp = &PyGIValueInfo_Type; + break; + case GI_INFO_TYPE_FIELD: + tp = &PyGIFieldInfo_Type; + break; + default: + g_print ("Unhandled GIInfoType: %d\n", type_info); + Py_INCREF(Py_None); + return Py_None; + } + + if (tp->tp_flags & Py_TPFLAGS_HEAPTYPE) + Py_INCREF(tp); + + self = (PyGIBaseInfo*)PyObject_GC_New(PyGIBaseInfo, tp); + if (self == NULL) + return NULL; + + self->info = g_base_info_ref(info); + + self->instance_dict = NULL; + self->weakreflist = NULL; + + PyObject_GC_Track((PyObject *)self); + + return (PyObject*)self; +} + +static PyMethodDef _PyGIBaseInfo_methods[] = { + { "getName", (PyCFunction)_wrap_g_base_info_get_name, METH_NOARGS }, + { "getType", (PyCFunction)_wrap_g_base_info_get_type, METH_NOARGS }, + { "getNamespace", (PyCFunction)_wrap_g_base_info_get_namespace, METH_NOARGS }, + { NULL, NULL, 0 } +}; + + +/* CallableInfo */ +NEW_CLASS("CallableInfo", GICallableInfo); + +static PyObject * +_wrap_g_callable_info_get_args(PyGIBaseInfo *self) +{ + int i, length; + PyObject *retval; + + length = g_callable_info_get_n_args((GICallableInfo*)self->info); + retval = PyTuple_New(length); + + for (i = 0; i < length; i++) { + GIArgInfo *arg; + arg = g_callable_info_get_arg((GICallableInfo*)self->info, i); + PyTuple_SetItem(retval, i, pyg_info_new(arg)); + g_base_info_unref((GIBaseInfo*)arg); + } + + return retval; +} + +static PyObject * +_wrap_g_callable_info_get_return_type(PyGIBaseInfo *self) +{ + return pyg_info_new(g_callable_info_get_return_type((GICallableInfo*)self->info)); +} + +static PyMethodDef _PyGICallableInfo_methods[] = { + { "getArgs", (PyCFunction)_wrap_g_callable_info_get_args, METH_NOARGS }, + { "getReturnType", (PyCFunction)_wrap_g_callable_info_get_return_type, METH_NOARGS }, + { NULL, NULL, 0 } +}; + +/* FunctionInfo */ +NEW_CLASS("FunctionInfo", GIFunctionInfo); + +static PyObject * +_wrap_g_function_info_is_constructor(PyGIBaseInfo *self) +{ + return PyInt_FromLong(g_function_info_get_flags((GIFunctionInfo*)self->info) & + GI_FUNCTION_IS_CONSTRUCTOR); +} + +static PyObject * +_wrap_g_function_info_is_method(PyGIBaseInfo *self) +{ + return PyInt_FromLong(g_function_info_get_flags((GIFunctionInfo*)self->info) & + GI_FUNCTION_IS_METHOD); +} + +static PyObject * +_wrap_g_function_info_invoke(PyGIBaseInfo *self, PyObject *args) +{ + GArgument *in_args; + GArgument *out_args; + GArgument *out_values; + GArgument return_arg; + int n_args; + int expected_in_argc; + int expected_out_argc; + int i; + int argv_pos; + int in_args_pos; + int out_args_pos; + GError *error; + gboolean failed; + GIFunctionInfoFlags flags; + gboolean is_method; + gboolean is_constructor; + gboolean invoke_ok; + GITypeInfo *return_info; + GITypeTag return_tag; + PyObject **return_values; + int n_return_values; + int next_rval; + PyObject *retval; + PyObject *py_arg; + + 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; + + expected_in_argc = 0; + expected_out_argc = 0; + + n_args = g_callable_info_get_n_args( (GICallableInfo*) self->info); + for (i = 0; i < n_args; i++) { + GIDirection direction; + GIArgInfo *arg_info; + + arg_info = g_callable_info_get_arg( (GICallableInfo*) self->info, i); + direction = g_arg_info_get_direction(arg_info); + if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT) + expected_in_argc += 1; + if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT) + expected_out_argc += 1; + g_base_info_unref( (GIBaseInfo*) arg_info); + } + /* + g_debug("Call is to %s %s.%s with expected: %d in args, %d out args, %d total args", + is_method ? "method" : "function", + g_base_info_get_namespace( (GIBaseInfo*) self->info), + g_base_info_get_name( (GIBaseInfo*) self->info), + expected_in_argc, + expected_out_argc, + n_args); + */ + if (is_method) + expected_in_argc += 1; + + in_args = g_newa(GArgument, expected_in_argc); + out_args = g_newa(GArgument, expected_out_argc); + /* each out arg is a pointer, they point to these values */ + /* FIXME: This will break for caller-allocates funcs: + http://bugzilla.gnome.org/show_bug.cgi?id=573314 */ + out_values = g_newa(GArgument, expected_out_argc); + + failed = FALSE; + in_args_pos = 0; /* index into in_args */ + out_args_pos = 0; /* into out_args */ + argv_pos = 0; /* index into argv */ + + if (is_method && !is_constructor) { + GIBaseInfo *container = g_base_info_get_container((GIBaseInfo *) self->info); + GIInfoType type = g_base_info_get_type(container); + + py_arg = PyTuple_GetItem(args, 0); + if (!py_arg) { + PyErr_SetString(PyExc_ValueError, "Calling a method without passing an instance"); + return NULL; + } + if (py_arg == Py_None) { + in_args[0].v_pointer = NULL; + } else if (type == GI_INFO_TYPE_STRUCT || type == GI_INFO_TYPE_BOXED) { + PyObject *pybuffer = PyObject_GetAttrString((PyObject *)py_arg, + "__buffer__"); + PyBufferProcs *buffer_procs = pybuffer->ob_type->tp_as_buffer; + (*buffer_procs->bf_getreadbuffer)(pybuffer, 0, &in_args[0].v_pointer); + } else { /* by fallback is always object */ + in_args[0].v_pointer = pygobject_get(py_arg); + } + ++in_args_pos; + } + + for (i = 0; i < n_args; i++) { + GIDirection direction; + GIArgInfo *arg_info; + GArgument *out_value; + + arg_info = g_callable_info_get_arg( (GICallableInfo*) self->info, i); + direction = g_arg_info_get_direction(arg_info); + + out_value = NULL; + if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT) { + g_assert(out_args_pos < expected_out_argc); + + out_value = &out_values[out_args_pos]; + out_args[out_args_pos].v_pointer = out_value; + ++out_args_pos; + } + + if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT) { + if (is_method || is_constructor) + py_arg = PyTuple_GetItem(args, i + 1); + else + py_arg = PyTuple_GetItem(args, i); + + GArgument in_value = pyg_argument_from_pyobject(py_arg, g_arg_info_get_type(arg_info)); + + ++argv_pos; + + if (direction == GI_DIRECTION_IN) { + in_args[in_args_pos] = in_value; + } else { + /* INOUT means we pass a pointer */ + g_assert(out_value != NULL); + *out_value = in_value; + in_args[in_args_pos].v_pointer = out_value; + } + + ++in_args_pos; + } + + g_base_info_unref( (GIBaseInfo*) arg_info); + + if (failed) + break; + } + + if (failed) { + PyErr_SetString(PyExc_ValueError, "Failed to convert all args."); + return NULL; + } + + g_assert(in_args_pos == expected_in_argc); + g_assert(out_args_pos == expected_out_argc); + + error = NULL; + invoke_ok = g_function_info_invoke( (GIFunctionInfo*) self->info, + in_args, expected_in_argc, + out_args, expected_out_argc, + &return_arg, + &error); + + return_info = g_callable_info_get_return_type( (GICallableInfo*) self->info); + g_assert(return_info != NULL); + + if (!invoke_ok) { + char buf[256]; + snprintf(buf, sizeof(buf), "Error invoking %s.%s: %s", + g_base_info_get_namespace( (GIBaseInfo*) self->info), + g_base_info_get_name( (GIBaseInfo*) self->info), + error->message); + + g_assert(error != NULL); + PyErr_SetString(PyExc_RuntimeError, buf); + g_error_free(error); + + return NULL; + } + + return_tag = g_type_info_get_tag(return_info); + + if (is_constructor) { + py_arg = PyTuple_GetItem(args, 0); + + if (return_tag == GI_TYPE_TAG_INTERFACE) { + GIBaseInfo *interface_info = g_type_info_get_interface(return_info); + GIInfoType interface_type = g_base_info_get_type(interface_info); + + if (interface_type == GI_INFO_TYPE_STRUCT || interface_type == GI_INFO_TYPE_BOXED) { + // FIXME: We should reuse this. Perhaps by separating the + // wrapper creation from the binding to the wrapper. + gsize size = g_struct_info_get_size ((GIStructInfo*)return_info); + PyObject *buffer = PyBuffer_FromReadWriteMemory(return_arg.v_pointer, size); + + //PyObject *dict = PyObject_GetDict(py_arg); + PyObject_SetAttrString(py_arg, "__buffer__", buffer); + + Py_INCREF(py_arg); + return py_arg; + } else { + PyGObject *self = (PyGObject *) py_arg; + if (self->obj != NULL) { + PyErr_SetString(PyExc_ValueError, "Calling constructor on an instance that isn't a GObject"); + return NULL; + } + self->obj = return_arg.v_pointer; + g_object_ref(return_arg.v_pointer); + pygobject_register_wrapper(py_arg); + Py_INCREF(py_arg); + return py_arg; + } + } else { + PyErr_SetString(PyExc_NotImplementedError, ""); + return NULL; + } + } + + retval = NULL; + + next_rval = 0; /* index into return_values */ + + n_return_values = expected_out_argc; + if (return_tag != GI_TYPE_TAG_VOID) + n_return_values += 1; + + return_values = g_newa(PyObject*, n_return_values); + if (!is_constructor && n_return_values > 0) { + if (return_tag != GI_TYPE_TAG_VOID) { + PyObject *obj = pyg_argument_to_pyobject(&return_arg, return_info); + if (obj == NULL) { + return NULL; + } + return_values[next_rval] = obj; + + ++next_rval; + } + } + + /* We walk over all args, release in args (if allocated) and convert + * all out args + */ + in_args_pos = is_method ? 1 : 0; /* index into in_args */ + out_args_pos = 0; /* into out_args */ + + for (i = 0; i < n_args; i++) { + GIDirection direction; + GIArgInfo *arg_info; + GITypeInfo *arg_type_info; + + arg_info = g_callable_info_get_arg( (GICallableInfo*) self->info, i); + direction = g_arg_info_get_direction(arg_info); + + arg_type_info = g_arg_info_get_type(arg_info); + + if (direction == GI_DIRECTION_IN) { + g_assert(in_args_pos < expected_in_argc); + + ++in_args_pos; + } else { + /* INOUT or OUT */ + if (direction == GI_DIRECTION_INOUT) + g_assert(in_args_pos < expected_in_argc); + g_assert(next_rval < n_return_values); + g_assert(out_args_pos < expected_out_argc); + + PyObject *obj; + GITypeTag type_tag = g_type_info_get_tag(arg_type_info); + + if (type_tag == GI_TYPE_TAG_ARRAY) { + GArgument *arg = out_args[out_args_pos].v_pointer; + gint length_arg_index = g_type_info_get_array_length(arg_type_info); + GArgument *length_arg; + + if (is_method) + length_arg_index--; + + if (length_arg_index == -1) { + PyErr_SetString(PyExc_NotImplementedError, "Need a field to specify the array length"); + return NULL; + } + + length_arg = out_args[length_arg_index].v_pointer; + + if (length_arg == NULL) { + PyErr_SetString(PyExc_RuntimeError, "Failed to get the length of the array"); + return NULL; + } + + obj = pyarray_to_pyobject(arg->v_pointer, length_arg->v_int, arg_type_info); + } else + obj = pyg_argument_to_pyobject(out_args[out_args_pos].v_pointer, arg_type_info); + if (obj == NULL) { + return NULL; + } + return_values[next_rval] = obj; + + if (direction == GI_DIRECTION_INOUT) + ++in_args_pos; + + ++out_args_pos; + + ++next_rval; + } + + g_base_info_unref( (GIBaseInfo*) arg_type_info); + g_base_info_unref( (GIBaseInfo*) arg_info); + } + + g_assert(next_rval == n_return_values); + g_assert(out_args_pos == expected_out_argc); + g_assert(in_args_pos == expected_in_argc); + + if (n_return_values > 0) { + if (n_return_values == 0) { + retval = Py_None; + Py_INCREF(retval); + } else if (n_return_values == 1) { + retval = return_values[0]; + } else { + retval = PyTuple_New(n_return_values); + for (i = 0; i < n_return_values; i++) { + PyTuple_SetItem(retval, i, return_values[i]); + } + } + } + + g_base_info_unref( (GIBaseInfo*) return_info); + + if (retval == NULL) { + Py_INCREF(Py_None); + retval = Py_None; + } + + return retval; +} + +static PyMethodDef _PyGIFunctionInfo_methods[] = { + { "isConstructor", (PyCFunction)_wrap_g_function_info_is_constructor, METH_NOARGS }, + { "isMethod", (PyCFunction)_wrap_g_function_info_is_method, METH_NOARGS }, + { "invoke", (PyCFunction)_wrap_g_function_info_invoke, METH_VARARGS }, + { NULL, NULL, 0 } +}; + +/* GICallbackInfo */ +NEW_CLASS("CallbackInfo", GICallbackInfo); + +static PyMethodDef _PyGICallbackInfo_methods[] = { + { NULL, NULL, 0 } +}; + +/* RegisteredTypeInfo */ +NEW_CLASS("RegisteredTypeInfo", GIRegisteredTypeInfo); + +static PyObject * +_wrap_g_registered_type_info_get_g_type (PyGIBaseInfo* self) +{ + int gtype; + + gtype = g_registered_type_info_get_g_type ((GIRegisteredTypeInfo*)self->info); + return PyInt_FromLong(gtype); +} + +static PyMethodDef _PyGIRegisteredTypeInfo_methods[] = { + { "getGType", (PyCFunction)_wrap_g_registered_type_info_get_g_type, METH_NOARGS }, + { NULL, NULL, 0 } +}; + +/* GIStructInfo */ +NEW_CLASS("StructInfo", GIStructInfo); + +static PyObject * +_wrap_g_struct_info_get_fields(PyGIBaseInfo *self) +{ + int i, length; + PyObject *retval; + + g_base_info_ref(self->info); + length = g_struct_info_get_n_fields((GIStructInfo*)self->info); + retval = PyTuple_New(length); + + for (i = 0; i < length; i++) { + GIFieldInfo *field; + field = g_struct_info_get_field((GIStructInfo*)self->info, i); + PyTuple_SetItem(retval, i, pyg_info_new(field)); + g_base_info_unref((GIBaseInfo*)field); + } + g_base_info_unref(self->info); + + return retval; +} + +static PyObject * +_wrap_g_struct_info_get_methods(PyGIBaseInfo *self) +{ + int i, length; + PyObject *retval; + + g_base_info_ref(self->info); + length = g_struct_info_get_n_methods((GIStructInfo*)self->info); + retval = PyTuple_New(length); + + for (i = 0; i < length; i++) { + GIFunctionInfo *function; + function = g_struct_info_get_method((GIStructInfo*)self->info, i); + PyTuple_SetItem(retval, i, pyg_info_new(function)); + g_base_info_unref((GIBaseInfo*)function); + } + g_base_info_unref(self->info); + + return retval; +} + +static PyObject * +_wrap_g_struct_info_new_buffer(PyGIBaseInfo *self) +{ + gsize size = g_struct_info_get_size ((GIStructInfo*)self->info); + PyObject *buffer = PyBuffer_New (size); + Py_INCREF(buffer); + return buffer; +} + +static PyMethodDef _PyGIStructInfo_methods[] = { + { "getFields", (PyCFunction)_wrap_g_struct_info_get_fields, METH_NOARGS }, + { "getMethods", (PyCFunction)_wrap_g_struct_info_get_methods, METH_NOARGS }, + { "newBuffer", (PyCFunction)_wrap_g_struct_info_new_buffer, METH_NOARGS }, + { NULL, NULL, 0 } +}; + +/* GIUnionInfo */ +NEW_CLASS("UnionInfo", GIUnionInfo); + +static PyMethodDef _PyGIUnionInfo_methods[] = { + { NULL, NULL, 0 } +}; + +/* EnumInfo */ +NEW_CLASS("EnumInfo", GIEnumInfo); + +static PyObject * +_wrap_g_enum_info_get_values(PyGIBaseInfo *self) +{ + int n_values, i; + GIValueInfo *value; + PyObject *list; + + g_base_info_ref(self->info); + n_values = g_enum_info_get_n_values((GIEnumInfo*)self->info); + list = PyList_New(n_values); + for (i = 0; i < n_values; i++) + { + value = g_enum_info_get_value((GIEnumInfo*)self->info, i); + PyList_SetItem(list, i, pyg_info_new(value)); + g_base_info_unref((GIBaseInfo*)value); + } + g_base_info_unref(self->info); + + return list; +} + +static PyMethodDef _PyGIEnumInfo_methods[] = { + { "getValues", (PyCFunction)_wrap_g_enum_info_get_values, METH_NOARGS }, + { NULL, NULL, 0 } +}; + +/* BoxedInfo */ +NEW_CLASS("BoxedInfo", GIBoxedInfo); + +static PyMethodDef _PyGIBoxedInfo_methods[] = { + { NULL, NULL, 0 } +}; + +/* ObjectInfo */ +NEW_CLASS("ObjectInfo", GIObjectInfo); + +static PyObject * +_wrap_g_object_info_get_parent(PyGIBaseInfo *self) +{ + GIObjectInfo *parent_info; + + g_base_info_ref(self->info); + parent_info = g_object_info_get_parent((GIObjectInfo*)self->info); + g_base_info_unref(self->info); + + if (parent_info) + return pyg_info_new(parent_info); + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +_wrap_g_object_info_get_type_name(PyGIBaseInfo *self) +{ + const gchar *type_name; + + g_base_info_ref(self->info); + type_name = g_object_info_get_type_name((GIObjectInfo*)self->info); + g_base_info_unref(self->info); + + return PyString_FromString(type_name); +} + +static PyObject * +_wrap_g_object_info_get_methods(PyGIBaseInfo *self) +{ + int i, length; + PyObject *retval; + + g_base_info_ref(self->info); + length = g_object_info_get_n_methods((GIObjectInfo*)self->info); + retval = PyTuple_New(length); + + for (i = 0; i < length; i++) { + GIFunctionInfo *function; + function = g_object_info_get_method((GIObjectInfo*)self->info, i); + PyTuple_SetItem(retval, i, pyg_info_new(function)); + g_base_info_unref((GIBaseInfo*)function); + } + g_base_info_unref(self->info); + + return retval; +} + +static PyObject * +_wrap_g_object_info_get_fields(PyGIBaseInfo *self) +{ + int i, length; + PyObject *retval; + + g_base_info_ref(self->info); + length = g_object_info_get_n_fields((GIObjectInfo*)self->info); + retval = PyTuple_New(length); + + for (i = 0; i < length; i++) { + GIFieldInfo *field; + field = g_object_info_get_field((GIObjectInfo*)self->info, i); + PyTuple_SetItem(retval, i, pyg_info_new(field)); + g_base_info_unref((GIBaseInfo*)field); + } + g_base_info_unref(self->info); + + return retval; +} + +static PyObject * +_wrap_g_object_info_get_interfaces(PyGIBaseInfo *self) +{ + int i, length; + PyObject *retval; + + g_base_info_ref(self->info); + length = g_object_info_get_n_interfaces((GIObjectInfo*)self->info); + retval = PyTuple_New(length); + + for (i = 0; i < length; i++) { + GIInterfaceInfo *interface; + interface = g_object_info_get_interface((GIObjectInfo*)self->info, i); + PyTuple_SetItem(retval, i, pyg_info_new(interface)); + g_base_info_unref((GIBaseInfo*)interface); + } + g_base_info_unref(self->info); + + return retval; +} + +static PyMethodDef _PyGIObjectInfo_methods[] = { + { "getParent", (PyCFunction)_wrap_g_object_info_get_parent, METH_NOARGS }, + { "getTypeName", (PyCFunction)_wrap_g_object_info_get_type_name, METH_NOARGS }, + { "getMethods", (PyCFunction)_wrap_g_object_info_get_methods, METH_NOARGS }, + { "getFields", (PyCFunction)_wrap_g_object_info_get_fields, METH_NOARGS }, + { "getInterfaces", (PyCFunction)_wrap_g_object_info_get_interfaces, METH_NOARGS }, + { NULL, NULL, 0 } +}; + + + +/* GIInterfaceInfo */ +NEW_CLASS("InterfaceInfo", GIInterfaceInfo); + +static PyObject * +_wrap_g_interface_info_get_methods(PyGIBaseInfo *self) +{ + int i, length; + PyObject *retval; + + g_base_info_ref(self->info); + length = g_interface_info_get_n_methods((GIInterfaceInfo*)self->info); + retval = PyTuple_New(length); + + for (i = 0; i < length; i++) { + GIFunctionInfo *function; + function = g_interface_info_get_method((GIInterfaceInfo*)self->info, i); + PyTuple_SetItem(retval, i, pyg_info_new(function)); + g_base_info_unref((GIBaseInfo*)function); + } + g_base_info_unref(self->info); + + return retval; +} + +static void +initialize_interface (GTypeInterface *iface, PyTypeObject *pytype) +{ + // TODO: Implement this when g-i adds supports for vfunc offsets: + // http://bugzilla.gnome.org/show_bug.cgi?id=560281 + /* + GIRepository *repo = g_irepository_get_default(); + GIBaseInfo *iface_info = g_irepository_find_by_gtype(repo, G_TYPE_FROM_INTERFACE(iface)); + int length, i; + GTypeInterface *parent_iface = g_type_interface_peek_parent(iface); + + length = g_interface_info_get_n_methods((GIInterfaceInfo *) iface_info); + + for (i = 0; i < length; i++) { + GIFunctionInfo *method = g_interface_info_get_method((GIInterfaceInfo *) iface_info, i); + const gchar *method_name = g_base_info_get_name((GIBaseInfo *) method); + gchar pymethod_name[250]; + PyObject *py_method; + void *method_ptr = iface + i * sizeof(void*); + + printf("%s\n", method_name); + + g_snprintf(pymethod_name, sizeof(pymethod_name), "do_%s", pymethod_name); + py_method = PyObject_GetAttrString((PyObject *) pytype, pymethod_name); + if (py_method && !PyObject_TypeCheck(py_method, &PyCFunction_Type)) { + method_ptr = interface_method; + } else { + PyErr_Clear(); + if (parent_iface) { + method_ptr = parent_iface + i * sizeof(void*); + } + Py_XDECREF(py_method); + } + + g_base_info_unref((GIBaseInfo *) method); + } + */ +} + +static PyObject * +_wrap_g_interface_info_register(PyGIBaseInfo *self) +{ + GType gtype; + GInterfaceInfo *info_struct = g_new0(GInterfaceInfo, 1); + + info_struct->interface_init = (GInterfaceInitFunc) initialize_interface; + info_struct->interface_finalize = NULL; + info_struct->interface_data = NULL; + + gtype = g_registered_type_info_get_g_type((GIRegisteredTypeInfo *) self->info); + pyg_register_interface_info(gtype, info_struct); + + Py_INCREF(Py_None); + return Py_None; +} + +static PyMethodDef _PyGIInterfaceInfo_methods[] = { + { "getMethods", (PyCFunction)_wrap_g_interface_info_get_methods, METH_NOARGS }, + { "register", (PyCFunction)_wrap_g_interface_info_register, METH_NOARGS }, + { NULL, NULL, 0 } +}; + + +/* GIConstantInfo */ +NEW_CLASS("ConstantInfo", GIConstantInfo); + +static PyMethodDef _PyGIConstantInfo_methods[] = { + { NULL, NULL, 0 } +}; + + +/* GIValueInfo */ +NEW_CLASS("ValueInfo", GIValueInfo); + +static PyObject * +_wrap_g_value_info_get_value(PyGIBaseInfo *self) +{ + glong value; + + g_base_info_ref(self->info); + value = g_value_info_get_value((GIValueInfo*)self->info); + g_base_info_unref(self->info); + + return PyLong_FromLong(value); +} + + +static PyMethodDef _PyGIValueInfo_methods[] = { + { "getValue", (PyCFunction)_wrap_g_value_info_get_value, METH_NOARGS }, + { NULL, NULL, 0 } +}; + + +/* GISignalInfo */ +NEW_CLASS("SignalInfo", GISignalInfo); + +static PyMethodDef _PyGISignalInfo_methods[] = { + { NULL, NULL, 0 } +}; + + +/* GIVFuncInfo */ +NEW_CLASS("VFuncInfo", GIVFuncInfo); + +static PyMethodDef _PyGIVFuncInfo_methods[] = { + { NULL, NULL, 0 } +}; + +/* GIPropertyInfo */ +NEW_CLASS("PropertyInfo", GIPropertyInfo); + +static PyMethodDef _PyGIPropertyInfo_methods[] = { + { NULL, NULL, 0 } +}; + +/* GIFieldInfo */ +NEW_CLASS("FieldInfo", GIFieldInfo); + +static PyObject * +_wrap_g_field_info_get_value(PyGIBaseInfo *self, PyObject *args) +{ + PyObject *obj; + void *buffer; + GArgument value; + GIFieldInfo *field_info; + PyObject *retval; + + field_info = (GIFieldInfo *)self->info; + + if (!PyArg_ParseTuple(args, "O:TypeInfo.getValue", &obj)) + return NULL; + + GIBaseInfo *container = g_base_info_get_container((GIBaseInfo *) self->info); + GIInfoType container_type = g_base_info_get_type(container); + + if (container_type == GI_INFO_TYPE_STRUCT || container_type == GI_INFO_TYPE_BOXED) { + PyObject *pybuffer = PyObject_GetAttrString(obj, "__buffer__"); + PyBufferProcs *buffer_procs = pybuffer->ob_type->tp_as_buffer; + if (buffer_procs == NULL || buffer_procs->bf_getreadbuffer == 0) { + PyErr_SetString(PyExc_RuntimeError, "Failed to get buffer for struct"); + return NULL; + } + (*buffer_procs->bf_getreadbuffer)(pybuffer, 0, &buffer); + } else { + buffer = ((PyGObject *) obj)->obj; + printf("obj: %p\n", buffer); + } + + if (!g_field_info_get_field (field_info, buffer, &value)) { + PyErr_SetString(PyExc_RuntimeError, "Failed to get value for field"); + return NULL; + } + + retval = pyg_argument_to_pyobject (&value, g_field_info_get_type (field_info)); + if (retval == NULL) { + return NULL; + } + + Py_INCREF(retval); + return retval; +} + +static PyObject * +_wrap_g_field_info_set_value(PyGIBaseInfo *self, PyObject *args) +{ + PyObject *obj; + void *buffer; + GArgument arg; + GIFieldInfo *field_info; + PyObject *value; + + field_info = (GIFieldInfo *)self->info; + + if (!PyArg_ParseTuple(args, "OO:TypeInfo.setValue", &obj, &value)) + return NULL; + + GIBaseInfo *container = g_base_info_get_container((GIBaseInfo *) self->info); + GIInfoType container_type = g_base_info_get_type(container); + + if (container_type == GI_INFO_TYPE_STRUCT || container_type == GI_INFO_TYPE_BOXED) { + PyObject *pybuffer = PyObject_GetAttrString(obj, "__buffer__"); + PyBufferProcs *buffer_procs = pybuffer->ob_type->tp_as_buffer; + if (buffer_procs == NULL || buffer_procs->bf_getreadbuffer == 0) { + PyErr_SetString(PyExc_RuntimeError, "Failed to get buffer for struct"); + return NULL; + } + (*buffer_procs->bf_getreadbuffer)(pybuffer, 0, &buffer); + } else { + buffer = ((PyGObject *) obj)->obj; + } + + arg = pyg_argument_from_pyobject(value, g_field_info_get_type (field_info)); + + if (!g_field_info_set_field (field_info, buffer, &arg)) { + PyErr_SetString(PyExc_RuntimeError, "Failed to set value for field"); + return NULL; + } + + Py_INCREF(Py_None); + return Py_None; +} + +static PyMethodDef _PyGIFieldInfo_methods[] = { + { "getValue", (PyCFunction)_wrap_g_field_info_get_value, METH_VARARGS }, + { "setValue", (PyCFunction)_wrap_g_field_info_set_value, METH_VARARGS }, + { NULL, NULL, 0 } +}; + +/* ArgInfo */ +NEW_CLASS("ArgInfo", GIArgInfo); + +static PyObject * +_wrap_g_arg_info_get_type(PyGIBaseInfo *self) +{ + return pyg_info_new(g_arg_info_get_type((GIArgInfo*)self->info)); +} + +static PyObject * +_wrap_g_arg_info_get_direction(PyGIBaseInfo *self) +{ + return PyInt_FromLong(g_arg_info_get_direction((GIArgInfo*)self->info)); +} + +static PyMethodDef _PyGIArgInfo_methods[] = { + { "getType", (PyCFunction)_wrap_g_arg_info_get_type, METH_NOARGS }, + { "getDirection", (PyCFunction)_wrap_g_arg_info_get_direction, METH_NOARGS }, + { NULL, NULL, 0 } +}; + +/* TypeInfo */ +NEW_CLASS("TypeInfo", GITypeInfo); + +static PyObject * +_wrap_g_type_info_get_tag(PyGIBaseInfo *self) +{ + return PyInt_FromLong(g_type_info_get_tag((GITypeInfo*)self->info)); +} + +static PyObject * +_wrap_g_type_info_get_param_type(PyGIBaseInfo *self, PyObject *args) +{ + int index; + + if (!PyArg_ParseTuple(args, "i:TypeInfo.getParamType", + &index)) + return NULL; + + return pyg_info_new(g_type_info_get_param_type((GITypeInfo*)self->info, index)); +} + +static PyObject * +_wrap_g_type_info_get_interface(PyGIBaseInfo *self) +{ + return pyg_info_new(g_type_info_get_interface((GITypeInfo*)self->info)); +} + +static PyMethodDef _PyGITypeInfo_methods[] = { + { "getTag", (PyCFunction)_wrap_g_type_info_get_tag, METH_NOARGS }, + { "getParamType", (PyCFunction)_wrap_g_type_info_get_param_type, METH_VARARGS }, + { "getInterface", (PyCFunction)_wrap_g_type_info_get_interface, METH_NOARGS }, + { NULL, NULL, 0 } +}; + +#if 0 +GIErrorDomainInfo +#endif + +/* GIUnresolvedInfo */ +NEW_CLASS("UnresolvedInfo", GIUnresolvedInfo); + +static PyMethodDef _PyGIUnresolvedInfo_methods[] = { + { NULL, NULL, 0 } +}; + + diff --git a/girepository/bank-repository.c b/girepository/bank-repository.c new file mode 100644 index 0000000..699806c --- /dev/null +++ b/girepository/bank-repository.c @@ -0,0 +1,237 @@ +/* -*- Mode: C; c-basic-offset: 4 -*- + * vim: set ts=8 sts=4 sw=4 noet ai cindent : + * + * Copyright (C) 2005 Johan Dahlin <johan@gnome.org> + * + * 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 St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "bank.h" + +static PyMethodDef _PyGIRepository_methods[]; + +PyTypeObject PyGIRepository_Type = { + PyObject_HEAD_INIT(NULL) + 0, + "bank.IRepository", + sizeof(PyGIRepository), + 0, + /* methods */ + (destructor)0, + (printfunc)0, + (getattrfunc)0, + (setattrfunc)0, + (cmpfunc)0, + (reprfunc)0, + 0, + 0, + 0, + (hashfunc)0, + (ternaryfunc)0, + (reprfunc)0, + (getattrofunc)0, + (setattrofunc)0, + 0, + Py_TPFLAGS_DEFAULT, + NULL, + (traverseproc)0, + (inquiry)0, + (richcmpfunc)0, + 0, + (getiterfunc)0, + (iternextfunc)0, + _PyGIRepository_methods, + 0, + 0, + NULL, + NULL, + (descrgetfunc)0, + (descrsetfunc)0, + 0, + (initproc)0, +}; + +static PyObject * +_wrap_g_irepository_require(PyGIRepository *self, + PyObject *args, + PyObject *kwargs) +{ + static char *kwlist[] = { "namespace", "lazy", NULL }; + gchar *namespace; + PyObject *lazy_obj = NULL; + int flags = 0; + GTypelib *ret; + PyObject *pyret; + GError *error = NULL; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, + "s|O:GIRepository.require", + kwlist, &namespace, &lazy_obj)) + return NULL; + + if (lazy_obj != NULL && PyObject_IsTrue(lazy_obj)) + flags |= G_IREPOSITORY_LOAD_FLAG_LAZY; + + /* TODO - handle versioning in some way, need to figure out what + * this looks like Python side. + */ + ret = g_irepository_require(self->repo, namespace, NULL, flags, &error); + + if (ret == NULL) { +#if 0 + g_print ("ERROR: %s (FIXME: raise GError exception)\n", + error->message); + g_clear_error (&error); +#endif + Py_INCREF(Py_None); + return Py_None; + } + pyret = PyBool_FromLong(ret != NULL); + Py_INCREF(pyret); + return pyret; +} + +static PyObject * +_wrap_g_irepository_find_by_name(PyGIRepository *self, + PyObject *args, + PyObject *kwargs) +{ + static char *kwlist[] = { "namespace", "name", NULL }; + char *namespace, *name; + GIBaseInfo *info; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, + "ss:GIRepository.findByName", + kwlist, &namespace, &name)) + return NULL; + + info = g_irepository_find_by_name (self->repo, namespace, name); + if (!info) { + Py_INCREF(Py_None); + return Py_None; + } + + return pyg_info_new(info); +} + +static PyObject * +_wrap_g_irepository_get_namespaces(PyGIRepository *self) +{ + char ** namespaces; + int i, length; + PyObject *retval; + + namespaces = g_irepository_get_loaded_namespaces(self->repo); + + length = g_strv_length(namespaces); + retval = PyTuple_New(length); + + for (i = 0; i < length; i++) + PyTuple_SetItem(retval, i, PyString_FromString(namespaces[i])); + + g_strfreev (namespaces); + + return retval; +} + +static PyObject * +_wrap_g_irepository_get_infos(PyGIRepository *self, + PyObject *args, + PyObject *kwargs) +{ + static char *kwlist[] = { "namespace", NULL }; + char *namespace; + int i, length; + PyObject *retval; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, + "s:GIRepository.getInfos", + kwlist, &namespace)) + return NULL; + + length = g_irepository_get_n_infos(self->repo, namespace); + + retval = PyTuple_New(length); + + for (i = 0; i < length; i++) { + GIBaseInfo *info = g_irepository_get_info(self->repo, namespace, i); + PyTuple_SetItem(retval, i, pyg_info_new(info)); + } + + return retval; +} + +static PyObject * +_wrap_g_irepository_is_registered(PyGIRepository *self, + PyObject *args, + PyObject *kwargs) +{ + static char *kwlist[] = { "namespace", NULL }; + char *namespace; + + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, + "s:GIRepository.isRegistered", + kwlist, &namespace)) + return NULL; + + return PyBool_FromLong(g_irepository_is_registered(self->repo, namespace, NULL)); +} + +static PyObject * +_wrap_g_irepository_get_c_prefix(PyGIRepository *self, + PyObject *args, + PyObject *kwargs) +{ + static char *kwlist[] = { "namespace", NULL }; + char *namespace; + + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, + "s:GIRepository.getCPrefix", + kwlist, &namespace)) + return NULL; + + return PyString_FromString(g_irepository_get_c_prefix(self->repo, namespace)); +} + +static PyObject * +_wrap_g_irepository_get_default(PyObject *_) +{ + static PyGIRepository *self = NULL; + + if (!self) { + self = (PyGIRepository *)PyObject_New(PyGIRepository, + &PyGIRepository_Type); + if (self == NULL) + return NULL; + + self->repo = g_irepository_get_default(); + } + + return (PyObject*)self; +} + +static PyMethodDef _PyGIRepository_methods[] = { + { "require", (PyCFunction)_wrap_g_irepository_require, METH_VARARGS|METH_KEYWORDS }, + { "getNamespaces", (PyCFunction)_wrap_g_irepository_get_namespaces, METH_NOARGS }, + { "getInfos", (PyCFunction)_wrap_g_irepository_get_infos, METH_VARARGS|METH_KEYWORDS }, + { "getDefault", (PyCFunction)_wrap_g_irepository_get_default, METH_STATIC|METH_NOARGS }, + { "findByName", (PyCFunction)_wrap_g_irepository_find_by_name, METH_VARARGS|METH_KEYWORDS }, + { "isRegistered", (PyCFunction)_wrap_g_irepository_is_registered, METH_VARARGS|METH_KEYWORDS }, + { "getCPrefix", (PyCFunction)_wrap_g_irepository_get_c_prefix, METH_VARARGS|METH_KEYWORDS }, + { NULL, NULL, 0 } +}; + diff --git a/girepository/bank.c b/girepository/bank.c new file mode 100644 index 0000000..c069a18 --- /dev/null +++ b/girepository/bank.c @@ -0,0 +1,155 @@ +/* -*- Mode: C; c-basic-offset: 4 -*- + * vim: set ts=8 sts=4 sw=4 noet ai cindent : + * + * Copyright (C) 2005 Johan Dahlin <johan@gnome.org> + * + * 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 St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "bank.h" +#include <pygobject.h> + +#define REGISTER_TYPE(d, type, name) \ + type.ob_type = &PyType_Type; \ + type.tp_alloc = PyType_GenericAlloc; \ + type.tp_new = PyType_GenericNew; \ + if (PyType_Ready(&type)) \ + return; \ + PyDict_SetItemString(d, name, (PyObject *)&type); \ + Py_INCREF(&type); + +#define REGISTER_SUBTYPE(d, type, name, base) \ + type.tp_base = &base; \ + REGISTER_TYPE(d, type, name) + +static PyObject * +_wrap_set_object_has_new_constructor(PyGIBaseInfo *self, PyObject *args) +{ + PyObject *pygtype; + + if (!PyArg_ParseTuple(args, "O:setObjectHasNewConstructor", &pygtype)) + return NULL; + + pyg_set_object_has_new_constructor(pyg_type_from_object(pygtype)); + + Py_INCREF(Py_None); + return Py_None; +} + +static PyMethodDef pybank_functions[] = { + { "setObjectHasNewConstructor", (PyCFunction)_wrap_set_object_has_new_constructor, METH_VARARGS }, + { NULL, NULL, 0 } +}; + +static void +register_types(PyObject *d) +{ + REGISTER_TYPE(d, PyGIRepository_Type, "Repository"); + REGISTER_TYPE(d, PyGIBaseInfo_Type, "BaseInfo"); + REGISTER_SUBTYPE(d, PyGIUnresolvedInfo_Type, + "UnresolvedInfo", PyGIBaseInfo_Type); + REGISTER_SUBTYPE(d, PyGICallableInfo_Type, + "CallableInfo", PyGIBaseInfo_Type); + REGISTER_SUBTYPE(d, PyGIFunctionInfo_Type, + "FunctionInfo", PyGICallableInfo_Type); + REGISTER_SUBTYPE(d, PyGICallbackInfo_Type, + "CallbackInfo", PyGICallableInfo_Type); + REGISTER_SUBTYPE(d, PyGIRegisteredTypeInfo_Type, + "RegisteredTypeInfo", PyGIBaseInfo_Type); + REGISTER_SUBTYPE(d, PyGIStructInfo_Type, + "StructInfo", PyGIRegisteredTypeInfo_Type); + REGISTER_SUBTYPE(d, PyGIEnumInfo_Type, + "EnumInfo", PyGIRegisteredTypeInfo_Type); + REGISTER_SUBTYPE(d, PyGIObjectInfo_Type, + "ObjectInfo", PyGIRegisteredTypeInfo_Type); + REGISTER_SUBTYPE(d, PyGIBoxedInfo_Type, + "BoxedInfo", PyGIRegisteredTypeInfo_Type); + REGISTER_SUBTYPE(d, PyGIInterfaceInfo_Type, + "InterfaceInfo", PyGIRegisteredTypeInfo_Type); + REGISTER_SUBTYPE(d, PyGIConstantInfo_Type, + "ConstantInfo", PyGIBaseInfo_Type); + REGISTER_SUBTYPE(d, PyGIValueInfo_Type, + "ValueInfo", PyGIBaseInfo_Type); + REGISTER_SUBTYPE(d, PyGISignalInfo_Type, + "SignalInfo", PyGICallableInfo_Type); + REGISTER_SUBTYPE(d, PyGIVFuncInfo_Type, + "VFuncInfo", PyGICallableInfo_Type); + REGISTER_SUBTYPE(d, PyGIPropertyInfo_Type, + "PropertyInfo", PyGIBaseInfo_Type); + REGISTER_SUBTYPE(d, PyGIFieldInfo_Type, + "FieldInfo", PyGIBaseInfo_Type); + REGISTER_SUBTYPE(d, PyGIArgInfo_Type, + "ArgInfo", PyGIBaseInfo_Type); + REGISTER_SUBTYPE(d, PyGITypeInfo_Type, + "TypeInfo", PyGIBaseInfo_Type); + REGISTER_SUBTYPE(d, PyGIUnionInfo_Type, + "UnionInfo", PyGIRegisteredTypeInfo_Type); +} + +static void +register_constants(PyObject *m) +{ + PyModule_AddIntConstant(m, "TYPE_TAG_VOID", GI_TYPE_TAG_VOID); + PyModule_AddIntConstant(m, "TYPE_TAG_BOOLEAN", GI_TYPE_TAG_BOOLEAN); + PyModule_AddIntConstant(m, "TYPE_TAG_INT8", GI_TYPE_TAG_INT8); + PyModule_AddIntConstant(m, "TYPE_TAG_UINT8", GI_TYPE_TAG_UINT8); + PyModule_AddIntConstant(m, "TYPE_TAG_INT16", GI_TYPE_TAG_INT16); + PyModule_AddIntConstant(m, "TYPE_TAG_UINT16", GI_TYPE_TAG_UINT16); + PyModule_AddIntConstant(m, "TYPE_TAG_INT32", GI_TYPE_TAG_INT32); + PyModule_AddIntConstant(m, "TYPE_TAG_UINT32", GI_TYPE_TAG_UINT32); + PyModule_AddIntConstant(m, "TYPE_TAG_INT64", GI_TYPE_TAG_INT64); + PyModule_AddIntConstant(m, "TYPE_TAG_UINT64", GI_TYPE_TAG_UINT64); + /* FIXME: Removed from metadata format, fix properly by introducing + special-case struct */ +/* PyModule_AddIntConstant(m, "TYPE_TAG_GSTRING", GI_TYPE_TAG_GSTRING); */ + PyModule_AddIntConstant(m, "TYPE_TAG_INT", GI_TYPE_TAG_INT); + PyModule_AddIntConstant(m, "TYPE_TAG_UINT", GI_TYPE_TAG_UINT); + PyModule_AddIntConstant(m, "TYPE_TAG_LONG", GI_TYPE_TAG_LONG); + PyModule_AddIntConstant(m, "TYPE_TAG_ULONG", GI_TYPE_TAG_ULONG); + PyModule_AddIntConstant(m, "TYPE_TAG_SSIZE", GI_TYPE_TAG_SSIZE); + PyModule_AddIntConstant(m, "TYPE_TAG_SIZE", GI_TYPE_TAG_SIZE); + PyModule_AddIntConstant(m, "TYPE_TAG_FLOAT", GI_TYPE_TAG_FLOAT); + PyModule_AddIntConstant(m, "TYPE_TAG_DOUBLE", GI_TYPE_TAG_DOUBLE); + PyModule_AddIntConstant(m, "TYPE_TAG_TIME_T", GI_TYPE_TAG_TIME_T); + PyModule_AddIntConstant(m, "TYPE_TAG_GTYPE", GI_TYPE_TAG_GTYPE); + PyModule_AddIntConstant(m, "TYPE_TAG_UTF8", GI_TYPE_TAG_UTF8); + PyModule_AddIntConstant(m, "TYPE_TAG_FILENAME", GI_TYPE_TAG_FILENAME); + PyModule_AddIntConstant(m, "TYPE_TAG_ARRAY", GI_TYPE_TAG_ARRAY); + PyModule_AddIntConstant(m, "TYPE_TAG_INTERFACE", GI_TYPE_TAG_INTERFACE); + PyModule_AddIntConstant(m, "TYPE_TAG_GLIST", GI_TYPE_TAG_GLIST); + PyModule_AddIntConstant(m, "TYPE_TAG_GSLIST", GI_TYPE_TAG_GSLIST); + PyModule_AddIntConstant(m, "TYPE_TAG_GHASH", GI_TYPE_TAG_GHASH); + PyModule_AddIntConstant(m, "TYPE_TAG_ERROR", GI_TYPE_TAG_ERROR); + + PyModule_AddIntConstant(m, "DIRECTION_IN", GI_DIRECTION_IN); + PyModule_AddIntConstant(m, "DIRECTION_OUT", GI_DIRECTION_OUT); + PyModule_AddIntConstant(m, "DIRECTION_INOUT", GI_DIRECTION_INOUT); +} + +void +initrepo(void) +{ + PyObject *d, *m; + + m = Py_InitModule("girepository.repo", pybank_functions); + d = PyModule_GetDict(m); + + g_type_init(); + + pygobject_init(-1, -1, -1); + register_types(d); + register_constants(m); +} + diff --git a/girepository/bank.h b/girepository/bank.h new file mode 100644 index 0000000..d960483 --- /dev/null +++ b/girepository/bank.h @@ -0,0 +1,80 @@ +/* -*- Mode: C; c-basic-offset: 4 -*- */ +/* + * Copyright (C) 2005 Johan Dahlin <johan@gnome.org> + * + * 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 St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <Python.h> +#include <girepository.h> + +/* This was added in Python 2.4 */ +#ifndef Py_CLEAR +#define Py_CLEAR(op) \ + do { \ + if (op) { \ + PyObject *tmp = (PyObject *)(op); \ + (op) = NULL; \ + Py_DECREF(tmp); \ + } \ + } while (0) +#endif /* Py_CLEAR */ + +typedef struct { + PyObject_HEAD + GIRepository *repo; +} PyGIRepository; + +extern PyTypeObject PyGIRepository_Type; + +PyObject * pyg_info_new(gpointer info); + +typedef struct { + PyObject_HEAD + GIBaseInfo *info; + PyObject *instance_dict; + PyObject *weakreflist; +} PyGIBaseInfo; + +extern PyTypeObject PyGIBaseInfo_Type; +extern PyTypeObject PyGICallableInfo_Type; +extern PyTypeObject PyGIFunctionInfo_Type; +extern PyTypeObject PyGICallbackInfo_Type; +extern PyTypeObject PyGIRegisteredTypeInfo_Type; +extern PyTypeObject PyGIStructInfo_Type; +extern PyTypeObject PyGIUnionInfo_Type; +extern PyTypeObject PyGIEnumInfo_Type; +extern PyTypeObject PyGIObjectInfo_Type; +extern PyTypeObject PyGIBoxedInfo_Type; +extern PyTypeObject PyGIInterfaceInfo_Type; +extern PyTypeObject PyGIConstantInfo_Type; +extern PyTypeObject PyGIValueInfo_Type; +extern PyTypeObject PyGISignalInfo_Type; +extern PyTypeObject PyGIVFuncInfo_Type; +extern PyTypeObject PyGIPropertyInfo_Type; +extern PyTypeObject PyGIFieldInfo_Type; +extern PyTypeObject PyGIArgInfo_Type; +extern PyTypeObject PyGITypeInfo_Type; +#if 0 +extern PyTypeObject PyGIErrorDomainInfo_Type; +#endif +extern PyTypeObject PyGIUnresolvedInfo_Type; + +GArgument pyg_argument_from_pyobject(PyObject *object, + GITypeInfo *info); +PyObject* pyg_argument_to_pyobject(GArgument *arg, + GITypeInfo *info); +PyObject* pyarray_to_pyobject(gpointer array, int length, GITypeInfo *info); + diff --git a/girepository/btypes.py b/girepository/btypes.py new file mode 100644 index 0000000..03e8826 --- /dev/null +++ b/girepository/btypes.py @@ -0,0 +1,300 @@ +# -*- Mode: Python; py-indent-offset: 4 -*- +# +# Copyright (C) 2005, 2007 Johan Dahlin <johan@gnome.org> +# +# 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 St, Fifth Floor, Boston, MA 02110-1301 USA +# + +import gobject + +import new + +from . import repo + +from .repository import repository + +class Callable(object): + + # Types of callables + INSTANCE_METHOD = 'method' + STATIC_METHOD = 'static' + CLASS_METHOD = 'class' + FUNTION = 'function' + + def __init__(self, info): + self.info = info + self.call_type = None + + def type_check(self, name, value, argType): + tag = argType.getTag() + if tag == repo.TYPE_TAG_UTF8: + if not isinstance(value, basestring) and value is not None: + raise TypeError("%s must be string, not %s" % ( + name, type(value).__name__)) + elif tag in (repo.TYPE_TAG_INT, + repo.TYPE_TAG_INT8, + repo.TYPE_TAG_UINT, + repo.TYPE_TAG_UINT8, + repo.TYPE_TAG_INT16, + repo.TYPE_TAG_UINT16, + repo.TYPE_TAG_INT32): + try: + int(value) + except ValueError: + raise TypeError("%s must be int, not %s" % (name, type(value).__name__)) + if tag in (repo.TYPE_TAG_UINT, + repo.TYPE_TAG_UINT8, + repo.TYPE_TAG_UINT16) and value < 0: + raise TypeError("%s must be an unsigned value, not %s", name, value) + elif tag in (repo.TYPE_TAG_UINT32, + repo.TYPE_TAG_INT64, + repo.TYPE_TAG_UINT64, + repo.TYPE_TAG_ULONG): + try: + long(value) + except ValueError: + raise TypeError("%s must be int or long, not %s" % (name, type(value).__name__)) + if tag in (repo.TYPE_TAG_UINT32, + repo.TYPE_TAG_UINT64, + repo.TYPE_TAG_ULONG) and value < 0: + raise TypeError("%s must be an unsigned value, not %s", name, value) + elif tag in (repo.TYPE_TAG_FLOAT, + repo.TYPE_TAG_DOUBLE): + try: + float(value) + except ValueError: + raise TypeError("%s must be float, not %s" % (name, type(value).__name__)) + elif tag == repo.TYPE_TAG_INTERFACE: + # TODO + pass + elif tag == repo.TYPE_TAG_BOOLEAN: + try: + bool(value) + except ValueError: + raise TypeError("%s must be bool, not %s" % (name, type(value).__name__)) + elif tag == repo.TYPE_TAG_ARRAY: + if value is not None: + raise TypeError("Must pass None for arrays currently") + elif tag == repo.TYPE_TAG_ERROR: + # TODO + pass + elif tag == repo.TYPE_TAG_VOID: + # TODO + pass + else: + raise NotImplementedError('type checking for tag %d' % tag) + + def __call__(self, *args, **kwargs): + infoArgs = list(self.info.getArgs()) + requiredArgs = 0 + for arg in infoArgs: + direct = arg.getDirection() + if direct in [repo.DIRECTION_IN, repo.DIRECTION_INOUT]: + requiredArgs += 1 + + is_method = self.call_type in [self.INSTANCE_METHOD, self.CLASS_METHOD] + if is_method: + requiredArgs += 1 + + # TODO: put the kwargs in their right positions + totalInArgs = args + tuple(kwargs.values()) + + if len(totalInArgs) != requiredArgs: + raise TypeError('%r requires %d arguments, passed %d instead.' % ( + self, requiredArgs, len(totalInArgs))) + + for i, value in enumerate(totalInArgs): + if not is_method or i > 0: + off = is_method and 1 or 0 + infoArg = infoArgs[i - off] + argType = infoArg.getType() + name = infoArg.getName() + self.type_check(name, value, argType) + + retval = self.info.invoke(*totalInArgs) + + if self.info.isConstructor(): + return None + + return retval + +class Function(Callable): + def __init__(self, info): + Callable.__init__(self, info) + self.info = info + self.static = True + + def __repr__(self): + return "<function %s>" % (self.info.getName(),) + + +class Method(Callable): + + def __init__(self, info, className, call_type=Callable.INSTANCE_METHOD): + Callable.__init__(self, info) + self.object = None + self.className = className + self.call_type = call_type + self.__name__ = info.getName() + self.__module__ = info.getNamespace() + + def newType(self, retval, type_info=None): + if type_info == None: + type_info = self.info.getReturnType() + + info = type_info.getInterface() + klass = getClass(info) + obj = klass.__new__(klass) + obj._object = retval + return obj + + #def __get__(self, instance, type): + #if instance is None: + #return self + + #def wrapper(*args, **kwargs): + #return self(instance, *args, **kwargs) + + #return wrapper + + def __repr__(self): + return "<method %s of %s.%s object>" % ( + self.__name__, + self.__module__, + self.className) + +class FieldDescriptor(object): + def __init__(self, info): + self._info = info + + def __get__(self, obj, klass=None): + return self._info.getValue(obj) + + def __set__(self, obj, value): + return self._info.setValue(obj, value) + +class PyBankMeta(gobject.GObjectMeta): + def __init__(cls, name, bases, dict_): + gobject.GObjectMeta.__init__(cls, name, bases, dict_) + + if hasattr(cls, '__gtype__'): + repo.setObjectHasNewConstructor(cls.__gtype__) + + # Only set up the wrapper methods and fields in their base classes + if name == cls.__info__.getName(): + needs_constructor = not '__init__' in dict_ + cls._setup_methods(needs_constructor) + + if hasattr(cls.__info__, 'getFields'): + cls._setup_fields() + + def _setup_methods(cls, needs_constructor): + info = cls.__info__ + constructors = [] + static_methods = [] + for method in info.getMethods(): + name = method.getName() + + if method.isConstructor(): + constructors.append(method) + elif method.isMethod(): + func = Method(method, cls.__name__) + setattr(cls, name, new.instancemethod(func, None, cls)) + else: + static_methods.append(method) + + if hasattr(info, 'getInterfaces'): + for interface in info.getInterfaces(): + for method in interface.getMethods(): + name = method.getName() + if method.isMethod(): + func = Method(method, interface.getName()) + setattr(cls, name, new.instancemethod(func, None, cls)) + else: + static_methods.append(method) + + winner = None + if needs_constructor: + if len(constructors) == 1: + winner = constructors[0] + else: + for constructor in constructors: + if constructor.getName() == 'new': + winner = constructor + break + + if winner is not None: + func = Method(winner, cls.__name__, call_type=Method.CLASS_METHOD) + func.__name__ = '__init__' + func.__orig_name__ = winner.getName() + cls.__init__ = new.instancemethod(func, None, cls) + # TODO: do we want the constructor as a static method? + #constructors.remove(winner) + + static_methods.extend(constructors) + for static_method in static_methods: + func = Method(static_method, cls.__name__, call_type=Method.STATIC_METHOD) + setattr(cls, static_method.getName(), staticmethod(func)) + + def _setup_fields(cls): + info = cls.__info__ + for field in info.getFields(): + name = field.getName().replace('-', '_') + setattr(cls, name, FieldDescriptor(field)) + +_classDict = {} + +def getClass(info): + className = info.getName() + namespaceName = info.getNamespace() + fullName = namespaceName + '.' + className + + klass = _classDict.get(fullName) + if klass is None: + module = repository.get_module(info.getNamespace()) + klass = getattr(module, className) + return klass + +def buildType(info, bases): + className = info.getName() + namespaceName = info.getNamespace() + fullName = namespaceName + '.' + className + + if _classDict.has_key(fullName): + return _classDict[fullName] + + namespace = {} + namespace['__info__'] = info + namespace['__module__'] = namespaceName + newType = PyBankMeta(className, bases, namespace) + + _classDict[fullName] = newType + + return newType + +class BaseBlob(object): + """Base class for Struct, Boxed and Union. + """ + def __init__(self, buf=None): + if buf is None: + buf = self.__info__.newBuffer() + self.__buffer__ = buf + + def __eq__(self, other): + for field in self.__info__.getFields(): + if getattr(self, field.getName()) != getattr(other, field.getName()): + return False + return True + diff --git a/girepository/importer.py b/girepository/importer.py new file mode 100644 index 0000000..c371f79 --- /dev/null +++ b/girepository/importer.py @@ -0,0 +1,52 @@ +# -*- Mode: Python; py-indent-offset: 4 -*- +# +# Copyright (C) 2005,2007 Johan Dahlin <johan@gnome.org> +# +# 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 St, Fifth Floor, Boston, MA 02110-1301 USA +# + +import os +import sys + +from .repository import repository + +class DynamicImporter(object): + def __init__(self, name, path): + self.name = name + self.path = path + + @staticmethod + def find_module(name, path=None): + if name == 'cairo': + return None + namespace = repository.require(name) + if namespace: + return DynamicImporter(name, path) + + def load_module(self, name): + from .module import DynamicModule + module_name = 'girepository.overrides.%s' % (name,) + try: + d = {} + module = __import__(module_name, d, d, ' ', 2) + modtype = getattr(module, name + 'Module') + except ImportError, e: + modtype = DynamicModule + return modtype(name, self.path) + + +def install_importhook(): + sys.meta_path.append(DynamicImporter) + diff --git a/girepository/module.py b/girepository/module.py new file mode 100644 index 0000000..2a87816 --- /dev/null +++ b/girepository/module.py @@ -0,0 +1,224 @@ +# -*- Mode: Python; py-indent-offset: 4 -*- +# +# Copyright (C) 2007 Johan Dahlin <johan@gnome.org> +# +# 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 St, Fifth Floor, Boston, MA 02110-1301 USA +# + +import os + +import gobject +from gobject import GEnum + +from .btypes import Function, BaseBlob, buildType +from .repo import EnumInfo, FunctionInfo, ObjectInfo, UnresolvedInfo, \ + InterfaceInfo, StructInfo, BoxedInfo +from .repository import repository + +class DynamicModule(object): + def __init__(self, namespace, path): + self._namespace = namespace + self._path = path + repository.register(self, namespace, path) + self.created() + + @property + def __file__(self): + return self._namespace + + @property + def __name__(self): + return self._namespace + + @property + def __path__(self): + return [os.path.dirname(self.__file__)] + + def __repr__(self): + return "<dyn-module %r from %r>" % (self._namespace, self._path) + + def __getattr__(self, name): + type_info = repository.get_by_name(self._namespace, name) + if not type_info: + raise AttributeError("%r object has no attribute %r" % ( + self.__class__.__name__, name)) + + value = self._create_attribute(name, type_info) + self.__dict__[name] = value + return value + + @property + def __members__(self): + r = [] + for type_info in repository.get_infos(self._namespace): + if type_info is None: + continue + r.append(type_info.getName()) + return r + + + + # Override this in a subclass + + def created(self): + pass + + # Private API + + def _create_attribute(self, attr, type_info): + if isinstance(type_info, ObjectInfo): + return self._create_object(type_info) + elif isinstance(type_info, EnumInfo): + return self._create_enum(type_info) + elif isinstance(type_info, FunctionInfo): + return self._create_function(type_info) + elif isinstance(type_info, InterfaceInfo): + return self._create_interface(type_info) + elif isinstance(type_info, StructInfo) or \ + isinstance(type_info, BoxedInfo): + return self._create_boxed(type_info) + else: + raise NotImplementedError(type_info) + + def _get_parent_for_object(self, object_info): + parent_info = object_info.getParent() + + if isinstance(parent_info, UnresolvedInfo): + namespace = parent_info.getNamespace() + __import__(namespace) + parent_info = object_info.getParent() + + if not parent_info: + parent = object + else: + namespace = parent_info.getNamespace() + module = repository.get_module(namespace) + name = parent_info.getName() + try: + # Hack for gobject.Object + if module == gobject and name == 'Object': + name = 'GObject' + parent = getattr(module, name) + except AttributeError: + return self._get_parent_for_object(parent_info) + + if parent is None: + parent = object + return parent + + def _create_object(self, object_info): + name = object_info.getName() + + namespace = repository.get_c_prefix(object_info.getNamespace()) + full_name = namespace + name + object_info.getGType() + gtype = None + try: + gtype = gobject.GType.from_name(full_name) + except RuntimeError: + pass + else: + if gtype.pytype is not None: + return gtype.pytype + # Check if the klass is already created, eg + # present in our namespace, this is necessary since we're + # not always entering here through the __getattr__ hook. + klass = self.__dict__.get(name) + if klass: + return klass + + parent = self._get_parent_for_object(object_info) + klass = buildType(object_info, (parent,)) + if gtype is not None: + klass.__gtype__ = gtype + gtype.pytype = klass + self.__dict__[name] = klass + + return klass + + def _create_enum(self, enum_info): + ns = dict(__name__=enum_info.getName(), + __module__=enum_info.getNamespace()) + for value in enum_info.getValues(): + ns[value.getName().upper()] = value.getValue() + return type(enum_info.getName(), (GEnum,), ns) + + def _create_function(self, function_info): + return Function(function_info) + + def _create_interface(self, interface_info): + name = interface_info.getName() + + namespace = repository.get_c_prefix(interface_info.getNamespace()) + full_name = namespace + name + interface_info.getGType() + gtype = None + try: + gtype = gobject.GType.from_name(full_name) + except RuntimeError: + pass + else: + if gtype.pytype is not None: + return gtype.pytype + # Check if the klass is already created, eg + # present in our namespace, this is necessary since we're + # not always entering here through the __getattr__ hook. + klass = self.__dict__.get(name) + if klass: + return klass + + bases = (gobject.GInterface,) + klass = buildType(interface_info, bases) + if gtype is not None: + klass.__gtype__ = gtype + gtype.pytype = klass + interface_info.register() + self.__dict__[name] = klass + + return klass + + def _create_boxed(self, boxed_info): + name = boxed_info.getName() + + namespace = repository.get_c_prefix(boxed_info.getNamespace()) + full_name = namespace + name + boxed_info.getGType() + gtype = None + try: + gtype = gobject.GType.from_name(full_name) + except RuntimeError: + pass + else: + if gtype.pytype is not None: + return gtype.pytype + # Check if the klass is already created, eg + # present in our namespace, this is necessary since we're + # not always entering here through the __getattr__ hook. + klass = self.__dict__.get(name) + if klass: + return klass + + bases = (BaseBlob,) + if isinstance(boxed_info, BoxedInfo): + bases += gobject.Boxed + + klass = buildType(boxed_info, bases) + if gtype is not None: + klass.__gtype__ = gtype + gtype.pytype = klass + self.__dict__[name] = klass + + return klass + diff --git a/girepository/repository.py b/girepository/repository.py new file mode 100644 index 0000000..a72c6a9 --- /dev/null +++ b/girepository/repository.py @@ -0,0 +1,51 @@ +# -*- Mode: Python; py-indent-offset: 4 -*- +# +# Copyright (C) 2007 Johan Dahlin <johan@gnome.org> +# +# 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 St, Fifth Floor, Boston, MA 02110-1301 USA +# + +import gobject + +from .repo import Repository + +class _Repository(object): + def __init__(self): + self._repo = Repository.getDefault() + self._modules = {} + + def register(self, module, namespace, filename): + self._modules[namespace] = module + + def require(self, namespace): + return self._repo.require(namespace) + + def get_module(self, namespace): + return self._modules.get(namespace) + + def get_by_name(self, namespace, name): + return self._repo.findByName(namespace, name) + + def get_by_typename(self, typename): + raise NotImplemented + + def get_infos(self, namespace): + return self._repo.getInfos(namespace) + + def get_c_prefix(self, namespace): + return self._repo.getCPrefix(namespace) + +repository = _Repository() +repository.register(gobject, 'GObject', None) |