summaryrefslogtreecommitdiffstats
path: root/gi
diff options
context:
space:
mode:
authorTomeu Vizoso <tomeu@sugarlabs.org>2009-11-30 10:03:34 +0000
committerTomeu Vizoso <tomeu@sugarlabs.org>2009-11-30 10:55:58 +0000
commit66c34805223af9e63c7d61f21a3dbd7505a8f256 (patch)
tree327da9017ab1d261bf650291750a81fd8434c29d /gi
parente7e2fccae36c28c7e9f288fcd4c90a001140e307 (diff)
downloadpygi-66c34805223af9e63c7d61f21a3dbd7505a8f256.tar.gz
pygi-66c34805223af9e63c7d61f21a3dbd7505a8f256.tar.xz
pygi-66c34805223af9e63c7d61f21a3dbd7505a8f256.zip
Set a default constructor for boxed structs that don't have one
https://bugzilla.gnome.org/show_bug.cgi?id=602735
Diffstat (limited to 'gi')
-rw-r--r--gi/Makefile.am2
-rw-r--r--gi/gimodule.c1
-rw-r--r--gi/module.py2
-rw-r--r--gi/pygi-argument.c14
-rw-r--r--gi/pygi-boxed.c184
-rw-r--r--gi/pygi-boxed.h40
-rw-r--r--gi/pygi-info.c2
-rw-r--r--gi/pygi-private.h1
-rw-r--r--gi/pygi.h6
-rw-r--r--gi/types.py18
10 files changed, 249 insertions, 21 deletions
diff --git a/gi/Makefile.am b/gi/Makefile.am
index 2657d3f..bda8a34 100644
--- a/gi/Makefile.am
+++ b/gi/Makefile.am
@@ -34,6 +34,8 @@ _gi_la_SOURCES = \
pygi-argument.h \
pygi-type.c \
pygi-type.h \
+ pygi-boxed.c \
+ pygi-boxed.h \
pygi.h \
pygi-private.h \
pygobject-external.h \
diff --git a/gi/gimodule.c b/gi/gimodule.c
index bc5f9ca..8811539 100644
--- a/gi/gimodule.c
+++ b/gi/gimodule.c
@@ -166,6 +166,7 @@ init_gi(void)
_pygi_repository_register_types(m);
_pygi_info_register_types(m);
_pygi_struct_register_types(m);
+ _pygi_boxed_register_types(m);
_pygi_argument_init();
api = PyCObject_FromVoidPtr((void *)&PyGI_API, NULL);
diff --git a/gi/module.py b/gi/module.py
index 1a54971..efc8af8 100644
--- a/gi/module.py
+++ b/gi/module.py
@@ -35,12 +35,12 @@ from ._gi import \
ConstantInfo, \
StructInfo, \
Struct, \
+ Boxed, \
enum_add, \
flags_add
from .types import \
GObjectMeta, \
StructMeta, \
- Boxed, \
Function
repository = Repository.get_default()
diff --git a/gi/pygi-argument.c b/gi/pygi-argument.c
index 8411b62..eab48f6 100644
--- a/gi/pygi-argument.c
+++ b/gi/pygi-argument.c
@@ -1557,8 +1557,20 @@ _pygi_argument_to_object (GArgument *arg,
g_assert(is_pointer);
object = pyg_value_as_pyobject(arg->v_pointer, FALSE);
} else if (g_type_is_a(type, G_TYPE_BOXED)) {
+ PyObject *py_type;
+
g_assert(is_pointer);
- object = pyg_boxed_new(type, arg->v_pointer, FALSE, transfer == GI_TRANSFER_EVERYTHING);
+
+ py_type = _pygi_type_get_from_g_type(type);
+ if (py_type == NULL) {
+ PyErr_Format(PyExc_ValueError, "couldn't find a wrapper for type '%s'",
+ g_type_name(type));
+ break;
+ }
+
+ object = _pygi_boxed_new((PyTypeObject *)py_type, arg->v_pointer, transfer == GI_TRANSFER_EVERYTHING);
+
+ Py_DECREF(py_type);
} else if (g_type_is_a(type, G_TYPE_POINTER)) {
PyObject *py_type;
diff --git a/gi/pygi-boxed.c b/gi/pygi-boxed.c
new file mode 100644
index 0000000..d17da2d
--- /dev/null
+++ b/gi/pygi-boxed.c
@@ -0,0 +1,184 @@
+/* -*- Mode: C; c-basic-offset: 4 -*-
+ * vim: tabstop=4 shiftwidth=4 expandtab
+ *
+ * Copyright (C) 2009 Simon van der Linden <svdlinden@src.gnome.org>
+ *
+ * pygi-boxed.c: wrapper to handle 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
+_boxed_dealloc (PyGIBoxed *self)
+{
+ GType g_type;
+
+ PyObject_GC_UnTrack((PyObject *)self);
+
+ PyObject_ClearWeakRefs((PyObject *)self);
+
+ if (((PyGBoxed *)self)->free_on_dealloc) {
+ if (self->slice_allocated) {
+ g_slice_free1(self->size, ((PyGBoxed *)self)->boxed);
+ } else {
+ g_type = pyg_type_from_object((PyObject *)self);
+ g_boxed_free (g_type, ((PyGBoxed *)self)->boxed);
+ }
+ }
+
+ ((PyGObject *)self)->ob_type->tp_free((PyObject *)self);
+}
+
+static PyObject *
+_boxed_new (PyTypeObject *type,
+ PyObject *args,
+ PyObject *kwargs)
+{
+ static char *kwlist[] = { NULL };
+
+ GIBaseInfo *info;
+ gboolean is_simple;
+ gsize size;
+ gpointer boxed;
+ PyGIBoxed *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;
+ }
+
+ size = g_struct_info_get_size((GIStructInfo *)info);
+ boxed = g_slice_alloc0(size);
+ if (boxed == NULL) {
+ PyErr_NoMemory();
+ goto out;
+ }
+
+ self = (PyGIBoxed *)_pygi_boxed_new(type, boxed, TRUE);
+ if (self == NULL) {
+ g_slice_free1(size, boxed);
+ goto out;
+ }
+
+ self->size = size;
+ self->slice_allocated = TRUE;
+
+out:
+ g_base_info_unref(info);
+
+ return (PyObject *)self;
+}
+
+static int
+_boxed_init (PyObject *self,
+ PyObject *args,
+ PyObject *kwargs)
+{
+ /* Don't call PyGBoxed's init, which raises an exception. */
+ return 0;
+}
+
+
+PyTypeObject PyGIBoxed_Type = {
+ PyObject_HEAD_INIT(NULL)
+ 0,
+ "gi.Boxed", /* tp_name */
+ sizeof(PyGIBoxed), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)_boxed_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_boxed_new (PyTypeObject *type,
+ gpointer boxed,
+ gboolean free_on_dealloc)
+{
+ PyGIBoxed *self;
+ GType g_type;
+
+ if (!boxed) {
+ Py_RETURN_NONE;
+ }
+
+ if (!PyType_IsSubtype(type, &PyGIBoxed_Type)) {
+ PyErr_SetString(PyExc_TypeError, "must be a subtype of gi.Boxed");
+ return NULL;
+ }
+
+ self = (PyGIBoxed *)type->tp_alloc(type, 0);
+ if (self == NULL) {
+ return NULL;
+ }
+
+ ((PyGBoxed *)self)->gtype = pyg_type_from_object((PyObject *)type);
+ ((PyGBoxed *)self)->boxed = boxed;
+ ((PyGBoxed *)self)->free_on_dealloc = free_on_dealloc;
+ self->size = 0;
+ self->slice_allocated = FALSE;
+
+ return (PyObject *)self;
+}
+
+void
+_pygi_boxed_register_types (PyObject *m)
+{
+ PyGIBoxed_Type.ob_type = &PyType_Type;
+ PyGIBoxed_Type.tp_base = &PyGBoxed_Type;
+ PyGIBoxed_Type.tp_new = (newfunc)_boxed_new;
+ PyGIBoxed_Type.tp_init = (initproc)_boxed_init;
+ if (PyType_Ready(&PyGIBoxed_Type))
+ return;
+ if (PyModule_AddObject(m, "Boxed", (PyObject *)&PyGIBoxed_Type))
+ return;
+}
diff --git a/gi/pygi-boxed.h b/gi/pygi-boxed.h
new file mode 100644
index 0000000..4f84060
--- /dev/null
+++ b/gi/pygi-boxed.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_BOXED_H__
+#define __PYGI_BOXED_H__
+
+#include <Python.h>
+
+G_BEGIN_DECLS
+
+extern PyTypeObject PyGIBoxed_Type;
+
+PyObject *
+_pygi_boxed_new (PyTypeObject *type,
+ gpointer boxed,
+ gboolean free_on_dealloc);
+
+void _pygi_boxed_register_types (PyObject *m);
+
+G_END_DECLS
+
+#endif /* __PYGI_BOXED_H__ */
diff --git a/gi/pygi-info.c b/gi/pygi-info.c
index 5f4a174..56aee16 100644
--- a/gi/pygi-info.c
+++ b/gi/pygi-info.c
@@ -981,7 +981,7 @@ _wrap_g_function_info_invoke (PyGIBaseInfo *self,
break;
}
g_warn_if_fail(transfer == GI_TRANSFER_EVERYTHING);
- return_value = pyg_boxed_new(type, return_arg.v_pointer, FALSE, transfer == GI_TRANSFER_EVERYTHING);
+ return_value = _pygi_boxed_new(py_type, return_arg.v_pointer, 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");
diff --git a/gi/pygi-private.h b/gi/pygi-private.h
index 6ca85c8..4e2615f 100644
--- a/gi/pygi-private.h
+++ b/gi/pygi-private.h
@@ -21,6 +21,7 @@
#include "pygi-repository.h"
#include "pygi-info.h"
#include "pygi-struct.h"
+#include "pygi-boxed.h"
#include "pygi-argument.h"
#include "pygi-type.h"
diff --git a/gi/pygi.h b/gi/pygi.h
index 930017d..5ee8d94 100644
--- a/gi/pygi.h
+++ b/gi/pygi.h
@@ -44,6 +44,12 @@ typedef struct {
gboolean free_on_dealloc;
} PyGIStruct;
+typedef struct {
+ PyGBoxed base;
+ gboolean slice_allocated;
+ gsize size;
+} PyGIBoxed;
+
struct PyGI_API {
PyObject* (*type_import_by_g_type) (GType g_type);
diff --git a/gi/types.py b/gi/types.py
index 87dbe16..75b41b9 100644
--- a/gi/types.py
+++ b/gi/types.py
@@ -33,24 +33,6 @@ from ._gi import \
register_interface_info
-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):