From 000f7c36e667c6e078e3370769ea868e56a1b4ee Mon Sep 17 00:00:00 2001 From: Simon van der Linden Date: Sat, 7 Nov 2009 16:43:35 +0100 Subject: Add capabilities to import wrappers from pygi At instance creation for boxed and pointers, at lookup for objects, when the gtype has no wrapper yet, a wrapper may be imported from pygi. The feature is turned on at configure time by --enable-pygi. Because we couldn't create a circular build dependency, PyGI's import function and API definition had to be copied in this tree. --- configure.ac | 8 ++++++ gobject/pygboxed.c | 10 ++++++++ gobject/pygi-external.h | 66 +++++++++++++++++++++++++++++++++++++++++++++++++ gobject/pygobject.c | 10 ++++++++ gobject/pygpointer.c | 11 +++++++++ 5 files changed, 105 insertions(+) create mode 100644 gobject/pygi-external.h diff --git a/configure.ac b/configure.ac index 0bf7610..dc8dea6 100644 --- a/configure.ac +++ b/configure.ac @@ -215,6 +215,14 @@ if test "$enable_introspection" != no; then fi fi +AC_ARG_ENABLE(pygi, + AC_HELP_STRING([--enable-pygi], [Use PyGI to create wrappers for introspection-enabled types]), + enable_pygi=$enableval, + enable_pygi=no) +if test "$enable_pygi" != no; then + AC_DEFINE(ENABLE_PYGI,1,Use PyGI to create wrappers for introspection-enabled types) +fi + dnl add required cflags ... if test "x$GCC" = "xyes"; then JH_ADD_CFLAG([-Wall]) diff --git a/gobject/pygboxed.c b/gobject/pygboxed.c index eb274a2..8a4c8a8 100644 --- a/gobject/pygboxed.c +++ b/gobject/pygboxed.c @@ -28,6 +28,8 @@ #include "pygobject-private.h" #include "pygboxed.h" +#include "pygi-external.h" + GQuark pygboxed_type_key; GQuark pygboxed_marshal_key; @@ -182,6 +184,14 @@ pyg_boxed_new(GType boxed_type, gpointer boxed, gboolean copy_boxed, } tp = g_type_get_qdata(boxed_type, pygboxed_type_key); + + if (tp == NULL) { + tp = (PyTypeObject *)pygi_type_import_by_g_type(boxed_type); + if (tp == NULL) { + PyErr_Clear(); + } + } + if (!tp) tp = (PyTypeObject *)&PyGBoxed_Type; /* fallback */ self = PyObject_NEW(PyGBoxed, tp); diff --git a/gobject/pygi-external.h b/gobject/pygi-external.h new file mode 100644 index 0000000..e0d11c2 --- /dev/null +++ b/gobject/pygi-external.h @@ -0,0 +1,66 @@ +/* -*- Mode: C; c-basic-offset: 4 -*- + * vim: tabstop=4 shiftwidth=4 expandtab + */ + +#ifndef _PYGI_EXTERNAL_H_ +#define _PYGI_EXTERNAL_H_ + +#include +#include + +struct PyGI_API { + PyObject* (*type_import_by_g_type) (GType g_type); +}; + +static struct PyGI_API *PyGI_API = NULL; + +static int +_pygi_import (void) +{ +#if ENABLE_PYGI + PyObject *module; + PyObject *api; + + if (PyGI_API != NULL) { + return 1; + } + + module = PyImport_ImportModule("gi"); + if (module == NULL) { + return -1; + } + + api = PyObject_GetAttrString(module, "_API"); + if (api == NULL) { + Py_DECREF(module); + return -1; + } + if (!PyCObject_Check(api)) { + Py_DECREF(module); + Py_DECREF(api); + PyErr_Format(PyExc_TypeError, "gi._API must be cobject, not %s", + api->ob_type->tp_name); + return -1; + } + + PyGI_API = (struct PyGI_API *)PyCObject_AsVoidPtr(api); + + Py_DECREF(module); + + return 0; +#else + PyErr_SetString(PyExc_ImportError, "PyGI support not enabled"); + return -1; +#endif /* ENABLE_PYGI */ +} + +static inline PyObject * +pygi_type_import_by_g_type (GType g_type) +{ + if (_pygi_import() < 0) { + return NULL; + } + return PyGI_API->type_import_by_g_type(g_type); +} + +#endif /* _PYGI_EXTERNAL_H_ */ diff --git a/gobject/pygobject.c b/gobject/pygobject.c index b4274e1..222280b 100644 --- a/gobject/pygobject.c +++ b/gobject/pygobject.c @@ -29,6 +29,8 @@ #include "pyginterface.h" #include "pygparamspec.h" +#include "pygi-external.h" + static void pygobject_dealloc(PyGObject *self); static int pygobject_traverse(PyGObject *self, visitproc visit, void *arg); @@ -871,6 +873,14 @@ pygobject_lookup_class(GType gtype) py_type = g_type_get_qdata(gtype, pygobject_class_key); if (py_type == NULL) { py_type = g_type_get_qdata(gtype, pyginterface_type_key); + + if (py_type == NULL) { + py_type = (PyTypeObject *)pygi_type_import_by_g_type(gtype); + if (py_type == NULL) { + PyErr_Clear(); + } + } + if (py_type == NULL) { py_type = pygobject_new_with_interfaces(gtype); g_type_set_qdata(gtype, pyginterface_type_key, py_type); diff --git a/gobject/pygpointer.c b/gobject/pygpointer.c index ee0a8da..449b80c 100644 --- a/gobject/pygpointer.c +++ b/gobject/pygpointer.c @@ -28,6 +28,9 @@ #include "pygobject-private.h" #include "pygpointer.h" +#include "pygi-external.h" + + GQuark pygpointer_class_key; PYGLIB_DEFINE_TYPE("gobject.GPointer", PyGPointer_Type, PyGPointer); @@ -155,6 +158,14 @@ pyg_pointer_new(GType pointer_type, gpointer pointer) } tp = g_type_get_qdata(pointer_type, pygpointer_class_key); + + if (tp == NULL) { + tp = (PyTypeObject *)pygi_type_import_by_g_type(pointer_type); + if (tp == NULL) { + PyErr_Clear(); + } + } + if (!tp) tp = (PyTypeObject *)&PyGPointer_Type; /* fallback */ self = PyObject_NEW(PyGPointer, tp); -- cgit