[pygobject] Add foreign struct support for GVariant



commit e65275bc57f345c111eb12a6b4476ff1ddc3bc24
Author: Tomeu Vizoso <tomeu vizoso collabora co uk>
Date:   Thu Jul 15 13:31:33 2010 +0200

    Add foreign struct support for GVariant
    
     * gi/pygi-invoke.c: Wrap foreign structs returned by constructors
     * gi/pygi-foreign.c: Register foreign support for GVariant
     * gi/pygi-struct.c: properly release foreign structs
     * gi/pygi-argument.c, gi/pygi-foreign-cairo.c, gi/pygi.h: Adapt to API changes
     * tests/test_everything.py: Add basic tests for GVariant
    
    https://bugzilla.gnome.org/show_bug.cgi?id=619501

 gi/Makefile.am           |    2 +
 gi/pygi-argument.c       |    2 +-
 gi/pygi-foreign-cairo.c  |   16 +++---
 gi/pygi-foreign.c        |  107 ++++++++++++++++++++++++++++-----------------
 gi/pygi-foreign.h        |    7 +--
 gi/pygi-invoke.c         |   18 ++++----
 gi/pygi-struct.c         |   10 ++++-
 gi/pygi.h                |    9 ++--
 tests/test_everything.py |    8 +++
 9 files changed, 110 insertions(+), 69 deletions(-)
---
diff --git a/gi/Makefile.am b/gi/Makefile.am
index c651c97..fc57edb 100644
--- a/gi/Makefile.am
+++ b/gi/Makefile.am
@@ -34,6 +34,8 @@ _gi_la_SOURCES = \
 	pygi-invoke.h \
 	pygi-foreign.c \
 	pygi-foreign.h \
+	pygi-foreign-gvariant.c \
+	pygi-foreign-gvariant.h \
 	pygi-struct.c \
 	pygi-struct.h \
 	pygi-argument.c \
diff --git a/gi/pygi-argument.c b/gi/pygi-argument.c
index 9ace5d2..1b2e0d2 100644
--- a/gi/pygi-argument.c
+++ b/gi/pygi-argument.c
@@ -1649,7 +1649,7 @@ _pygi_argument_release (GArgument   *arg,
                         }
                     } else if (g_struct_info_is_foreign ( (GIStructInfo*) info)) {
                         if (direction == GI_DIRECTION_OUT && transfer == GI_TRANSFER_EVERYTHING) {
-                            pygi_struct_foreign_release_g_argument (transfer, type_info, arg);
+                            pygi_struct_foreign_release (info, arg->v_pointer);
                         }
                     } else if (g_type_is_a (type, G_TYPE_BOXED)) {
                     } else if (g_type_is_a (type, G_TYPE_POINTER) || type == G_TYPE_NONE) {
diff --git a/gi/pygi-foreign-cairo.c b/gi/pygi-foreign-cairo.c
index 08d50ad..56c9321 100644
--- a/gi/pygi-foreign-cairo.c
+++ b/gi/pygi-foreign-cairo.c
@@ -57,10 +57,10 @@ cairo_context_from_arg (GITypeInfo *type_info, GArgument  *arg)
 }
 
 PyObject *
-cairo_context_release_arg (GITransfer  transfer, GITypeInfo *type_info,
-                           GArgument  *arg)
+cairo_context_release (GIBaseInfo *base_info,
+                       gpointer    struct_)
 {
-    cairo_destroy ( (cairo_t*) arg->v_pointer);
+    cairo_destroy ( (cairo_t*) struct_);
     Py_RETURN_NONE;
 }
 
@@ -96,10 +96,10 @@ cairo_surface_from_arg (GITypeInfo *type_info, GArgument  *arg)
 }
 
 PyObject *
-cairo_surface_release_arg (GITransfer  transfer, GITypeInfo *type_info,
-                           GArgument  *arg)
+cairo_surface_release (GIBaseInfo *base_info,
+                       gpointer    struct_)
 {
-    cairo_surface_destroy ( (cairo_surface_t*) arg->v_pointer);
+    cairo_surface_destroy ( (cairo_surface_t*) struct_);
     Py_RETURN_NONE;
 }
 
@@ -121,11 +121,11 @@ init_gi_cairo (void)
                                   "Context",
                                   cairo_context_to_arg,
                                   cairo_context_from_arg,
-                                  cairo_context_release_arg);
+                                  cairo_context_release);
 
     pygi_register_foreign_struct ("cairo",
                                   "Surface",
                                   cairo_surface_to_arg,
                                   cairo_surface_from_arg,
-                                  cairo_surface_release_arg);
+                                  cairo_surface_release);
 }
