diff options
author | Simon van der Linden <svdlinden@src.gnome.org> | 2009-11-08 12:35:08 +0100 |
---|---|---|
committer | Simon van der Linden <svdlinden@src.gnome.org> | 2009-11-08 13:02:56 +0100 |
commit | b24fd9633cabe1d95cde173a04e9a49833b06a26 (patch) | |
tree | d78195fc9dc55c4b59aecd7a7d992aaf10ead558 /gi | |
download | pygi-b24fd9633cabe1d95cde173a04e9a49833b06a26.tar.gz pygi-b24fd9633cabe1d95cde173a04e9a49833b06a26.tar.xz pygi-b24fd9633cabe1d95cde173a04e9a49833b06a26.zip |
Initial import
Diffstat (limited to 'gi')
-rw-r--r-- | gi/Makefile.am | 50 | ||||
-rw-r--r-- | gi/__init__.py | 24 | ||||
-rw-r--r-- | gi/gimodule.c | 144 | ||||
-rw-r--r-- | gi/importer.py | 89 | ||||
-rw-r--r-- | gi/module.py | 167 | ||||
-rw-r--r-- | gi/overrides/Gdk.py | 21 | ||||
-rw-r--r-- | gi/overrides/Gtk.py | 13 | ||||
-rw-r--r-- | gi/overrides/Makefile.am | 10 | ||||
-rw-r--r-- | gi/overrides/__init__.py | 0 | ||||
-rw-r--r-- | gi/pygi-argument.c | 1976 | ||||
-rw-r--r-- | gi/pygi-argument.h | 65 | ||||
-rw-r--r-- | gi/pygi-info.c | 2093 | ||||
-rw-r--r-- | gi/pygi-info.h | 64 | ||||
-rw-r--r-- | gi/pygi-private.h | 55 | ||||
-rw-r--r-- | gi/pygi-repository.c | 238 | ||||
-rw-r--r-- | gi/pygi-repository.h | 39 | ||||
-rw-r--r-- | gi/pygi-struct.c | 175 | ||||
-rw-r--r-- | gi/pygi-struct.h | 40 | ||||
-rw-r--r-- | gi/pygi-type.c | 96 | ||||
-rw-r--r-- | gi/pygi-type.h | 43 | ||||
-rw-r--r-- | gi/pygi.h | 99 | ||||
-rw-r--r-- | gi/pygobject-external.h | 83 | ||||
-rw-r--r-- | gi/repository/Makefile.am | 8 | ||||
-rw-r--r-- | gi/repository/__init__.py | 30 | ||||
-rw-r--r-- | gi/types.py | 163 |
25 files changed, 5785 insertions, 0 deletions
diff --git a/gi/Makefile.am b/gi/Makefile.am new file mode 100644 index 0000000..2657d3f --- /dev/null +++ b/gi/Makefile.am @@ -0,0 +1,50 @@ +PLATFORM_VERSION = 2.0 + +pkgincludedir = $(includedir)/pygtk-$(PLATFORM_VERSION) +pkgpyexecdir = $(pyexecdir)/gtk-2.0 + +SUBDIRS = \ + repository \ + overrides + +pygidir = $(pkgpyexecdir)/gi +pygi_PYTHON = \ + types.py \ + module.py \ + importer.py \ + __init__.py + +_gi_la_CFLAGS = \ + $(PYTHON_INCLUDES) \ + $(GNOME_CFLAGS) +_gi_la_LDFLAGS = \ + -module \ + -avoid-version \ + -export-symbols-regex init_gi +_gi_la_LIBADD = \ + $(GNOME_LIBS) +_gi_la_SOURCES = \ + pygi-repository.c \ + pygi-repository.h \ + pygi-info.c \ + pygi-info.h \ + pygi-struct.c \ + pygi-struct.h \ + pygi-argument.c \ + pygi-argument.h \ + pygi-type.c \ + pygi-type.h \ + pygi.h \ + pygi-private.h \ + pygobject-external.h \ + gimodule.c + +pygi_LTLIBRARIES = _gi.la + +.la.so: + $(LN_S) .libs/$@ $@ || true + +all: $(pygi_LTLIBRARIES:.la=.so) +clean-local: + rm -f $(pygi_LTLIBRARIES:.la=.so) + diff --git a/gi/__init__.py b/gi/__init__.py new file mode 100644 index 0000000..3edea9f --- /dev/null +++ b/gi/__init__.py @@ -0,0 +1,24 @@ +# -*- Mode: Python; py-indent-offset: 4 -*- +# vim: tabstop=4 shiftwidth=4 expandtab +# +# Copyright (C) 2005-2009 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 __future__ import absolute_import + +from ._gi import _API + diff --git a/gi/gimodule.c b/gi/gimodule.c new file mode 100644 index 0000000..d9ee17b --- /dev/null +++ b/gi/gimodule.c @@ -0,0 +1,144 @@ +/* -*- Mode: C; c-basic-offset: 4 -*- + * vim: tabstop=4 shiftwidth=4 expandtab + * + * Copyright (C) 2005-2009 Johan Dahlin <johan@gnome.org> + * + * gimodule.c: wrapper for the gobject-introspection library. + * + * 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 "pygi-private.h" + +#include <pygobject.h> + +static PyObject * +_wrap_pyg_enum_add (PyObject *self, + PyObject *args, + PyObject *kwargs) +{ + static char *kwlist[] = { "g_type", NULL }; + PyObject *py_g_type; + GType g_type; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, + "O!:enum_add", + kwlist, &PyGTypeWrapper_Type, &py_g_type)) { + return NULL; + } + + g_type = pyg_type_from_object(py_g_type); + if (g_type == G_TYPE_INVALID) { + return NULL; + } + + return pyg_enum_add(NULL, g_type_name(g_type), NULL, g_type); +} + +static PyObject * +_wrap_pyg_flags_add (PyObject *self, + PyObject *args, + PyObject *kwargs) +{ + static char *kwlist[] = { "g_type", NULL }; + PyObject *py_g_type; + GType g_type; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, + "O!:flags_add", + kwlist, &PyGTypeWrapper_Type, &py_g_type)) { + return NULL; + } + + g_type = pyg_type_from_object(py_g_type); + if (g_type == G_TYPE_INVALID) { + return NULL; + } + + return pyg_flags_add(NULL, g_type_name(g_type), NULL, g_type); +} + +static PyObject * +_wrap_pyg_set_object_has_new_constructor (PyObject *self, + PyObject *args, + PyObject *kwargs) +{ + static char *kwlist[] = { "g_type", NULL }; + PyObject *py_g_type; + GType g_type; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, + "O!:set_object_has_new_constructor", + kwlist, &PyGTypeWrapper_Type, &py_g_type)) { + return NULL; + } + + g_type = pyg_type_from_object(py_g_type); + if (!g_type_is_a(g_type, G_TYPE_OBJECT)) { + PyErr_SetString(PyExc_TypeError, "must be a subtype of GObject"); + return NULL; + } + + pyg_set_object_has_new_constructor(g_type); + + Py_RETURN_NONE; +} + + +static PyMethodDef _pygi_functions[] = { + { "enum_add", (PyCFunction)_wrap_pyg_enum_add, METH_VARARGS | METH_KEYWORDS }, + { "flags_add", (PyCFunction)_wrap_pyg_flags_add, METH_VARARGS | METH_KEYWORDS }, + + { "set_object_has_new_constructor", (PyCFunction)_wrap_pyg_set_object_has_new_constructor, METH_VARARGS | METH_KEYWORDS }, + { NULL, NULL, 0 } +}; + +struct PyGI_API PyGI_API = { + pygi_type_import_by_g_type +}; + + +PyMODINIT_FUNC +init_gi(void) +{ + PyObject *m; + PyObject *api; + + m = Py_InitModule("_gi", _pygi_functions); + if (m == NULL) { + return; + } + + if (pygobject_init(-1, -1, -1) == NULL) { + return; + } + + if (_pygobject_import() < 0) { + return; + } + + _pygi_repository_register_types(m); + _pygi_info_register_types(m); + _pygi_struct_register_types(m); + _pygi_argument_init(); + + api = PyCObject_FromVoidPtr((void *)&PyGI_API, NULL); + if (api == NULL) { + return; + } + PyModule_AddObject(m, "_API", api); +} + diff --git a/gi/importer.py b/gi/importer.py new file mode 100644 index 0000000..48392b4 --- /dev/null +++ b/gi/importer.py @@ -0,0 +1,89 @@ +# -*- Mode: Python; py-indent-offset: 4 -*- +# vim: tabstop=4 shiftwidth=4 expandtab +# +# Copyright (C) 2005-2009 Johan Dahlin <johan@gnome.org> +# +# importer.py: dynamic importer for introspected libraries. +# +# 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 __future__ import absolute_import + +import sys +import gobject + +from ._gi import Repository, RepositoryError +from .module import DynamicModule + + +repository = Repository.get_default() + + +class DynamicImporter(object): + + # Note: see PEP302 for the Importer Protocol implemented below. + + def __init__(self, path): + self.path = path + + def find_module(self, fullname, path=None): + if not fullname.startswith(self.path): + return + + path, namespace = fullname.rsplit('.', 1) + if path != self.path: + return + try: + repository.require(namespace) + except RepositoryError: + pass + else: + return self + + def load_module(self, fullname): + if fullname in sys.modules: + return sys.modules[name] + + path, namespace = fullname.rsplit('.', 1) + + # Workaround for GObject + if namespace == 'GObject': + sys.modules[fullname] = gobject + return gobject + + # Look for an overrides module + overrides_name = 'gi.overrides.%s' % namespace + try: + overrides_type_name = '%sModule' % namespace + overrides_module = __import__(overrides_name, fromlist=[overrides_type_name]) + module_type = getattr(overrides_module, overrides_type_name) + except ImportError, e: + module_type = DynamicModule + + module = module_type.__new__(module_type) + module.__dict__ = { + '__file__': '<%s>' % fullname, + '__name__': fullname, + '__namespace__': namespace, + '__loader__': self + } + + sys.modules[fullname] = module + + module.__init__() + + return module + diff --git a/gi/module.py b/gi/module.py new file mode 100644 index 0000000..1a54971 --- /dev/null +++ b/gi/module.py @@ -0,0 +1,167 @@ +# -*- Mode: Python; py-indent-offset: 4 -*- +# vim: tabstop=4 shiftwidth=4 expandtab +# +# Copyright (C) 2007-2009 Johan Dahlin <johan@gnome.org> +# +# module.py: dynamic module for introspected libraries. +# +# 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 __future__ import absolute_import + +import os +import gobject + +from ._gi import \ + Repository, \ + FunctionInfo, \ + RegisteredTypeInfo, \ + EnumInfo, \ + ObjectInfo, \ + InterfaceInfo, \ + ConstantInfo, \ + StructInfo, \ + Struct, \ + enum_add, \ + flags_add +from .types import \ + GObjectMeta, \ + StructMeta, \ + Boxed, \ + Function + +repository = Repository.get_default() + + +def get_parent_for_object(object_info): + parent_object_info = object_info.get_parent() + + if not parent_object_info: + return object + + namespace = parent_object_info.get_namespace() + name = parent_object_info.get_name() + + # Workaround for GObject.Object and GObject.InitiallyUnowned. + if namespace == 'GObject' and name == 'Object' or name == 'InitiallyUnowned': + return gobject.GObject + + module = __import__('gi.repository.%s' % namespace, fromlist=[name]) + return getattr(module, name) + +def get_interfaces_for_object(object_info): + interfaces = [] + for interface_info in object_info.get_interfaces(): + namespace = interface_info.get_namespace() + name = interface_info.get_name() + + module = __import__('gi.repository.%s' % namespace, fromlist=[name]) + interfaces.append(getattr(module, name)) + return interfaces + + +class DynamicModule(object): + + def __str__(self): + path = repository.get_typelib_path(self.__namespace__) + return "<dynamic module %r from %r>" % (self.__name__, path) + + def __getattr__(self, name): + if self.__dict__.has_key(name): + return self.__dict__[name] + + info = repository.find_by_name(self.__namespace__, name) + if not info: + raise AttributeError("%r object has no attribute %r" % ( + self.__class__.__name__, name)) + + if isinstance(info, EnumInfo): + g_type = info.get_g_type() + value = g_type.pytype + + if value is None: + if g_type.is_a(gobject.TYPE_ENUM): + value = enum_add(g_type) + else: + value = flags_add(g_type) + + value.__info__ = info + value.__module__ = info.get_namespace() + + for value_info in info.get_values(): + name = value_info.get_name().upper() + setattr(value, name, value(value_info.get_value())) + + elif isinstance(info, RegisteredTypeInfo): + g_type = info.get_g_type() + + # Check if there is already a Python wrapper. + if g_type != gobject.TYPE_NONE: + type_ = g_type.pytype + if type_ is not None: + self.__dict__[name] = type_ + return type_ + + # Create a wrapper. + if isinstance(info, ObjectInfo): + parent = get_parent_for_object(info) + interfaces = tuple(interface for interface in get_interfaces_for_object(info) + if not issubclass(parent, interface)) + bases = (parent,) + interfaces + metaclass = GObjectMeta + elif isinstance(info, InterfaceInfo): + bases = (gobject.GInterface,) + metaclass = GObjectMeta + elif isinstance(info, StructInfo): + if g_type.is_a(gobject.TYPE_BOXED): + bases = (Boxed,) + elif g_type.is_a(gobject.TYPE_POINTER) or g_type == gobject.TYPE_NONE: + bases = (Struct,) + else: + raise TypeError, "unable to create a wrapper for %s.%s" % (info.get_namespace(), info.get_name()) + metaclass = StructMeta + else: + raise NotImplementedError(info) + + name = info.get_name() + dict_ = { + '__info__': info, + '__module__': self.__namespace__, + '__gtype__': g_type + } + value = metaclass(name, bases, dict_) + + # Register the new Python wrapper. + if g_type != gobject.TYPE_NONE: + g_type.pytype = value + + elif isinstance(info, FunctionInfo): + value = Function(info) + elif isinstance(info, ConstantInfo): + value = info.get_value() + else: + raise NotImplementedError(info) + + self.__dict__[name] = value + return value + + @property + def __members__(self): + r = [] + for type_info in repository.get_infos(self.__namespace__): + r.append(type_info.get_name()) + return r + diff --git a/gi/overrides/Gdk.py b/gi/overrides/Gdk.py new file mode 100644 index 0000000..e3e2d29 --- /dev/null +++ b/gi/overrides/Gdk.py @@ -0,0 +1,21 @@ +import sys + +from ..module import DynamicModule + +class GdkModule(DynamicModule): + + def __init__(self): + super(GdkModule, self).__init__() + + initialized, argv = self.init_check(tuple(sys.argv)) + if not initialized: + raise RuntimeError("Gdk couldn't be initialized") + + def rectangle_new(self, x, y, width, height): + rectangle = self.Rectangle() + rectangle.x = x + rectangle.y = y + rectangle.width = width + rectangle.height = height + return rectangle + diff --git a/gi/overrides/Gtk.py b/gi/overrides/Gtk.py new file mode 100644 index 0000000..3de0e7e --- /dev/null +++ b/gi/overrides/Gtk.py @@ -0,0 +1,13 @@ +import sys + +from ..module import DynamicModule + +class GtkModule(DynamicModule): + + def __init__(self): + super(GtkModule, self).__init__() + + initialized, argv = self.init_check(tuple(sys.argv)) + if not initialized: + raise RuntimeError("Gtk couldn't be initialized") + diff --git a/gi/overrides/Makefile.am b/gi/overrides/Makefile.am new file mode 100644 index 0000000..1c3bee7 --- /dev/null +++ b/gi/overrides/Makefile.am @@ -0,0 +1,10 @@ +PLATFORM_VERSION = 2.0 + +pkgpyexecdir = $(pyexecdir)/gtk-2.0/gi + +pygioverridesdir = $(pkgpyexecdir)/overrides +pygioverrides_PYTHON = \ + Gtk.py \ + Gdk.py \ + __init__.py + diff --git a/gi/overrides/__init__.py b/gi/overrides/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/gi/overrides/__init__.py diff --git a/gi/pygi-argument.c b/gi/pygi-argument.c new file mode 100644 index 0000000..34d68e2 --- /dev/null +++ b/gi/pygi-argument.c @@ -0,0 +1,1976 @@ +/* -*- Mode: C; c-basic-offset: 4 -*- + * vim: tabstop=4 shiftwidth=4 expandtab + * + * Copyright (C) 2005-2009 Johan Dahlin <johan@gnome.org> + * + * pygi-argument.c: GArgument - PyObject conversion functions. + * + * 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 <string.h> +#include <time.h> + +#include <datetime.h> +#include <pygobject.h> + +static void +_pygi_g_type_tag_py_bounds (GITypeTag type_tag, + PyObject **lower, + PyObject **upper) +{ + switch(type_tag) { + case GI_TYPE_TAG_INT8: + *lower = PyInt_FromLong(-128); + *upper = PyInt_FromLong(127); + break; + case GI_TYPE_TAG_UINT8: + *upper = PyInt_FromLong(255); + *lower = PyInt_FromLong(0); + break; + case GI_TYPE_TAG_INT16: + *lower = PyInt_FromLong(-32768); + *upper = PyInt_FromLong(32767); + break; + case GI_TYPE_TAG_UINT16: + *upper = PyInt_FromLong(65535); + *lower = PyInt_FromLong(0); + break; + case GI_TYPE_TAG_INT32: + *lower = PyInt_FromLong(-2147483648); + *upper = PyInt_FromLong(2147483647); + break; + case GI_TYPE_TAG_UINT32: + /* Note: On 32-bit archs, this number doesn't fit in a long. */ + *upper = PyLong_FromLongLong(4294967295); + *lower = PyInt_FromLong(0); + break; + case GI_TYPE_TAG_INT64: + /* Note: On 32-bit archs, these numbers don't fit in a long. */ + *lower = PyLong_FromLongLong(-9223372036854775808u); + *upper = PyLong_FromLongLong(9223372036854775807); + break; + case GI_TYPE_TAG_UINT64: + *upper = PyLong_FromUnsignedLongLong(18446744073709551615u); + *lower = PyInt_FromLong(0); + break; + case GI_TYPE_TAG_SHORT: + *lower = PyInt_FromLong(G_MINSHORT); + *upper = PyInt_FromLong(G_MAXSHORT); + break; + case GI_TYPE_TAG_USHORT: + *upper = PyInt_FromLong(G_MAXUSHORT); + *lower = PyInt_FromLong(0); + break; + case GI_TYPE_TAG_INT: + *lower = PyInt_FromLong(G_MININT); + *upper = PyInt_FromLong(G_MAXINT); + break; + case GI_TYPE_TAG_UINT: + /* Note: On 32-bit archs, this number doesn't fit in a long. */ + *upper = PyLong_FromLongLong(G_MAXUINT); + *lower = PyInt_FromLong(0); + break; + case GI_TYPE_TAG_LONG: + case GI_TYPE_TAG_SSIZE: + *lower = PyInt_FromLong(G_MINLONG); + *upper = PyInt_FromLong(G_MAXLONG); + break; + case GI_TYPE_TAG_ULONG: + case GI_TYPE_TAG_SIZE: + *upper = PyLong_FromUnsignedLongLong(G_MAXULONG); + *lower = PyInt_FromLong(0); + break; + case GI_TYPE_TAG_FLOAT: + *upper = PyFloat_FromDouble(G_MAXFLOAT); + *lower = PyFloat_FromDouble(-G_MAXFLOAT); + break; + case GI_TYPE_TAG_DOUBLE: + *upper = PyFloat_FromDouble(G_MAXDOUBLE); + *lower = PyFloat_FromDouble(-G_MAXDOUBLE); + break; + default: + PyErr_SetString(PyExc_TypeError, "Non-numeric type tag"); + *lower = *upper = NULL; + return; + } +} + +gint +_pygi_g_registered_type_info_check_object (GIRegisteredTypeInfo *info, + gboolean is_instance, + PyObject *object) +{ + gint retval; + + GType g_type; + PyObject *py_type; + gchar *type_name_expected = NULL; + + g_type = g_registered_type_info_get_g_type(info); + + if (g_type != G_TYPE_NONE) { + py_type = _pygi_type_get_from_g_type(g_type); + } else { + py_type = _pygi_type_import_by_gi_info((GIBaseInfo *)info); + } + + if (py_type == NULL) { + return FALSE; + } + + g_assert(PyType_Check(py_type)); + + if (is_instance) { + retval = PyObject_IsInstance(object, py_type); + if (!retval) { + type_name_expected = _pygi_g_base_info_get_fullname( + (GIBaseInfo *)info); + } + } else { + if (!PyObject_Type(py_type)) { + type_name_expected = "type"; + retval = 0; + } else if (!PyType_IsSubtype((PyTypeObject *)object, + (PyTypeObject *)py_type)) { + type_name_expected = _pygi_g_base_info_get_fullname( + (GIBaseInfo *)info); + retval = 0; + } else { + retval = 1; + } + } + + Py_DECREF(py_type); + + if (!retval) { + PyTypeObject *object_type; + + if (type_name_expected == NULL) { + return -1; + } + + object_type = (PyTypeObject *)PyObject_Type(object); + if (object_type == NULL) { + return -1; + } + + PyErr_Format(PyExc_TypeError, "Must be %s, not %s", + type_name_expected, object_type->tp_name); + + g_free(type_name_expected); + } + + return retval; +} + +gint +_pygi_g_type_info_check_object (GITypeInfo *type_info, + gboolean may_be_null, + PyObject *object) +{ + GITypeTag type_tag; + gboolean is_pointer; + gint retval = 1; + + type_tag = g_type_info_get_tag(type_info); + is_pointer = g_type_info_is_pointer(type_info); + + if (is_pointer && may_be_null && object == Py_None) { + return retval; + } + + switch (type_tag) { + case GI_TYPE_TAG_VOID: + if (object != Py_None) { + PyErr_Format(PyExc_TypeError, "Must be %s, not %s", + Py_None->ob_type->tp_name, object->ob_type->tp_name); + retval = 0; + } + break; + case GI_TYPE_TAG_BOOLEAN: + /* No check; every Python object has a truth value. */ + break; + 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_SSIZE: + case GI_TYPE_TAG_SIZE: + case GI_TYPE_TAG_FLOAT: + case GI_TYPE_TAG_DOUBLE: + { + PyObject *number, *lower, *upper; + + if (!PyNumber_Check(object)) { + PyErr_Format(PyExc_TypeError, "Must be number, not %s", + object->ob_type->tp_name); + retval = 0; + break; + } + + if (type_tag == GI_TYPE_TAG_FLOAT || type_tag == GI_TYPE_TAG_DOUBLE) { + number = PyNumber_Float(object); + } else { + number = PyNumber_Int(object); + } + + _pygi_g_type_tag_py_bounds(type_tag, &lower, &upper); + + if (lower == NULL || upper == NULL || number == NULL) { + retval = -1; + goto check_number_release; + } + + /* Check bounds */ + if (PyObject_Compare(lower, number) > 0 + || PyObject_Compare(upper, number) < 0) { + PyObject *lower_str; + PyObject *upper_str; + + if (PyErr_Occurred()) { + retval = -1; + goto check_number_release; + } + + lower_str = PyObject_Str(lower); + upper_str = PyObject_Str(upper); + if (lower_str == NULL || upper_str == NULL) { + retval = -1; + goto check_number_error_release; + } + + PyErr_Format(PyExc_ValueError, "Must range from %s to %s", + PyString_AS_STRING(lower_str), + PyString_AS_STRING(upper_str)); + + retval = 0; + +check_number_error_release: + Py_XDECREF(lower_str); + Py_XDECREF(upper_str); + } + +check_number_release: + Py_XDECREF(number); + Py_XDECREF(lower); + Py_XDECREF(upper); + break; + } + case GI_TYPE_TAG_TIME_T: + if (!PyDateTime_Check(object)) { + PyErr_Format(PyExc_TypeError, "Must be datetime.datetime, not %s", + object->ob_type->tp_name); + retval = 0; + break; + } + break; + case GI_TYPE_TAG_GTYPE: + { + gint is_instance; + + is_instance = PyObject_IsInstance(object, (PyObject *)&PyGTypeWrapper_Type); + if (is_instance < 0) { + retval = -1; + break; + } + + if (!is_instance && (!PyType_Check(object) || pyg_type_from_object(object) == 0)) { + PyErr_Format(PyExc_TypeError, "Must be gobject.GType, not %s", + object->ob_type->tp_name); + retval = 0; + } + break; + } + case GI_TYPE_TAG_UTF8: + case GI_TYPE_TAG_FILENAME: + if (!PyString_Check(object) && (!may_be_null || object != Py_None)) { + PyErr_Format(PyExc_TypeError, "Must be string, not %s", + object->ob_type->tp_name); + retval = 0; + } + break; + case GI_TYPE_TAG_ARRAY: + { + gssize fixed_size; + Py_ssize_t length; + GITypeInfo *item_type_info; + Py_ssize_t i; + + if (!PySequence_Check(object)) { + PyErr_Format(PyExc_TypeError, "Must be sequence, not %s", + object->ob_type->tp_name); + retval = 0; + break; + } + + length = PySequence_Length(object); + if (length < 0) { + retval = -1; + break; + } + + fixed_size = g_type_info_get_array_fixed_size(type_info); + if (fixed_size >= 0 && length != fixed_size) { + PyErr_Format(PyExc_ValueError, "Must contain %zd items, not %zd", + fixed_size, length); + retval = 0; + break; + } + + item_type_info = g_type_info_get_param_type(type_info, 0); + g_assert(item_type_info != NULL); + + for (i = 0; i < length; i++) { + PyObject *item; + + item = PySequence_GetItem(object, i); + if (item == NULL) { + retval = -1; + break; + } + + retval = _pygi_g_type_info_check_object(item_type_info, FALSE, item); + + Py_DECREF(item); + + if (retval < 0) { + break; + } + if (!retval) { + _PyGI_ERROR_PREFIX("Item %zd: ", i); + break; + } + } + + g_base_info_unref((GIBaseInfo *)item_type_info); + + break; + } + case GI_TYPE_TAG_INTERFACE: + { + GIBaseInfo *info; + GIInfoType info_type; + + info = g_type_info_get_interface(type_info); + g_assert(info != NULL); + + info_type = g_base_info_get_type(info); + + switch (info_type) { + case GI_INFO_TYPE_CALLBACK: + /* TODO */ + PyErr_SetString(PyExc_NotImplementedError, "callback marshalling is not supported yet"); + break; + case GI_INFO_TYPE_ENUM: + case GI_INFO_TYPE_FLAGS: + retval = _pygi_g_registered_type_info_check_object((GIRegisteredTypeInfo *)info, TRUE, object); + break; + case GI_INFO_TYPE_STRUCT: + { + GType type; + + /* Handle special cases. */ + type = g_registered_type_info_get_g_type((GIRegisteredTypeInfo *)info); + if (g_type_is_a(type, G_TYPE_VALUE)) { + GType object_type; + object_type = pyg_type_from_object((PyObject *)object->ob_type); + if (object_type == G_TYPE_INVALID) { + PyErr_Format(PyExc_TypeError, "Must be of a known GType, not %s", + object->ob_type->tp_name); + retval = 0; + } + break; + } else if (g_type_is_a(type, G_TYPE_CLOSURE)) { + if (!PyCallable_Check(object)) { + PyErr_Format(PyExc_TypeError, "Must be callable, not %s", + object->ob_type->tp_name); + retval = 0; + } + break; + } + + /* Fallback. */ + } + case GI_INFO_TYPE_BOXED: + case GI_INFO_TYPE_OBJECT: + retval = _pygi_g_registered_type_info_check_object((GIRegisteredTypeInfo *)info, TRUE, object); + break; + case GI_INFO_TYPE_UNION: + /* TODO */ + PyErr_SetString(PyExc_NotImplementedError, "union marshalling is not supported yet"); + break; + default: + g_assert_not_reached(); + } + + g_base_info_unref(info); + break; + } + case GI_TYPE_TAG_GLIST: + case GI_TYPE_TAG_GSLIST: + { + Py_ssize_t length; + GITypeInfo *item_type_info; + Py_ssize_t i; + + if (!PySequence_Check(object)) { + PyErr_Format(PyExc_TypeError, "Must be sequence, not %s", + object->ob_type->tp_name); + retval = 0; + break; + } + + length = PySequence_Length(object); + if (length < 0) { + retval = -1; + break; + } + + item_type_info = g_type_info_get_param_type(type_info, 0); + g_assert(item_type_info != NULL); + + for (i = 0; i < length; i++) { + PyObject *item; + + item = PySequence_GetItem(object, i); + if (item == NULL) { + retval = -1; + break; + } + + retval = _pygi_g_type_info_check_object(item_type_info, FALSE, item); + + Py_DECREF(item); + + if (retval < 0) { + break; + } + if (!retval) { + _PyGI_ERROR_PREFIX("Item %zd: ", i); + break; + } + } + + g_base_info_unref((GIBaseInfo *)item_type_info); + break; + } + case GI_TYPE_TAG_GHASH: + { + Py_ssize_t length; + PyObject *keys; + PyObject *values; + GITypeInfo *key_type_info; + GITypeInfo *value_type_info; + Py_ssize_t i; + + if (!PyMapping_Check(object)) { + PyErr_Format(PyExc_TypeError, "Must be mapping, not %s", + object->ob_type->tp_name); + retval = 0; + break; + } + + length = PyMapping_Length(object); + if (length < 0) { + retval = -1; + break; + } + + keys = PyMapping_Keys(object); + if (keys == NULL) { + retval = -1; + break; + } + + values = PyMapping_Values(object); + if (values == NULL) { + retval = -1; + Py_DECREF(keys); + break; + } + + key_type_info = g_type_info_get_param_type(type_info, 0); + g_assert(key_type_info != NULL); + + value_type_info = g_type_info_get_param_type(type_info, 1); + g_assert(value_type_info != NULL); + + for (i = 0; i < length; i++) { + PyObject *key; + PyObject *value; + + key = PyList_GET_ITEM(keys, i); + value = PyList_GET_ITEM(values, i); + + retval = _pygi_g_type_info_check_object(key_type_info, FALSE, key); + if (retval < 0) { + break; + } + if (!retval) { + _PyGI_ERROR_PREFIX("Key %zd :", i); + break; + } + + retval = _pygi_g_type_info_check_object(value_type_info, FALSE, value); + if (retval < 0) { + break; + } + if (!retval) { + _PyGI_ERROR_PREFIX("Value %zd :", i); + break; + } + } + + g_base_info_unref((GIBaseInfo *)key_type_info); + g_base_info_unref((GIBaseInfo *)value_type_info); + Py_DECREF(values); + Py_DECREF(keys); + break; + } + case GI_TYPE_TAG_ERROR: + PyErr_SetString(PyExc_NotImplementedError, "Error marshalling is not supported yet"); + /* TODO */ + break; + } + + return retval; +} + +GArray * +_pygi_argument_to_array (GArgument *arg, + GArgument *args[], + GITypeInfo *type_info) +{ + GITypeInfo *item_type_info; + gboolean is_zero_terminated; + gsize item_size; + gssize length; + GArray *g_array; + + is_zero_terminated = g_type_info_is_zero_terminated(type_info); + item_type_info = g_type_info_get_param_type(type_info, 0); + + item_size = _pygi_g_type_info_size(item_type_info); + + g_base_info_unref((GIBaseInfo *)item_type_info); + + if (is_zero_terminated) { + length = g_strv_length(arg->v_pointer); + } else { + length = g_type_info_get_array_fixed_size(type_info); + if (length < 0) { + gint length_arg_pos; + + length_arg_pos = g_type_info_get_array_length(type_info); + g_assert(length_arg_pos >= 0); + + /* FIXME: Take into account the type of the argument. */ + length = args[length_arg_pos]->v_int; + } + } + + g_array = g_array_new(is_zero_terminated, FALSE, item_size); + + g_array->data = arg->v_pointer; + g_array->len = length; + + return g_array; +} + +GArgument +_pygi_argument_from_object (PyObject *object, + GITypeInfo *type_info, + GITransfer transfer) +{ + GArgument arg; + GITypeTag type_tag; + gboolean is_pointer; + + type_tag = g_type_info_get_tag(type_info); + is_pointer = g_type_info_is_pointer(type_info); + + if (object == Py_None && is_pointer + && type_tag != GI_TYPE_TAG_BOOLEAN) { /* We want None == FALSE. */ + arg.v_pointer = NULL; + return arg; + } + + switch (type_tag) { + case GI_TYPE_TAG_VOID: + arg.v_pointer = NULL; + break; + case GI_TYPE_TAG_BOOLEAN: + { + gboolean value; + + value = PyObject_IsTrue(object); + + if (is_pointer) { + g_warn_if_fail(transfer == GI_TRANSFER_NOTHING); + arg.v_pointer = g_try_new(gboolean, 1); + if (arg.v_pointer == NULL) { + PyErr_NoMemory(); + break; + } + *(gboolean *)arg.v_pointer = value; + } else { + arg.v_boolean = value; + } + + break; + } + 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_SHORT: + case GI_TYPE_TAG_USHORT: + case GI_TYPE_TAG_INT: + case GI_TYPE_TAG_LONG: + case GI_TYPE_TAG_SSIZE: + { + PyObject *int_; + glong value; + + int_ = PyNumber_Int(object); + if (int_ == NULL) { + break; + } + + value = PyInt_AsLong(int_); + Py_DECREF(int_); + + if (is_pointer) { + g_warn_if_fail(transfer == GI_TRANSFER_NOTHING); + arg.v_pointer = g_try_new(glong, 1); + if (arg.v_pointer == NULL) { + PyErr_NoMemory(); + break; + } + *(glong *)arg.v_pointer = value; + } else { + arg.v_long = value; + } + + break; + } + case GI_TYPE_TAG_UINT32: + case GI_TYPE_TAG_UINT64: + case GI_TYPE_TAG_UINT: + case GI_TYPE_TAG_ULONG: + case GI_TYPE_TAG_SIZE: + { + PyObject *number; + guint64 value; + + number = PyNumber_Int(object); + if (number == NULL) { + break; + } + + if (PyInt_Check(number)) { + value = PyInt_AS_LONG(number); + } else { + value = PyLong_AsUnsignedLongLong(number); + } + + Py_DECREF(number); + + if (is_pointer) { + g_warn_if_fail(transfer == GI_TRANSFER_NOTHING); + arg.v_pointer = g_try_new(guint64, 1); + if (arg.v_pointer == NULL) { + PyErr_NoMemory(); + break; + } + *(guint64 *)arg.v_pointer = value; + } else { + arg.v_uint64 = value; + } + + break; + } + case GI_TYPE_TAG_INT64: + { + PyObject *number; + gint64 value; + + number = PyNumber_Int(object); + if (number == NULL) { + break; + } + + if (PyInt_Check(number)) { + value = PyInt_AS_LONG(number); + } else { + value = PyLong_AsLongLong(number); + } + + Py_DECREF(number); + + if (is_pointer) { + g_warn_if_fail(transfer == GI_TRANSFER_NOTHING); + arg.v_pointer = g_try_new(gint64, 1); + if (arg.v_pointer == NULL) { + PyErr_NoMemory(); + break; + } + *(gint64 *)arg.v_pointer = value; + } else { + arg.v_int64 = value; + } + + break; + } + case GI_TYPE_TAG_FLOAT: + { + PyObject *float_; + gfloat value; + + float_ = PyNumber_Float(object); + if (float_ == NULL) { + break; + } + + value = (float)PyFloat_AsDouble(float_); + Py_DECREF(float_); + + if (is_pointer) { + g_warn_if_fail(transfer == GI_TRANSFER_NOTHING); + arg.v_pointer = g_try_new(gfloat, 1); + if (arg.v_pointer == NULL) { + PyErr_NoMemory(); + break; + } + *(gfloat *)arg.v_pointer = value; + } else { + arg.v_float = value; + } + + break; + } + case GI_TYPE_TAG_DOUBLE: + { + PyObject *float_; + gdouble value; + + float_ = PyNumber_Float(object); + if (float_ == NULL) { + break; + } + + value = PyFloat_AsDouble(float_); + Py_DECREF(float_); + + if (is_pointer) { + g_warn_if_fail(transfer == GI_TRANSFER_NOTHING); + arg.v_pointer = g_try_new(gdouble, 1); + if (arg.v_pointer == NULL) { + PyErr_NoMemory(); + break; + } + *(gdouble *)arg.v_pointer = value; + } else { + arg.v_double = value; + } + + break; + } + case GI_TYPE_TAG_TIME_T: + { + PyDateTime_DateTime *py_datetime; + struct tm datetime; + time_t time_; + + py_datetime = (PyDateTime_DateTime *)object; + + if (py_datetime->hastzinfo) { + if (PyErr_WarnEx(NULL, "tzinfo ignored; only local time is supported", 1) < 0) { + break; + } + } + + datetime.tm_sec = PyDateTime_DATE_GET_SECOND(py_datetime); + datetime.tm_min = PyDateTime_DATE_GET_MINUTE(py_datetime); + datetime.tm_hour = PyDateTime_DATE_GET_HOUR(py_datetime); + datetime.tm_mday = PyDateTime_GET_DAY(py_datetime); + datetime.tm_mon = PyDateTime_GET_MONTH(py_datetime) - 1; + datetime.tm_year = PyDateTime_GET_YEAR(py_datetime) - 1900; + datetime.tm_isdst = -1; + + time_ = mktime(&datetime); + if (time_ == -1) { + PyErr_SetString(PyExc_RuntimeError, "datetime conversion failed"); + break; + } + + if (is_pointer) { + g_warn_if_fail(transfer == GI_TRANSFER_NOTHING); + arg.v_pointer = g_try_new(time_t, 1); + if (arg.v_pointer == NULL) { + PyErr_NoMemory(); + break; + } + *(time_t *)arg.v_pointer = time_; + } else { + arg.v_long = time_; + } + + break; + } + case GI_TYPE_TAG_GTYPE: + { + GType type; + + type = pyg_type_from_object(object); + + if (is_pointer) { + g_warn_if_fail(transfer == GI_TRANSFER_NOTHING); + arg.v_pointer = g_try_new(GType, 1); + if (arg.v_pointer == NULL) { + PyErr_NoMemory(); + break; + } + *(GType *)arg.v_pointer = type; + } else { + arg.v_long = type; + } + + break; + } + case GI_TYPE_TAG_UTF8: + { + const gchar *string; + + g_assert(is_pointer); + + string = PyString_AsString(object); + + /* Don't need to check for errors, since g_strdup is NULL-proof. */ + arg.v_string = g_strdup(string); + break; + } + case GI_TYPE_TAG_FILENAME: + { + GError *error = NULL; + const gchar *string; + + g_assert(is_pointer); + + string = PyString_AsString(object); + if (string == NULL) { + break; + } + + arg.v_string = g_filename_from_utf8(string, -1, NULL, NULL, &error); + if (arg.v_string == NULL) { + PyErr_SetString(PyExc_Exception, error->message); + /* TODO: Convert the error to an exception. */ + } + + break; + } + case GI_TYPE_TAG_ARRAY: + { + Py_ssize_t length; + gboolean is_zero_terminated; + GITypeInfo *item_type_info; + gsize item_size; + GArray *array; + GITransfer item_transfer; + Py_ssize_t i; + + length = PySequence_Length(object); + if (length < 0) { + break; + } + + is_zero_terminated = g_type_info_is_zero_terminated(type_info); + item_type_info = g_type_info_get_param_type(type_info, 0); + + item_size = _pygi_g_type_info_size(item_type_info); + + array = g_array_sized_new(is_zero_terminated, FALSE, item_size, length); + if (array == NULL) { + g_base_info_unref((GIBaseInfo *)item_type_info); + PyErr_NoMemory(); + break; + } + + item_transfer = transfer == GI_TRANSFER_CONTAINER ? GI_TRANSFER_NOTHING : transfer; + + for (i = 0; i < length; i++) { + PyObject *py_item; + GArgument item; + + py_item = PySequence_GetItem(object, i); + if (py_item == NULL) { + goto array_item_error; + } + + item = _pygi_argument_from_object(py_item, item_type_info, item_transfer); + + Py_DECREF(py_item); + + if (PyErr_Occurred()) { + goto array_item_error; + } + + g_array_insert_val(array, i, item); + continue; + +array_item_error: + /* Free everything we have converted so far. */ + _pygi_argument_release((GArgument *)&array, type_info, + GI_TRANSFER_NOTHING, GI_DIRECTION_IN); + array = NULL; + + _PyGI_ERROR_PREFIX("Item %zd: ", i); + break; + } + + arg.v_pointer = array; + + g_base_info_unref((GIBaseInfo *)item_type_info); + 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_CALLBACK: + PyErr_SetString(PyExc_NotImplementedError, "callback marshalling is not supported yet"); + /* TODO */ + break; + case GI_INFO_TYPE_BOXED: + case GI_INFO_TYPE_STRUCT: + { + GType type; + + type = g_registered_type_info_get_g_type((GIRegisteredTypeInfo *)info); + + /* Handle special cases first. */ + if (g_type_is_a(type, G_TYPE_VALUE)) { + GValue *value; + GType object_type; + gint retval; + + object_type = pyg_type_from_object((PyObject *)object->ob_type); + if (object_type == G_TYPE_INVALID) { + PyErr_SetString(PyExc_RuntimeError, "unable to retrieve object's GType"); + break; + } + + g_assert(is_pointer); + g_warn_if_fail(transfer == GI_TRANSFER_NOTHING); + + value = g_slice_new0(GValue); + g_value_init(value, object_type); + + retval = pyg_value_from_pyobject(value, object); + if (retval < 0) { + g_slice_free(GValue, value); + PyErr_SetString(PyExc_RuntimeError, "PyObject conversion to GValue failed"); + break; + } + + arg.v_pointer = value; + } else if (g_type_is_a(type, G_TYPE_CLOSURE)) { + GClosure *closure; + + g_assert(is_pointer); + g_warn_if_fail(transfer == GI_TRANSFER_NOTHING); + + closure = pyg_closure_new(object, NULL, NULL); + if (closure == NULL) { + PyErr_SetString(PyExc_RuntimeError, "PyObject conversion to GClosure failed"); + break; + } + + arg.v_pointer = closure; + } else if (g_type_is_a(type, G_TYPE_BOXED)) { + g_assert(is_pointer); + arg.v_pointer = pyg_boxed_get(object, void); + if (transfer == GI_TRANSFER_EVERYTHING) { + arg.v_pointer = g_boxed_copy(type, arg.v_pointer); + } + } else if (g_type_is_a(type, G_TYPE_POINTER) || type == G_TYPE_NONE) { + g_warn_if_fail(!is_pointer || transfer == GI_TRANSFER_NOTHING); + arg.v_pointer = pyg_pointer_get(object, void); + } else { + PyErr_Format(PyExc_NotImplementedError, "structure type '%s' is not supported yet", g_type_name(type)); + } + + break; + } + case GI_INFO_TYPE_ENUM: + case GI_INFO_TYPE_FLAGS: + { + PyObject *int_; + glong value; + + int_ = PyNumber_Int(object); + if (int_ == NULL) { + break; + } + + value = PyInt_AsLong(int_); + Py_DECREF(int_); + + if (is_pointer) { + g_warn_if_fail(transfer == GI_TRANSFER_NOTHING); + arg.v_pointer = g_try_new(glong, 1); + if (arg.v_pointer == NULL) { + PyErr_NoMemory(); + break; + } + *(glong *)arg.v_pointer = value; + } else { + arg.v_long = value; + } + + break; + } + case GI_INFO_TYPE_OBJECT: + g_assert(is_pointer); + + arg.v_pointer = pygobject_get(object); + if (transfer == GI_TRANSFER_EVERYTHING) { + g_object_ref(arg.v_pointer); + } + + break; + case GI_INFO_TYPE_UNION: + PyErr_SetString(PyExc_NotImplementedError, "union marshalling is not supported yet"); + /* TODO */ + break; + default: + g_assert_not_reached(); + } + g_base_info_unref(info); + break; + } + case GI_TYPE_TAG_GLIST: + case GI_TYPE_TAG_GSLIST: + { + Py_ssize_t length; + GITypeInfo *item_type_info; + GSList *list = NULL; + GITransfer item_transfer; + Py_ssize_t i; + + g_assert(is_pointer); + + length = PySequence_Length(object); + if (length < 0) { + break; + } + + item_type_info = g_type_info_get_param_type(type_info, 0); + g_assert(item_type_info != NULL); + + item_transfer = transfer == GI_TRANSFER_CONTAINER ? GI_TRANSFER_NOTHING : transfer; + + for (i = length - 1; i >= 0; i--) { + PyObject *py_item; + GArgument item; + + py_item = PySequence_GetItem(object, i); + if (py_item == NULL) { + goto list_item_error; + } + + item = _pygi_argument_from_object(py_item, item_type_info, item_transfer); + + Py_DECREF(py_item); + + if (PyErr_Occurred()) { + goto list_item_error; + } + + if (type_tag == GI_TYPE_TAG_GLIST) { + list = (GSList *)g_list_prepend((GList *)list, item.v_pointer); + } else { + list = g_slist_prepend(list, item.v_pointer); + } + + continue; + +list_item_error: + /* Free everything we have converted so far. */ + _pygi_argument_release((GArgument *)&list, type_info, + GI_TRANSFER_NOTHING, GI_DIRECTION_IN); + list = NULL; + + _PyGI_ERROR_PREFIX("Item %zd: ", i); + break; + } + + arg.v_pointer = list; + + g_base_info_unref((GIBaseInfo *)item_type_info); + + break; + } + case GI_TYPE_TAG_GHASH: + { + Py_ssize_t length; + PyObject *keys; + PyObject *values; + GITypeInfo *key_type_info; + GITypeInfo *value_type_info; + GITypeTag key_type_tag; + GHashFunc hash_func; + GEqualFunc equal_func; + GHashTable *hash_table; + GITransfer item_transfer; + Py_ssize_t i; + + g_assert(is_pointer); + + length = PyMapping_Length(object); + if (length < 0) { + break; + } + + keys = PyMapping_Keys(object); + if (keys == NULL) { + break; + } + + values = PyMapping_Values(object); + if (values == NULL) { + Py_DECREF(keys); + break; + } + + key_type_info = g_type_info_get_param_type(type_info, 0); + g_assert(key_type_info != NULL); + + value_type_info = g_type_info_get_param_type(type_info, 1); + g_assert(value_type_info != NULL); + + key_type_tag = g_type_info_get_tag(key_type_info); + + switch(key_type_tag) { + case GI_TYPE_TAG_UTF8: + case GI_TYPE_TAG_FILENAME: + hash_func = g_str_hash; + equal_func = g_str_equal; + break; + default: + hash_func = NULL; + equal_func = NULL; + } + + hash_table = g_hash_table_new(hash_func, equal_func); + if (hash_table == NULL) { + PyErr_NoMemory(); + goto hash_table_release; + } + + item_transfer = transfer == GI_TRANSFER_CONTAINER ? GI_TRANSFER_NOTHING : transfer; + + for (i = 0; i < length; i++) { + PyObject *py_key; + PyObject *py_value; + GArgument key; + GArgument value; + + py_key = PyList_GET_ITEM(keys, i); + py_value = PyList_GET_ITEM(values, i); + + key = _pygi_argument_from_object(py_key, key_type_info, item_transfer); + if (PyErr_Occurred()) { + goto hash_table_item_error; + } + + value = _pygi_argument_from_object(py_value, value_type_info, item_transfer); + if (PyErr_Occurred()) { + _pygi_argument_release(&key, type_info, GI_TRANSFER_NOTHING, GI_DIRECTION_IN); + goto hash_table_item_error; + } + + g_hash_table_insert(hash_table, key.v_pointer, value.v_pointer); + continue; + +hash_table_item_error: + /* Free everything we have converted so far. */ + _pygi_argument_release((GArgument *)&hash_table, type_info, + GI_TRANSFER_NOTHING, GI_DIRECTION_IN); + hash_table = NULL; + + _PyGI_ERROR_PREFIX("Item %zd: ", i); + break; + } + + arg.v_pointer = hash_table; + +hash_table_release: + g_base_info_unref((GIBaseInfo *)key_type_info); + g_base_info_unref((GIBaseInfo *)value_type_info); + Py_DECREF(keys); + Py_DECREF(values); + break; + } + case GI_TYPE_TAG_ERROR: + PyErr_SetString(PyExc_NotImplementedError, "error marshalling is not supported yet"); + /* TODO */ + break; + } + + return arg; +} + +PyObject * +_pygi_argument_to_object (GArgument *arg, + GITypeInfo *type_info, + GITransfer transfer) +{ + GITypeTag type_tag; + gboolean is_pointer; + PyObject *object = NULL; + + type_tag = g_type_info_get_tag(type_info); + is_pointer = g_type_info_is_pointer(type_info); + + if (is_pointer && arg->v_pointer == NULL) { + Py_RETURN_NONE; + } + + switch (type_tag) { + case GI_TYPE_TAG_VOID: + Py_INCREF(Py_None); + object = Py_None; + break; + case GI_TYPE_TAG_BOOLEAN: + { + gboolean value; + value = is_pointer ? *(gboolean *)arg->v_pointer : arg->v_boolean; + object = PyBool_FromLong(value); + break; + } + case GI_TYPE_TAG_INT8: + { + gint8 value; + value = is_pointer ? *(gint8 *)arg->v_pointer : arg->v_int8; + object = PyInt_FromLong(value); + break; + } + case GI_TYPE_TAG_UINT8: + { + guint8 value; + value = is_pointer ? *(guint8 *)arg->v_pointer : arg->v_uint8; + object = PyInt_FromLong(value); + break; + } + case GI_TYPE_TAG_INT16: + { + gint16 value; + value = is_pointer ? *(gint16 *)arg->v_pointer : arg->v_int16; + object = PyInt_FromLong(value); + break; + } + case GI_TYPE_TAG_UINT16: + { + guint16 value; + value = is_pointer ? *(guint16 *)arg->v_pointer : arg->v_uint16; + object = PyInt_FromLong(value); + break; + } + case GI_TYPE_TAG_INT32: + { + gint32 value; + value = is_pointer ? *(gint32 *)arg->v_pointer : arg->v_int32; + object = PyInt_FromLong(value); + break; + } + case GI_TYPE_TAG_UINT32: + { + guint32 value; + value = is_pointer ? *(guint32 *)arg->v_pointer : arg->v_uint32; + object = PyInt_FromLong(value); + break; + } + case GI_TYPE_TAG_INT64: + { + gint64 value; + value = is_pointer ? *(gint64 *)arg->v_pointer : arg->v_int64; + object = PyLong_FromLongLong(value); + break; + } + case GI_TYPE_TAG_UINT64: + { + guint64 value; + value = is_pointer ? *(guint64 *)arg->v_pointer : arg->v_uint64; + object = PyLong_FromUnsignedLongLong(value); + break; + } + case GI_TYPE_TAG_SHORT: + { + gshort value; + value = is_pointer ? *(gshort *)arg->v_pointer : arg->v_short; + object = PyInt_FromLong(value); + break; + } + case GI_TYPE_TAG_USHORT: + { + gushort value; + value = is_pointer ? *(gushort *)arg->v_pointer : arg->v_ushort; + object = PyInt_FromLong(value); + break; + } + case GI_TYPE_TAG_INT: + { + gint value; + value = is_pointer ? *(gint *)arg->v_pointer : arg->v_int; + object = PyInt_FromLong(value); + break; + } + case GI_TYPE_TAG_UINT: + { + guint value; + value = is_pointer ? *(guint *)arg->v_pointer : arg->v_uint; + object = PyLong_FromLongLong(value); + break; + } + case GI_TYPE_TAG_LONG: + { + glong value; + value = is_pointer ? *(glong *)arg->v_pointer : arg->v_long; + object = PyInt_FromLong(value); + break; + } + case GI_TYPE_TAG_ULONG: + { + gulong value; + value = is_pointer ? *(gulong *)arg->v_pointer : arg->v_ulong; + object = PyLong_FromUnsignedLongLong(value); + break; + } + case GI_TYPE_TAG_SSIZE: + { + gssize value; + value = is_pointer ? *(gssize *)arg->v_pointer : arg->v_ssize; + object = PyInt_FromLong(value); + break; + } + case GI_TYPE_TAG_SIZE: + { + gsize value; + value = is_pointer ? *(gsize *)arg->v_pointer : arg->v_size; + object = PyLong_FromUnsignedLongLong(value); + break; + } + case GI_TYPE_TAG_FLOAT: + { + gfloat value; + value = is_pointer ? *(gfloat *)arg->v_pointer : arg->v_float; + object = PyFloat_FromDouble(value); + break; + } + case GI_TYPE_TAG_DOUBLE: + { + gdouble value; + value = is_pointer ? *(gdouble *)arg->v_pointer : arg->v_double; + object = PyFloat_FromDouble(value); + break; + } + case GI_TYPE_TAG_TIME_T: + { + time_t *time_; + struct tm *datetime; + time_ = is_pointer ? arg->v_pointer : &arg->v_long; + datetime = localtime(time_); + object = PyDateTime_FromDateAndTime( + datetime->tm_year + 1900, + datetime->tm_mon + 1, + datetime->tm_mday, + datetime->tm_hour, + datetime->tm_min, + datetime->tm_sec, + 0); + break; + } + case GI_TYPE_TAG_GTYPE: + { + GType type; + type = is_pointer ? *(GType *)arg->v_pointer : arg->v_long; + object = pyg_type_wrapper_new(type); + break; + } + case GI_TYPE_TAG_UTF8: + g_assert(is_pointer); + object = PyString_FromString(arg->v_string); + break; + case GI_TYPE_TAG_FILENAME: + { + GError *error = NULL; + gchar *string; + + g_assert(is_pointer); + + string = g_filename_to_utf8(arg->v_string, -1, NULL, NULL, &error); + if (string == NULL) { + PyErr_SetString(PyExc_Exception, error->message); + /* TODO: Convert the error to an exception. */ + break; + } + + object = PyString_FromString(string); + + g_free(string); + + break; + } + case GI_TYPE_TAG_ARRAY: + { + GArray *array; + GITypeInfo *item_type_info; + GITransfer item_transfer; + gsize i; + + array = arg->v_pointer; + + object = PyTuple_New(array->len); + if (object == NULL) { + break; + } + + item_type_info = g_type_info_get_param_type(type_info, 0); + g_assert(item_type_info != NULL); + + item_transfer = transfer == GI_TRANSFER_CONTAINER ? GI_TRANSFER_NOTHING : transfer; + + for(i = 0; i < array->len; i++) { + GArgument item; + PyObject *py_item; + + item = _g_array_index(array, GArgument, i); + py_item = _pygi_argument_to_object(&item, item_type_info, item_transfer); + if (py_item == NULL) { + Py_CLEAR(object); + _PyGI_ERROR_PREFIX("Item %zu: ", i); + break; + } + + PyTuple_SET_ITEM(object, i, py_item); + } + + g_base_info_unref((GIBaseInfo *)item_type_info); + 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_CALLBACK: + { + PyErr_SetString(PyExc_NotImplementedError, "callback marshalling is not supported yet"); + /* TODO */ + break; + } + case GI_INFO_TYPE_BOXED: + 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_VALUE)) { + g_assert(is_pointer); + object = pyg_value_as_pyobject(arg->v_pointer, FALSE); + } else if (g_type_is_a(type, G_TYPE_BOXED)) { + g_assert(is_pointer); + object = pyg_boxed_new(type, arg->v_pointer, FALSE, transfer == GI_TRANSFER_EVERYTHING); + } else if (g_type_is_a(type, G_TYPE_POINTER)) { + PyObject *py_type; + + g_assert(is_pointer); + + py_type = _pygi_type_get_from_g_type(type); + + if (py_type == NULL || !PyType_IsSubtype((PyTypeObject *)type, &PyGIStruct_Type)) { + g_warn_if_fail(transfer == GI_TRANSFER_NOTHING); + object = pyg_pointer_new(type, arg->v_pointer); + } else { + object = _pygi_struct_new((PyTypeObject *)py_type, arg->v_pointer, transfer == GI_TRANSFER_EVERYTHING); + } + + Py_XDECREF(py_type); + } else if (type == G_TYPE_NONE) { + PyObject *py_type; + + py_type = _pygi_type_import_by_gi_info(info); + if (py_type == NULL) { + break; + } + + object = _pygi_struct_new((PyTypeObject *)py_type, arg->v_pointer, + transfer == GI_TRANSFER_EVERYTHING); + + Py_DECREF(py_type); + } else { + PyErr_Format(PyExc_NotImplementedError, "structure type '%s' is not supported yet", g_type_name(type)); + } + + break; + } + case GI_INFO_TYPE_ENUM: + case GI_INFO_TYPE_FLAGS: + { + GType type; + glong value; + + type = g_registered_type_info_get_g_type((GIRegisteredTypeInfo *)info); + value = is_pointer ? *(glong *)arg->v_pointer : arg->v_long; + + if (info_type == GI_INFO_TYPE_ENUM) { + object = pyg_enum_from_gtype(type, value); + } else { + object = pyg_flags_from_gtype(type, value); + } + + break; + } + case GI_INFO_TYPE_OBJECT: + g_assert(is_pointer); + object = pygobject_new(arg->v_pointer); + break; + case GI_INFO_TYPE_UNION: + /* TODO */ + PyErr_SetString(PyExc_NotImplementedError, "union marshalling is not supported yet"); + break; + default: + g_assert_not_reached(); + } + + g_base_info_unref(info); + break; + } + case GI_TYPE_TAG_GLIST: + case GI_TYPE_TAG_GSLIST: + { + GSList *list; + gsize length; + GITypeInfo *item_type_info; + GITransfer item_transfer; + gsize i; + + g_assert(is_pointer); + + list = arg->v_pointer; + length = g_slist_length(list); + + object = PyList_New(length); + if (object == NULL) { + break; + } + + item_type_info = g_type_info_get_param_type(type_info, 0); + g_assert(item_type_info != NULL); + + item_transfer = transfer == GI_TRANSFER_CONTAINER ? GI_TRANSFER_NOTHING : transfer; + + for (i = 0; list != NULL; list = g_slist_next(list), i++) { + GArgument item; + PyObject *py_item; + + item.v_pointer = list->data; + + py_item = _pygi_argument_to_object(&item, item_type_info, item_transfer); + if (py_item == NULL) { + Py_CLEAR(object); + _PyGI_ERROR_PREFIX("Item %zu: ", i); + break; + } + + PyList_SET_ITEM(object, i, py_item); + } + + g_base_info_unref((GIBaseInfo *)item_type_info); + break; + } + case GI_TYPE_TAG_GHASH: + { + GITypeInfo *key_type_info; + GITypeInfo *value_type_info; + GITransfer item_transfer; + GHashTableIter hash_table_iter; + GArgument key; + GArgument value; + + g_assert(is_pointer); + + object = PyDict_New(); + if (object == NULL) { + break; + } + + key_type_info = g_type_info_get_param_type(type_info, 0); + g_assert(key_type_info != NULL); + + value_type_info = g_type_info_get_param_type(type_info, 1); + g_assert(value_type_info != NULL); + + item_transfer = transfer == GI_TRANSFER_CONTAINER ? GI_TRANSFER_NOTHING : transfer; + + g_hash_table_iter_init(&hash_table_iter, (GHashTable *)arg->v_pointer); + while (g_hash_table_iter_next(&hash_table_iter, &key.v_pointer, &value.v_pointer)) { + PyObject *py_key; + PyObject *py_value; + int retval; + + py_key = _pygi_argument_to_object(&key, key_type_info, item_transfer); + if (py_key == NULL) { + break; + } + + py_value = _pygi_argument_to_object(&value, value_type_info, item_transfer); + if (py_value == NULL) { + Py_DECREF(py_key); + break; + } + + retval = PyDict_SetItem(object, py_key, py_value); + + Py_DECREF(py_key); + Py_DECREF(py_value); + + if (retval < 0) { + Py_CLEAR(object); + break; + } + } + + g_base_info_unref((GIBaseInfo *)key_type_info); + g_base_info_unref((GIBaseInfo *)value_type_info); + break; + } + case GI_TYPE_TAG_ERROR: + /* Errors should be handled in the invoke wrapper. */ + g_assert_not_reached(); + } + + return object; +} + +void +_pygi_argument_release (GArgument *arg, + GITypeInfo *type_info, + GITransfer transfer, + GIDirection direction) +{ + GITypeTag type_tag; + gboolean is_pointer; + + type_tag = g_type_info_get_tag(type_info); + is_pointer = g_type_info_is_pointer(type_info); + + if (is_pointer && arg->v_pointer == NULL) { + return; + } + + switch(type_tag) { + case GI_TYPE_TAG_VOID: + 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_SSIZE: + case GI_TYPE_TAG_SIZE: + case GI_TYPE_TAG_FLOAT: + case GI_TYPE_TAG_DOUBLE: + case GI_TYPE_TAG_TIME_T: + case GI_TYPE_TAG_GTYPE: + if (is_pointer) { + g_warn_if_fail(transfer == GI_TRANSFER_NOTHING); + if ((direction == GI_DIRECTION_IN && transfer == GI_TRANSFER_NOTHING) + || (direction == GI_DIRECTION_OUT && transfer == GI_TRANSFER_EVERYTHING)) { + g_free(arg->v_pointer); + } + } + break; + case GI_TYPE_TAG_FILENAME: + case GI_TYPE_TAG_UTF8: + g_assert(is_pointer); + if ((direction == GI_DIRECTION_IN && transfer == GI_TRANSFER_NOTHING) + || (direction == GI_DIRECTION_OUT && transfer == GI_TRANSFER_EVERYTHING)) { + g_free(arg->v_string); + } + break; + case GI_TYPE_TAG_ARRAY: + { + GArray *array; + gsize i; + + g_assert(is_pointer); + + array = arg->v_pointer; + + if ((direction == GI_DIRECTION_IN && transfer != GI_TRANSFER_EVERYTHING) + || (direction == GI_DIRECTION_OUT && transfer == GI_TRANSFER_EVERYTHING)) { + GITypeInfo *item_type_info; + GITransfer item_transfer; + + item_type_info = g_type_info_get_param_type(type_info, 0); + + item_transfer = direction == GI_DIRECTION_IN ? GI_TRANSFER_NOTHING : GI_TRANSFER_EVERYTHING; + + /* Free the items */ + for (i = 0; i < array->len; i++) { + GArgument item; + item = _g_array_index(array, GArgument, i); + _pygi_argument_release(&item, item_type_info, item_transfer, direction); + } + + g_base_info_unref((GIBaseInfo *)item_type_info); + } + + if ((direction == GI_DIRECTION_IN && transfer == GI_TRANSFER_NOTHING) + || (direction == GI_DIRECTION_OUT && transfer != GI_TRANSFER_NOTHING)) { + g_array_free(array, TRUE); + } + + 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_CALLBACK: + /* TODO */ + break; + case GI_INFO_TYPE_BOXED: + 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_VALUE)) { + GValue *value; + + g_assert(is_pointer); + + value = arg->v_pointer; + + if ((direction == GI_DIRECTION_IN && transfer != GI_TRANSFER_EVERYTHING) + || (direction == GI_DIRECTION_OUT && transfer == GI_TRANSFER_EVERYTHING)) { + g_value_unset(value); + } + + if ((direction == GI_DIRECTION_IN && transfer == GI_TRANSFER_NOTHING) + || (direction == GI_DIRECTION_OUT && transfer != GI_TRANSFER_NOTHING)) { + g_slice_free(GValue, value); + } + } else if (g_type_is_a(type, G_TYPE_CLOSURE)) { + g_assert(is_pointer); + if (direction == GI_DIRECTION_IN && transfer == GI_TRANSFER_NOTHING) { + g_closure_unref(arg->v_pointer); + } + } else if (g_type_is_a(type, G_TYPE_BOXED)) { + g_assert(is_pointer); + } else if (g_type_is_a(type, G_TYPE_POINTER) || type == G_TYPE_NONE) { + g_warn_if_fail(!is_pointer || transfer == GI_TRANSFER_NOTHING); + } + + break; + } + case GI_INFO_TYPE_ENUM: + case GI_INFO_TYPE_FLAGS: + if (is_pointer) { + g_warn_if_fail(transfer == GI_TRANSFER_NOTHING); + if ((direction == GI_DIRECTION_IN && transfer == GI_TRANSFER_NOTHING) + || (direction == GI_DIRECTION_OUT && transfer == GI_TRANSFER_EVERYTHING)) { + g_free(arg->v_pointer); + } + } + break; + case GI_INFO_TYPE_OBJECT: + g_assert(is_pointer); + if (direction == GI_DIRECTION_OUT && transfer == GI_TRANSFER_EVERYTHING) { + g_object_unref(arg->v_pointer); + } + break; + case GI_INFO_TYPE_UNION: + /* TODO */ + break; + default: + g_assert_not_reached(); + } + + g_base_info_unref(info); + break; + } + case GI_TYPE_TAG_GLIST: + case GI_TYPE_TAG_GSLIST: + { + GSList *list; + + g_assert(is_pointer); + + list = arg->v_pointer; + + if ((direction == GI_DIRECTION_IN && transfer != GI_TRANSFER_EVERYTHING) + || (direction == GI_DIRECTION_OUT && transfer == GI_TRANSFER_EVERYTHING)) { + GITypeInfo *item_type_info; + GITransfer item_transfer; + GSList *item; + + item_type_info = g_type_info_get_param_type(type_info, 0); + g_assert(item_type_info != NULL); + + item_transfer = direction == GI_DIRECTION_IN ? GI_TRANSFER_NOTHING : GI_TRANSFER_EVERYTHING; + + /* Free the items */ + for (item = list; item != NULL; item = g_slist_next(item)) { + _pygi_argument_release((GArgument *)&item->data, item_type_info, + item_transfer, direction); + } + + g_base_info_unref((GIBaseInfo *)item_type_info); + } + + if ((direction == GI_DIRECTION_IN && transfer == GI_TRANSFER_NOTHING) + || (direction == GI_DIRECTION_OUT && transfer != GI_TRANSFER_NOTHING)) { + if (type_tag == GI_TYPE_TAG_GLIST) { + g_list_free((GList *)list); + } else { + /* type_tag == GI_TYPE_TAG_GSLIST */ + g_slist_free(list); + } + } + + break; + } + case GI_TYPE_TAG_GHASH: + { + GHashTable *hash_table; + + g_assert(is_pointer); + + hash_table = arg->v_pointer; + + if (direction == GI_DIRECTION_IN && transfer != GI_TRANSFER_EVERYTHING) { + /* We created the table without a destroy function, so keys and + * values need to be released. */ + GITypeInfo *key_type_info; + GITypeInfo *value_type_info; + GITransfer item_transfer; + GHashTableIter hash_table_iter; + gpointer key; + gpointer value; + + key_type_info = g_type_info_get_param_type(type_info, 0); + g_assert(key_type_info != NULL); + + value_type_info = g_type_info_get_param_type(type_info, 1); + g_assert(value_type_info != NULL); + + if (direction == GI_DIRECTION_IN) { + item_transfer = GI_TRANSFER_NOTHING; + } else { + item_transfer = GI_TRANSFER_EVERYTHING; + } + + g_hash_table_iter_init(&hash_table_iter, hash_table); + while (g_hash_table_iter_next(&hash_table_iter, &key, &value)) { + _pygi_argument_release((GArgument *)&key, key_type_info, + item_transfer, direction); + _pygi_argument_release((GArgument *)&value, value_type_info, + item_transfer, direction); + } + + g_base_info_unref((GIBaseInfo *)key_type_info); + g_base_info_unref((GIBaseInfo *)value_type_info); + } else if (direction == GI_DIRECTION_OUT && transfer == GI_TRANSFER_CONTAINER) { + /* Be careful to avoid keys and values being freed if the + * callee gave a destroy function. */ + g_hash_table_steal_all(hash_table); + } + + if ((direction == GI_DIRECTION_IN && transfer == GI_TRANSFER_NOTHING) + || (direction == GI_DIRECTION_OUT && transfer != GI_TRANSFER_NOTHING)) { + g_hash_table_unref(hash_table); + } + + break; + } + case GI_TYPE_TAG_ERROR: + { + GError *error; + + g_assert(is_pointer); + + error = *(GError **)arg->v_pointer; + + if (error != NULL) { + g_error_free(error); + } + + g_slice_free(GError *, arg->v_pointer); + break; + } + } +} + +void +_pygi_argument_init (void) +{ + PyDateTime_IMPORT; + _pygobject_import(); +} + diff --git a/gi/pygi-argument.h b/gi/pygi-argument.h new file mode 100644 index 0000000..59458fc --- /dev/null +++ b/gi/pygi-argument.h @@ -0,0 +1,65 @@ +/* -*- Mode: C; c-basic-offset: 4 -*- + * vim: tabstop=4 shiftwidth=4 expandtab + * + * Copyright (C) 2005-2009 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 Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#ifndef __PYGI_ARGUMENT_H__ +#define __PYGI_ARGUMENT_H__ + +#include <Python.h> + +#include <girepository.h> + +G_BEGIN_DECLS + + +/* Private */ + +gint _pygi_g_type_info_check_object (GITypeInfo *type_info, + gboolean may_be_null, + PyObject *object); + +gint _pygi_g_registered_type_info_check_object (GIRegisteredTypeInfo *info, + gboolean is_instance, + PyObject *object); + + +GArray* _pygi_argument_to_array (GArgument *arg, + GArgument *args[], + GITypeInfo *type_info); + +GArgument _pygi_argument_from_object (PyObject *object, + GITypeInfo *type_info, + GITransfer transfer); + +PyObject* _pygi_argument_to_object (GArgument *arg, + GITypeInfo *type_info, + GITransfer transfer); + + +void _pygi_argument_release (GArgument *arg, + GITypeInfo *type_info, + GITransfer transfer, + GIDirection direction); + +void _pygi_argument_init (void); + +G_END_DECLS + +#endif /* __PYGI_ARGUMENT_H__ */ 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 +} diff --git a/gi/pygi-info.h b/gi/pygi-info.h new file mode 100644 index 0000000..437ef9a --- /dev/null +++ b/gi/pygi-info.h @@ -0,0 +1,64 @@ +/* -*- Mode: C; c-basic-offset: 4 -*- + * vim: tabstop=4 shiftwidth=4 expandtab + * + * Copyright (C) 2005-2009 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 Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#ifndef __PYGI_INFO_H__ +#define __PYGI_INFO_H__ + +#include <Python.h> + +#include <girepository.h> + +G_BEGIN_DECLS + +gboolean pygi_g_struct_info_is_simple (GIStructInfo *struct_info); + + +/* Private */ + +extern PyTypeObject PyGIBaseInfo_Type; +extern PyTypeObject PyGICallableInfo_Type; +extern PyTypeObject PyGIFunctionInfo_Type; +extern PyTypeObject PyGIRegisteredTypeInfo_Type; +extern PyTypeObject PyGIStructInfo_Type; +extern PyTypeObject PyGIEnumInfo_Type; +extern PyTypeObject PyGIObjectInfo_Type; +extern PyTypeObject PyGIInterfaceInfo_Type; +extern PyTypeObject PyGIConstantInfo_Type; +extern PyTypeObject PyGIValueInfo_Type; +extern PyTypeObject PyGIFieldInfo_Type; +extern PyTypeObject PyGIUnresolvedInfo_Type; + +#define PyGIBaseInfo_GET_GI_INFO(object) g_base_info_ref(((PyGIBaseInfo *)object)->info) + +PyObject* _pygi_info_new (GIBaseInfo *info); +GIBaseInfo* _pygi_object_get_gi_info (PyObject *object, + PyTypeObject *type); + +gchar* _pygi_g_base_info_get_fullname (GIBaseInfo *info); + +gsize _pygi_g_type_tag_size (GITypeTag type_tag); +gsize _pygi_g_type_info_size (GITypeInfo *type_info); + +void _pygi_info_register_types (PyObject *m); + +G_END_DECLS + +#endif /* __PYGI_INFO_H__ */ diff --git a/gi/pygi-private.h b/gi/pygi-private.h new file mode 100644 index 0000000..6ca85c8 --- /dev/null +++ b/gi/pygi-private.h @@ -0,0 +1,55 @@ +/* -*- Mode: C; c-basic-offset: 4 -*- + * vim: tabstop=4 shiftwidth=4 expandtab + */ +#ifndef __PYGI_PRIVATE_H__ +#define __PYGI_PRIVATE_H__ + +#ifdef __PYGI_H__ +# error "Import pygi.h or pygi-private.h, but not both" +#endif + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <Python.h> + +#include "pygi.h" + +#include "pygobject-external.h" + +#include "pygi-repository.h" +#include "pygi-info.h" +#include "pygi-struct.h" +#include "pygi-argument.h" +#include "pygi-type.h" + +G_BEGIN_DECLS + +#define _PyGI_ERROR_PREFIX(format, ...) G_STMT_START { \ + PyObject *py_error_prefix; \ + py_error_prefix = PyString_FromFormat(format, ## __VA_ARGS__); \ + if (py_error_prefix != NULL) { \ + PyObject *py_error_type, *py_error_value, *py_error_traceback; \ + PyErr_Fetch(&py_error_type, &py_error_value, &py_error_traceback); \ + if (PyString_Check(py_error_value)) { \ + PyString_ConcatAndDel(&py_error_prefix, py_error_value); \ + if (py_error_prefix != NULL) { \ + py_error_value = py_error_prefix; \ + } \ + } \ + PyErr_Restore(py_error_type, py_error_value, py_error_traceback); \ + } \ +} G_STMT_END + + +/* Redefine g_array_index because we want it to return the i-th element, casted + * to the type t, of the array a, and not the i-th element of the array a + * casted to the type t. */ +#define _g_array_index(a,t,i) \ + *(t *)((a)->data + g_array_get_element_size(a) * (i)) + + +G_END_DECLS + +#endif /* __PYGI_PRIVATE_H__ */ diff --git a/gi/pygi-repository.c b/gi/pygi-repository.c new file mode 100644 index 0000000..f84fc7b --- /dev/null +++ b/gi/pygi-repository.c @@ -0,0 +1,238 @@ +/* -*- Mode: C; c-basic-offset: 4 -*- + * vim: tabstop=4 shiftwidth=4 expandtab + * + * Copyright (C) 2005-2009 Johan Dahlin <johan@gnome.org> + * + * pygi-repository.c: GIRepository wrapper. + * + * 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" + +PyObject *PyGIRepositoryError; + +static PyMethodDef _PyGIRepository_methods[]; + +PyTypeObject PyGIRepository_Type = { + PyObject_HEAD_INIT(NULL) + 0, + "gi.Repository", /* tp_name */ + sizeof(PyGIRepository), /* 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, /* tp_flags */ + NULL, /* tp_doc */ + (traverseproc)NULL, /* tp_traverse */ + (inquiry)NULL, /* tp_clear */ + (richcmpfunc)NULL, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + (getiterfunc)NULL, /* tp_iter */ + (iternextfunc)NULL, /* tp_iternext */ + _PyGIRepository_methods, /* tp_methods */ +}; + +static PyObject * +_wrap_g_irepository_get_default (PyObject *self) +{ + static PyGIRepository *repository = NULL; + + if (!repository) { + repository = (PyGIRepository *)PyObject_New(PyGIRepository, &PyGIRepository_Type); + if (repository == NULL) { + return NULL; + } + + repository->repository = g_irepository_get_default(); + } + + Py_INCREF((PyObject *)repository); + return (PyObject *)repository; +} + +static PyObject * +_wrap_g_irepository_require (PyGIRepository *self, + PyObject *args, + PyObject *kwargs) +{ + static char *kwlist[] = { "namespace", "version", "lazy", NULL }; + + const char *namespace_; + const char *version = NULL; + PyObject *lazy = NULL; + GIRepositoryLoadFlags flags = 0; + GTypelib *typelib; + GError *error; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|sO:Repository.require", + kwlist, &namespace_, &version, &lazy)) { + return NULL; + } + + if (lazy != NULL && PyObject_IsTrue(lazy)) { + flags |= G_IREPOSITORY_LOAD_FLAG_LAZY; + } + + error = NULL; + typelib = g_irepository_require(self->repository, namespace_, version, flags, &error); + if (error != NULL) { + PyErr_SetString(PyGIRepositoryError, error->message); + g_error_free(error); + return NULL; + } + + Py_RETURN_NONE; +} + +static PyObject * +_wrap_g_irepository_find_by_name (PyGIRepository *self, + PyObject *args, + PyObject *kwargs) +{ + static char *kwlist[] = { "namespace", "name", NULL }; + + const char *namespace_; + const char *name; + GIBaseInfo *info; + PyObject *py_info; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, + "ss:Repository.find_by_name", kwlist, &namespace_, &name)) { + return NULL; + } + + info = g_irepository_find_by_name(self->repository, namespace_, name); + if (info == NULL) { + Py_RETURN_NONE; + } + + py_info = _pygi_info_new(info); + + g_base_info_unref(info); + + return py_info; +} + +static PyObject * +_wrap_g_irepository_get_infos (PyGIRepository *self, + PyObject *args, + PyObject *kwargs) +{ + static char *kwlist[] = { "namespace", NULL }; + + const char *namespace_; + gssize n_infos; + PyObject *infos; + gssize i; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s:Repository.get_infos", + kwlist, &namespace_)) { + return NULL; + } + + n_infos = g_irepository_get_n_infos(self->repository, namespace_); + if (n_infos < 0) { + PyErr_Format(PyExc_RuntimeError, "Namespace '%s' not loaded", namespace_); + return NULL; + } + + infos = PyTuple_New(n_infos); + + for (i = 0; i < n_infos; i++) { + GIBaseInfo *info; + PyObject *py_info; + + info = g_irepository_get_info(self->repository, namespace_, 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_irepository_get_typelib_path (PyGIRepository *self, + PyObject *args, + PyObject *kwargs) +{ + static char *kwlist[] = { "namespace", NULL }; + const char *namespace_; + const gchar *typelib_path; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, + "s:Repository.get_typelib_path", kwlist, &namespace_)) { + return NULL; + } + + typelib_path = g_irepository_get_typelib_path(self->repository, namespace_); + if (typelib_path == NULL) { + PyErr_Format(PyExc_RuntimeError, "Namespace '%s' not loaded", namespace_); + return NULL; + } + + return PyString_FromString(typelib_path); +} + +static PyMethodDef _PyGIRepository_methods[] = { + { "get_default", (PyCFunction)_wrap_g_irepository_get_default, METH_STATIC|METH_NOARGS }, + { "require", (PyCFunction)_wrap_g_irepository_require, METH_VARARGS|METH_KEYWORDS }, + { "get_infos", (PyCFunction)_wrap_g_irepository_get_infos, METH_VARARGS|METH_KEYWORDS }, + { "find_by_name", (PyCFunction)_wrap_g_irepository_find_by_name, METH_VARARGS|METH_KEYWORDS }, + { "get_typelib_path", (PyCFunction)_wrap_g_irepository_get_typelib_path, METH_VARARGS|METH_KEYWORDS }, + { NULL, NULL, 0 } +}; + +void +_pygi_repository_register_types (PyObject *m) +{ + PyGIRepository_Type.ob_type = &PyType_Type; + if (PyType_Ready(&PyGIRepository_Type)) { + return; + } + if (PyModule_AddObject(m, "Repository", (PyObject *)&PyGIRepository_Type)) { + return; + } + + PyGIRepositoryError = PyErr_NewException("gi.RepositoryError", NULL, NULL); + if (PyModule_AddObject(m, "RepositoryError", PyGIRepositoryError)) { + return; + } +} + diff --git a/gi/pygi-repository.h b/gi/pygi-repository.h new file mode 100644 index 0000000..d8eb8cf --- /dev/null +++ b/gi/pygi-repository.h @@ -0,0 +1,39 @@ +/* -*- Mode: C; c-basic-offset: 4 -*- + * vim: tabstop=4 shiftwidth=4 expandtab + * + * Copyright (C) 2005-2009 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 Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#ifndef __PYGI_REPOSITORY_H__ +#define __PYGI_REPOSITORY_H__ + +#include <Python.h> + +G_BEGIN_DECLS + +/* Private */ + +extern PyTypeObject PyGIRepository_Type; + +extern PyObject *PyGIRepositoryError; + +void _pygi_repository_register_types (PyObject *m); + +G_END_DECLS + +#endif /* __PYGI_REPOSITORY_H__ */ diff --git a/gi/pygi-struct.c b/gi/pygi-struct.c new file mode 100644 index 0000000..8b672c7 --- /dev/null +++ b/gi/pygi-struct.c @@ -0,0 +1,175 @@ +/* -*- Mode: C; c-basic-offset: 4 -*- + * vim: tabstop=4 shiftwidth=4 expandtab + * + * Copyright (C) 2009 Simon van der Linden <svdlinden@src.gnome.org> + * + * pygi-struct.c: wrapper to handle non-registered structures. + * + * 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> +#include <girepository.h> + +static void +_struct_dealloc (PyGIStruct *self) +{ + PyObject_GC_UnTrack((PyObject *)self); + + PyObject_ClearWeakRefs((PyObject *)self); + + if (self->free_on_dealloc) { + g_free(((PyGPointer *)self)->pointer); + } + + ((PyGPointer *)self)->ob_type->tp_free((PyObject *)self); +} + +static PyObject * +_struct_new (PyTypeObject *type, + PyObject *args, + PyObject *kwargs) +{ + static char *kwlist[] = { NULL }; + + GIBaseInfo *info; + gboolean is_simple; + gsize size; + gpointer pointer; + PyObject *self = NULL; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "", kwlist)) { + return NULL; + } + + info = _pygi_object_get_gi_info((PyObject *)type, &PyGIStructInfo_Type); + if (info == NULL) { + if (PyErr_ExceptionMatches(PyExc_AttributeError)) { + PyErr_Format(PyExc_TypeError, "missing introspection information"); + } + return NULL; + } + + is_simple = pygi_g_struct_info_is_simple((GIStructInfo *)info); + if (!is_simple) { + PyErr_Format(PyExc_TypeError, "cannot create '%s' instances", type->tp_name); + goto out; + } + + size = g_struct_info_get_size((GIStructInfo *)info); + pointer = g_try_malloc(size); + if (pointer == NULL) { + PyErr_NoMemory(); + goto out; + } + + self = _pygi_struct_new(type, pointer, TRUE); + if (self == NULL) { + g_free(pointer); + } + +out: + g_base_info_unref(info); + + return (PyObject *)self; +} + +static int +_struct_init (PyObject *self, + PyObject *args, + PyObject *kwargs) +{ + /* Don't call PyGPointer's init, which raises an exception. */ + return 0; +} + + +PyTypeObject PyGIStruct_Type = { + PyObject_HEAD_INIT(NULL) + 0, + "gi.Struct", /* tp_name */ + sizeof(PyGIStruct), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)_struct_dealloc, /* 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 */ + 0, /* tp_weaklistoffset */ + (getiterfunc)NULL, /* tp_iter */ + (iternextfunc)NULL, /* tp_iternext */ + NULL, /* tp_methods */ + NULL, /* tp_members */ + NULL, /* tp_getset */ + (PyTypeObject *)NULL, /* tp_base */ +}; + +PyObject * +_pygi_struct_new (PyTypeObject *type, + gpointer pointer, + gboolean free_on_dealloc) +{ + PyGIStruct *self; + GType g_type; + + if (!PyType_IsSubtype(type, &PyGIStruct_Type)) { + PyErr_SetString(PyExc_TypeError, "must be a subtype of gi.Struct"); + return NULL; + } + + self = (PyGIStruct *)type->tp_alloc(type, 0); + if (self == NULL) { + return NULL; + } + + g_type = pyg_type_from_object((PyObject *)type); + + ((PyGPointer *)self)->gtype = g_type; + ((PyGPointer *)self)->pointer = pointer; + self->free_on_dealloc = free_on_dealloc; + + return (PyObject *)self; +} + +void +_pygi_struct_register_types (PyObject *m) +{ + PyGIStruct_Type.ob_type = &PyType_Type; + PyGIStruct_Type.tp_base = &PyGPointer_Type; + PyGIStruct_Type.tp_new = (newfunc)_struct_new; + PyGIStruct_Type.tp_init = (initproc)_struct_init; + if (PyType_Ready(&PyGIStruct_Type)) + return; + if (PyModule_AddObject(m, "Struct", (PyObject *)&PyGIStruct_Type)) + return; +} diff --git a/gi/pygi-struct.h b/gi/pygi-struct.h new file mode 100644 index 0000000..963d05a --- /dev/null +++ b/gi/pygi-struct.h @@ -0,0 +1,40 @@ +/* -*- Mode: C; c-basic-offset: 4 -*- + * vim: tabstop=4 shiftwidth=4 expandtab + * + * Copyright (C) 2009 Simon van der Linden <svdlinden@src.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 Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#ifndef __PYGI_STRUCT_H__ +#define __PYGI_STRUCT_H__ + +#include <Python.h> + +G_BEGIN_DECLS + +extern PyTypeObject PyGIStruct_Type; + +PyObject * +_pygi_struct_new (PyTypeObject *type, + gpointer pointer, + gboolean free_on_dealloc); + +void _pygi_struct_register_types (PyObject *m); + +G_END_DECLS + +#endif /* __PYGI_STRUCT_H__ */ diff --git a/gi/pygi-type.c b/gi/pygi-type.c new file mode 100644 index 0000000..c95da86 --- /dev/null +++ b/gi/pygi-type.c @@ -0,0 +1,96 @@ +/* -*- Mode: C; c-basic-offset: 4 -*- + * vim: tabstop=4 shiftwidth=4 expandtab + * + * Copyright (C) 2009 Simon van der Linden <svdlinden@src.gnome.org> + * + * pygi-type.c: helpers to lookup Python wrappers from GType and GIBaseInfo. + * + * 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" + + +PyObject * +_pygi_type_import_by_gi_info (GIBaseInfo *info) +{ + const gchar *namespace_; + const gchar *name; + gchar *module_name; + PyObject *py_module; + PyObject *py_object; + + namespace_ = g_base_info_get_namespace(info); + name = g_base_info_get_name(info); + + module_name = g_strconcat("gi.repository.", namespace_, NULL); + + py_module = PyImport_ImportModule(module_name); + + g_free(module_name); + + if (py_module == NULL) { + return NULL; + } + + py_object = PyObject_GetAttrString(py_module, name); + + Py_DECREF(py_module); + + return py_object; +} + +PyObject * +pygi_type_import_by_g_type (GType g_type) +{ + GIRepository *repository; + GIBaseInfo *info; + PyObject *type; + + repository = g_irepository_get_default(); + + info = g_irepository_find_by_gtype(repository, g_type); + if (info == NULL) { + return NULL; + } + + type = _pygi_type_import_by_gi_info(info); + g_base_info_unref(info); + + return type; +} + +PyObject * +_pygi_type_get_from_g_type(GType g_type) +{ + PyObject *py_g_type; + PyObject *py_type; + + py_g_type = pyg_type_wrapper_new(g_type); + if (py_g_type == NULL) { + return NULL; + } + + py_type = PyObject_GetAttrString(py_g_type, "pytype"); + if (py_type == Py_None) { + py_type = pygi_type_import_by_g_type(g_type); + } + + Py_DECREF(py_g_type); + + return py_type; +} + diff --git a/gi/pygi-type.h b/gi/pygi-type.h new file mode 100644 index 0000000..19d07dc --- /dev/null +++ b/gi/pygi-type.h @@ -0,0 +1,43 @@ +/* -*- Mode: C; c-basic-offset: 4 -*- + * vim: tabstop=4 shiftwidth=4 expandtab + * + * Copyright (C) 2009 Simon van der Linden <svdlinden@src.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 Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#ifndef __PYGI_TYPE_H__ +#define __PYGI_TYPE_H__ + +#include <Python.h> + +G_BEGIN_DECLS + +/* Public */ + +PyObject *pygi_type_import_by_g_type (GType g_type); + + +/* Private */ + +PyObject *_pygi_type_import_by_gi_info (GIBaseInfo *info); + +PyObject *_pygi_type_get_from_g_type (GType g_type); + + +G_END_DECLS + +#endif /* __PYGI_TYPE_H__ */ diff --git a/gi/pygi.h b/gi/pygi.h new file mode 100644 index 0000000..930017d --- /dev/null +++ b/gi/pygi.h @@ -0,0 +1,99 @@ +/* -*- Mode: C; c-basic-offset: 4 -*- + * vim: tabstop=4 shiftwidth=4 expandtab + * + * Copyright (C) 2005-2009 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 Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#ifndef __PYGI_H__ +#define __PYGI_H__ + +#include <pygobject.h> + +#include <girepository.h> + +G_BEGIN_DECLS + +typedef struct { + PyObject_HEAD + GIRepository *repository; +} PyGIRepository; + +typedef struct { + PyObject_HEAD + GIBaseInfo *info; + PyObject *inst_weakreflist; +} PyGIBaseInfo; + +typedef struct { + PyGPointer base; + gboolean free_on_dealloc; +} PyGIStruct; + + +struct PyGI_API { + PyObject* (*type_import_by_g_type) (GType g_type); +}; + + +#ifndef __PYGI_PRIVATE_H__ + +static struct PyGI_API *PyGI_API = NULL; + +#define pygi_type_import_by_g_type (PyGI_API->type_import_by_g_type) + + +static int +pygi_import (void) +{ + PyObject *module; + PyObject *api; + + if (PyGI_API != NULL) { + return 1; + } + + module = PyImport_ImportModule("gi"); + if (module == NULL) { + return -1; + } + + api = PyObject_GetAttrString(module, "_API"); + if (api == NULL) { + Py_DECREF(module); + return -1; + } + if (!PyCObject_Check(api)) { + Py_DECREF(module); + Py_DECREF(api); + PyErr_Format(PyExc_TypeError, "gi._API must be cobject, not %s", + api->ob_type->tp_name); + return -1; + } + + PyGI_API = (struct PyGI_API *)PyCObject_AsVoidPtr(api); + + Py_DECREF(api); + + return 0; +} + +#endif /* __PYGI_PRIVATE_H__ */ + +G_END_DECLS + +#endif /* __PYGI_H__ */ diff --git a/gi/pygobject-external.h b/gi/pygobject-external.h new file mode 100644 index 0000000..6dc63a5 --- /dev/null +++ b/gi/pygobject-external.h @@ -0,0 +1,83 @@ +/* -*- Mode: C; c-basic-offset: 4 -*- + * vim: tabstop=4 shiftwidth=4 expandtab + * + * Copyright (C) 2009 Simon van der Linden <svdlinden@src.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 Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +#ifndef __PYGOBJECT_EXTERN_H__ +#define __PYGOBJECT_EXTERN_H__ + +#include <Python.h> + +G_BEGIN_DECLS + +static PyTypeObject *_PyGObject_Type; +static PyTypeObject *_PyGTypeWrapper_Type; + +#define PyGObject_Type (*_PyGObject_Type) +#define PyGTypeWrapper_Type (*_PyGTypeWrapper_Type) + + +static int +_pygobject_import (void) +{ + static gboolean imported = FALSE; + PyObject *from_list; + PyObject *module; + int retval = 0; + + if (imported) { + return 1; + } + + from_list = Py_BuildValue("(ss)", "GObject", "GTypeWrapper"); + if (from_list == NULL) { + return -1; + } + + module = PyImport_ImportModuleEx("gobject", NULL, NULL, from_list); + + Py_DECREF(from_list); + + if (module == NULL) { + return -1; + } + + _PyGObject_Type = (PyTypeObject *)PyObject_GetAttrString(module, "GObject"); + if (_PyGObject_Type == NULL) { + retval = -1; + goto out; + } + + _PyGTypeWrapper_Type = (PyTypeObject *)PyObject_GetAttrString(module, "GType"); + if (_PyGTypeWrapper_Type == NULL) { + retval = -1; + goto out; + } + + imported = TRUE; + +out: + Py_DECREF(module); + + return retval; +} + +G_END_DECLS + +#endif /* __PYGOBJECT_EXTERN_H__ */ diff --git a/gi/repository/Makefile.am b/gi/repository/Makefile.am new file mode 100644 index 0000000..c9138ce --- /dev/null +++ b/gi/repository/Makefile.am @@ -0,0 +1,8 @@ +PLATFORM_VERSION = 2.0 + +pkgpyexecdir = $(pyexecdir)/gtk-2.0/gi + +pygirepositorydir = $(pkgpyexecdir)/repository +pygirepository_PYTHON = \ + __init__.py + diff --git a/gi/repository/__init__.py b/gi/repository/__init__.py new file mode 100644 index 0000000..5c5552a --- /dev/null +++ b/gi/repository/__init__.py @@ -0,0 +1,30 @@ +# -*- Mode: Python; py-indent-offset: 4 -*- +# vim: tabstop=4 shiftwidth=4 expandtab +# +# Copyright (C) 2009 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 __future__ import absolute_import + +import sys + +from ..importer import DynamicImporter + +sys.meta_path.append(DynamicImporter('gi.repository')) + +del DynamicImporter +del sys diff --git a/gi/types.py b/gi/types.py new file mode 100644 index 0000000..10d7fde --- /dev/null +++ b/gi/types.py @@ -0,0 +1,163 @@ +# -*- Mode: Python; py-indent-offset: 4 -*- +# vim: tabstop=4 shiftwidth=4 expandtab +# +# Copyright (C) 2005-2009 Johan Dahlin <johan@gnome.org> +# +# types.py: base types for introspected items. +# +# 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 __future__ import absolute_import + +import sys +import gobject + +from ._gi import \ + InterfaceInfo, \ + ObjectInfo, \ + StructInfo, \ + set_object_has_new_constructor + + +class Boxed(gobject.GBoxed): + # Instances of boxed structures cannot be constructed unless they have a + # specific constructor. + # + # To achieve this behavior, PyGBoxed_Type's constructor creates an + # instance, and the initializer eventually raises an exception. If things + # had been implemented correctly, PyGBoxed_Type.tp_new would have been set to + # NULL, and neither a creator nor an initializer wouldn't have been needed. + # + # In order to keep the code generic, we need to revert the right behavior. + + def __new__(cls): + raise TypeError, "instances of '%s' cannot be created" % cls.__name__ + + def __init__(self, *args, **kwargs): + pass + + +def Function(info): + + def function(*args): + return info.invoke(*args) + function.__info__ = info + function.__name__ = info.get_name() + function.__module__ = info.get_namespace() + + return function + + +def Constructor(info): + + def constructor(cls, *args): + cls_name = info.get_container().get_name() + if cls.__name__ != cls_name: + raise TypeError, '%s constructor cannot be used to create instances of a subclass' % cls_name + return info.invoke(cls, *args) + + constructor.__info__ = info + constructor.__name__ = info.get_name() + constructor.__module__ = info.get_namespace() + + return constructor + + +class MetaClassHelper(object): + + def _setup_methods(cls): + for method_info in cls.__info__.get_methods(): + name = method_info.get_name() + function = Function(method_info) + if method_info.is_method(): + method = function + elif method_info.is_constructor(): + continue + else: + method = staticmethod(function) + setattr(cls, name, method) + + def _setup_fields(cls): + for field_info in cls.__info__.get_fields(): + name = field_info.get_name().replace('-', '_') + setattr(cls, name, property(field_info.get_value, field_info.set_value)) + + def _setup_constants(cls): + for constant_info in cls.__info__.get_constants(): + name = constant_info.get_name() + value = constant_info.get_value() + setattr(cls, name, value) + + +class GObjectMeta(gobject.GObjectMeta, MetaClassHelper): + + def _setup_constructors(cls): + for method_info in cls.__info__.get_methods(): + if method_info.is_constructor(): + name = method_info.get_name() + constructor = classmethod(Constructor(method_info)) + setattr(cls, name, constructor) + + def __init__(cls, name, bases, dict_): + super(GObjectMeta, cls).__init__(name, bases, dict_) + + # Avoid touching anything else than the base class. + if cls.__name__ != cls.__info__.get_name(): + return; + + cls._setup_methods() + cls._setup_constants() + + if (isinstance(cls.__info__, ObjectInfo)): + cls._setup_fields() + cls._setup_constructors() + set_object_has_new_constructor(cls.__info__.get_g_type()) + + +class StructMeta(type, MetaClassHelper): + + def _setup_constructors(cls): + constructor_infos = [] + default_constructor_info = None + + for method_info in cls.__info__.get_methods(): + if method_info.is_constructor(): + name = method_info.get_name() + constructor = classmethod(Function(method_info)) + + setattr(cls, name, constructor) + + constructor_infos.append(method_info) + if name == "new": + default_constructor_info = method_info + + if default_constructor_info is None and constructor_infos: + default_constructor_info = constructor_infos[0] + + if default_constructor_info is not None: + cls.__new__ = staticmethod(Function(default_constructor_info)) + + def __init__(cls, name, bases, dict_): + super(StructMeta, cls).__init__(name, bases, dict_) + + # Avoid touching anything else than the base class. + if cls.__name__ != cls.__info__.get_name(): + return; + + cls._setup_fields() + cls._setup_methods() + cls._setup_constructors() + |