[pygobject] Add cairo marshaling support for non-introspected signals



commit de827d00762f2a741f90bc38f8b55518593f4509
Author: Simon Feltman <sfeltman src gnome org>
Date:   Sun Mar 23 01:59:00 2014 -0700

    Add cairo marshaling support for non-introspected signals
    
    Add link dependency of cairo-gobject to _gi_cairo_la needed for retrieving
    the GTypes of cairo classes.
    Add GValue marshalers for cairo Context, Surface, FontFace, ScaledFont,
    and Pattern classes.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=694604

 gi/Makefile.am          |    2 +
 gi/pygi-foreign-cairo.c |  186 +++++++++++++++++++++++++++++++++++++++++++++++
 gi/pygi-type.h          |    1 +
 gi/pygtype.c            |    2 +
 tests/test_cairo.py     |   65 ++++++++++++++++
 5 files changed, 256 insertions(+), 0 deletions(-)
---
diff --git a/gi/Makefile.am b/gi/Makefile.am
index 61e4ee7..6fb1c5d 100644
--- a/gi/Makefile.am
+++ b/gi/Makefile.am
@@ -140,12 +140,14 @@ _gi_cairo_la_SOURCES = \
        pygi-foreign-cairo.c
 _gi_cairo_la_CFLAGS = \
        $(GI_CFLAGS) \
+       $(CAIRO_CFLAGS) \
        $(PYCAIRO_CFLAGS)
 _gi_cairo_la_CPPFLAGS = \
        $(extension_cppflags)
 _gi_cairo_la_LIBADD = \
        $(extension_libadd) \
        $(GI_LIBS) \
+       $(CAIRO_LIBS) \
        $(PYCAIRO_LIBS)
 _gi_cairo_la_LDFLAGS = \
        $(extension_ldflags) \
diff --git a/gi/pygi-foreign-cairo.c b/gi/pygi-foreign-cairo.c
index a53ae4f..5937759 100644
--- a/gi/pygi-foreign-cairo.c
+++ b/gi/pygi-foreign-cairo.c
@@ -31,6 +31,8 @@ static Pycairo_CAPI_t *Pycairo_CAPI;
 #include <pycairo/py3cairo.h>
 #endif
 