diff --git a/gi/pygi-foreign.c b/gi/pygi-foreign.c
index 13a0f77..c80c42d 100644
--- a/gi/pygi-foreign.c
+++ b/gi/pygi-foreign.c
@@ -23,6 +23,7 @@
  */
 
 #include "pygi-foreign.h"
+#include "pygi-foreign-gvariant.h"
 
 #include <config.h>
 #include <girepository.h>
@@ -32,60 +33,85 @@ typedef struct {
     const char *name;
     PyGIArgOverrideToGArgumentFunc to_func;
     PyGIArgOverrideFromGArgumentFunc from_func;
-    PyGIArgOverrideReleaseGArgumentFunc release_func;
+    PyGIArgOverrideReleaseFunc release_func;
 } PyGIForeignStruct;
 
 static GPtrArray *foreign_structs = NULL;
 
+void
+init_foreign_structs ()
+{
+    foreign_structs = g_ptr_array_new ();
+
+    pygi_register_foreign_struct ("GLib",
+                                  "Variant",
+                                  g_variant_to_arg,
+                                  g_variant_from_arg,
+                                  g_variant_release_foreign);
+}
+
 static PyGIForeignStruct *
-pygi_struct_foreign_lookup (GITypeInfo *type_info)
+do_lookup (const gchar *namespace, const gchar *name)
 {
     gint i;
-    PyObject *module;
-    gchar *module_name;
-    GIBaseInfo *base_info;
-    const gchar *namespace;
-    const gchar *name;
-
-    base_info = g_type_info_get_interface (type_info);
-    if (base_info == NULL) {
-        PyErr_Format (PyExc_ValueError, "Couldn't resolve the type of this foreign struct");
-        return NULL;
+    for (i = 0; i < foreign_structs->len; i++) {
+        PyGIForeignStruct *foreign_struct = \
+                g_ptr_array_index (foreign_structs, i);
+
+        if ( (strcmp (namespace, foreign_struct->namespace) == 0) &&
+                (strcmp (name, foreign_struct->name) == 0)) {
+            return foreign_struct;
+        }
+    }
+    return NULL;
+}
+
+static PyGIForeignStruct *
+pygi_struct_foreign_lookup (GIBaseInfo *base_info)
+{
+    PyGIForeignStruct *result;
+    const gchar *namespace = g_base_info_get_namespace (base_info);
+    const gchar *name = g_base_info_get_name (base_info);
+
+    if (foreign_structs == NULL) {
+        init_foreign_structs ();
     }
 
-    namespace = g_base_info_get_namespace (base_info);
-    name = g_base_info_get_name (base_info);
+    result = do_lookup (namespace, name);
 
-    module_name = g_strconcat ("gi._gi_", g_base_info_get_namespace (base_info), NULL);
-    module = PyImport_ImportModule (module_name);
-    g_free (module_name);
+    if (result == NULL) {
+        gchar *module_name = g_strconcat ("gi._gi_", namespace, NULL);
+        PyObject *module = PyImport_ImportModule (module_name);
 
-    if (foreign_structs != NULL) {
-        for (i = 0; i < foreign_structs->len; i++) {
-            PyGIForeignStruct *foreign_struct = \
-                    g_ptr_array_index (foreign_structs, i);
+        g_free (module_name);
 
-            if ( (strcmp (namespace, foreign_struct->namespace) == 0) &&
-                    (strcmp (name, foreign_struct->name) == 0)) {
-                g_base_info_unref (base_info);
-                return foreign_struct;
-            }
+        if (module == NULL)
+            PyErr_Clear ();
+        else {
+            Py_DECREF (module);
+            result = do_lookup (namespace, name);
         }
     }
 
-    g_base_info_unref (base_info);
+    if (result == NULL) {
+        PyErr_Format (PyExc_TypeError,
+                      "Couldn't find conversion for foreign struct '%s.%s'",
+                      namespace,
+                      name);
+    }
 
-    PyErr_Format (PyExc_TypeError, "Couldn't find conversion for foreign struct '%s.%s'", namespace, name);
-    return NULL;
+    return result;
 }
 
 PyObject *
-pygi_struct_foreign_convert_to_g_argument (PyObject      *value,
+pygi_struct_foreign_convert_to_g_argument (PyObject       *value,
                                            GITypeInfo     *type_info,
                                            GITransfer      transfer,
                                            GArgument      *arg)
 {
-    PyGIForeignStruct *foreign_struct = pygi_struct_foreign_lookup (type_info);
+    GIBaseInfo *base_info = g_type_info_get_interface (type_info);
+    PyGIForeignStruct *foreign_struct = pygi_struct_foreign_lookup (base_info);
+    g_base_info_unref (base_info);
 
     if (foreign_struct == NULL)
         return NULL;
@@ -100,7 +126,10 @@ PyObject *
 pygi_struct_foreign_convert_from_g_argument (GITypeInfo *type_info,
                                              GArgument  *arg)
 {
-    PyGIForeignStruct *foreign_struct = pygi_struct_foreign_lookup (type_info);
+    GIBaseInfo *base_info = g_type_info_get_interface (type_info);
+    PyGIForeignStruct *foreign_struct = pygi_struct_foreign_lookup (base_info);
+    g_base_info_unref (base_info);
+
 
     if (foreign_struct == NULL)
         return NULL;
@@ -109,11 +138,10 @@ pygi_struct_foreign_convert_from_g_argument (GITypeInfo *type_info,
 }
 
 PyObject *
-pygi_struct_foreign_release_g_argument (GITransfer  transfer,
-                                        GITypeInfo *type_info,
-                                        GArgument  *arg)
+pygi_struct_foreign_release (GIBaseInfo *base_info,
+                             gpointer    struct_)
 {
-    PyGIForeignStruct *foreign_struct = pygi_struct_foreign_lookup (type_info);
+    PyGIForeignStruct *foreign_struct = pygi_struct_foreign_lookup (base_info);
 
     if (foreign_struct == NULL)
         return NULL;
@@ -121,7 +149,7 @@ pygi_struct_foreign_release_g_argument (GITransfer  transfer,
     if (!foreign_struct->release_func)
         Py_RETURN_NONE;
 
-    if (!foreign_struct->release_func (transfer, type_info, arg))
+    if (!foreign_struct->release_func (base_info, struct_))
         return NULL;
 
     Py_RETURN_NONE;
@@ -132,7 +160,7 @@ pygi_register_foreign_struct_real (const char* namespace_,
                                    const char* name,
                                    PyGIArgOverrideToGArgumentFunc to_func,
                                    PyGIArgOverrideFromGArgumentFunc from_func,
-                                   PyGIArgOverrideReleaseGArgumentFunc release_func)
+                                   PyGIArgOverrideReleaseFunc release_func)
 {
     PyGIForeignStruct *new_struct = g_slice_new0 (PyGIForeignStruct);
     new_struct->namespace = namespace_;
@@ -141,8 +169,5 @@ pygi_register_foreign_struct_real (const char* namespace_,
     new_struct->from_func = from_func;
     new_struct->release_func = release_func;
 
-    if (foreign_structs == NULL)
-        foreign_structs = g_ptr_array_new ();
-
     g_ptr_array_add (foreign_structs, new_struct);
 }
diff --git a/gi/pygi-foreign.h b/gi/pygi-foreign.h
index 9a35bd8..9582960 100644
--- a/gi/pygi-foreign.h
+++ b/gi/pygi-foreign.h
@@ -36,14 +36,13 @@ PyObject *pygi_struct_foreign_convert_to_g_argument (PyObject           *value,
                                                      GArgument          *arg);
 PyObject *pygi_struct_foreign_convert_from_g_argument (GITypeInfo *type_info,
                                                        GArgument  *arg);
-PyObject *pygi_struct_foreign_release_g_argument (GITransfer          transfer,
-                                                  GITypeInfo         *type_info,
-                                                  GArgument          *arg);
+PyObject *pygi_struct_foreign_release (GITypeInfo *type_info,
+                                       gpointer struct_);
 
 void pygi_register_foreign_struct_real (const char* namespace_,
                                         const char* name,
                                         PyGIArgOverrideToGArgumentFunc to_func,
                                         PyGIArgOverrideFromGArgumentFunc from_func,
-                                        PyGIArgOverrideReleaseGArgumentFunc release_func);
+                                        PyGIArgOverrideReleaseFunc release_func);
 
 #endif /* __PYGI_FOREIGN_H__ */
diff --git a/gi/pygi-invoke.c b/gi/pygi-invoke.c
index a470003..022874e 100644
--- a/gi/pygi-invoke.c
+++ b/gi/pygi-invoke.c
@@ -639,6 +639,11 @@ _process_invocation_state (struct invocation_state *state,
         GIInfoType info_type;
         GITransfer transfer;
 
+        if (state->return_arg.v_pointer == NULL) {
+            PyErr_SetString (PyExc_TypeError, "constructor returned NULL");
+            return FALSE;
+        }
+
         g_assert (state->n_py_args > 0);
         py_type = (PyTypeObject *) PyTuple_GET_ITEM (py_args, 0);
 
@@ -662,18 +667,13 @@ _process_invocation_state (struct invocation_state *state,
                 type = g_registered_type_info_get_g_type ( (GIRegisteredTypeInfo *) info);
 
                 if (g_type_is_a (type, G_TYPE_BOXED)) {
-                    if (state->return_arg.v_pointer == NULL) {
-                        PyErr_SetString (PyExc_TypeError, "constructor returned NULL");
-                        break;
-                    }
                     g_warn_if_fail (transfer == GI_TRANSFER_EVERYTHING);
                     state->return_value = _pygi_boxed_new (py_type, state->return_arg.v_pointer, transfer == GI_TRANSFER_EVERYTHING);
+                } else if (type == G_TYPE_NONE && g_struct_info_is_foreign (info)) {
+                    state->return_value =
+                        pygi_struct_foreign_convert_from_g_argument (
+                            state->return_type_info, state->return_arg.v_pointer);
                 } else if (g_type_is_a (type, G_TYPE_POINTER) || type == G_TYPE_NONE) {
-                    if (state->return_arg.v_pointer == NULL) {
-                        PyErr_SetString (PyExc_TypeError, "constructor returned NULL");
-                        break;
-                    }
-
                     if (transfer != GI_TRANSFER_NOTHING)
                         g_warning ("Transfer mode should be set to None for "
                                    "struct types as there is no way to free "
diff --git a/gi/pygi-struct.c b/gi/pygi-struct.c
index 2f1ce42..e639c35 100644
--- a/gi/pygi-struct.c
+++ b/gi/pygi-struct.c
@@ -29,14 +29,22 @@
 static void
 _struct_dealloc (PyGIStruct *self)
 {
+    GIBaseInfo *info = _pygi_object_get_gi_info (
+                           (PyObject *) ( (PyObject *) self)->ob_type,
+                           &PyGIStructInfo_Type);
+
     PyObject_GC_UnTrack ( (PyObject *) self);
 
     PyObject_ClearWeakRefs ( (PyObject *) self);
 
-    if (self->free_on_dealloc) {
+    if (info != NULL && g_struct_info_is_foreign ( (GIStructInfo *) info)) {
+        pygi_struct_foreign_release (info, ( (PyGPointer *) self)->pointer);
+    } else if (self->free_on_dealloc) {
         g_free ( ( (PyGPointer *) self)->pointer);
     }
 
+    g_base_info_unref (info);
+
     ( (PyGPointer *) self)->ob_type->tp_free ( (PyObject *) self);
 }
 
diff --git a/gi/pygi.h b/gi/pygi.h
index 0a8cbf5..92b7bae 100644
--- a/gi/pygi.h
+++ b/gi/pygi.h
@@ -57,9 +57,8 @@ typedef PyObject * (*PyGIArgOverrideToGArgumentFunc) (PyObject       *value,
                                                       GArgument      *arg);
 typedef PyObject * (*PyGIArgOverrideFromGArgumentFunc) (GITypeInfo *type_info,
                                                         GArgument  *arg);
-typedef PyObject * (*PyGIArgOverrideReleaseGArgumentFunc) (GITransfer  transfer,
-                                                           GITypeInfo *type_info,
-                                                           GArgument  *arg);
+typedef PyObject * (*PyGIArgOverrideReleaseFunc) (GITypeInfo *type_info,
+                                                  gpointer  struct_);
 
 struct PyGI_API {
     PyObject* (*type_import_by_g_type) (GType g_type);
@@ -67,7 +66,7 @@ struct PyGI_API {
                                      const char* name,
                                      PyGIArgOverrideToGArgumentFunc to_func,
                                      PyGIArgOverrideFromGArgumentFunc from_func,
-                                     PyGIArgOverrideReleaseGArgumentFunc release_func);
+                                     PyGIArgOverrideReleaseFunc release_func);
 };
 
 static struct PyGI_API *PyGI_API = NULL;
@@ -101,7 +100,7 @@ pygi_register_foreign_struct (const char* namespace_,
                               const char* name,
                               PyGIArgOverrideToGArgumentFunc to_func,
                               PyGIArgOverrideFromGArgumentFunc from_func,
-                              PyGIArgOverrideReleaseGArgumentFunc release_func)
+                              PyGIArgOverrideReleaseFunc release_func)
 {
     if (_pygi_import() < 0) {
         return NULL;
diff --git a/tests/test_everything.py b/tests/test_everything.py
index 69d1954..4e68b65 100644
--- a/tests/test_everything.py
+++ b/tests/test_everything.py
@@ -10,6 +10,7 @@ from sys import getrefcount
 import cairo
 
 from gi.repository import GObject
+from gi.repository import GLib
 from gi.repository import Everything
 
 class TestEverything(unittest.TestCase):
@@ -47,6 +48,13 @@ class TestEverything(unittest.TestCase):
         self.assertEquals(surface.get_width(), 10)
         self.assertEquals(surface.get_height(), 10)
 
+    def test_gvariant(self):
+        variant = GLib.Variant.new_int32(42);
+        self.assertEquals(variant.get_int32(), 42)
+
+        variant = GLib.Variant.new_strv(['mec', 'mac']);
+        self.assertEquals(variant.get_strv(), ['mec', 'mac'])
+
     def test_floating(self):
         Everything.TestFloating()
 



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