[pygi] Add support for foreign structs



commit a34cb9f0038a6c89e5e6c5f7761d48a5a833044f
Author: Tomeu Vizoso <tomeu sugarlabs org>
Date:   Sat Apr 17 10:54:45 2010 -0400

    Add support for foreign structs
    
    https://bugzilla.gnome.org/show_bug.cgi?id=603712

 configure.ac             |    6 ++
 gi/Makefile.am           |   10 +++-
 gi/gimodule.c            |    7 +++
 gi/pygi-argument.c       |   27 +++++++++-
 gi/pygi-foreign-cairo.c  |  103 ++++++++++++++++++++++++++++++++++++++
 gi/pygi-foreign-cairo.h  |   55 ++++++++++++++++++++
 gi/pygi-foreign.c        |  123 ++++++++++++++++++++++++++++++++++++++++++++++
 gi/pygi-foreign.h        |   52 +++++++++++++++++++
 gi/pygi-private.h        |    1 +
 tests/test_everything.py |   48 ++++++++++++++++++
 10 files changed, 428 insertions(+), 4 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 33f30e9..3a596c3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -47,6 +47,12 @@ INTROSPECTION_COMPILER=`$PKG_CONFIG --variable=g_ir_compiler gobject-introspecti
 AC_SUBST(INTROSPECTION_SCANNER) 
 AC_SUBST(INTROSPECTION_COMPILER) 
 
+m4_define(pycairo_required_version,    1.0.2)
+PKG_CHECK_MODULES(PYCAIRO, [pycairo >= pycairo_required_version],
+        have_pycairo=true, have_pycairo=false)
+AC_SUBST(PYCAIRO_CFLAGS)
+AC_SUBST(PYCAIRO_LIBS)
+
 AC_OUTPUT(
 	Makefile
 	gi/Makefile
diff --git a/gi/Makefile.am b/gi/Makefile.am
index 63f90e3..0299d01 100644
--- a/gi/Makefile.am
+++ b/gi/Makefile.am
@@ -8,7 +8,8 @@ SUBDIRS = \
 	overrides
 AM_CFLAGS = \
 	$(PYTHON_INCLUDES) \
-	$(GNOME_CFLAGS)
+	$(GNOME_CFLAGS) \
+	$(PYCAIRO_CFLAGS)
 
 pygidir = $(pkgpyexecdir)/gi
 pygi_PYTHON = \
@@ -22,12 +23,17 @@ _gi_la_LDFLAGS = \
 	-avoid-version \
 	-export-symbols-regex init_gi
 _gi_la_LIBADD = \
-	$(GNOME_LIBS)
+	$(GNOME_LIBS) \
+	$(PYCAIRO_LIBS)
 _gi_la_SOURCES = \
 	pygi-repository.c \
 	pygi-repository.h \
 	pygi-info.c \
 	pygi-info.h \
+	pygi-foreign.c \
+	pygi-foreign.h \
+	pygi-foreign-cairo.c \
+	pygi-foreign-cairo.h \
 	pygi-struct.c \
 	pygi-struct.h \
 	pygi-argument.c \
diff --git a/gi/gimodule.c b/gi/gimodule.c
index 8811539..8dd8ac5 100644
--- a/gi/gimodule.c
+++ b/gi/gimodule.c
@@ -25,6 +25,9 @@
 
 #include <pygobject.h>
 
+# include <pycairo.h>
+Pycairo_CAPI_t *Pycairo_CAPI;
+
 static PyObject *
 _wrap_pyg_enum_add (PyObject *self,
                     PyObject *args,
@@ -163,6 +166,10 @@ init_gi(void)
         return;
     }
 
+    Pycairo_IMPORT;
+    if (Pycairo_CAPI == NULL)
+        return;
+
     _pygi_repository_register_types(m);
     _pygi_info_register_types(m);
     _pygi_struct_register_types(m);
diff --git a/gi/pygi-argument.c b/gi/pygi-argument.c
index edbb31f..335074e 100644
--- a/gi/pygi-argument.c
+++ b/gi/pygi-argument.c
@@ -121,9 +121,16 @@ _pygi_g_registered_type_info_check_object (GIRegisteredTypeInfo *info,
     GType g_type;
     PyObject *py_type;
     gchar *type_name_expected = NULL;
+    GIInfoType interface_type;
 
-    g_type = g_registered_type_info_get_g_type(info);
+    interface_type = g_base_info_get_type(info);
+    if ((interface_type == GI_INFO_TYPE_STRUCT) &&
+            (g_struct_info_is_foreign((GIStructInfo*)info))) {
+        /* TODO: Could we check is the correct foreign type? */
+        return 1;
+    }
 
+    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 {
@@ -131,7 +138,7 @@ _pygi_g_registered_type_info_check_object (GIRegisteredTypeInfo *info,
     }
 
     if (py_type == NULL) {
-        return FALSE;
+        return 0;
     }
 
     g_assert(PyType_Check(py_type));
@@ -932,6 +939,16 @@ array_item_error:
                         if (transfer == GI_TRANSFER_EVERYTHING) {
                             arg.v_pointer = g_boxed_copy(type, arg.v_pointer);
                         }
+                    } else if ((type == G_TYPE_NONE) && (g_struct_info_is_foreign (info))) {
+                        gint retval;
+
+                        retval = pygi_struct_foreign_convert_to_g_argument(
+                                object, type_info, transfer, &arg);
+
+                        if (!retval) {
+                            PyErr_SetString(PyExc_RuntimeError, "PyObject conversion to foreign struct failed");
+                            break;
+                        }
                     } else if (g_type_is_a(type, G_TYPE_POINTER) || type == G_TYPE_NONE) {
                         g_warn_if_fail(!g_type_info_is_pointer(type_info) || transfer == GI_TRANSFER_NOTHING);
                         arg.v_pointer = pyg_pointer_get(object, void);
@@ -1433,6 +1450,8 @@ _pygi_argument_to_object (GArgument  *arg,
                         }
 
                         Py_XDECREF(py_type);
+                    } else if ((type == G_TYPE_NONE) && (g_struct_info_is_foreign (info))) {
+                        object = pygi_struct_foreign_convert_from_g_argument(type_info, arg->v_pointer);
                     } else if (type == G_TYPE_NONE) {
                         PyObject *py_type;
 
@@ -1721,6 +1740,10 @@ _pygi_argument_release (GArgument   *arg,
                         if (direction == GI_DIRECTION_IN && transfer == GI_TRANSFER_NOTHING) {
                             g_closure_unref(arg->v_pointer);
                         }
+                    } 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);
+                        }
                     } else if (g_type_is_a(type, G_TYPE_BOXED)) {
                     } else if (g_type_is_a(type, G_TYPE_POINTER) || type == G_TYPE_NONE) {
                         g_warn_if_fail(!g_type_info_is_pointer(type_info) || transfer == GI_TRANSFER_NOTHING);
diff --git a/gi/pygi-foreign-cairo.c b/gi/pygi-foreign-cairo.c
new file mode 100644
index 0000000..a051d33
--- /dev/null
+++ b/gi/pygi-foreign-cairo.c
@@ -0,0 +1,103 @@
+/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
+/*
+ * Copyright (c) 2010  Collabora Ltd. <http://www.collabora.co.uk/>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <cairo.h>
+#include <pycairo.h>
+extern Pycairo_CAPI_t *Pycairo_CAPI;
+
+#include "pygi-foreign.h"
+#include "pygi-foreign-cairo.h"
+
+gboolean
+cairo_context_to_arg(PyObject       *value,
+                     GITypeInfo     *type_info,
+                     GITransfer      transfer,
+                     GArgument      *arg)
+{
+    cairo_t *cr;
+
+    g_assert (transfer == GI_TRANSFER_NOTHING);
+
+    cr = PycairoContext_GET(value);
+    if (!cr)
+        return FALSE;
+
+    arg->v_pointer = cr;
+    return TRUE;
+}
+
+PyObject *
+cairo_context_from_arg(GITypeInfo *type_info, GArgument  *arg)
+{
+    cairo_t *context = (cairo_t*) arg;
+
+    cairo_reference (context);
+
+    return PycairoContext_FromContext (context, &PycairoContext_Type, NULL);
+}
+
+gboolean
+cairo_context_release_arg(GITransfer  transfer, GITypeInfo *type_info,
+                          GArgument  *arg)
+{
+    cairo_destroy((cairo_t*)arg->v_pointer);
+    return TRUE;
+}
+
+
+gboolean
+cairo_surface_to_arg(PyObject       *value,
+                     GITypeInfo     *type_info,
+                     GITransfer      transfer,
+                     GArgument      *arg)
+{
+    cairo_surface_t *surface;
+
+    g_assert (transfer == GI_TRANSFER_NOTHING);
+
+    surface = ((PycairoSurface*)value)->surface;
+    if (!surface)
+        return FALSE;
+
+    arg->v_pointer = surface;
+    return TRUE;
+}
+
+PyObject *
+cairo_surface_from_arg(GITypeInfo *type_info, GArgument  *arg)
+{
+    cairo_surface_t *surface = (cairo_surface_t*) arg;
+
+    cairo_surface_reference (surface);
+
+    return PycairoSurface_FromSurface (surface, NULL);
+}
+
+gboolean
+cairo_surface_release_arg(GITransfer  transfer, GITypeInfo *type_info,
+                          GArgument  *arg)
+{
+    cairo_surface_destroy((cairo_surface_t*)arg->v_pointer);
+    return TRUE;
+}
+
diff --git a/gi/pygi-foreign-cairo.h b/gi/pygi-foreign-cairo.h
new file mode 100644
index 0000000..b8dbcaa
--- /dev/null
+++ b/gi/pygi-foreign-cairo.h
@@ -0,0 +1,55 @@
+/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
+/*
+ * Copyright (c) 2010  Collabora Ltd. <http://www.collabora.co.uk/>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef __PYGI_FOREIGN_CAIRO_H__
+#define __PYGI_FOREIGN_CAIRO_H__
+
+#include "pygi-foreign.h"
+
+gboolean cairo_context_to_arg(PyObject       *value,
+                              GITypeInfo     *type_info,
+                              GITransfer      transfer,
+                              GArgument      *arg);
+
+PyObject *cairo_context_from_arg(GITypeInfo *type_info,
+                                 GArgument  *arg);
+
+gboolean cairo_context_release_arg(GITransfer  transfer,
+                                   GITypeInfo *type_info,
+                                   GArgument  *arg);
+
+
+gboolean cairo_surface_to_arg(PyObject       *value,
+                              GITypeInfo     *type_info,
+                              GITransfer      transfer,
+                              GArgument      *arg);
+
+PyObject *cairo_surface_from_arg(GITypeInfo *type_info,
+                                 GArgument  *arg);
+
+gboolean cairo_surface_release_arg(GITransfer  transfer,
+                                   GITypeInfo *type_info,
+                                   GArgument  *arg);
+
+#endif /* __PYGI_FOREIGN_CAIRO_H__ */
+
diff --git a/gi/pygi-foreign.c b/gi/pygi-foreign.c
new file mode 100644
index 0000000..cde56b0
--- /dev/null
+++ b/gi/pygi-foreign.c
@@ -0,0 +1,123 @@
+/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
+/*
+ * Copyright (c) 2010  litl, LLC
+ * Copyright (c) 2010  Collabora Ltd. <http://www.collabora.co.uk/>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "pygi-foreign.h"
+
+#include <config.h>
+#include <girepository.h>
+
+#include "pygi-foreign-cairo.h"
+
+static struct {
+    char *namespace;
+    char *name;
+    PyGIArgOverrideToGArgumentFunc to_func;
+    PyGIArgOverrideFromGArgumentFunc from_func;
+    PyGIArgOverrideReleaseGArgumentFunc release_func;
+} foreign_structs[] = {
+    { "cairo", "Context", cairo_context_to_arg, cairo_context_from_arg,
+                          cairo_context_release_arg },
+    { "cairo", "Surface", cairo_surface_to_arg, cairo_surface_from_arg,
+                          cairo_surface_release_arg },
+    { NULL }
+};
+
+static gint
+pygi_struct_foreign_lookup(GITypeInfo *type_info)
+{
+    GIBaseInfo *base_info;
+
+    base_info = g_type_info_get_interface(type_info);
+    if (base_info) {
+        gint i;
+        const gchar *namespace = g_base_info_get_namespace(base_info);
+        const gchar *name = g_base_info_get_name(base_info);
+
+        for (i = 0; foreign_structs[i].namespace; ++i) {
+
+            if ((strcmp(namespace, foreign_structs[i].namespace) == 0) &&
+                (strcmp(name, foreign_structs[i].name) == 0)) {
+                g_base_info_unref(base_info);
+                return i;
+            }
+        }
+
+        PyErr_Format(PyExc_TypeError, "Couldn't find type %s.%s", namespace,
+                     name);
+
+        g_base_info_unref(base_info);
+    }
+    return -1;
+}
+
+gboolean
+pygi_struct_foreign_convert_to_g_argument(PyObject      *value,
+                                         GITypeInfo     *type_info,
+                                         GITransfer      transfer,
+                                         GArgument      *arg)
+{
+    gint struct_index;
+
+    struct_index = pygi_struct_foreign_lookup (type_info);
+    if (struct_index < 0)
+        return FALSE;
+
+    if (!foreign_structs[struct_index].to_func(value, type_info, transfer, arg))
+        return FALSE;
+
+    return TRUE;
+}
+
+PyObject *
+pygi_struct_foreign_convert_from_g_argument(GITypeInfo *type_info,
+                                            GArgument  *arg)
+{
+    gint struct_index;
+
+    struct_index = pygi_struct_foreign_lookup (type_info);
+    if (struct_index < 0)
+        return NULL;
+
+    return foreign_structs[struct_index].from_func(type_info, arg);
+}
+
+gboolean
+pygi_struct_foreign_release_g_argument(GITransfer  transfer,
+                                       GITypeInfo *type_info,
+                                       GArgument  *arg)
+{
+    gint struct_index;
+
+    struct_index = pygi_struct_foreign_lookup (type_info);
+    if (struct_index < 0)
+        return FALSE;
+
+    if (!foreign_structs[struct_index].release_func)
+        return TRUE;
+
+   if (!foreign_structs[struct_index].release_func(transfer, type_info, arg))
+        return FALSE;
+
+    return TRUE;
+}
diff --git a/gi/pygi-foreign.h b/gi/pygi-foreign.h
new file mode 100644
index 0000000..2f13b0f
--- /dev/null
+++ b/gi/pygi-foreign.h
@@ -0,0 +1,52 @@
+/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
+/*
+ * Copyright (c) 2010  litl, LLC
+ * Copyright (c) 2010  Collabora Ltd. <http://www.collabora.co.uk/>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef __PYGI_FOREIGN_H__
+#define __PYGI_FOREIGN_H__
+
+#include <Python.h>
+#include <girepository.h>
+
+typedef gboolean (*PyGIArgOverrideToGArgumentFunc) (PyObject       *value,
+                                                    GITypeInfo     *type_info,
+                                                    GITransfer      transfer,
+                                                    GArgument      *arg);
+
+typedef PyObject * (*PyGIArgOverrideFromGArgumentFunc) (GITypeInfo *type_info,
+                                                        GArgument  *arg);
+typedef gboolean (*PyGIArgOverrideReleaseGArgumentFunc) (GITransfer  transfer,
+                                                         GITypeInfo *type_info,
+                                                         GArgument  *arg);
+
+gboolean pygi_struct_foreign_convert_to_g_argument (PyObject           *value,
+                                                    GITypeInfo         *type_info,
+                                                    GITransfer          transfer,
+                                                    GArgument          *arg);
+PyObject *pygi_struct_foreign_convert_from_g_argument(GITypeInfo *type_info,
+                                                      GArgument  *arg);
+gboolean pygi_struct_foreign_release_g_argument    (GITransfer          transfer,
+                                                    GITypeInfo         *type_info,
+                                                    GArgument          *arg);
+
+#endif /* __PYGI_FOREIGN_H__ */
diff --git a/gi/pygi-private.h b/gi/pygi-private.h
index 562c8ab..9f39d0d 100644
--- a/gi/pygi-private.h
+++ b/gi/pygi-private.h
@@ -24,6 +24,7 @@
 #include "pygi-boxed.h"
 #include "pygi-argument.h"
 #include "pygi-type.h"
+#include "pygi-foreign.h"
 
 G_BEGIN_DECLS
 
diff --git a/tests/test_everything.py b/tests/test_everything.py
new file mode 100644
index 0000000..60e8f9d
--- /dev/null
+++ b/tests/test_everything.py
@@ -0,0 +1,48 @@
+# -*- Mode: Python; py-indent-offset: 4 -*-
+# vim: tabstop=4 shiftwidth=4 expandtab
+
+import unittest
+
+import sys
+sys.path.insert(0, "../")
+
+import gobject
+import cairo
+
+from gi.repository import Everything
+
+class TestEverything(unittest.TestCase):
+
+    def test_cairo_context(self):
+        context = Everything.test_cairo_context_full_return()
+        self.assertTrue(isinstance(context, cairo.Context))
+
+        surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 10, 10)
+        context = cairo.Context(surface)
+        Everything.test_cairo_context_none_in(context)
+
+    def test_cairo_surface(self):
+        surface = Everything.test_cairo_surface_none_return()
+        self.assertTrue(isinstance(surface, cairo.ImageSurface))
+        self.assertTrue(isinstance(surface, cairo.Surface))
+        self.assertEquals(surface.get_format(), cairo.FORMAT_ARGB32)
+        self.assertEquals(surface.get_width(), 10)
+        self.assertEquals(surface.get_height(), 10)
+
+        surface = Everything.test_cairo_surface_full_return()
+        self.assertTrue(isinstance(surface, cairo.ImageSurface))
+        self.assertTrue(isinstance(surface, cairo.Surface))
+        self.assertEquals(surface.get_format(), cairo.FORMAT_ARGB32)
+        self.assertEquals(surface.get_width(), 10)
+        self.assertEquals(surface.get_height(), 10)
+
+        surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 10, 10)
+        Everything.test_cairo_surface_none_in(surface)
+
+        surface = Everything.test_cairo_surface_full_out()
+        self.assertTrue(isinstance(surface, cairo.ImageSurface))
+        self.assertTrue(isinstance(surface, cairo.Surface))
+        self.assertEquals(surface.get_format(), cairo.FORMAT_ARGB32)
+        self.assertEquals(surface.get_width(), 10)
+        self.assertEquals(surface.get_height(), 10)
+



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