+#include <cairo-gobject.h>
+
 /* Limit includes from PyGI to APIs which do not have link dependencies
  * (pygobject.h and pygi-foreign-api.h) since _gi_cairo is built as a separate
  * shared library that interacts with PyGI through a PyCapsule API at runtime.
@@ -38,6 +40,10 @@ static Pycairo_CAPI_t *Pycairo_CAPI;
 #include <pygi-foreign-api.h>
 #include <pyglib-python-compat.h>
 
+/*
+ * cairo_t marshaling
+ */
+
 static PyObject *
 cairo_context_to_arg (PyObject        *value,
                       GIInterfaceInfo *interface_info,
@@ -70,6 +76,7 @@ cairo_context_from_arg (GIInterfaceInfo *interface_info,
     return PycairoContext_FromContext (context, &PycairoContext_Type, NULL);
 }
 
+
 static PyObject *
 cairo_context_release (GIBaseInfo *base_info,
                        gpointer    struct_)
@@ -78,6 +85,36 @@ cairo_context_release (GIBaseInfo *base_info,
     Py_RETURN_NONE;
 }
 
+static int
+cairo_context_to_gvalue (GValue *value, PyObject *obj)
+{
+    cairo_t *cr = PycairoContext_GET (obj);
+    if (!cr) {
+        return -1;
+    }
+
+    /* PycairoContext_GET returns a borrowed reference, use set_boxed
+     * to add new ref to the context which will be managed by the GValue. */
+    g_value_set_boxed (value, cr);
+    return 0;
+}
+
+static PyObject *
+cairo_context_from_gvalue (const GValue *value)
+{
+    /* PycairoContext_FromContext steals a ref, so we dup it out of the GValue. */
+    cairo_t *cr = g_value_dup_boxed (value);
+    if (!cr) {
+        return NULL;
+    }
+
+    return PycairoContext_FromContext (cr, &PycairoContext_Type, NULL);
+}
+
+
+/*
+ * cairo_surface_t marshaling
+ */
 
 static PyObject *
 cairo_surface_to_arg (PyObject        *value,
@@ -120,6 +157,36 @@ cairo_surface_release (GIBaseInfo *base_info,
     Py_RETURN_NONE;
 }
 
+static int
+cairo_surface_to_gvalue (GValue *value, PyObject *obj)
+{
+    cairo_surface_t *surface = ((PycairoSurface*) obj)->surface;
+    if (!surface) {
+        return -1;
+    }
+
+    /* surface is a borrowed reference, use set_boxed
+     * to add new ref to the context which will be managed by the GValue. */
+    g_value_set_boxed (value, surface);
+    return 0;
+}
+
+static PyObject *
+cairo_surface_from_gvalue (const GValue *value)
+{
+    /* PycairoSurface_FromSurface steals a ref, so we dup it out of the GValue. */
+    cairo_surface_t *surface = g_value_dup_boxed (value);
+    if (!surface) {
+        return NULL;
+    }
+
+    return PycairoSurface_FromSurface (surface, NULL);
+}
+
+
+/*
+ * cairo_path_t marshaling
+ */
 
 static PyObject *
 cairo_path_to_arg (PyObject        *value,
@@ -164,6 +231,39 @@ cairo_path_release (GIBaseInfo *base_info,
     Py_RETURN_NONE;
 }
 
+
+/*
+ * cairo_font_face_t marshaling
+ */
+
+static int
+cairo_font_face_to_gvalue (GValue *value, PyObject *obj)
+{
+    cairo_font_face_t *font_face = ((PycairoFontFace*) obj)->font_face;
+    if (!font_face) {
+        return -1;
+    }
+
+    g_value_set_boxed (value, font_face);
+    return 0;
+}
+
+static PyObject *
+cairo_font_face_from_gvalue (const GValue *value)
+{
+    cairo_font_face_t *font_face = g_value_dup_boxed (value);
+    if (!font_face) {
+        return NULL;
+    }
+
+    return PycairoFontFace_FromFontFace (font_face);
+}
+
+
+/*
+ * cairo_font_options_t marshaling
+ */
+
 static PyObject *
 cairo_font_options_to_arg (PyObject        *value,
                            GIInterfaceInfo *interface_info,
@@ -205,6 +305,69 @@ cairo_font_options_release (GIBaseInfo *base_info,
     Py_RETURN_NONE;
 }
 
+
+/*
+ * scaled_font_t marshaling
+ */
+
+static int
+cairo_scaled_font_to_gvalue (GValue *value, PyObject *obj)
+{
+    cairo_scaled_font_t *scaled_font = ((PycairoScaledFont*) obj)->scaled_font;
+    if (!scaled_font) {
+        return -1;
+    }
+
+    /* scaled_font is a borrowed reference, use set_boxed
+     * to add new ref to the context which will be managed by the GValue. */
+    g_value_set_boxed (value, scaled_font);
+    return 0;
+}
+
+static PyObject *
+cairo_scaled_font_from_gvalue (const GValue *value)
+{
+    /* PycairoScaledFont_FromScaledFont steals a ref, so we dup it out of the GValue. */
+    cairo_scaled_font_t *scaled_font = g_value_dup_boxed (value);
+    if (!scaled_font) {
+        return NULL;
+    }
+
+    return PycairoScaledFont_FromScaledFont (scaled_font);
+}
+
+
+/*
+ * cairo_pattern_t marshaling
+ */
+
+static int
+cairo_pattern_to_gvalue (GValue *value, PyObject *obj)
+{
+    cairo_pattern_t *pattern = ((PycairoPattern*) obj)->pattern;
+    if (!pattern) {
+        return -1;
+    }
+
+    /* pattern is a borrowed reference, use set_boxed
+     * to add new ref to the context which will be managed by the GValue. */
+    g_value_set_boxed (value, pattern);
+    return 0;
+}
+
+static PyObject *
+cairo_pattern_from_gvalue (const GValue *value)
+{
+    /* PycairoPattern_FromPattern steals a ref, so we dup it out of the GValue. */
+    cairo_pattern_t *pattern = g_value_dup_boxed (value);
+    if (!pattern) {
+        return NULL;
+    }
+
+    return PycairoPattern_FromPattern (pattern, NULL);
+}
+
+
 static PyMethodDef _gi_cairo_functions[] = { {0,} };
 PYGLIB_MODULE_START(_gi_cairo, "_gi_cairo")
 {
@@ -217,6 +380,8 @@ PYGLIB_MODULE_START(_gi_cairo, "_gi_cairo")
     if (Pycairo_CAPI == NULL)
         return PYGLIB_MODULE_ERROR_RETURN;
 
+    pygobject_init (3, 13, 2);
+
     pygi_register_foreign_struct ("cairo",
                                   "Context",
                                   cairo_context_to_arg,
@@ -240,5 +405,26 @@ PYGLIB_MODULE_START(_gi_cairo, "_gi_cairo")
                                   cairo_font_options_to_arg,
                                   cairo_font_options_from_arg,
                                   cairo_font_options_release);
+
+    pyg_register_gtype_custom (CAIRO_GOBJECT_TYPE_CONTEXT,
+                               cairo_context_from_gvalue,
+                               cairo_context_to_gvalue);
+
+    pyg_register_gtype_custom (CAIRO_GOBJECT_TYPE_SURFACE,
+                               cairo_surface_from_gvalue,
+                               cairo_surface_to_gvalue);
+
+    pyg_register_gtype_custom (CAIRO_GOBJECT_TYPE_FONT_FACE,
+                               cairo_font_face_from_gvalue,
+                               cairo_font_face_to_gvalue);
+
+    pyg_register_gtype_custom (CAIRO_GOBJECT_TYPE_SCALED_FONT,
+                               cairo_scaled_font_from_gvalue,
+                               cairo_scaled_font_to_gvalue);
+
+    pyg_register_gtype_custom (CAIRO_GOBJECT_TYPE_PATTERN,
+                               cairo_pattern_from_gvalue,
+                               cairo_pattern_to_gvalue);
+
 }
 PYGLIB_MODULE_END;
diff --git a/gi/pygi-type.h b/gi/pygi-type.h
index fdac5c0..85f7551 100644
--- a/gi/pygi-type.h
+++ b/gi/pygi-type.h
@@ -21,6 +21,7 @@
 #define __PYGI_TYPE_H__
 
 #include <Python.h>
+#include <girepository.h>
 
 G_BEGIN_DECLS
 
diff --git a/gi/pygtype.c b/gi/pygtype.c
index 131a271..5957e5c 100644
--- a/gi/pygtype.c
+++ b/gi/pygtype.c
@@ -28,6 +28,7 @@
 #include "pygparamspec.h"
 #include "pygtype.h"
 
+#include "pygi-type.h"
 #include "pygi-value.h"
 
 /* -------------- __gtype__ objects ---------------------------- */
@@ -621,6 +622,7 @@ pyg_type_lookup(GType type)
 
     /* recursively lookup types */
     while (ptype) {
+        pygi_type_import_by_g_type (ptype);
        if ((tm = g_type_get_qdata(ptype, pyg_type_marshal_key)) != NULL)
            break;
        ptype = g_type_parent(ptype);
diff --git a/tests/test_cairo.py b/tests/test_cairo.py
index e4ef65a..fdf86a2 100644
--- a/tests/test_cairo.py
+++ b/tests/test_cairo.py
@@ -7,6 +7,7 @@ import unittest
 import gi
 
 try:
+    gi.require_foreign('cairo')
     import cairo
     from gi.repository import Regress
     has_cairo = True
@@ -19,6 +20,8 @@ try:
 except:
     Gtk = None
 
+from gi.repository import GObject
+
 
 @unittest.skipUnless(has_cairo, 'built without cairo support')
 class Test(unittest.TestCase):
@@ -72,5 +75,67 @@ class TestPango(unittest.TestCase):
         self.assertEqual(type(font_opts.get_subpixel_order()), int)
 
 
+if has_cairo:
+    from gi.repository import cairo as CairoGObject
+
+    # Use PyGI signals to test non-introspected foreign marshaling.
+    class CairoSignalTester(GObject.Object):
+        sig_context = GObject.Signal(arg_types=[CairoGObject.Context])
+        sig_surface = GObject.Signal(arg_types=[CairoGObject.Surface])
+        sig_font_face = GObject.Signal(arg_types=[CairoGObject.FontFace])
+        sig_scaled_font = GObject.Signal(arg_types=[CairoGObject.ScaledFont])
+        sig_pattern = GObject.Signal(arg_types=[CairoGObject.Pattern])
+
+
+ unittest skipUnless(has_cairo, 'built without cairo support')
+class TestSignalMarshaling(unittest.TestCase):
+    # Tests round tripping of cairo objects through non-introspected signals.
+
+    def setUp(self):
+        self.surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 10, 10)
+        self.context = cairo.Context(self.surface)
+        self.tester = CairoSignalTester()
+
+    def pass_object_through_signal(self, obj, signal):
+        """Pass the given `obj` through the `signal` emission storing the
+        `obj` passed through the signal and returning it."""
+        passthrough_result = []
+
+        def callback(instance, passthrough):
+            passthrough_result.append(passthrough)
+
+        signal.connect(callback)
+        signal.emit(obj)
+
+        return passthrough_result[0]
+
+    def test_context(self):
+        result = self.pass_object_through_signal(self.context, self.tester.sig_context)
+        self.assertTrue(isinstance(result, cairo.Context))
+
+    def test_surface(self):
+        result = self.pass_object_through_signal(self.surface, self.tester.sig_surface)
+        self.assertTrue(isinstance(result, cairo.Surface))
+
+    def test_font_face(self):
+        font_face = self.context.get_font_face()
+        result = self.pass_object_through_signal(font_face, self.tester.sig_font_face)
+        self.assertTrue(isinstance(result, cairo.FontFace))
+
+    def test_scaled_font(self):
+        scaled_font = cairo.ScaledFont(self.context.get_font_face(),
+                                       cairo.Matrix(),
+                                       cairo.Matrix(),
+                                       self.context.get_font_options())
+        result = self.pass_object_through_signal(scaled_font, self.tester.sig_scaled_font)
+        self.assertTrue(isinstance(result, cairo.ScaledFont))
+
+    def test_pattern(self):
+        pattern = cairo.SolidPattern(1, 1, 1, 1)
+        result = self.pass_object_through_signal(pattern, self.tester.sig_pattern)
+        self.assertTrue(isinstance(result, cairo.Pattern))
+        self.assertTrue(isinstance(result, cairo.SolidPattern))
+
+
 if __name__ == '__main__':
     unittest.main()


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