diff options
author | Tomeu Vizoso <tomeu@sugarlabs.org> | 2010-04-17 10:54:45 -0400 |
---|---|---|
committer | Tomeu Vizoso <tomeu@sugarlabs.org> | 2010-04-17 10:57:27 -0400 |
commit | a34cb9f0038a6c89e5e6c5f7761d48a5a833044f (patch) | |
tree | 5523fe12e0bd925be8d95620999b45a8acaf0568 | |
parent | e73b6f6fe8b5f23a2a390ae0a6bbced593ded155 (diff) | |
download | pygi-a34cb9f0038a6c89e5e6c5f7761d48a5a833044f.tar.gz pygi-a34cb9f0038a6c89e5e6c5f7761d48a5a833044f.tar.xz pygi-a34cb9f0038a6c89e5e6c5f7761d48a5a833044f.zip |
Add support for foreign structs
https://bugzilla.gnome.org/show_bug.cgi?id=603712
-rw-r--r-- | configure.ac | 6 | ||||
-rw-r--r-- | gi/Makefile.am | 10 | ||||
-rw-r--r-- | gi/gimodule.c | 7 | ||||
-rw-r--r-- | gi/pygi-argument.c | 27 | ||||
-rw-r--r-- | gi/pygi-foreign-cairo.c | 103 | ||||
-rw-r--r-- | gi/pygi-foreign-cairo.h | 55 | ||||
-rw-r--r-- | gi/pygi-foreign.c | 123 | ||||
-rw-r--r-- | gi/pygi-foreign.h | 52 | ||||
-rw-r--r-- | gi/pygi-private.h | 1 | ||||
-rw-r--r-- | 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) + |