Commit e65275bc authored by Tomeu Vizoso's avatar Tomeu Vizoso

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
parent 3b3bd4da
......@@ -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 \
......
......@@ -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) {
......
......@@ -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);
}
......@@ -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);
}
......@@ -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__ */
......@@ -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 "
......
......@@ -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);
}
......
......@@ -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;
......
......@@ -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()
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment