[pygobject/gsoc2009] Add support for structures registered as GPointers



commit 96ec342126cc8c3aa960b39d6f30455a908a4f66
Author: Simon van der Linden <svdlinden src gnome org>
Date:   Sat Aug 15 15:15:36 2009 +0200

    Add support for structures registered as GPointers

 gi/gimodule.c               |    6 +-
 gi/module.py                |    7 ++-
 gi/pygi-argument.c          |   10 ++-
 gi/pygi-boxed.c             |  177 -------------------------------------------
 gi/pygi-boxed.h             |    5 -
 gi/pygi-info.c              |  155 ++++++++++++++++++++++++++++++++++----
 gi/pygi-info.h              |    2 +
 gi/pygi-private.h           |    6 +-
 gi/pygi.h                   |   19 +++--
 gobject/gobjectmodule.c     |    2 +
 gobject/pygboxed.c          |   25 ------
 gobject/pygobject-private.h |    3 +
 gobject/pygobject.h         |    7 ++
 gobject/pygpointer.c        |  157 ++++++++++++++++++++++++++++++++------
 tests/test_girepository.py  |    2 +-
 15 files changed, 320 insertions(+), 263 deletions(-)
---
diff --git a/gi/gimodule.c b/gi/gimodule.c
index 2557ea0..3ec456a 100644
--- a/gi/gimodule.c
+++ b/gi/gimodule.c
@@ -76,7 +76,7 @@ pygi_type_find_by_gi_info (GIBaseInfo *info)
 }
 
 GIBaseInfo *
-_pygi_object_get_gi_info (PyObject     *object,
+pygi_object_get_gi_info (PyObject     *object,
                           PyTypeObject *type)
 {
     PyObject *py_info;
@@ -133,8 +133,10 @@ static PyMethodDef _pygi_functions[] = {
 };
 
 struct PyGI_API PyGI_API = {
+    &PyGIStructInfo_Type,
+    pygi_g_struct_info_is_simple,
     pygi_type_find_by_gi_info,
-    pygi_boxed_new_from_type
+    pygi_object_get_gi_info
 };
 
 PyMODINIT_FUNC
diff --git a/gi/module.py b/gi/module.py
index 969c876..ef0956a 100644
--- a/gi/module.py
+++ b/gi/module.py
@@ -113,7 +113,12 @@ class DynamicModule(object):
                 bases = (gobject.GInterface,)
                 metaclass = GObjectMeta
             elif isinstance(info, StructInfo):
-                bases = (gobject.GBoxed,)
+                if g_type.is_a(gobject.TYPE_BOXED):
+                    bases = (gobject.GBoxed,)
+                elif g_type.is_a(gobject.TYPE_POINTER) or g_type == gobject.TYPE_NONE:
+                    bases = (gobject.GPointer,)
+                else:
+                    raise TypeError, "unable to create a wrapper for %s.%s" % (info.get_namespace(), info.get_name())
                 metaclass = StructMeta
             else:
                 raise NotImplementedError(info)
diff --git a/gi/pygi-argument.c b/gi/pygi-argument.c
index ee2b242..5e7b13b 100644
--- a/gi/pygi-argument.c
+++ b/gi/pygi-argument.c
@@ -1168,9 +1168,9 @@ array_item_error:
                         if (transfer == GI_TRANSFER_EVERYTHING) {
                             arg.v_pointer = g_boxed_copy(type, arg.v_pointer);
                         }
-                    } else if (type == G_TYPE_NONE) {
+                    } 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_boxed_get(object, void);
+                        arg.v_pointer = pyg_pointer_get(object, void);
                     } else {
                         PyErr_Format(PyExc_NotImplementedError, "structure type '%s' is not supported yet", g_type_name(type));
                     }
@@ -1691,6 +1691,8 @@ _pygi_argument_to_object (GArgument  *arg,
                     } 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)) {
+                        object = pyg_pointer_new(type, arg->v_pointer);
                     } else if (type == G_TYPE_NONE) {
                         PyObject *py_type;
 
@@ -1699,7 +1701,7 @@ _pygi_argument_to_object (GArgument  *arg,
                             break;
                         }
 
-                        object = pygi_boxed_new_from_type((PyTypeObject *)py_type, arg->v_pointer,
+                        object = pyg_pointer_new_from_type((PyTypeObject *)py_type, arg->v_pointer,
                                 transfer == GI_TRANSFER_EVERYTHING);
 
                         Py_DECREF(py_type);
@@ -1980,7 +1982,7 @@ _pygi_argument_release (GArgument   *arg,
                         }
                     } else if (g_type_is_a(type, G_TYPE_BOXED)) {
                         g_assert(is_pointer);
-                    } else if (type == G_TYPE_NONE) {
+                    } else if (g_type_is_a(type, G_TYPE_POINTER) || type == G_TYPE_NONE) {
                         g_warn_if_fail(!is_pointer || transfer == GI_TRANSFER_NOTHING);
                     }
 
diff --git a/gi/pygi-boxed.c b/gi/pygi-boxed.c
index eb7fc31..55ed53e 100644
--- a/gi/pygi-boxed.c
+++ b/gi/pygi-boxed.c
@@ -25,181 +25,4 @@
 
 #include <pygobject.h>
 
-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;
-}
-
-PyObject *
-pygi_boxed_new_from_type (PyTypeObject *type,
-                          gpointer      pointer,
-                          gboolean      own_pointer)
-{
-    GIBaseInfo *info;
-    GIInfoType info_type;
-    GType g_type;
-    PyGBoxed *self = NULL;
-
-    info = _pygi_object_get_gi_info((PyObject *)type, &PyGIRegisteredTypeInfo_Type);
-    if (info == NULL) {
-        if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
-            PyErr_Format(PyExc_TypeError, "cannot create '%s' instances", type->tp_name);
-        }
-        return NULL;
-    }
-
-    info_type = g_base_info_get_type(info);
-    g_type = g_registered_type_info_get_g_type((GIRegisteredTypeInfo *)info);
-
-    if (pointer == NULL) {
-        if (info_type == GI_INFO_TYPE_STRUCT && !g_type_is_a(g_type, G_TYPE_BOXED)) {
-            gboolean is_simple;
-            gsize size;
-
-            is_simple = _pygi_g_struct_info_is_simple((GIStructInfo *)info);
-            if (!is_simple) {
-                PyErr_Format(PyExc_TypeError,
-                        "cannot create '%s' instances; needs a specific constructor", 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;
-            }
-
-            own_pointer = TRUE;
-        } else {
-            PyErr_Format(PyExc_TypeError,
-                    "cannot create '%s' instances; needs a specific constructor", type->tp_name);
-            goto out;
-        }
-    }
-
-    self = (PyGBoxed *)type->tp_alloc(type, 0);
-    if (self == NULL) {
-        g_free(pointer);
-        goto out;
-    }
-
-    self->boxed = pointer;
-    self->gtype = g_type;
-    self->free_on_dealloc = own_pointer;
-
-out:
-    g_base_info_unref(info);
-
-    return (PyObject *)self;
-}
 
diff --git a/gi/pygi-boxed.h b/gi/pygi-boxed.h
index ef23132..de6ecdd 100644
--- a/gi/pygi-boxed.h
+++ b/gi/pygi-boxed.h
@@ -26,14 +26,9 @@
 
 G_BEGIN_DECLS
 
-PyObject* pygi_boxed_new_from_type (PyTypeObject *type,
-                                    gpointer      pointer,
-                                    gboolean      own_pointer);
-
 
 /* Private */
 
-gboolean _pygi_g_struct_info_is_simple (GIStructInfo *struct_info);
 
 G_END_DECLS
 
diff --git a/gi/pygi-info.c b/gi/pygi-info.c
index 1cf2e1a..ceb81a2 100644
--- a/gi/pygi-info.c
+++ b/gi/pygi-info.c
@@ -583,8 +583,22 @@ _wrap_g_function_info_invoke (PyGIBaseInfo *self,
                     g_assert_not_reached();
                     break;
                 case GI_INFO_TYPE_STRUCT:
-                    in_args[0].v_pointer = pyg_boxed_get(py_arg, void);
+                {
+                    GType type;
+
+                    type = g_registered_type_info_get_g_type((GIRegisteredTypeInfo *)container_info);
+
+                    if (g_type_is_a(type, G_TYPE_BOXED)) {
+                        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) {
+                        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 return_;
+                    }
+
                     break;
+                }
                 case GI_INFO_TYPE_OBJECT:
                 case GI_INFO_TYPE_INTERFACE:
                     in_args[0].v_pointer = pygobject_get(py_arg);
@@ -806,20 +820,18 @@ _wrap_g_function_info_invoke (PyGIBaseInfo *self,
 
                 type = g_registered_type_info_get_g_type((GIRegisteredTypeInfo *)info);
 
-                if (transfer == GI_TRANSFER_EVERYTHING && !g_type_is_a(type, G_TYPE_BOXED)) {
-                    gboolean is_simple;
-
-                    is_simple = _pygi_g_struct_info_is_simple((GIStructInfo *)info);
-
-                    if (is_simple) {
-                        PyErr_Format(PyExc_TypeError,
-                                "cannot create '%s' instances; non-boxed simple structures do not accept specific constructors",
-                                py_type->tp_name);
-                        /* TODO */
-                        goto return_;
-                    }
+                if (g_type_is_a(type, G_TYPE_BOXED)) {
+                    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) {
+                    g_warn_if_fail(transfer == GI_TRANSFER_NOTHING);
+                    return_value = pyg_pointer_new_from_type(py_type, return_arg.v_pointer, transfer == GI_TRANSFER_EVERYTHING);
+                } else {
+                    PyErr_Format(PyExc_TypeError, "cannot create '%s' instances", py_type->tp_name);
+                    /* TODO */
+                    goto return_;
                 }
-                return_value = pygi_boxed_new_from_type(py_type, return_arg.v_pointer, transfer == GI_TRANSFER_EVERYTHING);
+
                 break;
             }
             case GI_INFO_TYPE_OBJECT:
@@ -1106,6 +1118,119 @@ static PyMethodDef _PyGIStructInfo_methods[] = {
     { 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);
@@ -1541,7 +1666,7 @@ _wrap_g_field_info_set_value (PyGIBaseInfo *self,
                 gsize offset;
                 gssize size;
 
-                is_simple = _pygi_g_struct_info_is_simple((GIStructInfo *)info);
+                is_simple = pygi_g_struct_info_is_simple((GIStructInfo *)info);
 
                 if (!is_simple) {
                     PyErr_SetString(PyExc_TypeError,
diff --git a/gi/pygi-info.h b/gi/pygi-info.h
index c24fa11..aecf96e 100644
--- a/gi/pygi-info.h
+++ b/gi/pygi-info.h
@@ -28,6 +28,8 @@
 
 G_BEGIN_DECLS
 
+gboolean pygi_g_struct_info_is_simple (GIStructInfo *struct_info);
+
 
 /* Private */
 
diff --git a/gi/pygi-private.h b/gi/pygi-private.h
index a76cffc..e928c09 100644
--- a/gi/pygi-private.h
+++ b/gi/pygi-private.h
@@ -52,11 +52,11 @@ PyObject* pygi_type_find_by_name (const char *namespace_,
                                   const char *name);
 PyObject* pygi_type_find_by_gi_info (GIBaseInfo *info);
 
+GIBaseInfo* pygi_object_get_gi_info (PyObject     *object,
+                                     PyTypeObject *type);
 
-/* Private */
 
-GIBaseInfo* _pygi_object_get_gi_info (PyObject     *object,
-                                      PyTypeObject *type);
+/* Private */
 
 
 #define _PyGI_ERROR_PREFIX(format, ...) G_STMT_START { \
diff --git a/gi/pygi.h b/gi/pygi.h
index 7681fc5..b809da3 100644
--- a/gi/pygi.h
+++ b/gi/pygi.h
@@ -43,13 +43,14 @@ typedef struct {
 
 
 struct PyGI_API {
+    /* Info */
+    PyTypeObject *StructInfo_Type;
+    gboolean (*g_struct_info_is_simple) (GIStructInfo *struct_info);
+
     /* Misc */
     PyObject* (*type_find_by_gi_info) (GIBaseInfo *info);
-
-    /* Boxed */
-    PyObject* (*boxed_new_from_type) (PyTypeObject *type,
-                                      gpointer      pointer,
-                                      gboolean      own_pointer);
+    GIBaseInfo* (*object_get_gi_info) (PyObject     *object,
+                                       PyTypeObject *type);
 };
 
 
@@ -57,11 +58,13 @@ struct PyGI_API {
 
 static struct PyGI_API *PyGI_API = NULL;
 
+/* Info */
+#define PyGIStructInfo_Type (*PyGI_API->StructInfo_Type)
+#define pygi_g_struct_info_is_simple (PyGI_API->g_struct_info_is_simple)
+
 /* Misc */
 #define pygi_type_find_by_gi_info (PyGI_API->type_find_by_gi_info)
-
-/* Boxed */
-#define pygi_boxed_new_from_type (PyGI_API->boxed_new_from_type)
+#define pygi_object_get_gi_info (PyGI_API->object_get_gi_info)
 
 
 static int
diff --git a/gobject/gobjectmodule.c b/gobject/gobjectmodule.c
index 7c77d3e..df018ba 100644
--- a/gobject/gobjectmodule.c
+++ b/gobject/gobjectmodule.c
@@ -2579,6 +2579,8 @@ struct _PyGObject_Functions pygobject_api_functions = {
   pygobject_new_from_type,
 
   &PyGInterface_Type,
+
+  pyg_pointer_new_from_type
 };
 
 /* for addon libraries ... */
diff --git a/gobject/pygboxed.c b/gobject/pygboxed.c
index 7fe05d4..6dc7c6f 100644
--- a/gobject/pygboxed.c
+++ b/gobject/pygboxed.c
@@ -215,26 +215,6 @@ pyg_boxed_new(GType boxed_type, gpointer boxed, gboolean copy_boxed,
     return (PyObject *)self;
 }
 
-#if HAVE_PYGI_H
-static PyObject *
-pyg_boxed_new_ (PyTypeObject *type,
-                PyObject     *args,
-                PyObject     *kwds)
-{
-    static char *kwlist[] = { NULL };
-
-    if (!PyArg_ParseTupleAndKeywords(args, kwds, "", kwlist)) {
-        return NULL;
-    }
-
-    if (pygi_import() < 0) {
-        return NULL;
-    }
-
-    return pygi_boxed_new_from_type(type, NULL, TRUE);
-}
-#endif /* HAVE_PYGI_H */
-
 void
 pygobject_boxed_register_types(PyObject *d)
 {
@@ -248,16 +228,11 @@ pygobject_boxed_register_types(PyObject *d)
     PyGBoxed_Type.tp_methods = pygboxed_methods;
     PyGBoxed_Type.tp_free = (freefunc)pyg_boxed_free;
     PyGBoxed_Type.tp_hash = (hashfunc)pyg_boxed_hash;
-#if HAVE_PYGI_H
-    PyGBoxed_Type.tp_new = (newfunc)pyg_boxed_new_;
-#endif
 
     PYGOBJECT_REGISTER_GTYPE(d, PyGBoxed_Type, "GBoxed", G_TYPE_BOXED);
 
-#if !HAVE_PYGI_H
     /* We don't want instances to be created in Python, but
      * PYGOBJECT_REGISTER_GTYPE assigned PyObject_GenericNew as instance
      * constructor. It's not too late to revert it to NULL, though. */
     PyGBoxed_Type.tp_new = (newfunc)NULL;
-#endif
 }
diff --git a/gobject/pygobject-private.h b/gobject/pygobject-private.h
index a106ca8..c0fcf66 100644
--- a/gobject/pygobject-private.h
+++ b/gobject/pygobject-private.h
@@ -171,6 +171,9 @@ extern PyTypeObject PyGPointer_Type;
 void       pyg_register_pointer (PyObject *dict, const gchar *class_name,
 				 GType pointer_type, PyTypeObject *type);
 PyObject * pyg_pointer_new      (GType pointer_type, gpointer pointer);
+PyObject * pyg_pointer_new_from_type (PyTypeObject *type,
+                                      gpointer      pointer,
+                                      gboolean      free_on_dealloc);
 
 const gchar * pyg_constant_strip_prefix(const gchar *name, const gchar *strip_prefix);
 
diff --git a/gobject/pygobject.h b/gobject/pygobject.h
index fa963a2..cedd467 100644
--- a/gobject/pygobject.h
+++ b/gobject/pygobject.h
@@ -64,6 +64,7 @@ typedef struct {
     PyObject_HEAD
     gpointer pointer;
     GType gtype;
+	gboolean free_on_dealloc;
 } PyGPointer;
 
 #define pyg_pointer_get(v,t)      ((t *)((PyGPointer *)(v))->pointer)
@@ -207,6 +208,10 @@ struct _PyGObject_Functions {
                                        gboolean sink);
 
     PyTypeObject *interface_type;
+
+    PyObject* (*pointer_new_from_type) (PyTypeObject *type,
+                                        gpointer      pointer,
+                                        gboolean      free_on_dealloc);
 };
 
 #ifndef _INSIDE_PYGOBJECT_
@@ -280,6 +285,8 @@ struct _PyGObject_Functions *_PyGObject_API;
 
 #define PyGInterface_Type          (*_PyGObject_API->interface_type)
 
+#define pyg_pointer_new_from_type  (_PyGObject_API->pointer_new_from_type)
+
 #define pyg_block_threads()   G_STMT_START {   \
     if (_PyGObject_API->block_threads != NULL) \
       (* _PyGObject_API->block_threads)();     \
diff --git a/gobject/pygpointer.c b/gobject/pygpointer.c
index ee0a8da..b0341c9 100644
--- a/gobject/pygpointer.c
+++ b/gobject/pygpointer.c
@@ -25,6 +25,9 @@
 #endif
 
 #include <pyglib.h>
+#if HAVE_PYGI_H
+#   include <pygi.h>
+#endif
 #include "pygobject-private.h"
 #include "pygpointer.h"
 
@@ -35,6 +38,9 @@ PYGLIB_DEFINE_TYPE("gobject.GPointer", PyGPointer_Type, PyGPointer);
 static void
 pyg_pointer_dealloc(PyGPointer *self)
 {
+    if (self->free_on_dealloc) {
+        g_free(self->pointer);
+    }
     Py_TYPE(self)->tp_free((PyObject *)self);
 }
 
@@ -62,23 +68,6 @@ pyg_pointer_repr(PyGPointer *self)
     return _PyUnicode_FromString(buf);
 }
 
-static int
-pyg_pointer_init(PyGPointer *self, PyObject *args, PyObject *kwargs)
-{
-    gchar buf[512];
-
-    if (!PyArg_ParseTuple(args, ":GPointer.__init__"))
-	return -1;
-
-    self->pointer = NULL;
-    self->gtype = 0;
-
-    g_snprintf(buf, sizeof(buf), "%s can not be constructed",
-	       Py_TYPE(self)->tp_name);
-    PyErr_SetString(PyExc_NotImplementedError, buf);
-    return -1;
-}
-
 static void
 pyg_pointer_free(PyObject *op)
 {
@@ -125,6 +114,33 @@ pyg_register_pointer(PyObject *dict, const gchar *class_name,
     PyDict_SetItemString(dict, (char *)class_name, (PyObject *)type);
 }
 
+PyObject *
+pyg_pointer_new_from_type (PyTypeObject *type,
+                           gpointer      pointer,
+                           gboolean      free_on_dealloc)
+{
+    PyGPointer *self;
+    GType g_type;
+
+    if (!PyType_IsSubtype(type, &PyGPointer_Type)) {
+        PyErr_SetString(PyExc_TypeError, "must be a subtype of gobject.GPointer");
+        return NULL;
+    }
+
+    self = (PyGPointer *)type->tp_alloc(type, 0);
+    if (self == NULL) {
+        return NULL;
+    }
+
+    g_type = pyg_type_from_object((PyObject *)type);
+
+    self->pointer = pointer;
+    self->gtype = g_type;
+    self->free_on_dealloc = free_on_dealloc;
+
+    return (PyObject *)self;
+}
+
 /**
  * pyg_pointer_new:
  * @pointer_type: the GType of the pointer value.
@@ -155,21 +171,107 @@ pyg_pointer_new(GType pointer_type, gpointer pointer)
     }
 
     tp = g_type_get_qdata(pointer_type, pygpointer_class_key);
+
+#if HAVE_PYGI_H
+    if (tp == NULL) {
+        GIRepository *repository;
+        GIBaseInfo *info;
+
+        repository = g_irepository_get_default();
+
+        info = g_irepository_find_by_gtype(repository, pointer_type);
+
+        if (info != NULL) {
+            if (pygi_import() < 0) {
+                PyErr_WarnEx(NULL, "unable to import gi", 1);
+                PyErr_Clear();
+            } else {
+                tp = (PyTypeObject *)pygi_type_find_by_gi_info(info);
+                g_base_info_unref(info);
+                if (tp == NULL) {
+                    PyErr_Clear();
+                } else {
+                    /* Note: The type is registered, so at least a reference remains. */
+                    Py_DECREF((PyObject *)tp);
+                }
+            }
+        }
+    }
+#endif
+
     if (!tp)
 	tp = (PyTypeObject *)&PyGPointer_Type; /* fallback */
-    self = PyObject_NEW(PyGPointer, tp);
+
+    self = (PyGPointer *)pyg_pointer_new_from_type(tp, pointer, FALSE);
 
     pyglib_gil_state_release(state);
 
-    if (self == NULL)
-	return NULL;
+    if (self == NULL) {
+        return NULL;
+    }
 
-    self->pointer = pointer;
+    /* In case the g_type has no wrapper, we don't want self->gtype to be G_TYPE_POINTER. */
     self->gtype = pointer_type;
 
     return (PyObject *)self;
 }
 
+
+#if HAVE_PYGI_H
+static PyObject *
+_pyg_pointer_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;
+    }
+
+    if (pygi_import() < 0) {
+        return NULL;
+    }
+
+    info = pygi_object_get_gi_info((PyObject *)type, &PyGIStructInfo_Type);
+    if (info == NULL) {
+        if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+            PyErr_Format(PyExc_TypeError, "cannot create '%s' instances", type->tp_name);
+        }
+        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 = pyg_pointer_new_from_type(type, pointer, TRUE);
+    if (self == NULL) {
+        g_free(pointer);
+    }
+
+out:
+    g_base_info_unref(info);
+
+    return (PyObject *)self;
+}
+#endif
+
 void
 pygobject_pointer_register_types(PyObject *d)
 {
@@ -180,7 +282,18 @@ pygobject_pointer_register_types(PyObject *d)
     PyGPointer_Type.tp_repr = (reprfunc)pyg_pointer_repr;
     PyGPointer_Type.tp_hash = (hashfunc)pyg_pointer_hash;
     PyGPointer_Type.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE;
-    PyGPointer_Type.tp_init = (initproc)pyg_pointer_init;
     PyGPointer_Type.tp_free = (freefunc)pyg_pointer_free;
+
+#if HAVE_PYGI_H
+    PyGPointer_Type.tp_new = (newfunc)_pyg_pointer_new;
+#endif
+
     PYGOBJECT_REGISTER_GTYPE(d, PyGPointer_Type, "GPointer", G_TYPE_POINTER); 
+
+#if !HAVE_PYGI_H
+    /* We don't want instances to be created in Python, but
+     * PYGOBJECT_REGISTER_GTYPE assigned PyObject_GenericNew as instance
+     * constructor. It's not too late to revert it to NULL, though. */
+    PyGPointer_Type.tp_new = (newfunc)NULL;
+#endif
 }
diff --git a/tests/test_girepository.py b/tests/test_girepository.py
index 3b59f0c..d71053d 100644
--- a/tests/test_girepository.py
+++ b/tests/test_girepository.py
@@ -539,7 +539,7 @@ class TestGIEverything(unittest.TestCase):
 
     def testStructA(self):
         # Test inheritance.
-        self.assertTrue(issubclass(Everything.TestStructA, gobject.GBoxed))
+        self.assertTrue(issubclass(Everything.TestStructA, gobject.GPointer))
 
         # Test instanciation.
         a = Everything.TestStructA()



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]