summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--configure.ac11
-rwxr-xr-xexamples/cairo-demo.py6
-rw-r--r--gi/Makefile.am18
-rw-r--r--gi/overrides/GLib.py18
-rw-r--r--gi/overrides/Gtk.py41
-rw-r--r--gi/pygi-argument.c20
-rw-r--r--gi/pygi-cache.c1404
-rw-r--r--gi/pygi-cache.h172
-rw-r--r--gi/pygi-foreign-gvariant.h6
-rw-r--r--gi/pygi-foreign.c7
-rw-r--r--gi/pygi-info.c5
-rw-r--r--gi/pygi-invoke-ng.c464
-rw-r--r--gi/pygi-invoke-state-struct.h44
-rw-r--r--gi/pygi-invoke.h2
-rw-r--r--gi/pygi-marshal-cleanup.c517
-rw-r--r--gi/pygi-marshal-cleanup.h97
-rw-r--r--gi/pygi-marshal-in.c1412
-rw-r--r--gi/pygi-marshal-in.h186
-rw-r--r--gi/pygi-marshal-out.c767
-rw-r--r--gi/pygi-marshal-out.h144
-rw-r--r--gi/pygi-private.h6
-rw-r--r--gi/pygi.h4
-rw-r--r--gobject/pygtype.c7
-rw-r--r--tests/test_gi.py43
-rw-r--r--tests/test_overrides.py45
25 files changed, 5396 insertions, 50 deletions
diff --git a/configure.ac b/configure.ac
index fb692373..d4fcbe35 100644
--- a/configure.ac
+++ b/configure.ac
@@ -124,6 +124,16 @@ AC_ARG_ENABLE(thread,
AC_HELP_STRING([--disable-thread], [Disable pygobject threading support]),,
enable_thread=yes)
+dnl Build with the new caching invoker
+AC_ARG_ENABLE(invoke-ng,
+ AC_HELP_STRING([--disable-invoke-ng], [Disable the new caching invoke path]),,
+ enable_invoke_ng=yes)
+if test "${enable_invoke_ng}" == yes; then
+ AC_DEFINE(ENABLE_INVOKE_NG, 1, Enable the new invoke caching code path)
+fi
+
+AM_CONDITIONAL(ENABLE_INVOKE_NG, test x$enable_invoke_ng == xyes)
+
dnl Building documentation
AC_ARG_ENABLE(docs,
AC_HELP_STRING([--enable-docs], [Enable documentation building]),enable_docs=$enableval,
@@ -284,4 +294,5 @@ AC_OUTPUT
echo
echo "libffi support: $have_libffi"
echo "introspection support: $enable_introspection"
+echo "invoke-ng support: $enable_invoke_ng"
echo
diff --git a/examples/cairo-demo.py b/examples/cairo-demo.py
index 72a05333..9b8e8f9a 100755
--- a/examples/cairo-demo.py
+++ b/examples/cairo-demo.py
@@ -79,9 +79,7 @@ def fill_shapes(ctx, x, y):
def stroke_shapes(ctx, x, y):
draw_shapes(ctx, x, y, False)
-def expose (da, event):
- ctx = Gdk.cairo_create(da.window)
-
+def draw(da, ctx):
ctx.set_source_rgb(0, 0, 0)
ctx.set_line_width(SIZE / 4)
@@ -114,7 +112,7 @@ def main():
drawingarea = Gtk.DrawingArea()
win.add(drawingarea)
- drawingarea.connect('expose_event', expose)
+ drawingarea.connect('draw', draw)
win.show_all()
Gtk.main()
diff --git a/gi/Makefile.am b/gi/Makefile.am
index 31f6c790..fe1e1145 100644
--- a/gi/Makefile.am
+++ b/gi/Makefile.am
@@ -31,7 +31,6 @@ _gi_la_SOURCES = \
pygi-repository.h \
pygi-info.c \
pygi-info.h \
- pygi-invoke.c \
pygi-invoke.h \
pygi-foreign.c \
pygi-foreign.h \
@@ -58,6 +57,23 @@ _gi_la_SOURCES = \
pygobject-external.h \
gimodule.c
+if ENABLE_INVOKE_NG
+_gi_la_SOURCES += \
+ pygi-invoke-ng.c \
+ pygi-invoke-state-struct.h \
+ pygi-cache.h \
+ pygi-cache.c \
+ pygi-marshal-in.c \
+ pygi-marshal-in.h \
+ pygi-marshal-out.c \
+ pygi-marshal-out.h \
+ pygi-marshal-cleanup.c \
+ pygi-marshal-cleanup.h
+else
+_gi_la_SOURCES += \
+ pygi-invoke.c
+endif
+
_gi_cairo_la_CFLAGS = \
$(PYTHON_INCLUDES) \
$(GI_CFLAGS) \
diff --git a/gi/overrides/GLib.py b/gi/overrides/GLib.py
index ad9f2357..e42f854a 100644
--- a/gi/overrides/GLib.py
+++ b/gi/overrides/GLib.py
@@ -84,8 +84,7 @@ class _VariantCreator(object):
'''Handle the case where the outermost type of format is a tuple.'''
format = format[1:] # eat the '('
- builder = GLib.VariantBuilder()
- builder.init(variant_type_from_string('r'))
+ builder = GLib.VariantBuilder.new(variant_type_from_string('r'))
if args is not None:
if not args or type(args[0]) != type(()):
raise (TypeError, 'expected tuple argument')
@@ -102,7 +101,7 @@ class _VariantCreator(object):
def _create_dict(self, format, args):
'''Handle the case where the outermost type of format is a dict.'''
- builder = GLib.VariantBuilder()
+ builder = None
if args is None or not args[0]:
# empty value: we need to call _create() to parse the subtype,
# and specify the element type precisely
@@ -112,9 +111,9 @@ class _VariantCreator(object):
raise ValueError('dictionary type string not closed with }')
rest_format = rest_format[1:] # eat the }
element_type = format[:len(format) - len(rest_format)]
- builder.init(variant_type_from_string(element_type))
+ builder = GLib.VariantBuilder.new(variant_type_from_string(element_type))
else:
- builder.init(variant_type_from_string('a{?*}'))
+ builder = GLib.VariantBuilder.new(variant_type_from_string('a{?*}'))
for k, v in args[0].items():
(key_v, rest_format, _) = self._create(format[2:], [k])
(val_v, rest_format, _) = self._create(rest_format, [v])
@@ -123,8 +122,7 @@ class _VariantCreator(object):
raise ValueError('dictionary type string not closed with }')
rest_format = rest_format[1:] # eat the }
- entry = GLib.VariantBuilder()
- entry.init(variant_type_from_string('{?*}'))
+ entry = GLib.VariantBuilder.new(variant_type_from_string('{?*}'))
entry.add_value(key_v)
entry.add_value(val_v)
builder.add_value(entry.end())
@@ -136,15 +134,15 @@ class _VariantCreator(object):
def _create_array(self, format, args):
'''Handle the case where the outermost type of format is an array.'''
- builder = GLib.VariantBuilder()
+ builder = None
if args is None or not args[0]:
# empty value: we need to call _create() to parse the subtype,
# and specify the element type precisely
rest_format = self._create(format[1:], None)[1]
element_type = format[:len(format) - len(rest_format)]
- builder.init(variant_type_from_string(element_type))
+ builder = GLib.VariantBuilder.new(variant_type_from_string(element_type))
else:
- builder.init(variant_type_from_string('a*'))
+ builder = GLib.VariantBuilder.new(variant_type_from_string('a*'))
for i in range(len(args[0])):
(v, rest_format, _) = self._create(format[1:], args[0][i:])
builder.add_value(v)
diff --git a/gi/overrides/Gtk.py b/gi/overrides/Gtk.py
index e4525921..9c35b068 100644
--- a/gi/overrides/Gtk.py
+++ b/gi/overrides/Gtk.py
@@ -35,6 +35,18 @@ else:
Gtk = modules['Gtk']._introspection_module
__all__ = []
+if Gtk._version == '2.0':
+ import warnings
+ warn_msg = "You have imported the Gtk 2.0 module. Because Gtk 2.0 \
+was not designed for use with introspection some of the \
+interfaces and API will fail. As such this is not supported \
+by the pygobject development team and we encourage you to \
+port your app to Gtk 3 or greater. PyGTK is the recomended \
+python module to use with Gtk 2.0"
+
+ warnings.warn(warn_msg, RuntimeWarning)
+
+
class Widget(Gtk.Widget):
def translate_coordinates(self, dest_widget, src_x, src_y):
@@ -365,7 +377,8 @@ class Dialog(Gtk.Dialog, Container):
if flags & Gtk.DialogFlags.NO_SEPARATOR:
self.set_has_separator(False)
except AttributeError:
- pass
+ import warnings
+ warnings.warn("Gtk.DialogFlags.NO_SEPARATOR has been depricated since Gtk+-3.0", DeprecationWarning)
if buttons is not None:
self.add_buttons(*buttons)
@@ -401,16 +414,23 @@ class MessageDialog(Gtk.MessageDialog, Dialog):
def __init__(self,
parent=None,
flags=0,
- type=Gtk.MessageType.INFO,
+ message_type=Gtk.MessageType.INFO,
buttons=Gtk.ButtonsType.NONE,
message_format=None,
**kwds):
if message_format != None:
kwds['text'] = message_format
+
+ # type keyword is used for backwards compat with PyGTK
+ if 'type' in kwds:
+ import warnings
+ warnings.warn("The use of the keyword type as a parameter of the Gtk.MessageDialog constructor has been depricated. Please use message_type instead.", DeprecationWarning)
+ message_type = kwds.pop('type')
+
Gtk.MessageDialog.__init__(self,
_buttons_property=buttons,
- message_type=type,
+ message_type=message_type,
**kwds)
Dialog.__init__(self, parent=parent, flags=flags)
@@ -738,9 +758,7 @@ class TreeModel(Gtk.TreeModel):
# we may need to convert to a basic type
type_ = self.get_column_type(column)
- if type_ == GObject.TYPE_PYOBJECT:
- pass # short-circut branching
- elif type_ == GObject.TYPE_STRING:
+ if type_ == GObject.TYPE_STRING:
if isinstance(value, str):
value = str(value)
elif sys.version_info < (3, 0):
@@ -808,6 +826,9 @@ class TreeModel(Gtk.TreeModel):
elif type_ == GObject.TYPE_UINT64:
value_container.set_uint64(value)
value = value_container
+ elif type_ == GObject.TYPE_PYOBJECT:
+ value_container.set_boxed(value)
+ value = value_container
return value
@@ -884,6 +905,14 @@ class ListStore(Gtk.ListStore, TreeModel, TreeSortable):
return treeiter
+ def prepend(self, row=None):
+ treeiter = Gtk.ListStore.prepend(self)
+
+ if row is not None:
+ self.set_row(treeiter, row)
+
+ return treeiter
+
def set_value(self, treeiter, column, value):
value = self._convert_value(treeiter, column, value)
Gtk.ListStore.set_value(self, treeiter, column, value)
diff --git a/gi/pygi-argument.c b/gi/pygi-argument.c
index 2f14a94e..55cdfd18 100644
--- a/gi/pygi-argument.c
+++ b/gi/pygi-argument.c
@@ -29,6 +29,7 @@
#include <datetime.h>
#include <pygobject.h>
#include <pyglib-python-compat.h>
+#include <pyglib.h>
static void
_pygi_g_type_tag_py_bounds (GITypeTag type_tag,
@@ -1765,8 +1766,19 @@ _pygi_argument_to_object (GIArgument *arg,
break;
}
case GI_TYPE_TAG_ERROR:
- /* Errors should be handled in the invoke wrapper. */
- g_assert_not_reached();
+ if (pyglib_error_check (&arg->v_pointer)) {
+ PyObject *err_type;
+ PyObject *err_value;
+ PyObject *err_trace;
+ PyErr_Fetch (&err_type, &err_value, &err_trace);
+ Py_XDECREF (err_type);
+ Py_XDECREF (err_trace);
+ object = err_value;
+ } else {
+ object = Py_None;
+ Py_INCREF (object);
+ break;
+ }
}
return object;
@@ -1832,6 +1844,8 @@ _pygi_argument_from_g_value(const GValue *value,
switch (info_type) {
case GI_INFO_TYPE_FLAGS:
+ arg.v_long = g_value_get_flags (value);
+ break;
case GI_INFO_TYPE_ENUM:
arg.v_long = g_value_get_enum (value);
break;
@@ -1857,6 +1871,8 @@ _pygi_argument_from_g_value(const GValue *value,
break;
}
case GI_TYPE_TAG_ERROR:
+ arg.v_pointer = g_value_get_boxed (value);
+ break;
case GI_TYPE_TAG_VOID:
g_critical("Converting of type '%s' is not implemented", g_type_tag_to_string(type_tag));
g_assert_not_reached();
diff --git a/gi/pygi-cache.c b/gi/pygi-cache.c
new file mode 100644
index 00000000..aed59e09
--- /dev/null
+++ b/gi/pygi-cache.c
@@ -0,0 +1,1404 @@
+/* -*- Mode: C; c-basic-offset: 4 -*-
+ * vim: tabstop=4 shiftwidth=4 expandtab
+ *
+ * Copyright (C) 2011 John (J5) Palmieri <johnp@redhat.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#include "pygi-info.h"
+#include "pygi-cache.h"
+#include "pygi-marshal-in.h"
+#include "pygi-marshal-out.h"
+#include "pygi-marshal-cleanup.h"
+#include "pygi-type.h"
+#include <girepository.h>
+
+PyGIArgCache * _arg_cache_new (GITypeInfo *type_info,
+ PyGICallableCache *callable_cache,
+ GIArgInfo *arg_info,
+ GITransfer transfer,
+ GIDirection direction,
+ gssize c_arg_index,
+ gssize py_arg_index);
+
+PyGIArgCache * _arg_cache_new_for_interface (GIInterfaceInfo *iface_info,
+ PyGICallableCache *callable_cache,
+ GIArgInfo *arg_info,
+ GITransfer transfer,
+ GIDirection direction,
+ gssize c_arg_index,
+ gssize py_arg_index);
+/* cleanup */
+void
+_pygi_arg_cache_free (PyGIArgCache *cache)
+{
+ if (cache == NULL)
+ return;
+
+ if (cache->type_info != NULL)
+ g_base_info_unref ( (GIBaseInfo *)cache->type_info);
+ if (cache->destroy_notify)
+ cache->destroy_notify (cache);
+ else
+ g_slice_free (PyGIArgCache, cache);
+}
+
+static void
+_interface_cache_free_func (PyGIInterfaceCache *cache)
+{
+ if (cache != NULL) {
+ Py_XDECREF (cache->py_type);
+ if (cache->type_name != NULL)
+ g_free (cache->type_name);
+ if (cache->interface_info != NULL)
+ g_base_info_unref ( (GIBaseInfo *)cache->interface_info);
+ g_slice_free (PyGIInterfaceCache, cache);
+ }
+}
+
+static void
+_hash_cache_free_func (PyGIHashCache *cache)
+{
+ if (cache != NULL) {
+ _pygi_arg_cache_free (cache->key_cache);
+ _pygi_arg_cache_free (cache->value_cache);
+ g_slice_free (PyGIHashCache, cache);
+ }
+}
+
+static void
+_sequence_cache_free_func (PyGISequenceCache *cache)
+{
+ if (cache != NULL) {
+ _pygi_arg_cache_free (cache->item_cache);
+ g_slice_free (PyGISequenceCache, cache);
+ }
+}
+
+static void
+_callback_cache_free_func (PyGICallbackCache *cache)
+{
+ if (cache != NULL) {
+ if (cache->interface_info != NULL)
+ g_base_info_unref ( (GIBaseInfo *)cache->interface_info);
+
+ g_slice_free (PyGICallbackCache, cache);
+ }
+}
+
+void
+_pygi_callable_cache_free (PyGICallableCache *cache)
+{
+ gssize i;
+
+ if (cache == NULL)
+ return;
+
+ g_slist_free (cache->out_args);
+ for (i = 0; i < cache->n_args; i++) {
+ PyGIArgCache *tmp = cache->args_cache[i];
+ _pygi_arg_cache_free (tmp);
+ }
+ if (cache->return_cache != NULL)
+ _pygi_arg_cache_free (cache->return_cache);
+
+ g_slice_free1 (cache->n_args * sizeof (PyGIArgCache *), cache->args_cache);
+ g_slice_free (PyGICallableCache, cache);
+}
+
+/* cache generation */
+
+static PyGIInterfaceCache *
+_interface_cache_new (GIInterfaceInfo *iface_info)
+{
+ PyGIInterfaceCache *ic;
+
+ ic = g_slice_new0 (PyGIInterfaceCache);
+ ( (PyGIArgCache *)ic)->destroy_notify = (GDestroyNotify)_interface_cache_free_func;
+ ic->g_type = g_registered_type_info_get_g_type ( (GIRegisteredTypeInfo *)iface_info);
+ ic->py_type = _pygi_type_import_by_gi_info ( (GIBaseInfo *) iface_info);
+
+ if (ic->py_type == NULL)
+ return NULL;
+
+ ic->type_name = _pygi_g_base_info_get_fullname (iface_info);
+ return ic;
+}
+
+static PyGISequenceCache *
+_sequence_cache_new (GITypeInfo *type_info,
+ GIDirection direction,
+ GITransfer transfer,
+ gssize child_offset)
+{
+ PyGISequenceCache *sc;
+ GITypeInfo *item_type_info;
+ GITypeTag item_type_tag;
+ GITransfer item_transfer;
+
+ sc = g_slice_new0 (PyGISequenceCache);
+ ( (PyGIArgCache *)sc)->destroy_notify = (GDestroyNotify)_sequence_cache_free_func;
+
+ sc->fixed_size = -1;
+ sc->len_arg_index = -1;
+ sc->is_zero_terminated = g_type_info_is_zero_terminated (type_info);
+ if (!sc->is_zero_terminated) {
+ sc->fixed_size = g_type_info_get_array_fixed_size (type_info);
+ if (sc->fixed_size < 0)
+ sc->len_arg_index = g_type_info_get_array_length (type_info) + child_offset;
+ }
+
+ item_type_info = g_type_info_get_param_type (type_info, 0);
+
+ item_transfer =
+ transfer == GI_TRANSFER_CONTAINER ? GI_TRANSFER_NOTHING : transfer;
+
+ sc->item_cache = _arg_cache_new (item_type_info,
+ NULL,
+ NULL,
+ item_transfer,
+ direction,
+ 0, 0);
+
+ if (sc->item_cache == NULL) {
+ _pygi_arg_cache_free ( (PyGIArgCache *)sc);
+ return NULL;
+ }
+
+ sc->item_size = _pygi_g_type_info_size (item_type_info);
+ g_base_info_unref ( (GIBaseInfo *)item_type_info);
+
+ return sc;
+}
+static PyGIHashCache *
+_hash_cache_new (GITypeInfo *type_info,
+ GIDirection direction,
+ GITransfer transfer)
+{
+ PyGIHashCache *hc;
+ GITypeInfo *key_type_info;
+ GITypeInfo *value_type_info;
+ GITransfer item_transfer;
+
+ hc = g_slice_new0 (PyGIHashCache);
+ ( (PyGIArgCache *)hc)->destroy_notify = (GDestroyNotify)_hash_cache_free_func;
+ key_type_info = g_type_info_get_param_type (type_info, 0);
+ value_type_info = g_type_info_get_param_type (type_info, 1);
+
+ item_transfer =
+ transfer == GI_TRANSFER_CONTAINER ? GI_TRANSFER_NOTHING : transfer;
+
+ hc->key_cache = _arg_cache_new (key_type_info,
+ NULL,
+ NULL,
+ item_transfer,
+ direction,
+ 0, 0);
+
+ if (hc->key_cache == NULL) {
+ _pygi_arg_cache_free ( (PyGIArgCache *)hc);
+ return NULL;
+ }
+
+ hc->value_cache = _arg_cache_new (value_type_info,
+ NULL,
+ NULL,
+ item_transfer,
+ direction,
+ 0, 0);
+
+ if (hc->value_cache == NULL) {
+ _pygi_arg_cache_free ( (PyGIArgCache *)hc);
+ return NULL;
+ }
+
+ g_base_info_unref( (GIBaseInfo *)key_type_info);
+ g_base_info_unref( (GIBaseInfo *)value_type_info);
+
+ return hc;
+}
+
+static PyGICallbackCache *
+_callback_cache_new (GIArgInfo *arg_info,
+ GIInterfaceInfo *iface_info,
+ gssize child_offset)
+{
+ PyGICallbackCache *cc;
+
+ cc = g_slice_new0 (PyGICallbackCache);
+ cc->user_data_index = g_arg_info_get_closure (arg_info);
+ if (cc->user_data_index != -1)
+ cc->user_data_index += child_offset;
+ cc->destroy_notify_index = g_arg_info_get_destroy (arg_info);
+ if (cc->destroy_notify_index != -1)
+ cc->destroy_notify_index += child_offset;
+ cc->scope = g_arg_info_get_scope (arg_info);
+ g_base_info_ref( (GIBaseInfo *)iface_info);
+ cc->interface_info = iface_info;
+ return cc;
+}
+
+static PyGIArgCache *
+_arg_cache_alloc (void)
+{
+ return g_slice_new0 (PyGIArgCache);
+}
+
+static void
+_arg_cache_in_void_setup (PyGIArgCache *arg_cache)
+{
+ arg_cache->in_marshaller = _pygi_marshal_in_void;
+}
+
+static void
+_arg_cache_out_void_setup (PyGIArgCache *arg_cache)
+{
+ arg_cache->out_marshaller = _pygi_marshal_out_void;
+}
+
+static void
+_arg_cache_in_boolean_setup (PyGIArgCache *arg_cache)
+{
+ arg_cache->in_marshaller = _pygi_marshal_in_boolean;
+}
+
+static void
+_arg_cache_out_boolean_setup (PyGIArgCache *arg_cache)
+{
+ arg_cache->out_marshaller = _pygi_marshal_out_boolean;
+}
+
+static void
+_arg_cache_in_int8_setup (PyGIArgCache *arg_cache)
+{
+ arg_cache->in_marshaller = _pygi_marshal_in_int8;
+}
+
+static void
+_arg_cache_out_int8_setup (PyGIArgCache *arg_cache)
+{
+ arg_cache->out_marshaller = _pygi_marshal_out_int8;
+}
+
+static void
+_arg_cache_in_uint8_setup (PyGIArgCache *arg_cache)
+{
+ arg_cache->in_marshaller = _pygi_marshal_in_uint8;
+}
+
+static void
+_arg_cache_out_uint8_setup (PyGIArgCache *arg_cache)
+{
+ arg_cache->out_marshaller = _pygi_marshal_out_uint8;
+}
+
+static void
+_arg_cache_in_int16_setup (PyGIArgCache *arg_cache)
+{
+ arg_cache->in_marshaller = _pygi_marshal_in_int16;
+}
+
+static void
+_arg_cache_out_int16_setup (PyGIArgCache *arg_cache)
+{
+ arg_cache->out_marshaller = _pygi_marshal_out_int16;
+}
+
+static void
+_arg_cache_in_uint16_setup (PyGIArgCache *arg_cache)
+{
+ arg_cache->in_marshaller = _pygi_marshal_in_uint16;
+}
+
+static void
+_arg_cache_out_uint16_setup (PyGIArgCache *arg_cache)
+{
+ arg_cache->out_marshaller = _pygi_marshal_out_uint16;
+}
+
+static void
+_arg_cache_in_int32_setup (PyGIArgCache *arg_cache)
+{
+ arg_cache->in_marshaller = _pygi_marshal_in_int32;
+}
+
+static void
+_arg_cache_out_int32_setup (PyGIArgCache *arg_cache)
+{
+ arg_cache->out_marshaller = _pygi_marshal_out_int32;
+}
+
+static void
+_arg_cache_in_uint32_setup (PyGIArgCache *arg_cache)
+{
+ arg_cache->in_marshaller = _pygi_marshal_in_uint32;
+}
+
+static void
+_arg_cache_out_uint32_setup (PyGIArgCache *arg_cache)
+{
+ arg_cache->out_marshaller = _pygi_marshal_out_uint32;
+}
+
+static void
+_arg_cache_in_int64_setup (PyGIArgCache *arg_cache)
+{
+ arg_cache->in_marshaller = _pygi_marshal_in_int64;
+}
+
+static void
+_arg_cache_out_int64_setup (PyGIArgCache *arg_cache)
+{
+ arg_cache->out_marshaller = _pygi_marshal_out_int64;
+}
+
+static void
+_arg_cache_in_uint64_setup (PyGIArgCache *arg_cache)
+{
+ arg_cache->in_marshaller = _pygi_marshal_in_uint64;
+}
+
+static void
+_arg_cache_out_uint64_setup (PyGIArgCache *arg_cache)
+{
+ arg_cache->out_marshaller = _pygi_marshal_out_uint64;
+}
+
+static void
+_arg_cache_in_float_setup (PyGIArgCache *arg_cache)
+{
+ arg_cache->in_marshaller = _pygi_marshal_in_float;
+}
+
+static void
+_arg_cache_out_float_setup (PyGIArgCache *arg_cache)
+{
+ arg_cache->out_marshaller = _pygi_marshal_out_float;
+}
+
+static void
+_arg_cache_in_double_setup (PyGIArgCache *arg_cache)
+{
+ arg_cache->in_marshaller = _pygi_marshal_in_double;
+}
+
+static void
+_arg_cache_out_double_setup (PyGIArgCache *arg_cache)
+{
+ arg_cache->out_marshaller = _pygi_marshal_out_double;
+}
+
+static void
+_arg_cache_in_unichar_setup (PyGIArgCache *arg_cache)
+{
+ arg_cache->in_marshaller = _pygi_marshal_in_unichar;
+}
+
+static void
+_arg_cache_out_unichar_setup (PyGIArgCache *arg_cache)
+{
+ arg_cache->out_marshaller = _pygi_marshal_out_unichar;
+}
+
+static void
+_arg_cache_in_gtype_setup (PyGIArgCache *arg_cache)
+{
+ arg_cache->in_marshaller = _pygi_marshal_in_gtype;
+}
+
+static void
+_arg_cache_out_gtype_setup (PyGIArgCache *arg_cache)
+{
+ arg_cache->out_marshaller = _pygi_marshal_out_gtype;
+}
+
+static void
+_arg_cache_in_utf8_setup (PyGIArgCache *arg_cache,
+ GITransfer transfer)
+{
+ arg_cache->in_marshaller = _pygi_marshal_in_utf8;
+ arg_cache->in_cleanup = _pygi_marshal_cleanup_in_utf8;
+}
+
+static void
+_arg_cache_out_utf8_setup (PyGIArgCache *arg_cache,
+ GITransfer transfer)
+{
+ arg_cache->out_marshaller = _pygi_marshal_out_utf8;
+ arg_cache->out_cleanup = _pygi_marshal_cleanup_out_utf8;
+}
+
+static void
+_arg_cache_in_filename_setup (PyGIArgCache *arg_cache,
+ GITransfer transfer)
+{
+ arg_cache->in_marshaller = _pygi_marshal_in_filename;
+ arg_cache->in_cleanup = _pygi_marshal_cleanup_in_utf8;
+}
+
+static void
+_arg_cache_out_filename_setup (PyGIArgCache *arg_cache,
+ GITransfer transfer)
+{
+ arg_cache->out_marshaller = _pygi_marshal_out_filename;
+ arg_cache->out_cleanup = _pygi_marshal_cleanup_out_utf8;
+}
+
+static gboolean
+_arg_cache_in_array_setup (PyGIArgCache *arg_cache,
+ PyGICallableCache *callable_cache,
+ GITypeInfo *type_info,
+ GITransfer transfer,
+ GIDirection direction)
+{
+ PyGISequenceCache *seq_cache = (PyGISequenceCache *)arg_cache;
+ seq_cache->array_type = g_type_info_get_array_type (type_info);
+
+ arg_cache->in_marshaller = _pygi_marshal_in_array;
+
+ if (seq_cache->len_arg_index >= 0 &&
+ direction == GI_DIRECTION_IN) {
+ PyGIArgCache *child_cache =
+ callable_cache->args_cache[seq_cache->len_arg_index];
+
+ if (child_cache == NULL) {
+ child_cache = _arg_cache_alloc ();
+ } else if (child_cache->meta_type == PYGI_META_ARG_TYPE_CHILD) {
+ return TRUE;
+ }
+
+ child_cache->meta_type = PYGI_META_ARG_TYPE_CHILD;
+ child_cache->direction = direction;
+ child_cache->in_marshaller = NULL;
+ child_cache->out_marshaller = NULL;
+
+ callable_cache->args_cache[seq_cache->len_arg_index] = child_cache;
+ }
+
+ arg_cache->in_cleanup = _pygi_marshal_cleanup_in_array;
+
+ return TRUE;
+}
+
+static gboolean
+_arg_cache_out_array_setup (PyGIArgCache *arg_cache,
+ PyGICallableCache *callable_cache,
+ GITypeInfo *type_info,
+ GITransfer transfer,
+ GIDirection direction,
+ gssize arg_index)
+{
+ PyGISequenceCache *seq_cache = (PyGISequenceCache *)arg_cache;
+ arg_cache->out_marshaller = _pygi_marshal_out_array;
+ arg_cache->out_cleanup = _pygi_marshal_cleanup_out_array;
+
+ seq_cache->array_type = g_type_info_get_array_type (type_info);
+
+ if (seq_cache->len_arg_index >= 0) {
+ PyGIArgCache *child_cache = callable_cache->args_cache[seq_cache->len_arg_index];
+ if (seq_cache->len_arg_index < arg_index)
+ callable_cache->n_out_child_args++;
+
+ if (child_cache != NULL) {
+ if (child_cache->meta_type == PYGI_META_ARG_TYPE_CHILD)
+ return TRUE;
+
+ callable_cache->out_args =
+ g_slist_remove (callable_cache->out_args, child_cache);
+ } else {
+ child_cache = _arg_cache_alloc ();
+ }
+
+ child_cache->meta_type = PYGI_META_ARG_TYPE_CHILD;
+ child_cache->direction = direction;
+ child_cache->in_marshaller = NULL;
+ child_cache->out_marshaller = NULL;
+
+ callable_cache->args_cache[seq_cache->len_arg_index] = child_cache;
+ }
+
+ return TRUE;
+}
+
+static void
+_arg_cache_in_glist_setup (PyGIArgCache *arg_cache,
+ GITransfer transfer)
+{
+ arg_cache->in_marshaller = _pygi_marshal_in_glist;
+ arg_cache->in_cleanup = _pygi_marshal_cleanup_in_glist;
+}
+
+static void
+_arg_cache_out_glist_setup (PyGIArgCache *arg_cache,
+ GITransfer transfer)
+{
+ arg_cache->out_marshaller = _pygi_marshal_out_glist;
+ arg_cache->in_cleanup = _pygi_marshal_cleanup_out_glist;
+}
+
+static void
+_arg_cache_in_gslist_setup (PyGIArgCache *arg_cache,
+ GITransfer transfer)
+{
+ arg_cache->in_marshaller = _pygi_marshal_in_gslist;
+ arg_cache->in_cleanup = _pygi_marshal_cleanup_in_glist;
+}
+
+static void
+_arg_cache_out_gslist_setup (PyGIArgCache *arg_cache,
+ GITransfer transfer)
+{
+ arg_cache->out_marshaller = _pygi_marshal_out_gslist;
+ arg_cache->out_cleanup = _pygi_marshal_cleanup_out_glist;
+}
+
+static void
+_arg_cache_in_ghash_setup (PyGIArgCache *arg_cache)
+{
+ arg_cache->in_marshaller = _pygi_marshal_in_ghash;
+ arg_cache->in_cleanup = _pygi_marshal_cleanup_in_ghash;
+}
+
+static void
+_arg_cache_out_ghash_setup (PyGIArgCache *arg_cache)
+{
+ arg_cache->out_marshaller = _pygi_marshal_out_ghash;
+ arg_cache->out_cleanup = _pygi_marshal_cleanup_out_ghash;
+}
+
+static void
+_arg_cache_in_gerror_setup (PyGIArgCache *arg_cache)
+{
+ arg_cache->in_marshaller = _pygi_marshal_in_gerror;
+ arg_cache->meta_type = PYGI_META_ARG_TYPE_CHILD;
+}
+
+static void
+_arg_cache_out_gerror_setup (PyGIArgCache *arg_cache)
+{
+ arg_cache->out_marshaller = _pygi_marshal_out_gerror;
+ arg_cache->meta_type = PYGI_META_ARG_TYPE_CHILD;
+}
+
+static void
+_arg_cache_in_interface_union_setup (PyGIArgCache *arg_cache,
+ GITransfer transfer)
+{
+ arg_cache->in_marshaller = _pygi_marshal_in_interface_struct;
+}
+
+static void
+_arg_cache_out_interface_union_setup (PyGIArgCache *arg_cache,
+ GITransfer transfer)
+{
+ arg_cache->out_marshaller = _pygi_marshal_out_interface_struct;
+}
+
+static void
+_arg_cache_in_interface_struct_setup (PyGIArgCache *arg_cache,
+ GIInterfaceInfo *iface_info,
+ GITransfer transfer)
+{
+ PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)arg_cache;
+ iface_cache->is_foreign = g_struct_info_is_foreign ( (GIStructInfo*)iface_info);
+ arg_cache->in_marshaller = _pygi_marshal_in_interface_struct;
+
+ if (iface_cache->g_type == G_TYPE_VALUE)
+ arg_cache->in_cleanup = _pygi_marshal_cleanup_in_interface_struct_gvalue;
+ else if (iface_cache->is_foreign)
+ arg_cache->in_cleanup = _pygi_marshal_cleanup_in_interface_struct_foreign;
+}
+
+static void
+_arg_cache_out_interface_struct_setup (PyGIArgCache *arg_cache,
+ GIInterfaceInfo *iface_info,
+ GITransfer transfer)
+{
+ PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)arg_cache;
+ iface_cache->is_foreign = g_struct_info_is_foreign ( (GIStructInfo*)iface_info);
+ arg_cache->out_marshaller = _pygi_marshal_out_interface_struct;
+
+ if (iface_cache->is_foreign)
+ arg_cache->in_cleanup = _pygi_marshal_cleanup_out_interface_struct_foreign;
+}
+
+static void
+_arg_cache_in_interface_object_setup (PyGIArgCache *arg_cache,
+ GITransfer transfer)
+{
+ arg_cache->in_marshaller = _pygi_marshal_in_interface_object;
+ arg_cache->in_cleanup = _pygi_marshal_cleanup_in_interface_object;
+}
+
+static void
+_arg_cache_out_interface_object_setup (PyGIArgCache *arg_cache,
+ GITransfer transfer)
+{
+ arg_cache->out_marshaller = _pygi_marshal_out_interface_object;
+ arg_cache->out_cleanup = _pygi_marshal_cleanup_out_interface_object;
+}
+
+static void
+_arg_cache_in_interface_callback_setup (PyGIArgCache *arg_cache,
+ PyGICallableCache *callable_cache)
+{
+ PyGICallbackCache *callback_cache = (PyGICallbackCache *)arg_cache;
+ if (callback_cache->user_data_index >= 0) {
+ PyGIArgCache *user_data_arg_cache = _arg_cache_alloc ();
+ user_data_arg_cache->meta_type = PYGI_META_ARG_TYPE_CHILD_WITH_PYARG;
+ callable_cache->args_cache[callback_cache->user_data_index] = user_data_arg_cache;
+ }
+
+ if (callback_cache->destroy_notify_index >= 0) {
+ PyGIArgCache *destroy_arg_cache = _arg_cache_alloc ();
+ destroy_arg_cache->meta_type = PYGI_META_ARG_TYPE_CHILD;
+ callable_cache->args_cache[callback_cache->destroy_notify_index] = destroy_arg_cache;
+ }
+ arg_cache->in_marshaller = _pygi_marshal_in_interface_callback;
+}
+
+static void
+_arg_cache_out_interface_callback_setup (void)
+{
+ PyErr_Format(PyExc_NotImplementedError,
+ "Callback returns are not supported");
+}
+
+static void
+_arg_cache_in_interface_enum_setup (PyGIArgCache *arg_cache,
+ GITransfer transfer)
+{
+ arg_cache->in_marshaller = _pygi_marshal_in_interface_enum;
+}
+
+static void
+_arg_cache_out_interface_enum_setup (PyGIArgCache *arg_cache,
+ GITransfer transfer)
+{
+ arg_cache->out_marshaller = _pygi_marshal_out_interface_enum;
+}
+
+static void
+_arg_cache_in_interface_flags_setup (PyGIArgCache *arg_cache,
+ GITransfer transfer)
+{
+ arg_cache->in_marshaller = _pygi_marshal_in_interface_flags;
+}
+
+static void
+_arg_cache_out_interface_flags_setup (PyGIArgCache *arg_cache,
+ GITransfer transfer)
+{
+ arg_cache->out_marshaller = _pygi_marshal_out_interface_flags;
+}
+
+PyGIArgCache *
+_arg_cache_new_for_interface (GIInterfaceInfo *iface_info,
+ PyGICallableCache *callable_cache,
+ GIArgInfo *arg_info,
+ GITransfer transfer,
+ GIDirection direction,
+ gssize c_arg_index,
+ gssize py_arg_index)
+{
+ PyGIInterfaceCache *iface_cache = NULL;
+ PyGIArgCache *arg_cache = NULL;
+ gssize child_offset = 0;
+ GIInfoType info_type;
+
+ if (callable_cache != NULL)
+ child_offset =
+ (callable_cache->function_type == PYGI_FUNCTION_TYPE_METHOD ||
+ callable_cache->function_type == PYGI_FUNCTION_TYPE_VFUNC) ? 1: 0;
+
+ GI_IS_INTERFACE_INFO (iface_info);
+
+ info_type = g_base_info_get_type ( (GIBaseInfo *)iface_info);
+
+ /* Callbacks are special cased */
+ if (info_type != GI_INFO_TYPE_CALLBACK) {
+ iface_cache = _interface_cache_new (iface_info);
+
+ arg_cache = (PyGIArgCache *)iface_cache;
+ if (arg_cache == NULL)
+ return NULL;
+ }
+
+ switch (info_type) {
+ case GI_INFO_TYPE_UNION:
+ if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT)
+ _arg_cache_in_interface_union_setup (arg_cache, transfer);
+
+ if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT)
+ _arg_cache_out_interface_union_setup (arg_cache, transfer);
+
+ break;
+ case GI_INFO_TYPE_STRUCT:
+ if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT)
+ _arg_cache_in_interface_struct_setup (arg_cache,
+ iface_info,
+ transfer);
+
+ if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT)
+ _arg_cache_out_interface_struct_setup (arg_cache,
+ iface_info,
+ transfer);
+
+ break;
+ case GI_INFO_TYPE_OBJECT:
+ case GI_INFO_TYPE_INTERFACE:
+ if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT)
+ _arg_cache_in_interface_object_setup (arg_cache, transfer);
+
+ if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT)
+ _arg_cache_out_interface_object_setup (arg_cache, transfer);
+
+ break;
+ case GI_INFO_TYPE_BOXED:
+ if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT)
+ _arg_cache_in_interface_struct_setup (arg_cache,
+ iface_info,
+ transfer);
+
+ if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT)
+ _arg_cache_out_interface_struct_setup (arg_cache,
+ iface_info,
+ transfer);
+
+ break;
+ case GI_INFO_TYPE_CALLBACK:
+ {
+ PyGICallbackCache *callback_cache;
+
+ if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT) {
+ _arg_cache_out_interface_callback_setup ();
+ return NULL;
+ }
+
+ callback_cache =
+ _callback_cache_new (arg_info,
+ iface_info,
+ child_offset);
+
+ arg_cache = (PyGIArgCache *)callback_cache;
+ if (arg_cache == NULL)
+ return NULL;
+
+ if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT)
+ _arg_cache_in_interface_callback_setup (arg_cache, callable_cache);
+
+ break;
+ }
+ case GI_INFO_TYPE_ENUM:
+ if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT)
+ _arg_cache_in_interface_enum_setup (arg_cache, transfer);
+
+ if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT)
+ _arg_cache_out_interface_enum_setup (arg_cache, transfer);
+
+ break;
+ case GI_INFO_TYPE_FLAGS:
+ if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT)
+ _arg_cache_in_interface_flags_setup (arg_cache, transfer);
+
+ if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT)
+ _arg_cache_out_interface_flags_setup (arg_cache, transfer);
+
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+
+ if (arg_cache != NULL) {
+ arg_cache->direction = direction;
+ arg_cache->transfer = transfer;
+ arg_cache->type_tag = GI_TYPE_TAG_INTERFACE;
+ arg_cache->py_arg_index = py_arg_index;
+ arg_cache->c_arg_index = c_arg_index;
+
+ if (iface_cache != NULL) {
+ g_base_info_ref ( (GIBaseInfo *)iface_info);
+ iface_cache->interface_info = iface_info;
+ }
+ }
+
+ return arg_cache;
+}
+
+PyGIArgCache *
+_arg_cache_new (GITypeInfo *type_info,
+ PyGICallableCache *callable_cache,
+ GIArgInfo *arg_info,
+ GITransfer transfer,
+ GIDirection direction,
+ gssize c_arg_index,
+ gssize py_arg_index)
+{
+ PyGIArgCache *arg_cache = NULL;
+ gssize child_offset = 0;
+ GITypeTag type_tag;
+
+ GI_IS_TYPE_INFO (type_info);
+
+ type_tag = g_type_info_get_tag (type_info);
+
+ if (callable_cache != NULL)
+ child_offset =
+ (callable_cache->function_type == PYGI_FUNCTION_TYPE_METHOD ||
+ callable_cache->function_type == PYGI_FUNCTION_TYPE_VFUNC) ? 1: 0;
+
+ switch (type_tag) {
+ case GI_TYPE_TAG_VOID:
+ arg_cache = _arg_cache_alloc ();
+ if (arg_cache == NULL)
+ break;
+
+ if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT)
+ _arg_cache_in_void_setup (arg_cache);
+
+ if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT)
+ _arg_cache_out_void_setup (arg_cache);
+ break;
+ case GI_TYPE_TAG_BOOLEAN:
+ arg_cache = _arg_cache_alloc ();
+ if (arg_cache == NULL)
+ break;
+
+ if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT)
+ _arg_cache_in_boolean_setup (arg_cache);
+
+ if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT)
+ _arg_cache_out_boolean_setup (arg_cache);
+
+ break;
+ case GI_TYPE_TAG_INT8:
+ arg_cache = _arg_cache_alloc ();
+ if (arg_cache == NULL)
+ break;
+
+ if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT)
+ _arg_cache_in_int8_setup (arg_cache);
+
+ if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT)
+ _arg_cache_out_int8_setup (arg_cache);
+
+ break;
+ case GI_TYPE_TAG_UINT8:
+ arg_cache = _arg_cache_alloc ();
+ if (arg_cache == NULL)
+ break;
+
+ if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT)
+ _arg_cache_in_uint8_setup (arg_cache);
+
+ if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT)
+ _arg_cache_out_uint8_setup (arg_cache);
+
+ break;
+ case GI_TYPE_TAG_INT16:
+ arg_cache = _arg_cache_alloc ();
+ if (arg_cache == NULL)
+ break;
+
+ if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT)
+ _arg_cache_in_int16_setup (arg_cache);
+
+ if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT)
+ _arg_cache_out_int16_setup (arg_cache);
+
+ break;
+ case GI_TYPE_TAG_UINT16:
+ arg_cache = _arg_cache_alloc ();
+ if (arg_cache == NULL)
+ break;
+
+ if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT)
+ _arg_cache_in_uint16_setup (arg_cache);
+
+ if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT)
+ _arg_cache_out_uint16_setup (arg_cache);
+
+ break;
+ case GI_TYPE_TAG_INT32:
+ arg_cache = _arg_cache_alloc ();
+ if (arg_cache == NULL)
+ break;
+
+ if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT)
+ _arg_cache_in_int32_setup (arg_cache);
+
+ if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT)
+ _arg_cache_out_int32_setup (arg_cache);
+
+ break;
+ case GI_TYPE_TAG_UINT32:
+ arg_cache = _arg_cache_alloc ();
+ if (arg_cache == NULL)
+ break;
+
+ if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT)
+ _arg_cache_in_uint32_setup (arg_cache);
+
+ if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT)
+ _arg_cache_out_uint32_setup (arg_cache);
+
+ break;
+ case GI_TYPE_TAG_INT64:
+ arg_cache = _arg_cache_alloc ();
+ if (arg_cache == NULL)
+ break;
+
+ if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT)
+ _arg_cache_in_int64_setup (arg_cache);
+
+ if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT)
+ _arg_cache_out_int64_setup (arg_cache);
+
+ break;
+ case GI_TYPE_TAG_UINT64:
+ arg_cache = _arg_cache_alloc ();
+ if (arg_cache == NULL)
+ break;
+
+ if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT)
+ _arg_cache_in_uint64_setup (arg_cache);
+
+ if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT)
+ _arg_cache_out_uint64_setup (arg_cache);
+
+ break;
+ case GI_TYPE_TAG_FLOAT:
+ arg_cache = _arg_cache_alloc ();
+ if (arg_cache == NULL)
+ break;
+
+ if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT)
+ _arg_cache_in_float_setup (arg_cache);
+
+ if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT)
+ _arg_cache_out_float_setup (arg_cache);
+
+ break;
+ case GI_TYPE_TAG_DOUBLE:
+ arg_cache = _arg_cache_alloc ();
+ if (arg_cache == NULL)
+ break;
+
+ if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT)
+ _arg_cache_in_double_setup (arg_cache);
+
+ if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT)
+ _arg_cache_out_double_setup (arg_cache);
+
+ break;
+ case GI_TYPE_TAG_UNICHAR:
+ arg_cache = _arg_cache_alloc ();
+ if (arg_cache == NULL)
+ break;
+
+ if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT)
+ _arg_cache_in_unichar_setup (arg_cache);
+
+ if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT)
+ _arg_cache_out_unichar_setup (arg_cache);
+
+ break;
+ case GI_TYPE_TAG_GTYPE:
+ arg_cache = _arg_cache_alloc ();
+ if (arg_cache == NULL)
+ break;
+
+ if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT)
+ _arg_cache_in_gtype_setup (arg_cache);
+
+ if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT)
+ _arg_cache_out_gtype_setup (arg_cache);
+
+ break;
+ case GI_TYPE_TAG_UTF8:
+ arg_cache = _arg_cache_alloc ();
+ if (arg_cache == NULL)
+ break;
+
+ if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT)
+ _arg_cache_in_utf8_setup (arg_cache, transfer);
+
+ if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT)
+ _arg_cache_out_utf8_setup (arg_cache, transfer);
+
+ break;
+ case GI_TYPE_TAG_FILENAME:
+ arg_cache = _arg_cache_alloc ();
+ if (arg_cache == NULL)
+ break;
+
+ if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT)
+ _arg_cache_in_filename_setup (arg_cache, transfer);
+
+ if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT)
+ _arg_cache_out_filename_setup (arg_cache, transfer);
+
+ break;
+ case GI_TYPE_TAG_ARRAY:
+ {
+ PyGISequenceCache *seq_cache =
+ _sequence_cache_new (type_info,
+ direction,
+ transfer,
+ child_offset);
+
+ arg_cache = (PyGIArgCache *)seq_cache;
+ if (arg_cache == NULL)
+ break;
+
+ if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT)
+ _arg_cache_in_array_setup (arg_cache,
+ callable_cache,
+ type_info,
+ transfer,
+ direction);
+
+ if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT)
+ _arg_cache_out_array_setup (arg_cache,
+ callable_cache,
+ type_info,
+ transfer,
+ direction,
+ c_arg_index);
+
+ /* ugly edge case code:
+ *
+ * length can come before the array parameter which means we
+ * need to update indexes if this happens
+ */
+ if (seq_cache->len_arg_index > -1 &&
+ seq_cache->len_arg_index < c_arg_index) {
+ gssize i;
+
+ py_arg_index -= 1;
+ callable_cache->n_py_args -= 1;
+
+ for (i = seq_cache->len_arg_index + 1;
+ i < callable_cache->n_args;
+ i++) {
+ PyGIArgCache *update_cache = callable_cache->args_cache[i];
+ if (update_cache == NULL)
+ break;
+
+ update_cache->py_arg_index -= 1;
+ }
+ }
+
+ break;
+ }
+ case GI_TYPE_TAG_GLIST:
+ {
+ PyGISequenceCache *seq_cache =
+ _sequence_cache_new (type_info,
+ direction,
+ transfer,
+ child_offset);
+
+ arg_cache = (PyGIArgCache *)seq_cache;
+ if (arg_cache == NULL)
+ break;
+
+ if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT)
+ _arg_cache_in_glist_setup (arg_cache, transfer);
+
+ if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT)
+ _arg_cache_out_glist_setup (arg_cache, transfer);
+
+
+ break;
+ }
+ case GI_TYPE_TAG_GSLIST:
+ {
+ PyGISequenceCache *seq_cache =
+ _sequence_cache_new (type_info,
+ direction,
+ transfer,
+ child_offset);
+
+ arg_cache = (PyGIArgCache *)seq_cache;
+ if (arg_cache == NULL)
+ break;
+
+ if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT)
+ _arg_cache_in_gslist_setup (arg_cache, transfer);
+
+ if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT)
+ _arg_cache_out_gslist_setup (arg_cache, transfer);
+
+ break;
+ }
+ case GI_TYPE_TAG_GHASH:
+ arg_cache =
+ (PyGIArgCache *)_hash_cache_new (type_info,
+ direction,
+ transfer);
+
+ if (arg_cache == NULL)
+ break;
+
+ if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT)
+ _arg_cache_in_ghash_setup (arg_cache);
+
+ if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT) {
+ _arg_cache_out_ghash_setup (arg_cache);
+ }
+
+ break;
+ case GI_TYPE_TAG_INTERFACE:
+ {
+ GIInterfaceInfo *interface_info = g_type_info_get_interface (type_info);
+ arg_cache = _arg_cache_new_for_interface (interface_info,
+ callable_cache,
+ arg_info,
+ transfer,
+ direction,
+ c_arg_index,
+ py_arg_index);
+
+ g_base_info_unref ( (GIBaseInfo *)interface_info);
+ break;
+ }
+ case GI_TYPE_TAG_ERROR:
+ arg_cache = _arg_cache_alloc ();
+ if (arg_cache == NULL)
+ break;
+
+ if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT)
+ _arg_cache_in_gerror_setup (arg_cache);
+
+ if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT)
+ _arg_cache_out_gerror_setup (arg_cache);
+
+ break;
+ }
+
+ if (arg_cache != NULL) {
+ arg_cache->direction = direction;
+ arg_cache->transfer = transfer;
+ arg_cache->type_tag = type_tag;
+ arg_cache->py_arg_index = py_arg_index;
+ arg_cache->c_arg_index = c_arg_index;
+ arg_cache->is_pointer = g_type_info_is_pointer (type_info);
+ g_base_info_ref ( (GIBaseInfo *) type_info);
+ arg_cache->type_info = type_info;
+ }
+
+ return arg_cache;
+}
+
+/* Generate the cache for the callable's arguments */
+static gboolean
+_args_cache_generate (GICallableInfo *callable_info,
+ PyGICallableCache *callable_cache)
+{
+ gssize arg_index = 0;
+ gssize i;
+ GITypeInfo *return_info;
+ GITransfer return_transfer;
+ PyGIArgCache *return_cache;
+
+ /* cache the return arg */
+ return_info =
+ g_callable_info_get_return_type (callable_info);
+ return_transfer =
+ g_callable_info_get_caller_owns (callable_info);
+ return_cache =
+ _arg_cache_new (return_info,
+ callable_cache,
+ NULL,
+ return_transfer,
+ GI_DIRECTION_OUT,
+ -1,
+ -1);
+
+ callable_cache->return_cache = return_cache;
+ g_base_info_unref (return_info);
+
+ /* first arg is the instance */
+ if (callable_cache->function_type == PYGI_FUNCTION_TYPE_METHOD ||
+ callable_cache->function_type == PYGI_FUNCTION_TYPE_VFUNC) {
+ GIInterfaceInfo *interface_info;
+ PyGIArgCache *instance_cache;
+
+ interface_info = g_base_info_get_container ( (GIBaseInfo *)callable_info);
+
+ instance_cache =
+ _arg_cache_new_for_interface (interface_info,
+ callable_cache,
+ NULL,
+ GI_TRANSFER_NOTHING,
+ GI_DIRECTION_IN,
+ arg_index,
+ 0);
+
+ instance_cache->in_marshaller = _pygi_marshal_in_interface_instance;
+ g_base_info_unref ( (GIBaseInfo *)interface_info);
+
+ if (instance_cache == NULL)
+ return FALSE;
+
+ callable_cache->args_cache[arg_index] = instance_cache;
+
+ arg_index++;
+ callable_cache->n_in_args++;
+ callable_cache->n_py_args++;
+ }
+
+
+ for (i=0; arg_index < callable_cache->n_args; arg_index++, i++) {
+ PyGIArgCache *arg_cache = NULL;
+ GIArgInfo *arg_info;
+ GITypeInfo *type_info;
+ GIDirection direction;
+ GITransfer transfer;
+ GITypeTag type_tag;
+ gboolean is_caller_allocates = FALSE;
+ gssize py_arg_index = -1;
+
+ arg_info =
+ g_callable_info_get_arg (callable_info, i);
+
+ direction = g_arg_info_get_direction (arg_info);
+ transfer = g_arg_info_get_ownership_transfer (arg_info);
+ type_info = g_arg_info_get_type (arg_info);
+ type_tag = g_type_info_get_tag (type_info);
+
+ if (type_tag == GI_TYPE_TAG_INTERFACE)
+ is_caller_allocates = g_arg_info_is_caller_allocates (arg_info);
+
+ /* must be an child arg filled in by its owner
+ * fill in it's c_arg_index, add to the in count
+ * and continue
+ */
+ if (callable_cache->args_cache[arg_index] != NULL) {
+ arg_cache = callable_cache->args_cache[arg_index];
+ if (arg_cache->meta_type == PYGI_META_ARG_TYPE_CHILD_WITH_PYARG) {
+ arg_cache->py_arg_index = callable_cache->n_py_args;
+ callable_cache->n_py_args++;
+ }
+
+ if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT) {
+ arg_cache->c_arg_index = callable_cache->n_in_args;
+ callable_cache->n_in_args++;
+ }
+
+ if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT) {
+ callable_cache->n_out_args++;
+ callable_cache->n_out_child_args++;
+ }
+
+ g_base_info_unref ( (GIBaseInfo *)arg_info);
+ continue;
+ }
+
+ if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT) {
+ py_arg_index = callable_cache->n_py_args;
+ callable_cache->n_in_args++;
+ callable_cache->n_py_args++;
+ }
+
+ arg_cache =
+ _arg_cache_new (type_info,
+ callable_cache,
+ arg_info,
+ transfer,
+ direction,
+ arg_index,
+ py_arg_index);
+
+ if (arg_cache == NULL)
+ goto arg_err;
+
+ arg_cache->allow_none = g_arg_info_may_be_null(arg_info);
+ arg_cache->is_caller_allocates = is_caller_allocates;
+
+ if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT) {
+ callable_cache->n_out_args++;
+
+ if (arg_cache == NULL)
+ goto arg_err;
+
+ callable_cache->out_args =
+ g_slist_append (callable_cache->out_args, arg_cache);
+ }
+
+ callable_cache->args_cache[arg_index] = arg_cache;
+ g_base_info_unref( (GIBaseInfo *)type_info);
+ g_base_info_unref( (GIBaseInfo *)arg_info);
+
+ continue;
+arg_err:
+ g_base_info_unref( (GIBaseInfo *)type_info);
+ g_base_info_unref( (GIBaseInfo *)arg_info);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+PyGICallableCache *
+_pygi_callable_cache_new (GICallableInfo *callable_info)
+{
+ PyGICallableCache *cache;
+ GIInfoType type = g_base_info_get_type ( (GIBaseInfo *)callable_info);
+
+ cache = g_slice_new0 (PyGICallableCache);
+
+ if (cache == NULL)
+ return NULL;
+
+ cache->name = g_base_info_get_name ((GIBaseInfo *)callable_info);
+
+ if (type == GI_INFO_TYPE_FUNCTION) {
+ GIFunctionInfoFlags flags;
+
+ flags = g_function_info_get_flags ( (GIFunctionInfo *)callable_info);
+
+ if (flags & GI_FUNCTION_IS_CONSTRUCTOR)
+ cache->function_type = PYGI_FUNCTION_TYPE_CONSTRUCTOR;
+ else if (flags & GI_FUNCTION_IS_METHOD)
+ cache->function_type = PYGI_FUNCTION_TYPE_METHOD;
+ } else if (type == GI_INFO_TYPE_VFUNC) {
+ cache->function_type = PYGI_FUNCTION_TYPE_VFUNC;
+ } else if (type == GI_INFO_TYPE_CALLBACK) {
+ cache->function_type = PYGI_FUNCTION_TYPE_CALLBACK;
+ } else {
+ cache->function_type = PYGI_FUNCTION_TYPE_METHOD;
+ }
+
+ cache->n_args = g_callable_info_get_n_args (callable_info);
+
+ /* if we are a method or vfunc make sure the instance parameter is counted */
+ if (cache->function_type == PYGI_FUNCTION_TYPE_METHOD ||
+ cache->function_type == PYGI_FUNCTION_TYPE_VFUNC)
+ cache->n_args++;
+
+ if (cache->n_args > 0)
+ cache->args_cache = g_slice_alloc0 (cache->n_args * sizeof (PyGIArgCache *));
+
+ if (!_args_cache_generate (callable_info, cache))
+ goto err;
+
+ return cache;
+err:
+ _pygi_callable_cache_free (cache);
+ return NULL;
+}
diff --git a/gi/pygi-cache.h b/gi/pygi-cache.h
new file mode 100644
index 00000000..6509149f
--- /dev/null
+++ b/gi/pygi-cache.h
@@ -0,0 +1,172 @@
+/* -*- Mode: C; c-basic-offset: 4 -*-
+ * vim: tabstop=4 shiftwidth=4 expandtab
+ *
+ * Copyright (C) 2011 John (J5) Palmieri <johnp@redhat.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#ifdef ENABLE_INVOKE_NG
+#ifndef __PYGI_CACHE_H__
+#define __PYGI_CACHE_H__
+
+#include <Python.h>
+#include <girepository.h>
+
+#include "pygi-invoke-state-struct.h"
+
+G_BEGIN_DECLS
+
+typedef struct _PyGICallableCache PyGICallableCache;
+typedef struct _PyGIArgCache PyGIArgCache;
+
+typedef gboolean (*PyGIMarshalInFunc) (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ PyObject *py_arg,
+ GIArgument *arg);
+
+typedef PyObject *(*PyGIMarshalOutFunc) (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ GIArgument *arg);
+
+typedef void (*PyGIMarshalCleanupFunc) (PyGIInvokeState *state,
+ PyGIArgCache *arg_cache,
+ gpointer data,
+ gboolean was_processed);
+
+/* Argument meta types denote how we process the argument:
+ * - Parents (PYGI_META_ARG_TYPE_PARENT) may or may not have children
+ * but are always processed via the normal marshaller for their
+ * actual GI type. If they have children the marshaller will
+ * also handle marshalling the children.
+ * - Children without python argument (PYGI_META_ARG_TYPE_CHILD) are
+ * ignored by the marshallers and handled directly by their parents
+ * marshaller.
+ * - Children with pyargs (PYGI_META_ARG_TYPE_CHILD_WITH_PYARG) are processed
+ * the same as other child args but also have an index into the
+ * python parameters passed to the invoker
+ */
+typedef enum {
+ PYGI_META_ARG_TYPE_PARENT,
+ PYGI_META_ARG_TYPE_CHILD,
+ PYGI_META_ARG_TYPE_CHILD_WITH_PYARG
+} PyGIMetaArgType;
+
+/*
+ * GI determines function types via a combination of flags and info classes.
+ * Since for branching purposes they are mutually exclusive, the
+ * PyGIFunctionType enum consolidates them into one enumeration for ease of
+ * branching and debugging.
+ */
+ typedef enum {
+ PYGI_FUNCTION_TYPE_FUNCTION,
+ PYGI_FUNCTION_TYPE_METHOD,
+ PYGI_FUNCTION_TYPE_CONSTRUCTOR,
+ PYGI_FUNCTION_TYPE_VFUNC,
+ PYGI_FUNCTION_TYPE_CALLBACK
+ } PyGIFunctionType;
+
+struct _PyGIArgCache
+{
+ PyGIMetaArgType meta_type;
+ gboolean is_pointer;
+ gboolean is_caller_allocates;
+ gboolean allow_none;
+
+ GIDirection direction;
+ GITransfer transfer;
+ GITypeTag type_tag;
+ GITypeInfo *type_info;
+
+ PyGIMarshalInFunc in_marshaller;
+ PyGIMarshalOutFunc out_marshaller;
+
+ PyGIMarshalCleanupFunc in_cleanup;
+ PyGIMarshalCleanupFunc out_cleanup;
+
+ GDestroyNotify destroy_notify;
+
+ gssize c_arg_index;
+ gssize py_arg_index;
+};
+
+typedef struct _PyGISequenceCache
+{
+ PyGIArgCache arg_cache;
+ gssize fixed_size;
+ gssize len_arg_index;
+ gboolean is_zero_terminated;
+ gsize item_size;
+ GIArrayType array_type;
+ PyGIArgCache *item_cache;
+} PyGISequenceCache;
+
+typedef struct _PyGIInterfaceCache
+{
+ PyGIArgCache arg_cache;
+ gboolean is_foreign;
+ GType g_type;
+ PyObject *py_type;
+ GIInterfaceInfo *interface_info;
+ gchar *type_name;
+} PyGIInterfaceCache;
+
+typedef struct _PyGIHashCache
+{
+ PyGIArgCache arg_cache;
+ PyGIArgCache *key_cache;
+ PyGIArgCache *value_cache;
+} PyGIHashCache;
+
+typedef struct _PyGICallbackCache
+{
+ PyGIArgCache arg_cache;
+ gssize user_data_index;
+ gssize destroy_notify_index;
+ GIScopeType scope;
+ GIInterfaceInfo *interface_info;
+} PyGICallbackCache;
+
+struct _PyGICallableCache
+{
+ const gchar *name;
+
+ PyGIFunctionType function_type;
+
+ PyGIArgCache *return_cache;
+ PyGIArgCache **args_cache;
+ GSList *out_args;
+
+ /* counts */
+ gssize n_in_args;
+ gssize n_out_args;
+ gssize n_out_child_args;
+
+ gssize n_args;
+ gssize n_py_args;
+};
+
+void _pygi_arg_cache_clear (PyGIArgCache *cache);
+void _pygi_callable_cache_free (PyGICallableCache *cache);
+
+PyGICallableCache *_pygi_callable_cache_new (GICallableInfo *callable_info);
+
+G_END_DECLS
+
+#endif /* __PYGI_CACHE_H__ */
+#endif /* def ENABLE_INVOKE_NG */
diff --git a/gi/pygi-foreign-gvariant.h b/gi/pygi-foreign-gvariant.h
index b0c97811..43ea9c79 100644
--- a/gi/pygi-foreign-gvariant.h
+++ b/gi/pygi-foreign-gvariant.h
@@ -26,9 +26,9 @@
#include "pygi-foreign.h"
-PyObject *g_variant_to_arg(PyObject *value,
- GITypeInfo *type_info,
- GITransfer transfer,
+PyObject *g_variant_to_arg(PyObject *value,
+ GIInterfaceInfo *interface_info,
+ GITransfer transfer,
GIArgument *arg);
PyObject *g_variant_from_arg(GITypeInfo *type_info,
diff --git a/gi/pygi-foreign.c b/gi/pygi-foreign.c
index 127f8eae..0398450e 100644
--- a/gi/pygi-foreign.c
+++ b/gi/pygi-foreign.c
@@ -117,8 +117,11 @@ pygi_struct_foreign_convert_to_g_argument (PyObject *value,
GIBaseInfo *base_info = (GIBaseInfo *) interface_info;
PyGIForeignStruct *foreign_struct = pygi_struct_foreign_lookup (base_info);
- if (foreign_struct == NULL)
- return NULL;
+ if (foreign_struct == NULL) {
+ PyErr_Format(PyExc_KeyError, "could not find foreign type %s",
+ g_base_info_get_name (base_info));
+ return FALSE;
+ }
result = foreign_struct->to_func (value, interface_info, transfer, arg);
return result;
diff --git a/gi/pygi-info.c b/gi/pygi-info.c
index 1bfd7d82..56325110 100644
--- a/gi/pygi-info.c
+++ b/gi/pygi-info.c
@@ -22,6 +22,7 @@
*/
#include "pygi-private.h"
+#include "pygi-cache.h"
#include <pygobject.h>
#include <pyglib-python-compat.h>
@@ -37,6 +38,10 @@ _base_info_dealloc (PyGIBaseInfo *self)
g_base_info_unref (self->info);
+#ifdef ENABLE_INVOKE_NG
+ _pygi_callable_cache_free(self->cache);
+#endif
+
Py_TYPE( (PyObject *) self)->tp_free ( (PyObject *) self);
}
diff --git a/gi/pygi-invoke-ng.c b/gi/pygi-invoke-ng.c
new file mode 100644
index 00000000..d42a9de4
--- /dev/null
+++ b/gi/pygi-invoke-ng.c
@@ -0,0 +1,464 @@
+/* -*- Mode: C; c-basic-offset: 4 -*-
+ * vim: tabstop=4 shiftwidth=4 expandtab
+ *
+ * Copyright (C) 2005-2009 Johan Dahlin <johan@gnome.org>
+ * Copyright (C) 2011 John (J5) Palimier <johnp@redhat.com>
+ *
+ * pygi-invoke.c: main invocation function
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#include <pyglib.h>
+#include "pygi-invoke.h"
+
+
+static inline gboolean
+_invoke_callable (PyGIInvokeState *state,
+ PyGICallableCache *cache,
+ GICallableInfo *callable_info)
+{
+ GError *error;
+ gint retval;
+
+ error = NULL;
+
+ pyg_begin_allow_threads;
+
+ /* FIXME: use this for now but we can streamline the calls */
+ if (cache->function_type == PYGI_FUNCTION_TYPE_VFUNC)
+ retval = g_vfunc_info_invoke ( callable_info,
+ state->implementor_gtype,
+ state->in_args,
+ cache->n_in_args,
+ state->out_args,
+ cache->n_out_args,
+ &state->return_arg,
+ &error);
+ else
+ retval = g_function_info_invoke ( callable_info,
+ state->in_args,
+ cache->n_in_args,
+ state->out_args,
+ cache->n_out_args,
+ &state->return_arg,
+ &error);
+ pyg_end_allow_threads;
+
+ if (!retval) {
+ g_assert (error != NULL);
+ pyglib_error_check (&error);
+
+ /* It is unclear if the error occured before or after the C
+ * function was invoked so for now assume success
+ * We eventually should marshal directly to FFI so we no longer
+ * have to use the reference implementation
+ */
+ pygi_marshal_cleanup_args_in_marshal_success (state, cache);
+
+ return FALSE;
+ }
+
+ if (state->error != NULL) {
+ if (pyglib_error_check (&(state->error))) {
+ /* even though we errored out, the call itself was successful,
+ so we assume the call processed all of the parameters */
+ pygi_marshal_cleanup_args_in_marshal_success (state, cache);
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+static inline gboolean
+_invoke_state_init_from_callable_cache (PyGIInvokeState *state,
+ PyGICallableCache *cache,
+ PyObject *py_args,
+ PyObject *kwargs)
+{
+ state->py_in_args = py_args;
+ state->n_py_in_args = PySequence_Length (py_args);
+
+ /* TODO: We don't use the class parameter sent in by the structure
+ * so we remove it from the py_args tuple but we can keep it
+ * around if we want to call actual gobject constructors
+ * in the future instead of calling g_object_new
+ */
+ if (cache->function_type == PYGI_FUNCTION_TYPE_CONSTRUCTOR) {
+ PyObject *constructor_class;
+ constructor_class = PyTuple_GetItem (py_args, 0);
+
+ if (constructor_class == NULL) {
+ PyErr_Clear ();
+ PyErr_Format (PyExc_TypeError,
+ "Constructors require the class to be passed in as an argument, "
+ "No arguments passed to the %s constructor.",
+ cache->name);
+
+ return FALSE;
+ }
+
+ /* we could optimize this by using offsets instead of modifying the tuple but it makes the
+ * code more error prone and confusing so don't do that unless profiling shows
+ * significant gain
+ */
+ state->py_in_args = PyTuple_GetSlice (py_args, 1, state->n_py_in_args);
+ state->n_py_in_args--;
+ } else {
+ Py_INCREF (state->py_in_args);
+ }
+ state->implementor_gtype = 0;
+ if (cache->function_type == PYGI_FUNCTION_TYPE_VFUNC) {
+ PyObject *py_gtype;
+ py_gtype = PyDict_GetItemString (kwargs, "gtype");
+ if (py_gtype == NULL) {
+ PyErr_SetString (PyExc_TypeError,
+ "need the GType of the implementor class");
+ return FALSE;
+ }
+
+ state->implementor_gtype = pyg_type_from_object (py_gtype);
+
+ if (state->implementor_gtype == 0)
+ return FALSE;
+ }
+
+ state->args = g_slice_alloc0 (cache->n_args * sizeof (GIArgument *));
+ if (state->args == NULL && cache->n_args != 0) {
+ PyErr_NoMemory();
+ return FALSE;
+ }
+
+ state->in_args = g_slice_alloc0 (cache->n_in_args * sizeof(GIArgument));
+ if (state->in_args == NULL && cache->n_in_args != 0) {
+ PyErr_NoMemory ();
+ return FALSE;
+ }
+
+ state->out_values = g_slice_alloc0 (cache->n_out_args * sizeof(GIArgument));
+ if (state->out_values == NULL && cache->n_out_args != 0) {
+ PyErr_NoMemory ();
+ return FALSE;
+ }
+
+ state->out_args = g_slice_alloc0 (cache->n_out_args * sizeof(GIArgument));
+ if (state->out_args == NULL && cache->n_out_args != 0) {
+ PyErr_NoMemory ();
+ return FALSE;
+ }
+
+ state->error = NULL;
+
+ return TRUE;
+}
+
+static inline void
+_invoke_state_clear (PyGIInvokeState *state, PyGICallableCache *cache)
+{
+ g_slice_free1 (cache->n_args * sizeof(GIArgument *), state->args);
+ g_slice_free1 (cache->n_in_args * sizeof(GIArgument), state->in_args);
+ g_slice_free1 (cache->n_out_args * sizeof(GIArgument), state->out_args);
+ g_slice_free1 (cache->n_out_args * sizeof(GIArgument), state->out_values);
+
+ Py_XDECREF (state->py_in_args);
+}
+
+static gboolean _caller_alloc (PyGIInvokeState *state,
+ PyGIArgCache *arg_cache,
+ gssize arg_count,
+ gssize out_count)
+{
+ PyGIInterfaceCache *iface_cache;
+
+ g_assert (arg_cache->type_tag == GI_TYPE_TAG_INTERFACE);
+
+ iface_cache = (PyGIInterfaceCache *)arg_cache;
+
+ state->out_args[out_count].v_pointer = NULL;
+ state->args[arg_count] = &state->out_args[out_count];
+ if (iface_cache->g_type == G_TYPE_BOXED) {
+ state->args[arg_count]->v_pointer =
+ _pygi_boxed_alloc (iface_cache->interface_info, NULL);
+ } else if (iface_cache->g_type == G_TYPE_VALUE) {
+ state->args[arg_count]->v_pointer = g_slice_new0 (GValue);
+ } else if (iface_cache->is_foreign) {
+ PyObject *foreign_struct =
+ pygi_struct_foreign_convert_from_g_argument (
+ iface_cache->interface_info,
+ NULL);
+
+ pygi_struct_foreign_convert_to_g_argument (foreign_struct,
+ iface_cache->interface_info,
+ GI_TRANSFER_EVERYTHING,
+ state->args[arg_count]);
+ } else {
+ gssize size = g_struct_info_get_size(
+ (GIStructInfo *)iface_cache->interface_info);
+ state->args[arg_count]->v_pointer = g_malloc0 (size);
+ }
+
+ if (state->args[arg_count]->v_pointer == NULL)
+ return FALSE;
+
+
+ return TRUE;
+}
+
+static inline gboolean
+_invoke_marshal_in_args (PyGIInvokeState *state, PyGICallableCache *cache)
+{
+ gssize i, in_count, out_count;
+ in_count = 0;
+ out_count = 0;
+
+ if (state->n_py_in_args > cache->n_py_args) {
+ PyErr_Format (PyExc_TypeError,
+ "%s() takes exactly %zd argument(s) (%zd given)",
+ cache->name,
+ cache->n_py_args,
+ state->n_py_in_args);
+ return FALSE;
+ }
+
+ for (i = 0; i < cache->n_args; i++) {
+ GIArgument *c_arg;
+ PyGIArgCache *arg_cache = cache->args_cache[i];
+ PyObject *py_arg = NULL;
+
+ switch (arg_cache->direction) {
+ case GI_DIRECTION_IN:
+ state->args[i] = &(state->in_args[in_count]);
+ in_count++;
+
+ if (arg_cache->meta_type > 0)
+ continue;
+
+ if (arg_cache->py_arg_index >= state->n_py_in_args) {
+ PyErr_Format (PyExc_TypeError,
+ "%s() takes exactly %zd argument(s) (%zd given)",
+ cache->name,
+ cache->n_py_args,
+ state->n_py_in_args);
+
+ /* clean up all of the args we have already marshalled,
+ * since invoke will not be called
+ */
+ pygi_marshal_cleanup_args_in_parameter_fail (state,
+ cache,
+ i - 1);
+ return FALSE;
+ }
+
+ py_arg =
+ PyTuple_GET_ITEM (state->py_in_args,
+ arg_cache->py_arg_index);
+
+ break;
+ case GI_DIRECTION_INOUT:
+ /* this will be filled in if it is an child value */
+ if (state->in_args[in_count].v_pointer != NULL)
+ state->out_values[out_count] = state->in_args[in_count];
+
+ state->in_args[in_count].v_pointer = &state->out_values[out_count];
+ in_count++;
+
+ if (arg_cache->meta_type != PYGI_META_ARG_TYPE_CHILD) {
+ if (arg_cache->py_arg_index >= state->n_py_in_args) {
+ PyErr_Format (PyExc_TypeError,
+ "%s() takes exactly %zd argument(s) (%zd given)",
+ cache->name,
+ cache->n_py_args,
+ state->n_py_in_args);
+ pygi_marshal_cleanup_args_in_parameter_fail (state,
+ cache,
+ i - 1);
+ return FALSE;
+ }
+
+ py_arg =
+ PyTuple_GET_ITEM (state->py_in_args,
+ arg_cache->py_arg_index);
+ }
+ case GI_DIRECTION_OUT:
+ if (arg_cache->is_caller_allocates) {
+ if (!_caller_alloc (state, arg_cache, i, out_count)) {
+ PyErr_Format (PyExc_TypeError,
+ "Could not caller allocate argument %zd of callable %s",
+ i, cache->name);
+ pygi_marshal_cleanup_args_in_parameter_fail (state,
+ cache,
+ i - 1);
+ return FALSE;
+ }
+ } else {
+ state->out_args[out_count].v_pointer = &state->out_values[out_count];
+ state->args[i] = &state->out_values[out_count];
+ }
+ out_count++;
+ break;
+ }
+
+ c_arg = state->args[i];
+ if (arg_cache->in_marshaller != NULL) {
+ if (!arg_cache->allow_none && py_arg == Py_None) {
+ PyErr_Format (PyExc_TypeError,
+ "Argument %i does not allow None as a value",
+ i);
+
+ pygi_marshal_cleanup_args_in_parameter_fail (state,
+ cache,
+ i - 1);
+ return FALSE;
+ }
+ gboolean success = arg_cache->in_marshaller (state,
+ cache,
+ arg_cache,
+ py_arg,
+ c_arg);
+ if (!success) {
+ pygi_marshal_cleanup_args_in_parameter_fail (state,
+ cache,
+ i - 1);
+ return FALSE;
+ }
+
+ }
+
+ }
+
+ return TRUE;
+}
+
+static inline PyObject *
+_invoke_marshal_out_args (PyGIInvokeState *state, PyGICallableCache *cache)
+{
+ PyObject *py_out = NULL;
+ PyObject *py_return = NULL;
+ gssize total_out_args = cache->n_out_args;
+ gboolean has_return = FALSE;
+
+ if (cache->return_cache) {
+
+ if (cache->function_type == PYGI_FUNCTION_TYPE_CONSTRUCTOR) {
+ if (state->return_arg.v_pointer == NULL) {
+ PyErr_SetString (PyExc_TypeError, "constructor returned NULL");
+ pygi_marshal_cleanup_args_return_fail (state,
+ cache);
+ return NULL;
+ }
+ }
+
+ py_return = cache->return_cache->out_marshaller ( state,
+ cache,
+ cache->return_cache,
+ &state->return_arg);
+ if (py_return == NULL) {
+ pygi_marshal_cleanup_args_return_fail (state,
+ cache);
+ return NULL;
+ }
+
+
+ if (cache->return_cache->type_tag != GI_TYPE_TAG_VOID) {
+ total_out_args++;
+ has_return = TRUE;
+ }
+ }
+
+ total_out_args -= cache->n_out_child_args;
+
+ if (cache->n_out_args - cache->n_out_child_args == 0) {
+ py_out = py_return;
+ } else if (total_out_args == 1) {
+ /* if we get here there is one out arg an no return */
+ PyGIArgCache *arg_cache = (PyGIArgCache *)cache->out_args->data;
+ py_out = arg_cache->out_marshaller (state,
+ cache,
+ arg_cache,
+ state->args[arg_cache->c_arg_index]);
+ if (py_out == NULL) {
+ pygi_marshal_cleanup_args_out_parameter_fail (state,
+ cache,
+ 0);
+ return NULL;
+ }
+
+ } else {
+ gssize py_arg_index = 0;
+ GSList *cache_item = cache->out_args;
+ /* return a tuple */
+ py_out = PyTuple_New (total_out_args);
+ if (has_return) {
+ PyTuple_SET_ITEM (py_out, py_arg_index, py_return);
+ py_arg_index++;
+ }
+
+ for(; py_arg_index < total_out_args; py_arg_index++) {
+ PyGIArgCache *arg_cache = (PyGIArgCache *)cache_item->data;
+ PyObject *py_obj = arg_cache->out_marshaller (state,
+ cache,
+ arg_cache,
+ state->args[arg_cache->c_arg_index]);
+
+ if (py_obj == NULL) {
+ if (has_return)
+ py_arg_index--;
+
+ pygi_marshal_cleanup_args_out_parameter_fail (state,
+ cache,
+ py_arg_index);
+ Py_DECREF (py_out);
+ return NULL;
+ }
+
+ PyTuple_SET_ITEM (py_out, py_arg_index, py_obj);
+ cache_item = cache_item->next;
+ }
+ }
+ return py_out;
+}
+
+PyObject *
+_wrap_g_callable_info_invoke (PyGIBaseInfo *self,
+ PyObject *py_args,
+ PyObject *kwargs)
+{
+ PyGIInvokeState state = { 0, };
+ PyObject *ret = NULL;
+
+ if (self->cache == NULL) {
+ self->cache = _pygi_callable_cache_new (self->info);
+ if (self->cache == NULL)
+ return NULL;
+ }
+
+ _invoke_state_init_from_callable_cache (&state, self->cache, py_args, kwargs);
+ if (!_invoke_marshal_in_args (&state, self->cache))
+ goto err;
+
+ if (!_invoke_callable (&state, self->cache, self->info))
+ goto err;
+
+ pygi_marshal_cleanup_args_in_marshal_success (&state, self->cache);
+
+ ret = _invoke_marshal_out_args (&state, self->cache);
+ if (ret)
+ pygi_marshal_cleanup_args_out_marshal_success (&state, self->cache);
+err:
+ _invoke_state_clear (&state, self->cache);
+ return ret;
+}
diff --git a/gi/pygi-invoke-state-struct.h b/gi/pygi-invoke-state-struct.h
new file mode 100644
index 00000000..a4072b78
--- /dev/null
+++ b/gi/pygi-invoke-state-struct.h
@@ -0,0 +1,44 @@
+#ifndef __PYGI_INVOKE_STATE_STRUCT_H__
+#define __PYGI_INVOKE_STATE_STRUCT_H__
+
+#include <Python.h>
+
+#include <girepository.h>
+
+G_BEGIN_DECLS
+
+typedef struct _PyGIInvokeState
+{
+ PyObject *py_in_args;
+ gssize n_py_in_args;
+ gssize current_arg;
+
+ GType implementor_gtype;
+
+ GIArgument **args;
+ GIArgument *in_args;
+
+ /* Out args and out values
+ * In order to pass a parameter and get something back out in C
+ * we need to pass a pointer to the value, e.g.
+ * int *out_integer;
+ *
+ * so while out_args == out_integer, out_value == *out_integer
+ * or in other words out_args = &out_values
+ *
+ * We do all of our processing on out_values but we pass out_args to
+ * the actual function.
+ */
+ GIArgument *out_args;
+ GIArgument *out_values;
+
+ GIArgument return_arg;
+
+ GError *error;
+
+ gboolean failed;
+} PyGIInvokeState;
+
+G_END_DECLS
+
+#endif
diff --git a/gi/pygi-invoke.h b/gi/pygi-invoke.h
index dc1ce18a..0aa75806 100644
--- a/gi/pygi-invoke.h
+++ b/gi/pygi-invoke.h
@@ -27,7 +27,7 @@
#include <girepository.h>
#include "pygi-private.h"
-
+#include "pygi-invoke-state-struct.h"
G_BEGIN_DECLS
PyObject *_wrap_g_callable_info_invoke (PyGIBaseInfo *self, PyObject *py_args,
diff --git a/gi/pygi-marshal-cleanup.c b/gi/pygi-marshal-cleanup.c
new file mode 100644
index 00000000..cd072f42
--- /dev/null
+++ b/gi/pygi-marshal-cleanup.c
@@ -0,0 +1,517 @@
+/* -*- Mode: C; c-basic-offset: 4 -*-
+ * vim: tabstop=4 shiftwidth=4 expandtab
+ *
+ * Copyright (C) 2011 John (J5) Palmieri <johnp@redhat.com>, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+ #include "pygi-marshal-cleanup.h"
+ #include <glib.h>
+static inline void
+_cleanup_caller_allocates (PyGIInvokeState *state,
+ PyGIArgCache *cache,
+ gpointer data)
+{
+ PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)cache;
+
+ if (iface_cache->g_type == G_TYPE_BOXED) {
+ gsize size;
+ size = g_struct_info_get_size (iface_cache->interface_info);
+ g_slice_free1 (size, data);
+ } else if (iface_cache->g_type == G_TYPE_VALUE) {
+ g_slice_free (GValue, data);
+ } else if (iface_cache->is_foreign) {
+ pygi_struct_foreign_release ((GIBaseInfo *)iface_cache->interface_info,
+ data);
+ } else {
+ g_free (data);
+ }
+}
+
+/**
+ * Cleanup during invoke can happen in multiple
+ * stages, each of which can be the result of a
+ * successful compleation of that stage or an error
+ * occured which requires partial cleanup.
+ *
+ * For the most part, either the C interface being
+ * invoked or the python object which wraps the
+ * parameters, handle their lifecycles but in some
+ * cases, where we have intermediate objects,
+ * or when we fail processing a parameter, we need
+ * to handle the clean up manually.
+ *
+ * There are two argument processing stages.
+ * They are the in stage, where we process python
+ * parameters into their C counterparts, and the out
+ * stage, where we process out C parameters back
+ * into python objects. The in stage also sets up
+ * temporary out structures for caller allocated
+ * parameters which need to be cleaned up either on
+ * in stage failure or at the completion of the out
+ * stage (either success or failure)
+ *
+ * The in stage must call one of these cleanup functions:
+ * - pygi_marshal_cleanup_args_in_marshal_success
+ * (continue to out stage)
+ * - pygi_marshal_cleanup_args_in_parameter_fail
+ * (final, exit from invoke)
+ *
+ * The out stage must call one of these cleanup functions which are all final:
+ * - pygi_marshal_cleanup_args_out_marshal_success
+ * - pygi_marshal_cleanup_args_return_fail
+ * - pygi_marshal_cleanup_args_out_parameter_fail
+ *
+ **/
+void
+pygi_marshal_cleanup_args_in_marshal_success (PyGIInvokeState *state,
+ PyGICallableCache *cache)
+{
+ gssize i;
+
+ /* For in success, call cleanup for all GI_DIRECTION_IN values only. */
+ for (i = 0; i < cache->n_args; i++) {
+ PyGIArgCache *arg_cache = cache->args_cache[i];
+ PyGIMarshalCleanupFunc cleanup_func = arg_cache->in_cleanup;
+
+ if (cleanup_func &&
+ arg_cache->direction == GI_DIRECTION_IN &&
+ state->args[i]->v_pointer != NULL)
+ cleanup_func (state, arg_cache, state->args[i]->v_pointer, TRUE);
+ }
+}
+
+void
+pygi_marshal_cleanup_args_out_marshal_success (PyGIInvokeState *state,
+ PyGICallableCache *cache)
+{
+ /* clean up the return if available */
+ if (cache->return_cache != NULL) {
+ PyGIMarshalCleanupFunc cleanup_func = cache->return_cache->out_cleanup;
+ if (cleanup_func && state->return_arg.v_pointer != NULL)
+ cleanup_func (state,
+ cache->return_cache,
+ state->return_arg.v_pointer,
+ TRUE);
+ }
+
+ /* Now clean up args */
+ GSList *cache_item = cache->out_args;
+ while (cache_item) {
+ PyGIArgCache *arg_cache = (PyGIArgCache *) cache_item->data;
+ PyGIMarshalCleanupFunc cleanup_func = arg_cache->out_cleanup;
+ gpointer data = state->args[arg_cache->c_arg_index]->v_pointer;
+
+ if (cleanup_func != NULL && data != NULL)
+ cleanup_func (state,
+ arg_cache,
+ data,
+ TRUE);
+
+ cache_item = cache_item->next;
+ }
+}
+
+void
+pygi_marshal_cleanup_args_in_parameter_fail (PyGIInvokeState *state,
+ PyGICallableCache *cache,
+ gssize failed_arg_index)
+{
+ gssize i;
+
+ state->failed = TRUE;
+
+ for (i = 0; i < cache->n_args && i <= failed_arg_index; i++) {
+ PyGIArgCache *arg_cache = cache->args_cache[i];
+ PyGIMarshalCleanupFunc cleanup_func = arg_cache->in_cleanup;
+ gpointer data = state->args[i]->v_pointer;
+
+ if (cleanup_func &&
+ arg_cache->direction == GI_DIRECTION_IN &&
+ data != NULL) {
+ cleanup_func (state,
+ arg_cache,
+ data,
+ i < failed_arg_index);
+
+ } else if (arg_cache->is_caller_allocates && data != NULL) {
+ _cleanup_caller_allocates (state,
+ arg_cache,
+ data);
+ }
+ }
+}
+
+void
+pygi_marshal_cleanup_args_return_fail (PyGIInvokeState *state,
+ PyGICallableCache *cache)
+{
+ state->failed = TRUE;
+}
+
+void
+pygi_marshal_cleanup_args_out_parameter_fail (PyGIInvokeState *state,
+ PyGICallableCache *cache,
+ gssize failed_out_arg_index)
+{
+ state->failed = TRUE;
+}
+
+void
+_pygi_marshal_cleanup_closure_unref (PyGIInvokeState *state,
+ PyGIArgCache *arg_cache,
+ gpointer data,
+ gboolean was_processed)
+{
+ g_closure_unref ( (GClosure *)data);
+}
+
+void
+_pygi_marshal_cleanup_in_utf8 (PyGIInvokeState *state,
+ PyGIArgCache *arg_cache,
+ gpointer data,
+ gboolean was_processed)
+{
+ /* We strdup strings so always free if we have processed this
+ parameter for input */
+ if (was_processed)
+ g_free (data);
+}
+
+void
+_pygi_marshal_cleanup_out_utf8 (PyGIInvokeState *state,
+ PyGIArgCache *arg_cache,
+ gpointer data,
+ gboolean was_processed)
+{
+ /* Python copies the string so we need to free it
+ if the interface is transfering ownership,
+ whether or not it has been processed yet */
+ if (arg_cache->transfer == GI_TRANSFER_EVERYTHING)
+ g_free (data);
+}
+
+void
+_pygi_marshal_cleanup_in_interface_object (PyGIInvokeState *state,
+ PyGIArgCache *arg_cache,
+ gpointer data,
+ gboolean was_processed)
+{
+ /* If we processed the parameter but fail before invoking the method,
+ we need to remove the ref we added */
+ if (was_processed && state->failed && data != NULL &&
+ arg_cache->transfer == GI_TRANSFER_EVERYTHING)
+ g_object_unref (G_OBJECT(data));
+}
+
+void
+_pygi_marshal_cleanup_out_interface_object (PyGIInvokeState *state,
+ PyGIArgCache *arg_cache,
+ gpointer data,
+ gboolean was_processed)
+{
+ /* If we error out and the object is not marshalled into a PyGObject
+ we must take care of removing the ref */
+ if (!was_processed && arg_cache->transfer == GI_TRANSFER_EVERYTHING)
+ g_object_unref (G_OBJECT(data));
+}
+
+void
+_pygi_marshal_cleanup_in_interface_struct_gvalue (PyGIInvokeState *state,
+ PyGIArgCache *arg_cache,
+ gpointer data,
+ gboolean was_processed)
+{
+ if (was_processed) {
+ PyObject *py_arg = PyTuple_GET_ITEM (state->py_in_args,
+ arg_cache->py_arg_index);
+ GType py_object_type =
+ pyg_type_from_object_strict ( (PyObject *) py_arg->ob_type, FALSE);
+
+ if (py_object_type != G_TYPE_VALUE) {
+ g_value_unset ((GValue *) data);
+ g_slice_free (GValue, data);
+ }
+ }
+}
+
+void
+_pygi_marshal_cleanup_in_interface_struct_foreign (PyGIInvokeState *state,
+ PyGIArgCache *arg_cache,
+ gpointer data,
+ gboolean was_processed)
+{
+ if (state->failed && was_processed)
+ pygi_struct_foreign_release (
+ ( (PyGIInterfaceCache *)arg_cache)->interface_info,
+ data);
+}
+
+void
+_pygi_marshal_cleanup_out_interface_struct_foreign (PyGIInvokeState *state,
+ PyGIArgCache *arg_cache,
+ gpointer data,
+ gboolean was_processed)
+{
+ if (!was_processed && arg_cache->transfer == GI_TRANSFER_EVERYTHING)
+ pygi_struct_foreign_release (
+ ( (PyGIInterfaceCache *)arg_cache)->interface_info,
+ data);
+}
+
+void
+_pygi_marshal_cleanup_in_array (PyGIInvokeState *state,
+ PyGIArgCache *arg_cache,
+ gpointer data,
+ gboolean was_processed)
+{
+ if (was_processed) {
+ GArray *array_;
+ PyGISequenceCache *sequence_cache = (PyGISequenceCache *)arg_cache;
+
+ /* If this isn't a garray create one to help process variable sized
+ array elements */
+ if (sequence_cache->array_type == GI_ARRAY_TYPE_C) {
+ gsize len;
+ if (sequence_cache->fixed_size >= 0) {
+ len = sequence_cache->fixed_size;
+ } else if (sequence_cache->is_zero_terminated) {
+ len = g_strv_length ((gchar **)data);
+ } else {
+ GIArgument *len_arg = state->args[sequence_cache->len_arg_index];
+ len = len_arg->v_long;
+ }
+
+ array_ = g_array_new (FALSE,
+ FALSE,
+ sequence_cache->item_size);
+
+ if (array_ == NULL)
+ return;
+
+ array_->data = data;
+ array_->len = len;
+
+ } else {
+ array_ = (GArray *) data;
+ }
+
+ /* clean up items first */
+ if (sequence_cache->item_cache->in_cleanup != NULL) {
+ gsize i;
+ PyGIMarshalCleanupFunc cleanup_func =
+ sequence_cache->item_cache->in_cleanup;
+
+ for(i = 0; i < array_->len; i++) {
+ cleanup_func (state,
+ sequence_cache->item_cache,
+ g_array_index (array_, gpointer, i),
+ TRUE);
+ }
+ }
+
+ if (state->failed ||
+ arg_cache->transfer == GI_TRANSFER_NOTHING ||
+ arg_cache->transfer == GI_TRANSFER_CONTAINER) {
+ g_array_free (array_, TRUE);
+ } else if (sequence_cache->array_type == GI_ARRAY_TYPE_C) {
+ g_array_free (array_, FALSE);
+ }
+ }
+}
+
+void
+_pygi_marshal_cleanup_out_array (PyGIInvokeState *state,
+ PyGIArgCache *arg_cache,
+ gpointer data,
+ gboolean was_processed)
+{
+ PyGISequenceCache *sequence_cache = (PyGISequenceCache *)arg_cache;
+
+ if (arg_cache->transfer == GI_TRANSFER_EVERYTHING ||
+ arg_cache->transfer == GI_TRANSFER_CONTAINER) {
+ GArray *array_ = (GArray *) data;
+
+ if (sequence_cache->array_type == GI_ARRAY_TYPE_C) {
+ g_free (data);
+ return;
+ }
+
+ if (sequence_cache->item_cache->out_cleanup != NULL) {
+ gsize i;
+
+ PyGIMarshalCleanupFunc cleanup_func = sequence_cache->item_cache->out_cleanup;
+ for (i = 0; i < array_->len; i++) {
+ cleanup_func (state,
+ sequence_cache->item_cache,
+ g_array_index (array_, gpointer, i),
+ was_processed);
+ }
+ }
+
+ if (arg_cache->transfer == GI_TRANSFER_EVERYTHING)
+ g_array_free (array_, TRUE);
+ }
+}
+
+void
+_pygi_marshal_cleanup_in_glist (PyGIInvokeState *state,
+ PyGIArgCache *arg_cache,
+ gpointer data,
+ gboolean was_processed)
+{
+ if (was_processed) {
+ GSList *list_;
+ PyGISequenceCache *sequence_cache = (PyGISequenceCache *)arg_cache;
+
+ list_ = (GSList *)data;
+
+ /* clean up items first */
+ if (sequence_cache->item_cache->in_cleanup != NULL) {
+ PyGIMarshalCleanupFunc cleanup_func =
+ sequence_cache->item_cache->in_cleanup;
+ GSList *node = list_;
+ while (node != NULL) {
+ cleanup_func (state,
+ sequence_cache->item_cache,
+ node->data,
+ TRUE);
+ node = node->next;
+ }
+ }
+
+ if (state->failed ||
+ arg_cache->transfer == GI_TRANSFER_NOTHING ||
+ arg_cache->transfer == GI_TRANSFER_CONTAINER) {
+ switch (arg_cache->type_tag) {
+ case GI_TYPE_TAG_GLIST:
+ g_list_free ( (GList *)list_);
+ break;
+ case GI_TYPE_TAG_GSLIST:
+ g_slist_free (list_);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ }
+ }
+}
+
+void
+_pygi_marshal_cleanup_out_glist (PyGIInvokeState *state,
+ PyGIArgCache *arg_cache,
+ gpointer data,
+ gboolean was_processed)
+{
+ PyGISequenceCache *sequence_cache = (PyGISequenceCache *)arg_cache;
+
+ if (arg_cache->transfer == GI_TRANSFER_EVERYTHING ||
+ arg_cache->transfer == GI_TRANSFER_CONTAINER) {
+ GSList *list_ = (GSList *)data;
+
+ if (sequence_cache->item_cache->out_cleanup != NULL) {
+ PyGIMarshalCleanupFunc cleanup_func =
+ sequence_cache->item_cache->out_cleanup;
+ GSList *node = list_;
+
+ while (node != NULL) {
+ cleanup_func (state,
+ sequence_cache->item_cache,
+ node->data,
+ was_processed);
+ node = node->next;
+ }
+ }
+
+ if (arg_cache->transfer == GI_TRANSFER_EVERYTHING) {
+ switch (arg_cache->type_tag) {
+ case GI_TYPE_TAG_GLIST:
+ g_list_free ( (GList *)list_);
+ break;
+ case GI_TYPE_TAG_GSLIST:
+ g_slist_free (list_);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ }
+ }
+}
+
+void
+_pygi_marshal_cleanup_in_ghash (PyGIInvokeState *state,
+ PyGIArgCache *arg_cache,
+ gpointer data,
+ gboolean was_processed)
+{
+ if (data == NULL)
+ return;
+
+ if (was_processed) {
+ GHashTable *hash_;
+ PyGIHashCache *hash_cache = (PyGIHashCache *)arg_cache;
+
+ hash_ = (GHashTable *)data;
+
+ /* clean up keys and values first */
+ if (hash_cache->key_cache->in_cleanup != NULL ||
+ hash_cache->value_cache->in_cleanup != NULL) {
+ GHashTableIter hiter;
+ gpointer key;
+ gpointer value;
+
+ PyGIMarshalCleanupFunc key_cleanup_func =
+ hash_cache->key_cache->in_cleanup;
+ PyGIMarshalCleanupFunc value_cleanup_func =
+ hash_cache->value_cache->in_cleanup;
+
+ g_hash_table_iter_init (&hiter, hash_);
+ while (g_hash_table_iter_next (&hiter, &key, &value)) {
+ if (key != NULL && key_cleanup_func != NULL)
+ key_cleanup_func (state,
+ hash_cache->key_cache,
+ key,
+ TRUE);
+ if (value != NULL && value_cleanup_func != NULL)
+ value_cleanup_func (state,
+ hash_cache->value_cache,
+ value,
+ TRUE);
+ }
+ }
+
+ if (state->failed ||
+ arg_cache->transfer == GI_TRANSFER_NOTHING ||
+ arg_cache->transfer == GI_TRANSFER_CONTAINER)
+ g_hash_table_destroy (hash_);
+
+ }
+}
+
+void
+_pygi_marshal_cleanup_out_ghash (PyGIInvokeState *state,
+ PyGIArgCache *arg_cache,
+ gpointer data,
+ gboolean was_processed)
+{
+ if (data == NULL)
+ return;
+
+ /* assume hashtable has boxed key and value */
+ if (arg_cache->transfer == GI_TRANSFER_EVERYTHING)
+ g_hash_table_destroy ( (GHashTable *)data);
+}
diff --git a/gi/pygi-marshal-cleanup.h b/gi/pygi-marshal-cleanup.h
new file mode 100644
index 00000000..3aff8fa1
--- /dev/null
+++ b/gi/pygi-marshal-cleanup.h
@@ -0,0 +1,97 @@
+/* -*- Mode: C; c-basic-offset: 4 -*-
+ * vim: tabstop=4 shiftwidth=4 expandtab
+ *
+ * Copyright (C) 2011 John (J5) Palmieri <johnp@redhat.com>, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#ifndef __PYGI_MARSHAL_CLEANUP_H__
+#define __PYGI_MARSHAL_CLEANUP_H__
+
+#include "pygi-private.h"
+
+G_BEGIN_DECLS
+
+void pygi_marshal_cleanup_args_in_marshal_success (PyGIInvokeState *state,
+ PyGICallableCache *cache);
+void pygi_marshal_cleanup_args_in_parameter_fail (PyGIInvokeState *state,
+ PyGICallableCache *cache,
+ gssize failed_arg_index);
+
+void pygi_marshal_cleanup_args_out_marshal_success (PyGIInvokeState *state,
+ PyGICallableCache *cache);
+void pygi_marshal_cleanup_args_return_fail (PyGIInvokeState *state,
+ PyGICallableCache *cache);
+void pygi_marshal_cleanup_args_out_parameter_fail (PyGIInvokeState *state,
+ PyGICallableCache *cache,
+ gssize failed_out_arg_index);
+
+void _pygi_marshal_cleanup_in_utf8 (PyGIInvokeState *state,
+ PyGIArgCache *arg_cache,
+ gpointer data,
+ gboolean was_processed);
+void _pygi_marshal_cleanup_out_utf8 (PyGIInvokeState *state,
+ PyGIArgCache *arg_cache,
+ gpointer data,
+ gboolean was_processed);
+void _pygi_marshal_cleanup_in_interface_struct_gvalue (PyGIInvokeState *state,
+ PyGIArgCache *arg_cache,
+ gpointer data,
+ gboolean was_processed);
+void _pygi_marshal_cleanup_in_interface_struct_foreign (PyGIInvokeState *state,
+ PyGIArgCache *arg_cache,
+ gpointer data,
+ gboolean was_processed);
+void _pygi_marshal_cleanup_out_interface_struct_foreign (PyGIInvokeState *state,
+ PyGIArgCache *arg_cache,
+ gpointer data,
+ gboolean was_processed);
+void _pygi_marshal_cleanup_in_interface_object (PyGIInvokeState *state,
+ PyGIArgCache *arg_cache,
+ gpointer data,
+ gboolean was_processed);
+void _pygi_marshal_cleanup_out_interface_object (PyGIInvokeState *state,
+ PyGIArgCache *arg_cache,
+ gpointer data,
+ gboolean was_processed);
+void _pygi_marshal_cleanup_in_array (PyGIInvokeState *state,
+ PyGIArgCache *arg_cache,
+ gpointer data,
+ gboolean was_processed);
+void _pygi_marshal_cleanup_out_array (PyGIInvokeState *state,
+ PyGIArgCache *arg_cache,
+ gpointer data,
+ gboolean was_processed);
+void _pygi_marshal_cleanup_in_glist (PyGIInvokeState *state,
+ PyGIArgCache *arg_cache,
+ gpointer data,
+ gboolean was_processed);
+void _pygi_marshal_cleanup_out_glist (PyGIInvokeState *state,
+ PyGIArgCache *arg_cache,
+ gpointer data,
+ gboolean was_processed);
+void _pygi_marshal_cleanup_in_ghash (PyGIInvokeState *state,
+ PyGIArgCache *arg_cache,
+ gpointer data,
+ gboolean was_processed);
+void _pygi_marshal_cleanup_out_ghash (PyGIInvokeState *state,
+ PyGIArgCache *arg_cache,
+ gpointer data,
+ gboolean was_processed);
+G_END_DECLS
+
+#endif /* __PYGI_MARSHAL_CLEANUP_H__ */
diff --git a/gi/pygi-marshal-in.c b/gi/pygi-marshal-in.c
new file mode 100644
index 00000000..9ae7def8
--- /dev/null
+++ b/gi/pygi-marshal-in.c
@@ -0,0 +1,1412 @@
+/* -*- Mode: C; c-basic-offset: 4 -*-
+ * vim: tabstop=4 shiftwidth=4 expandtab
+ *
+ * Copyright (C) 2011 John (J5) Palmieri <johnp@redhat.com>, Red Hat, Inc.
+ *
+ * pygi-marshal-in.c: PyObject conversion functions for in parameters.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#include "pygi-private.h"
+
+#include <string.h>
+#include <time.h>
+
+#include <datetime.h>
+#include <pygobject.h>
+#include <pyglib-python-compat.h>
+
+#include "pygi-cache.h"
+#include "pygi-marshal-cleanup.h"
+#include "pygi-marshal-in.h"
+
+gboolean
+_pygi_marshal_in_void (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ PyObject *py_arg,
+ GIArgument *arg)
+{
+ g_warn_if_fail (arg_cache->transfer == GI_TRANSFER_NOTHING);
+
+ arg->v_pointer = py_arg;
+
+ return TRUE;
+}
+
+gboolean
+_pygi_marshal_in_boolean (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ PyObject *py_arg,
+ GIArgument *arg)
+{
+ arg->v_boolean = PyObject_IsTrue (py_arg);
+
+ return TRUE;
+}
+
+gboolean
+_pygi_marshal_in_int8 (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ PyObject *py_arg,
+ GIArgument *arg)
+{
+ PyObject *py_long;
+ long long_;
+
+ if (!PyNumber_Check (py_arg)) {
+ PyErr_Format (PyExc_TypeError, "Must be number, not %s",
+ py_arg->ob_type->tp_name);
+ return FALSE;
+ }
+
+ py_long = PYGLIB_PyNumber_Long (py_arg);
+ if (!py_long)
+ return FALSE;
+
+ long_ = PYGLIB_PyLong_AsLong (py_long);
+ Py_DECREF (py_long);
+
+ if (PyErr_Occurred ()) {
+ PyErr_Clear ();
+ PyErr_Format (PyExc_ValueError, "%ld not in range %d to %d", long_, -128, 127);
+ return FALSE;
+ }
+
+ if (long_ < -128 || long_ > 127) {
+ PyErr_Format (PyExc_ValueError, "%ld not in range %d to %d", long_, -128, 127);
+ return FALSE;
+ }
+
+ arg->v_long = long_;
+
+ return TRUE;
+}
+
+gboolean
+_pygi_marshal_in_uint8 (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ PyObject *py_arg,
+ GIArgument *arg)
+{
+ unsigned long long_;
+
+ if (PYGLIB_PyBytes_Check (py_arg)) {
+
+ if (PYGLIB_PyBytes_Size (py_arg) != 1) {
+ PyErr_Format (PyExc_TypeError, "Must be a single character");
+ return FALSE;
+ }
+
+ long_ = (unsigned char)(PYGLIB_PyBytes_AsString (py_arg)[0]);
+
+ } else if (PyNumber_Check (py_arg)) {
+ PyObject *py_long;
+ py_long = PYGLIB_PyNumber_Long (py_arg);
+ if (!py_long)
+ return FALSE;
+
+ long_ = PYGLIB_PyLong_AsLong (py_long);
+ Py_DECREF (py_long);
+
+ if (PyErr_Occurred ()) {
+ PyErr_Clear();
+
+ PyErr_Format (PyExc_ValueError, "%ld not in range %d to %d", long_, 0, 255);
+ return FALSE;
+ }
+ } else {
+ PyErr_Format (PyExc_TypeError, "Must be number or single byte string, not %s",
+ py_arg->ob_type->tp_name);
+ return FALSE;
+ }
+
+ if (long_ < 0 || long_ > 255) {
+ PyErr_Format (PyExc_ValueError, "%ld not in range %d to %d", long_, 0, 255);
+ return FALSE;
+ }
+
+ arg->v_long = long_;
+
+ return TRUE;
+}
+
+gboolean
+_pygi_marshal_in_int16 (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ PyObject *py_arg,
+ GIArgument *arg)
+{
+ PyObject *py_long;
+ long long_;
+
+ if (!PyNumber_Check (py_arg)) {
+ PyErr_Format (PyExc_TypeError, "Must be number, not %s",
+ py_arg->ob_type->tp_name);
+ return FALSE;
+ }
+
+ py_long = PYGLIB_PyNumber_Long (py_arg);
+ if (!py_long)
+ return FALSE;
+
+ long_ = PYGLIB_PyLong_AsLong (py_long);
+ Py_DECREF (py_long);
+
+ if (PyErr_Occurred ()) {
+ PyErr_Clear ();
+ PyErr_Format (PyExc_ValueError, "%ld not in range %d to %d", long_, -32768, 32767);
+ return FALSE;
+ }
+
+ if (long_ < -32768 || long_ > 32767) {
+ PyErr_Format (PyExc_ValueError, "%ld not in range %d to %d", long_, -32768, 32767);
+ return FALSE;
+ }
+
+ arg->v_long = long_;
+
+ return TRUE;
+}
+
+gboolean
+_pygi_marshal_in_uint16 (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ PyObject *py_arg,
+ GIArgument *arg)
+{
+ PyObject *py_long;
+ long long_;
+
+ if (!PyNumber_Check (py_arg)) {
+ PyErr_Format (PyExc_TypeError, "Must be number, not %s",
+ py_arg->ob_type->tp_name);
+ return FALSE;
+ }
+
+ py_long = PYGLIB_PyNumber_Long (py_arg);
+ if (!py_long)
+ return FALSE;
+
+ long_ = PYGLIB_PyLong_AsLong (py_long);
+ Py_DECREF (py_long);
+
+ if (PyErr_Occurred ()) {
+ PyErr_Clear ();
+ PyErr_Format (PyExc_ValueError, "%li not in range %d to %d", long_, 0, 65535);
+ return FALSE;
+ }
+
+ if (long_ < 0 || long_ > 65535) {
+ PyErr_Format (PyExc_ValueError, "%li not in range %d to %d", long_, 0, 65535);
+ return FALSE;
+ }
+
+ arg->v_long = long_;
+
+ return TRUE;
+}
+
+gboolean
+_pygi_marshal_in_int32 (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ PyObject *py_arg,
+ GIArgument *arg)
+{
+ PyObject *py_long;
+ long long_;
+
+ if (!PyNumber_Check (py_arg)) {
+ PyErr_Format (PyExc_TypeError, "Must be number, not %s",
+ py_arg->ob_type->tp_name);
+ return FALSE;
+ }
+
+ py_long = PYGLIB_PyNumber_Long (py_arg);
+ if (!py_long)
+ return FALSE;
+
+ long_ = PYGLIB_PyLong_AsLong (py_long);
+ Py_DECREF (py_long);
+
+ if (PyErr_Occurred ()) {
+ PyErr_Clear();
+ PyErr_Format (PyExc_ValueError, "%ld not in range %d to %d", long_, G_MININT32, G_MAXINT32);
+ return FALSE;
+ }
+
+ if (long_ < G_MININT32 || long_ > G_MAXINT32) {
+ PyErr_Format (PyExc_ValueError, "%ld not in range %d to %d", long_, G_MININT32, G_MAXINT32);
+ return FALSE;
+ }
+
+ arg->v_long = long_;
+
+ return TRUE;
+}
+
+gboolean
+_pygi_marshal_in_uint32 (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ PyObject *py_arg,
+ GIArgument *arg)
+{
+ PyObject *py_long;
+ long long long_;
+
+ if (!PyNumber_Check (py_arg)) {
+ PyErr_Format (PyExc_TypeError, "Must be number, not %s",
+ py_arg->ob_type->tp_name);
+ return FALSE;
+ }
+
+ py_long = PYGLIB_PyNumber_Long (py_arg);
+ if (!py_long)
+ return FALSE;
+
+#if PY_VERSION_HEX < 0x03000000
+ if (PyInt_Check (py_long))
+ long_ = PyInt_AsLong (py_long);
+ else
+#endif
+ long_ = PyLong_AsLongLong (py_long);
+
+ Py_DECREF (py_long);
+
+ if (PyErr_Occurred ()) {
+ PyErr_Clear ();
+ PyErr_Format (PyExc_ValueError, "%lli not in range %i to %u", long_, 0, G_MAXUINT32);
+ return FALSE;
+ }
+
+ if (long_ < 0 || long_ > G_MAXUINT32) {
+ PyErr_Format (PyExc_ValueError, "%lli not in range %i to %u", long_, 0, G_MAXUINT32);
+ return FALSE;
+ }
+
+ arg->v_uint64 = long_;
+
+ return TRUE;
+}
+
+gboolean
+_pygi_marshal_in_int64 (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ PyObject *py_arg,
+ GIArgument *arg)
+{
+ PyObject *py_long;
+ long long long_;
+
+ if (!PyNumber_Check (py_arg)) {
+ PyErr_Format (PyExc_TypeError, "Must be number, not %s",
+ py_arg->ob_type->tp_name);
+ return FALSE;
+ }
+
+ py_long = PYGLIB_PyNumber_Long (py_arg);
+ if (!py_long)
+ return FALSE;
+
+#if PY_VERSION_HEX < 0x03000000
+ if (PyInt_Check (py_long))
+ long_ = PyInt_AS_LONG (py_long);
+ else
+#endif
+ long_ = PyLong_AsLongLong (py_long);
+
+ Py_DECREF (py_long);
+
+ if (PyErr_Occurred ()) {
+ /* OverflowError occured but range errors should be returned as ValueError */
+ char *long_str;
+ PyObject *py_str;
+
+ PyErr_Clear ();
+
+ py_str = PyObject_Str (py_long);
+
+ if (PyUnicode_Check (py_str)) {
+ PyObject *py_bytes = PyUnicode_AsUTF8String (py_str);
+ if (py_bytes == NULL)
+ return FALSE;
+
+ long_str = g_strdup (PYGLIB_PyBytes_AsString (py_bytes));
+ if (long_str == NULL) {
+ PyErr_NoMemory ();
+ return FALSE;
+ }
+
+ Py_DECREF (py_bytes);
+ } else {
+ long_str = g_strdup (PYGLIB_PyBytes_AsString(py_str));
+ }
+
+ Py_DECREF (py_str);
+ PyErr_Format (PyExc_ValueError, "%s not in range %ld to %ld",
+ long_str, G_MININT64, G_MAXINT64);
+
+ g_free (long_str);
+ return FALSE;
+ }
+
+ if (long_ < G_MININT64 || long_ > G_MAXINT64) {
+ PyErr_Format (PyExc_ValueError, "%lld not in range %ld to %ld", long_, G_MININT64, G_MAXINT64);
+ return FALSE;
+ }
+
+ arg->v_int64 = long_;
+
+ return TRUE;
+}
+
+gboolean
+_pygi_marshal_in_uint64 (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ PyObject *py_arg,
+ GIArgument *arg)
+{
+ PyObject *py_long;
+ guint64 ulong_;
+
+ if (!PyNumber_Check (py_arg)) {
+ PyErr_Format (PyExc_TypeError, "Must be number, not %s",
+ py_arg->ob_type->tp_name);
+ return FALSE;
+ }
+
+ py_long = PYGLIB_PyNumber_Long (py_arg);
+ if (!py_long)
+ return FALSE;
+
+#if PY_VERSION_HEX < 0x03000000
+ if (PyInt_Check (py_long)) {
+ long long_ = PyInt_AsLong (py_long);
+ if (long_ < 0) {
+ PyErr_Format (PyExc_ValueError, "%ld not in range %d to %llu",
+ long_, 0, G_MAXUINT64);
+ return FALSE;
+ }
+ ulong_ = long_;
+ } else
+#endif
+ ulong_ = PyLong_AsUnsignedLongLong (py_long);
+
+ Py_DECREF (py_long);
+
+ if (PyErr_Occurred ()) {
+ /* OverflowError occured but range errors should be returned as ValueError */
+ char *long_str;
+ PyObject *py_str;
+
+ PyErr_Clear ();
+
+ py_str = PyObject_Str (py_long);
+
+ if (PyUnicode_Check (py_str)) {
+ PyObject *py_bytes = PyUnicode_AsUTF8String (py_str);
+ if (py_bytes == NULL)
+ return FALSE;
+
+ long_str = g_strdup (PYGLIB_PyBytes_AsString (py_bytes));
+ if (long_str == NULL) {
+ PyErr_NoMemory ();
+ return FALSE;
+ }
+
+ Py_DECREF (py_bytes);
+ } else {
+ long_str = g_strdup (PYGLIB_PyBytes_AsString (py_str));
+ }
+
+ Py_DECREF (py_str);
+
+ PyErr_Format (PyExc_ValueError, "%s not in range %d to %llu",
+ long_str, 0, G_MAXUINT64);
+
+ g_free (long_str);
+ return FALSE;
+ }
+
+ if (ulong_ > G_MAXUINT64) {
+ PyErr_Format (PyExc_ValueError, "%llu not in range %d to %llu", ulong_, 0, G_MAXUINT64);
+ return FALSE;
+ }
+
+ arg->v_uint64 = ulong_;
+
+ return TRUE;
+}
+
+gboolean
+_pygi_marshal_in_float (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ PyObject *py_arg,
+ GIArgument *arg)
+{
+ PyObject *py_float;
+ double double_;
+
+ if (!PyNumber_Check (py_arg)) {
+ PyErr_Format (PyExc_TypeError, "Must be number, not %s",
+ py_arg->ob_type->tp_name);
+ return FALSE;
+ }
+
+ py_float = PyNumber_Float (py_arg);
+ if (!py_float)
+ return FALSE;
+
+ double_ = PyFloat_AsDouble (py_float);
+ Py_DECREF (py_float);
+
+ if (PyErr_Occurred ()) {
+ PyErr_Clear ();
+ PyErr_Format (PyExc_ValueError, "%f not in range %f to %f", double_, -G_MAXFLOAT, G_MAXFLOAT);
+ return FALSE;
+ }
+
+ if (double_ < -G_MAXFLOAT || double_ > G_MAXFLOAT) {
+ PyErr_Format (PyExc_ValueError, "%f not in range %f to %f", double_, -G_MAXFLOAT, G_MAXFLOAT);
+ return FALSE;
+ }
+
+ arg->v_float = double_;
+
+ return TRUE;
+}
+
+gboolean
+_pygi_marshal_in_double (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ PyObject *py_arg,
+ GIArgument *arg)
+{
+ PyObject *py_float;
+ double double_;
+
+ if (!PyNumber_Check (py_arg)) {
+ PyErr_Format (PyExc_TypeError, "Must be number, not %s",
+ py_arg->ob_type->tp_name);
+ return FALSE;
+ }
+
+ py_float = PyNumber_Float (py_arg);
+ if (!py_float)
+ return FALSE;
+
+ double_ = PyFloat_AsDouble (py_float);
+ Py_DECREF (py_float);
+
+ if (PyErr_Occurred ()) {
+ PyErr_Clear ();
+ PyErr_Format (PyExc_ValueError, "%f not in range %f to %f", double_, -G_MAXDOUBLE, G_MAXDOUBLE);
+ return FALSE;
+ }
+
+ if (double_ < -G_MAXDOUBLE || double_ > G_MAXDOUBLE) {
+ PyErr_Format (PyExc_ValueError, "%f not in range %f to %f", double_, -G_MAXDOUBLE, G_MAXDOUBLE);
+ return FALSE;
+ }
+
+ arg->v_double = double_;
+
+ return TRUE;
+}
+
+gboolean
+_pygi_marshal_in_unichar (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ PyObject *py_arg,
+ GIArgument *arg)
+{
+ Py_ssize_t size;
+ gchar *string_;
+
+ if (PyUnicode_Check (py_arg)) {
+ PyObject *py_bytes;
+
+ size = PyUnicode_GET_SIZE (py_arg);
+ py_bytes = PyUnicode_AsUTF8String (py_arg);
+ string_ = strdup(PYGLIB_PyBytes_AsString (py_bytes));
+ Py_DECREF (py_bytes);
+
+#if PY_VERSION_HEX < 0x03000000
+ } else if (PyString_Check (py_arg)) {
+ PyObject *pyuni = PyUnicode_FromEncodedObject (py_arg, "UTF-8", "strict");
+ if (!pyuni)
+ return FALSE;
+
+ size = PyUnicode_GET_SIZE (pyuni);
+ string_ = g_strdup (PyString_AsString(py_arg));
+ Py_DECREF (pyuni);
+#endif
+ } else {
+ PyErr_Format (PyExc_TypeError, "Must be string, not %s",
+ py_arg->ob_type->tp_name);
+ return FALSE;
+ }
+
+ if (size != 1) {
+ PyErr_Format (PyExc_TypeError, "Must be a one character string, not %ld characters",
+ size);
+ g_free (string_);
+ return FALSE;
+ }
+
+ arg->v_uint32 = g_utf8_get_char (string_);
+ g_free (string_);
+
+ return TRUE;
+}
+gboolean
+_pygi_marshal_in_gtype (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ PyObject *py_arg,
+ GIArgument *arg)
+{
+ long type_ = pyg_type_from_object (py_arg);
+
+ if (type_ == 0) {
+ PyErr_Format (PyExc_TypeError, "Must be gobject.GType, not %s",
+ py_arg->ob_type->tp_name);
+ return FALSE;
+ }
+
+ arg->v_long = type_;
+ return TRUE;
+}
+gboolean
+_pygi_marshal_in_utf8 (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ PyObject *py_arg,
+ GIArgument *arg)
+{
+ gchar *string_;
+
+ if (py_arg == Py_None) {
+ arg->v_pointer = NULL;
+ return TRUE;
+ }
+
+ if (PyUnicode_Check (py_arg)) {
+ PyObject *pystr_obj = PyUnicode_AsUTF8String (py_arg);
+ if (!pystr_obj)
+ return FALSE;
+
+ string_ = g_strdup (PYGLIB_PyBytes_AsString (pystr_obj));
+ Py_DECREF (pystr_obj);
+ }
+#if PY_VERSION_HEX < 0x03000000
+ else if (PyString_Check (py_arg)) {
+ string_ = g_strdup (PyString_AsString (py_arg));
+ }
+#endif
+ else {
+ PyErr_Format (PyExc_TypeError, "Must be string, not %s",
+ py_arg->ob_type->tp_name);
+ return FALSE;
+ }
+
+ arg->v_string = string_;
+ return TRUE;
+}
+
+gboolean
+_pygi_marshal_in_filename (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ PyObject *py_arg,
+ GIArgument *arg)
+{
+ gchar *string_;
+ GError *error = NULL;
+
+ if (PyUnicode_Check (py_arg)) {
+ PyObject *pystr_obj = PyUnicode_AsUTF8String (py_arg);
+ if (!pystr_obj)
+ return FALSE;
+
+ string_ = g_strdup (PYGLIB_PyBytes_AsString (pystr_obj));
+ Py_DECREF (pystr_obj);
+ }
+#if PY_VERSION_HEX < 0x03000000
+ else if (PyString_Check (py_arg)) {
+ string_ = g_strdup (PyString_AsString (py_arg));
+ }
+#endif
+ else {
+ PyErr_Format (PyExc_TypeError, "Must be string, not %s",
+ py_arg->ob_type->tp_name);
+ return FALSE;
+ }
+
+ arg->v_string = g_filename_from_utf8 (string_, -1, NULL, NULL, &error);
+ g_free (string_);
+
+ if (arg->v_string == NULL) {
+ PyErr_SetString (PyExc_Exception, error->message);
+ g_error_free (error);
+ /* TODO: Convert the error to an exception. */
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+gboolean
+_pygi_marshal_in_array (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ PyObject *py_arg,
+ GIArgument *arg)
+{
+ PyGIMarshalInFunc in_marshaller;
+ int i;
+ Py_ssize_t length;
+ gboolean is_ptr_array;
+ GArray *array_ = NULL;
+ PyGISequenceCache *sequence_cache = (PyGISequenceCache *)arg_cache;
+
+
+ if (py_arg == Py_None) {
+ arg->v_pointer = NULL;
+ return TRUE;
+ }
+
+ if (!PySequence_Check (py_arg)) {
+ PyErr_Format (PyExc_TypeError, "Must be sequence, not %s",
+ py_arg->ob_type->tp_name);
+ return FALSE;
+ }
+
+ length = PySequence_Length (py_arg);
+ if (length < 0)
+ return FALSE;
+
+ if (sequence_cache->fixed_size >= 0 &&
+ sequence_cache->fixed_size != length) {
+ PyErr_Format (PyExc_ValueError, "Must contain %zd items, not %zd",
+ sequence_cache->fixed_size, length);
+
+ return FALSE;
+ }
+
+ is_ptr_array = (sequence_cache->array_type == GI_ARRAY_TYPE_PTR_ARRAY);
+ if (is_ptr_array) {
+ array_ = (GArray *)g_ptr_array_new ();
+ } else {
+ array_ = g_array_sized_new (sequence_cache->is_zero_terminated,
+ FALSE,
+ sequence_cache->item_size,
+ length);
+ }
+
+ if (array_ == NULL) {
+ PyErr_NoMemory ();
+ return FALSE;
+ }
+
+ if (sequence_cache->item_cache->type_tag == GI_TYPE_TAG_UINT8 &&
+ PYGLIB_PyBytes_Check (py_arg)) {
+ memcpy(array_->data, PYGLIB_PyBytes_AsString (py_arg), length);
+
+ goto array_success;
+ }
+
+ in_marshaller = sequence_cache->item_cache->in_marshaller;
+ for (i = 0; i < length; i++) {
+ GIArgument item;
+ PyObject *py_item = PySequence_GetItem (py_arg, i);
+ if (py_item == NULL)
+ goto err;
+
+ if (!in_marshaller ( state,
+ callable_cache,
+ sequence_cache->item_cache,
+ py_item,
+ &item))
+ goto err;
+
+ /* FIXME: it is much more efficent to have seperate marshaller
+ * for ptr arrays than doing the evaluation
+ * and casting each loop iteration
+ */
+ if (is_ptr_array)
+ g_ptr_array_add((GPtrArray *)array_, item.v_pointer);
+ else
+ g_array_insert_val (array_, i, item);
+ continue;
+err:
+ if (sequence_cache->item_cache->in_cleanup != NULL) {
+ gsize j;
+ PyGIMarshalCleanupFunc cleanup_func =
+ sequence_cache->item_cache->in_cleanup;
+
+ for(j = 0; j < i; j++) {
+ cleanup_func (state,
+ sequence_cache->item_cache,
+ g_array_index (array_, gpointer, j),
+ TRUE);
+ }
+ }
+
+ if (is_ptr_array)
+ g_ptr_array_free (array_, TRUE);
+ else
+ g_array_free (array_, TRUE);
+ _PyGI_ERROR_PREFIX ("Item %i: ", i);
+ return FALSE;
+ }
+
+array_success:
+ if (sequence_cache->len_arg_index >= 0) {
+ /* we have an child arg to handle */
+ PyGIArgCache *child_cache =
+ callable_cache->args_cache[sequence_cache->len_arg_index];
+
+ if (child_cache->direction == GI_DIRECTION_INOUT) {
+ gint *len_arg = (gint *)state->in_args[child_cache->c_arg_index].v_pointer;
+ /* if we are not setup yet just set the in arg */
+ if (len_arg == NULL)
+ state->in_args[child_cache->c_arg_index].v_long = length;
+ else
+ *len_arg = length;
+ } else {
+ state->in_args[child_cache->c_arg_index].v_long = length;
+ }
+ }
+
+ if (sequence_cache->array_type == GI_ARRAY_TYPE_C) {
+ arg->v_pointer = array_->data;
+ g_array_free (array_, FALSE);
+ } else {
+ arg->v_pointer = array_;
+ }
+
+ return TRUE;
+}
+
+gboolean
+_pygi_marshal_in_glist (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ PyObject *py_arg,
+ GIArgument *arg)
+{
+ PyGIMarshalInFunc in_marshaller;
+ int i;
+ Py_ssize_t length;
+ GList *list_ = NULL;
+ PyGISequenceCache *sequence_cache = (PyGISequenceCache *)arg_cache;
+
+
+ if (py_arg == Py_None) {
+ arg->v_pointer = NULL;
+ return TRUE;
+ }
+
+ if (!PySequence_Check (py_arg)) {
+ PyErr_Format (PyExc_TypeError, "Must be sequence, not %s",
+ py_arg->ob_type->tp_name);
+ return FALSE;
+ }
+
+ length = PySequence_Length (py_arg);
+ if (length < 0)
+ return FALSE;
+
+ if (sequence_cache->fixed_size >= 0 &&
+ sequence_cache->fixed_size != length) {
+ PyErr_Format (PyExc_ValueError, "Must contain %zd items, not %zd",
+ sequence_cache->fixed_size, length);
+
+ return FALSE;
+ }
+
+ in_marshaller = sequence_cache->item_cache->in_marshaller;
+ for (i = 0; i < length; i++) {
+ GIArgument item;
+ PyObject *py_item = PySequence_GetItem (py_arg, i);
+ if (py_item == NULL)
+ goto err;
+
+ if (!in_marshaller ( state,
+ callable_cache,
+ sequence_cache->item_cache,
+ py_item,
+ &item))
+ goto err;
+
+ list_ = g_list_append (list_, item.v_pointer);
+ continue;
+err:
+ if (sequence_cache->item_cache->in_cleanup != NULL) {
+ GDestroyNotify cleanup = sequence_cache->item_cache->in_cleanup;
+ }
+
+ g_list_free (list_);
+ _PyGI_ERROR_PREFIX ("Item %i: ", i);
+ return FALSE;
+ }
+
+ arg->v_pointer = list_;
+ return TRUE;
+}
+
+gboolean
+_pygi_marshal_in_gslist (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ PyObject *py_arg,
+ GIArgument *arg)
+{
+ PyGIMarshalInFunc in_marshaller;
+ int i;
+ Py_ssize_t length;
+ GSList *list_ = NULL;
+ PyGISequenceCache *sequence_cache = (PyGISequenceCache *)arg_cache;
+
+ if (py_arg == Py_None) {
+ arg->v_pointer = NULL;
+ return TRUE;
+ }
+
+ if (!PySequence_Check (py_arg)) {
+ PyErr_Format (PyExc_TypeError, "Must be sequence, not %s",
+ py_arg->ob_type->tp_name);
+ return FALSE;
+ }
+
+ length = PySequence_Length (py_arg);
+ if (length < 0)
+ return FALSE;
+
+ if (sequence_cache->fixed_size >= 0 &&
+ sequence_cache->fixed_size != length) {
+ PyErr_Format (PyExc_ValueError, "Must contain %zd items, not %zd",
+ sequence_cache->fixed_size, length);
+
+ return FALSE;
+ }
+
+ in_marshaller = sequence_cache->item_cache->in_marshaller;
+ for (i = 0; i < length; i++) {
+ GIArgument item;
+ PyObject *py_item = PySequence_GetItem (py_arg, i);
+ if (py_item == NULL)
+ goto err;
+
+ if (!in_marshaller ( state,
+ callable_cache,
+ sequence_cache->item_cache,
+ py_item,
+ &item))
+ goto err;
+
+ list_ = g_slist_append (list_, item.v_pointer);
+ continue;
+err:
+ if (sequence_cache->item_cache->in_cleanup != NULL) {
+ GDestroyNotify cleanup = sequence_cache->item_cache->in_cleanup;
+ }
+
+ g_slist_free (list_);
+ _PyGI_ERROR_PREFIX ("Item %i: ", i);
+ return FALSE;
+ }
+
+ arg->v_pointer = list_;
+ return TRUE;
+}
+
+gboolean
+_pygi_marshal_in_ghash (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ PyObject *py_arg,
+ GIArgument *arg)
+{
+ PyGIMarshalInFunc key_in_marshaller;
+ PyGIMarshalInFunc value_in_marshaller;
+
+ int i;
+ Py_ssize_t length;
+ PyObject *py_keys, *py_values;
+
+ GHashFunc hash_func;
+ GEqualFunc equal_func;
+
+ GHashTable *hash_ = NULL;
+ PyGIHashCache *hash_cache = (PyGIHashCache *)arg_cache;
+
+ if (py_arg == Py_None) {
+ arg->v_pointer = NULL;
+ return TRUE;
+ }
+
+ py_keys = PyMapping_Keys (py_arg);
+ if (py_keys == NULL) {
+ PyErr_Format (PyExc_TypeError, "Must be mapping, not %s",
+ py_arg->ob_type->tp_name);
+ return FALSE;
+ }
+
+ length = PyMapping_Length (py_arg);
+ if (length < 0) {
+ Py_DECREF (py_keys);
+ return FALSE;
+ }
+
+ py_values = PyMapping_Values (py_arg);
+ if (py_values == NULL) {
+ Py_DECREF (py_keys);
+ return FALSE;
+ }
+
+ key_in_marshaller = hash_cache->key_cache->in_marshaller;
+ value_in_marshaller = hash_cache->value_cache->in_marshaller;
+
+ switch (hash_cache->key_cache->type_tag) {
+ case GI_TYPE_TAG_UTF8:
+ case GI_TYPE_TAG_FILENAME:
+ hash_func = g_str_hash;
+ equal_func = g_str_equal;
+ break;
+ default:
+ hash_func = NULL;
+ equal_func = NULL;
+ }
+
+ hash_ = g_hash_table_new (hash_func, equal_func);
+ if (hash_ == NULL) {
+ PyErr_NoMemory ();
+ Py_DECREF (py_keys);
+ Py_DECREF (py_values);
+ return FALSE;
+ }
+
+ for (i = 0; i < length; i++) {
+ GIArgument key, value;
+ PyObject *py_key = PyList_GET_ITEM (py_keys, i);
+ PyObject *py_value = PyList_GET_ITEM (py_values, i);
+ if (py_key == NULL || py_value == NULL)
+ goto err;
+
+ if (!key_in_marshaller ( state,
+ callable_cache,
+ hash_cache->key_cache,
+ py_key,
+ &key))
+ goto err;
+
+ if (!value_in_marshaller ( state,
+ callable_cache,
+ hash_cache->value_cache,
+ py_value,
+ &value))
+ goto err;
+
+ g_hash_table_insert (hash_, key.v_pointer, value.v_pointer);
+ continue;
+err:
+ /* FIXME: cleanup hash keys and values */
+ Py_XDECREF (py_key);
+ Py_XDECREF (py_value);
+ Py_DECREF (py_keys);
+ Py_DECREF (py_values);
+ g_hash_table_unref (hash_);
+ _PyGI_ERROR_PREFIX ("Item %i: ", i);
+ return FALSE;
+ }
+
+ arg->v_pointer = hash_;
+ return TRUE;
+}
+
+gboolean
+_pygi_marshal_in_gerror (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ PyObject *py_arg,
+ GIArgument *arg)
+{
+ PyErr_Format (PyExc_NotImplementedError,
+ "Marshalling for GErrors is not implemented");
+ return FALSE;
+}
+
+gboolean
+_pygi_marshal_in_interface_callback (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ PyObject *py_arg,
+ GIArgument *arg)
+{
+ GICallableInfo *callable_info;
+ PyGICClosure *closure;
+ PyGIArgCache *user_data_cache = NULL;
+ PyGIArgCache *destroy_cache = NULL;
+ PyGICallbackCache *callback_cache;
+ PyObject *py_user_data = NULL;
+
+ callback_cache = (PyGICallbackCache *)arg_cache;
+
+ if (callback_cache->user_data_index > 0) {
+ user_data_cache = callable_cache->args_cache[callback_cache->user_data_index];
+ if (user_data_cache->py_arg_index < state->n_py_in_args) {
+ py_user_data = PyTuple_GetItem (state->py_in_args, user_data_cache->py_arg_index);
+ if (!py_user_data)
+ return FALSE;
+ } else {
+ py_user_data = Py_None;
+ Py_INCREF (Py_None);
+ }
+ }
+
+ if (py_arg == Py_None && !(py_user_data == Py_None || py_user_data == NULL)) {
+ Py_DECREF (py_user_data);
+ PyErr_Format (PyExc_TypeError,
+ "When passing None for a callback userdata must also be None");
+
+ return FALSE;
+ }
+
+ if (py_arg == Py_None) {
+ Py_XDECREF (py_user_data);
+ return TRUE;
+ }
+
+ if (!PyCallable_Check (py_arg)) {
+ Py_XDECREF (py_user_data);
+ PyErr_Format (PyExc_TypeError,
+ "Callback needs to be a function or method not %s",
+ py_arg->ob_type->tp_name);
+
+ return FALSE;
+ }
+
+ if (callback_cache->destroy_notify_index > 0)
+ destroy_cache = callable_cache->args_cache[callback_cache->destroy_notify_index];
+
+ callable_info = (GICallableInfo *)callback_cache->interface_info;
+
+ closure = _pygi_make_native_closure (callable_info, callback_cache->scope, py_arg, py_user_data);
+ arg->v_pointer = closure->closure;
+ if (user_data_cache != NULL) {
+ state->in_args[user_data_cache->c_arg_index].v_pointer = closure;
+ }
+
+ if (destroy_cache) {
+ PyGICClosure *destroy_notify = _pygi_destroy_notify_create ();
+ state->in_args[destroy_cache->c_arg_index].v_pointer = destroy_notify->closure;
+ }
+
+ return TRUE;
+}
+
+gboolean
+_pygi_marshal_in_interface_enum (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ PyObject *py_arg,
+ GIArgument *arg)
+{
+ PyObject *int_;
+ gint is_instance;
+ PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)arg_cache;
+
+ is_instance = PyObject_IsInstance (py_arg, iface_cache->py_type);
+
+ int_ = PYGLIB_PyNumber_Long (py_arg);
+ if (int_ == NULL) {
+ PyErr_Clear();
+ goto err;
+ }
+
+ arg->v_long = PYGLIB_PyLong_AsLong (int_);
+ Py_DECREF (int_);
+
+ /* If this is not an instance of the Enum type that we want
+ * we need to check if the value is equivilant to one of the
+ * Enum's memebers */
+ if (!is_instance) {
+ int i;
+ gboolean is_found = FALSE;
+
+ for (i = 0; i < g_enum_info_get_n_values (iface_cache->interface_info); i++) {
+ GIValueInfo *value_info =
+ g_enum_info_get_value (iface_cache->interface_info, i);
+ glong enum_value = g_value_info_get_value (value_info);
+ g_base_info_unref ( (GIBaseInfo *)value_info);
+ if (arg->v_long == enum_value) {
+ is_found = TRUE;
+ break;
+ }
+ }
+
+ if (!is_found)
+ goto err;
+ }
+
+ return TRUE;
+
+err:
+ PyErr_Format (PyExc_TypeError, "Expected a %s, but got %s",
+ iface_cache->type_name, py_arg->ob_type->tp_name);
+ return FALSE;
+}
+
+gboolean
+_pygi_marshal_in_interface_flags (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ PyObject *py_arg,
+ GIArgument *arg)
+{
+ PyObject *int_;
+ gint is_instance;
+ PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)arg_cache;
+
+ is_instance = PyObject_IsInstance (py_arg, iface_cache->py_type);
+
+ int_ = PYGLIB_PyNumber_Long (py_arg);
+ if (int_ == NULL) {
+ PyErr_Clear ();
+ goto err;
+ }
+
+ arg->v_long = PYGLIB_PyLong_AsLong (int_);
+ Py_DECREF (int_);
+
+ /* only 0 or argument of type Flag is allowed */
+ if (!is_instance && arg->v_long != 0)
+ goto err;
+
+ return TRUE;
+
+err:
+ PyErr_Format (PyExc_TypeError, "Expected a %s, but got %s",
+ iface_cache->type_name, py_arg->ob_type->tp_name);
+ return FALSE;
+
+}
+
+gboolean
+_pygi_marshal_in_interface_struct (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ PyObject *py_arg,
+ GIArgument *arg)
+{
+ PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)arg_cache;
+
+ if (py_arg == Py_None) {
+ arg->v_pointer = NULL;
+ return TRUE;
+ }
+
+ /* FIXME: handle this large if statement in the cache
+ * and set the correct marshaller
+ */
+
+ if (iface_cache->g_type == G_TYPE_CLOSURE) {
+ GClosure *closure;
+ GType object_gtype = pyg_type_from_object_strict (py_arg, FALSE);
+
+ if ( !(PyCallable_Check(py_arg) ||
+ g_type_is_a (object_gtype, G_TYPE_CLOSURE))) {
+ PyErr_Format (PyExc_TypeError, "Must be callable, not %s",
+ py_arg->ob_type->tp_name);
+ return FALSE;
+ }
+
+ if (g_type_is_a (object_gtype, G_TYPE_CLOSURE))
+ closure = (GClosure *)pyg_boxed_get (py_arg, void);
+ else
+ closure = pyg_closure_new (py_arg, NULL, NULL);
+
+ if (closure == NULL) {
+ PyErr_SetString (PyExc_RuntimeError, "PyObject conversion to GClosure failed");
+ return FALSE;
+ }
+
+ arg->v_pointer = closure;
+ return TRUE;
+ } else if (iface_cache->g_type == G_TYPE_VALUE) {
+ GValue *value;
+ GType object_type;
+
+ object_type = pyg_type_from_object_strict ( (PyObject *) py_arg->ob_type, FALSE);
+ if (object_type == G_TYPE_INVALID) {
+ PyErr_SetString (PyExc_RuntimeError, "unable to retrieve object's GType");
+ return FALSE;
+ }
+
+ /* if already a gvalue, use that, else marshal into gvalue */
+ if (object_type == G_TYPE_VALUE) {
+ value = (GValue *)( (PyGObject *)py_arg)->obj;
+ } else {
+ value = g_slice_new0 (GValue);
+ g_value_init (value, object_type);
+ if (pyg_value_from_pyobject (value, py_arg) < 0) {
+ g_slice_free (GValue, value);
+ PyErr_SetString (PyExc_RuntimeError, "PyObject conversion to GValue failed");
+ return FALSE;
+ }
+ }
+
+ arg->v_pointer = value;
+ return TRUE;
+ } else if (iface_cache->is_foreign) {
+ gboolean success;
+ success = pygi_struct_foreign_convert_to_g_argument (py_arg,
+ iface_cache->interface_info,
+ arg_cache->transfer,
+ arg);
+
+ return success;
+ } else if (!PyObject_IsInstance (py_arg, iface_cache->py_type)) {
+ PyErr_Format (PyExc_TypeError, "Expected %s, but got %s",
+ iface_cache->type_name,
+ iface_cache->py_type->ob_type->tp_name);
+ return FALSE;
+ }
+
+ if (g_type_is_a (iface_cache->g_type, G_TYPE_BOXED)) {
+ arg->v_pointer = pyg_boxed_get (py_arg, void);
+ if (arg_cache->transfer == GI_TRANSFER_EVERYTHING) {
+ arg->v_pointer = g_boxed_copy (iface_cache->g_type, arg->v_pointer);
+ }
+ } else if (g_type_is_a (iface_cache->g_type, G_TYPE_POINTER) ||
+ g_type_is_a (iface_cache->g_type, G_TYPE_VARIANT) ||
+ iface_cache->g_type == G_TYPE_NONE) {
+ arg->v_pointer = pyg_pointer_get (py_arg, void);
+ } else {
+ PyErr_Format (PyExc_NotImplementedError,
+ "structure type '%s' is not supported yet",
+ g_type_name(iface_cache->g_type));
+ return FALSE;
+ }
+ return TRUE;
+}
+
+gboolean
+_pygi_marshal_in_interface_boxed (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ PyObject *py_arg,
+ GIArgument *arg)
+{
+ PyErr_Format (PyExc_NotImplementedError,
+ "Marshalling for this type is not implemented yet");
+ return FALSE;
+}
+
+gboolean
+_pygi_marshal_in_interface_object (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ PyObject *py_arg,
+ GIArgument *arg)
+{
+ if (py_arg == Py_None) {
+ arg->v_pointer = NULL;
+ return TRUE;
+ }
+
+ if (!PyObject_IsInstance (py_arg, ( (PyGIInterfaceCache *)arg_cache)->py_type)) {
+ PyErr_Format (PyExc_TypeError, "Expected %s, but got %s",
+ ( (PyGIInterfaceCache *)arg_cache)->type_name,
+ ( (PyGIInterfaceCache *)arg_cache)->py_type->ob_type->tp_name);
+ return FALSE;
+ }
+
+ arg->v_pointer = pygobject_get(py_arg);
+ if (arg_cache->transfer == GI_TRANSFER_EVERYTHING)
+ g_object_ref (arg->v_pointer);
+
+ return TRUE;
+}
+
+gboolean
+_pygi_marshal_in_interface_union (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ PyObject *py_arg,
+ GIArgument *arg)
+{
+ PyErr_Format(PyExc_NotImplementedError,
+ "Marshalling for this type is not implemented yet");
+ return FALSE;
+}
+
+gboolean _pygi_marshal_in_interface_instance (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ PyObject *py_arg,
+ GIArgument *arg)
+{
+ GIInfoType info_type;
+ PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)arg_cache;
+
+ /* FIXME: add instance checks */
+
+ info_type = g_base_info_get_type (iface_cache->interface_info);
+ switch (info_type) {
+ case GI_INFO_TYPE_UNION:
+ case GI_INFO_TYPE_STRUCT:
+ {
+ GType type = iface_cache->g_type;
+ if (g_type_is_a (type, G_TYPE_BOXED)) {
+ arg->v_pointer = pyg_boxed_get (py_arg, void);
+ } else if (g_type_is_a (type, G_TYPE_POINTER) ||
+ g_type_is_a (type, G_TYPE_VARIANT) ||
+ type == G_TYPE_NONE) {
+ arg->v_pointer = pyg_pointer_get (py_arg, void);
+ } else {
+ PyErr_Format (PyExc_TypeError, "unable to convert an instance of '%s'", g_type_name (type));
+ return FALSE;
+ }
+
+ break;
+ }
+ case GI_INFO_TYPE_OBJECT:
+ case GI_INFO_TYPE_INTERFACE:
+ arg->v_pointer = pygobject_get (py_arg);
+ break;
+ default:
+ /* Other types don't have methods. */
+ g_assert_not_reached ();
+ }
+
+ return TRUE;
+}
diff --git a/gi/pygi-marshal-in.h b/gi/pygi-marshal-in.h
new file mode 100644
index 00000000..7d948bc9
--- /dev/null
+++ b/gi/pygi-marshal-in.h
@@ -0,0 +1,186 @@
+/* -*- Mode: C; c-basic-offset: 4 -*-
+ * vim: tabstop=4 shiftwidth=4 expandtab
+ *
+ * Copyright (C) 2011 John (J5) Palmieri <johnp@redhat.com>, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#ifndef __PYGI_MARSHAL_H__
+#define __PYGI_MARSHAL_H__
+
+#include <Python.h>
+
+#include <girepository.h>
+
+#include "pygi-private.h"
+
+G_BEGIN_DECLS
+
+gboolean _pygi_marshal_in_void (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ PyObject *py_arg,
+ GIArgument *arg);
+gboolean _pygi_marshal_in_boolean (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ PyObject *py_arg,
+ GIArgument *arg);
+gboolean _pygi_marshal_in_int8 (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ PyObject *py_arg,
+ GIArgument *arg);
+gboolean _pygi_marshal_in_uint8 (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ PyObject *py_arg,
+ GIArgument *arg);
+gboolean _pygi_marshal_in_int16 (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ PyObject *py_arg,
+ GIArgument *arg);
+gboolean _pygi_marshal_in_uint16 (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ PyObject *py_arg,
+ GIArgument *arg);
+gboolean _pygi_marshal_in_int32 (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ PyObject *py_arg,
+ GIArgument *arg);
+gboolean _pygi_marshal_in_uint32 (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ PyObject *py_arg,
+ GIArgument *arg);
+gboolean _pygi_marshal_in_int64 (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ PyObject *py_arg,
+ GIArgument *arg);
+gboolean _pygi_marshal_in_uint64 (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ PyObject *py_arg,
+ GIArgument *arg);
+gboolean _pygi_marshal_in_float (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ PyObject *py_arg,
+ GIArgument *arg);
+gboolean _pygi_marshal_in_double (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ PyObject *py_arg,
+ GIArgument *arg);
+gboolean _pygi_marshal_in_unichar (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ PyObject *py_arg,
+ GIArgument *arg);
+gboolean _pygi_marshal_in_gtype (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ PyObject *py_arg,
+ GIArgument *arg);
+gboolean _pygi_marshal_in_utf8 (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ PyObject *py_arg,
+ GIArgument *arg);
+gboolean _pygi_marshal_in_filename (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ PyObject *py_arg,
+ GIArgument *arg);
+gboolean _pygi_marshal_in_array (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ PyObject *py_arg,
+ GIArgument *arg);
+gboolean _pygi_marshal_in_glist (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ PyObject *py_arg,
+ GIArgument *arg);
+gboolean _pygi_marshal_in_gslist (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ PyObject *py_arg,
+ GIArgument *arg);
+gboolean _pygi_marshal_in_ghash (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ PyObject *py_arg,
+ GIArgument *arg);
+gboolean _pygi_marshal_in_gerror (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ PyObject *py_arg,
+ GIArgument *arg);
+gboolean _pygi_marshal_in_interface_callback (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ PyObject *py_arg,
+ GIArgument *arg);
+gboolean _pygi_marshal_in_interface_enum (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ PyObject *py_arg,
+ GIArgument *arg);
+gboolean _pygi_marshal_in_interface_flags (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ PyObject *py_arg,
+ GIArgument *arg);
+gboolean _pygi_marshal_in_interface_struct (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ PyObject *py_arg,
+ GIArgument *arg);
+gboolean _pygi_marshal_in_interface_interface(PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ PyObject *py_arg,
+ GIArgument *arg);
+gboolean _pygi_marshal_in_interface_boxed (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ PyObject *py_arg,
+ GIArgument *arg);
+gboolean _pygi_marshal_in_interface_object (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ PyObject *py_arg,
+ GIArgument *arg);
+gboolean _pygi_marshal_in_interface_union (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ PyObject *py_arg,
+ GIArgument *arg);
+gboolean _pygi_marshal_in_interface_instance (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ PyObject *py_arg,
+ GIArgument *arg);
+
+G_END_DECLS
+
+#endif /* __PYGI_MARSHAL_H__ */
diff --git a/gi/pygi-marshal-out.c b/gi/pygi-marshal-out.c
new file mode 100644
index 00000000..f99ee256
--- /dev/null
+++ b/gi/pygi-marshal-out.c
@@ -0,0 +1,767 @@
+/* -*- Mode: C; c-basic-offset: 4 -*-
+ * vim: tabstop=4 shiftwidth=4 expandtab
+ *
+ * Copyright (C) 2011 John (J5) Palmieri <johnp@redhat.com>, Red Hat, Inc.
+ *
+ * pygi-marshal-out.c: PyObject conversion functions for out parameters.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#include "pygi-private.h"
+
+#include <string.h>
+#include <time.h>
+
+#include <datetime.h>
+#include <pygobject.h>
+#include <pyglib-python-compat.h>
+
+#include "pygi-cache.h"
+#include "pygi-marshal-cleanup.h"
+#include "pygi-marshal-out.h"
+
+PyObject *
+_pygi_marshal_out_void (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ GIArgument *arg)
+{
+ PyObject *py_obj = NULL;
+ if (arg_cache->is_pointer)
+ py_obj = arg->v_pointer;
+ else
+ py_obj = Py_None;
+
+ Py_XINCREF (py_obj);
+ return py_obj;
+}
+
+PyObject *
+_pygi_marshal_out_boolean (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ GIArgument *arg)
+{
+ PyObject *py_obj = PyBool_FromLong (arg->v_boolean);
+ return py_obj;
+}
+
+PyObject *
+_pygi_marshal_out_int8 (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ GIArgument *arg)
+{
+ PyObject *py_obj = PYGLIB_PyLong_FromLong (arg->v_int8);
+ return py_obj;
+}
+
+PyObject *
+_pygi_marshal_out_uint8 (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ GIArgument *arg)
+{
+ PyObject *py_obj = PYGLIB_PyLong_FromLong (arg->v_uint8);
+
+ return py_obj;
+}
+
+PyObject *
+_pygi_marshal_out_int16 (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ GIArgument *arg)
+{
+ PyObject *py_obj = PYGLIB_PyLong_FromLong (arg->v_int16);
+
+ return py_obj;
+}
+
+PyObject *
+_pygi_marshal_out_uint16 (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ GIArgument *arg)
+{
+ PyObject *py_obj = PYGLIB_PyLong_FromLong (arg->v_uint16);
+
+ return py_obj;
+}
+
+PyObject *
+_pygi_marshal_out_int32 (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ GIArgument *arg)
+{
+ PyObject *py_obj = PYGLIB_PyLong_FromLong (arg->v_int32);
+
+ return py_obj;
+}
+
+PyObject *
+_pygi_marshal_out_uint32 (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ GIArgument *arg)
+{
+ PyObject *py_obj = PyLong_FromLongLong (arg->v_uint32);
+
+ return py_obj;
+}
+
+PyObject *
+_pygi_marshal_out_int64 (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ GIArgument *arg)
+{
+ PyObject *py_obj = PyLong_FromLongLong (arg->v_int64);
+
+ return py_obj;
+}
+
+PyObject *
+_pygi_marshal_out_uint64 (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ GIArgument *arg)
+{
+ PyObject *py_obj = PyLong_FromUnsignedLongLong (arg->v_uint64);
+
+ return py_obj;
+}
+
+PyObject *
+_pygi_marshal_out_float (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ GIArgument *arg)
+{
+ PyObject *py_obj = PyFloat_FromDouble (arg->v_float);
+
+ return py_obj;
+}
+
+PyObject *
+_pygi_marshal_out_double (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ GIArgument *arg)
+{
+ PyObject *py_obj = PyFloat_FromDouble (arg->v_double);
+
+ return py_obj;
+}
+
+PyObject *
+_pygi_marshal_out_unichar (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ GIArgument *arg)
+{
+ PyObject *py_obj = NULL;
+
+ /* Preserve the bidirectional mapping between 0 and "" */
+ if (arg->v_uint32 == 0) {
+ py_obj = PYGLIB_PyUnicode_FromString ("");
+ } else if (g_unichar_validate (arg->v_uint32)) {
+ gchar utf8[6];
+ gint bytes;
+
+ bytes = g_unichar_to_utf8 (arg->v_uint32, utf8);
+ py_obj = PYGLIB_PyUnicode_FromStringAndSize ((char*)utf8, bytes);
+ } else {
+ /* TODO: Convert the error to an exception. */
+ PyErr_Format (PyExc_TypeError,
+ "Invalid unicode codepoint %" G_GUINT32_FORMAT,
+ arg->v_uint32);
+ }
+
+ return py_obj;
+}
+
+PyObject *
+_pygi_marshal_out_gtype (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ GIArgument *arg)
+{
+ PyObject *py_obj = NULL;
+
+ py_obj = pyg_type_wrapper_new ( (GType)arg->v_long);
+ return py_obj;
+}
+
+PyObject *
+_pygi_marshal_out_utf8 (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ GIArgument *arg)
+{
+ PyObject *py_obj = NULL;
+ if (arg->v_string == NULL) {
+ py_obj = Py_None;
+ Py_INCREF (py_obj);
+ return py_obj;
+ }
+
+ py_obj = PYGLIB_PyUnicode_FromString (arg->v_string);
+ return py_obj;
+}
+
+PyObject *
+_pygi_marshal_out_filename (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ GIArgument *arg)
+{
+ gchar *string;
+ PyObject *py_obj = NULL;
+ GError *error = NULL;
+
+ if (arg->v_string == NULL) {
+ py_obj = Py_None;
+ Py_INCREF (py_obj);
+ return py_obj;
+ }
+
+ string = g_filename_to_utf8 (arg->v_string, -1, NULL, NULL, &error);
+ if (string == NULL) {
+ PyErr_SetString (PyExc_Exception, error->message);
+ /* TODO: Convert the error to an exception. */
+ return NULL;
+ }
+
+ py_obj = PYGLIB_PyUnicode_FromString (string);
+ g_free (string);
+
+ return py_obj;
+}
+
+PyObject *
+_pygi_marshal_out_array (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ GIArgument *arg)
+{
+ GArray *array_;
+ PyObject *py_obj = NULL;
+ PyGISequenceCache *seq_cache = (PyGISequenceCache *)arg_cache;
+ gsize processed_items = 0;
+
+ array_ = arg->v_pointer;
+
+ /* GArrays make it easier to iterate over arrays
+ * with different element sizes but requires that
+ * we allocate a GArray if the argument was a C array
+ */
+ if (seq_cache->array_type == GI_ARRAY_TYPE_C) {
+ gsize len;
+ if (seq_cache->fixed_size >= 0) {
+ len = seq_cache->fixed_size;
+ } else if (seq_cache->is_zero_terminated) {
+ len = g_strv_length (arg->v_string);
+ } else {
+ GIArgument *len_arg = state->args[seq_cache->len_arg_index];
+ len = len_arg->v_long;
+ }
+
+ array_ = g_array_new (FALSE,
+ FALSE,
+ seq_cache->item_size);
+ if (array_ == NULL) {
+ PyErr_NoMemory ();
+
+ if (arg_cache->transfer == GI_TRANSFER_EVERYTHING)
+ g_free (arg->v_pointer);
+
+ return NULL;
+ }
+
+ array_->data = arg->v_pointer;
+ array_->len = len;
+ }
+
+ if (seq_cache->item_cache->type_tag == GI_TYPE_TAG_UINT8) {
+ if (arg->v_pointer == NULL) {
+ py_obj = PYGLIB_PyBytes_FromString ("");
+ } else {
+ py_obj = PYGLIB_PyBytes_FromStringAndSize (array_->data, array_->len);
+ }
+ } else {
+ if (arg->v_pointer == NULL) {
+ py_obj = PyList_New (0);
+ } else {
+ int i;
+
+ gsize item_size;
+ PyGIMarshalOutFunc item_out_marshaller;
+ PyGIArgCache *item_arg_cache;
+
+ py_obj = PyList_New (array_->len);
+ if (py_obj == NULL)
+ goto err;
+
+
+ item_arg_cache = seq_cache->item_cache;
+ item_out_marshaller = item_arg_cache->out_marshaller;
+
+ item_size = g_array_get_element_size (array_);
+
+ for (i = 0; i < array_->len; i++) {
+ GIArgument item_arg;
+ PyObject *py_item;
+
+ if (seq_cache->array_type == GI_ARRAY_TYPE_PTR_ARRAY) {
+ item_arg.v_pointer = g_ptr_array_index ( ( GPtrArray *)array_, i);
+ } else if (item_arg_cache->type_tag == GI_TYPE_TAG_INTERFACE) {
+ item_arg.v_pointer = array_->data + i * item_size;
+ if (arg_cache->transfer == GI_TRANSFER_EVERYTHING) {
+ PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *) item_arg_cache;
+ switch (g_base_info_get_type (iface_cache->interface_info)) {
+ case GI_INFO_TYPE_STRUCT:
+ {
+ gpointer *_struct = g_malloc (item_size);
+ memcpy (_struct, item_arg.v_pointer, item_size);
+ item_arg.v_pointer = _struct;
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ } else {
+ memcpy (&item_arg, array_->data + i * item_size, item_size);
+ }
+
+ py_item = item_out_marshaller ( state,
+ callable_cache,
+ item_arg_cache,
+ &item_arg);
+
+ if (py_item == NULL) {
+ Py_CLEAR (py_obj);
+
+ if (seq_cache->array_type == GI_ARRAY_TYPE_C)
+ g_array_unref (array_);
+
+ goto err;
+ }
+ PyList_SET_ITEM (py_obj, i, py_item);
+ processed_items++;
+ }
+ }
+ }
+
+ if (seq_cache->array_type == GI_ARRAY_TYPE_C)
+ g_array_free (array_, FALSE);
+
+ return py_obj;
+
+err:
+ if (seq_cache->array_type == GI_ARRAY_TYPE_C) {
+ g_array_free (array_, arg_cache->transfer == GI_TRANSFER_EVERYTHING);
+ } else {
+ /* clean up unprocessed items */
+ if (seq_cache->item_cache->out_cleanup != NULL) {
+ int j;
+ PyGIMarshalCleanupFunc cleanup_func = seq_cache->item_cache->out_cleanup;
+ for (j = processed_items; j < array_->len; j++) {
+ cleanup_func (state,
+ seq_cache->item_cache,
+ g_array_index (array_, gpointer, j),
+ FALSE);
+ }
+ }
+
+ if (arg_cache->transfer == GI_TRANSFER_EVERYTHING)
+ g_array_free (array_, TRUE);
+ }
+
+ return NULL;
+}
+
+PyObject *
+_pygi_marshal_out_glist (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ GIArgument *arg)
+{
+ GList *list_;
+ gsize length;
+ gsize i;
+
+ PyGIMarshalOutFunc item_out_marshaller;
+ PyGIArgCache *item_arg_cache;
+ PyGISequenceCache *seq_cache = (PyGISequenceCache *)arg_cache;
+
+ PyObject *py_obj = NULL;
+
+ list_ = arg->v_pointer;
+ length = g_list_length (list_);
+
+ py_obj = PyList_New (length);
+ if (py_obj == NULL)
+ return NULL;
+
+ item_arg_cache = seq_cache->item_cache;
+ item_out_marshaller = item_arg_cache->out_marshaller;
+
+ for (i = 0; list_ != NULL; list_ = g_list_next (list_), i++) {
+ GIArgument item_arg;
+ PyObject *py_item;
+
+ item_arg.v_pointer = list_->data;
+ py_item = item_out_marshaller ( state,
+ callable_cache,
+ item_arg_cache,
+ &item_arg);
+
+ if (py_item == NULL) {
+ Py_CLEAR (py_obj);
+ _PyGI_ERROR_PREFIX ("Item %zu: ", i);
+ return NULL;
+ }
+
+ PyList_SET_ITEM (py_obj, i, py_item);
+ }
+
+ return py_obj;
+}
+
+PyObject *
+_pygi_marshal_out_gslist (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ GIArgument *arg)
+{
+ GSList *list_;
+ gsize length;
+ gsize i;
+
+ PyGIMarshalOutFunc item_out_marshaller;
+ PyGIArgCache *item_arg_cache;
+ PyGISequenceCache *seq_cache = (PyGISequenceCache *)arg_cache;
+
+ PyObject *py_obj = NULL;
+
+ list_ = arg->v_pointer;
+ length = g_slist_length (list_);
+
+ py_obj = PyList_New (length);
+ if (py_obj == NULL)
+ return NULL;
+
+ item_arg_cache = seq_cache->item_cache;
+ item_out_marshaller = item_arg_cache->out_marshaller;
+
+ for (i = 0; list_ != NULL; list_ = g_slist_next (list_), i++) {
+ GIArgument item_arg;
+ PyObject *py_item;
+
+ item_arg.v_pointer = list_->data;
+ py_item = item_out_marshaller ( state,
+ callable_cache,
+ item_arg_cache,
+ &item_arg);
+
+ if (py_item == NULL) {
+ Py_CLEAR (py_obj);
+ _PyGI_ERROR_PREFIX ("Item %zu: ", i);
+ return NULL;
+ }
+
+ PyList_SET_ITEM (py_obj, i, py_item);
+ }
+
+ return py_obj;
+}
+
+PyObject *
+_pygi_marshal_out_ghash (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ GIArgument *arg)
+{
+ GHashTable *hash_;
+ GHashTableIter hash_table_iter;
+
+ PyGIMarshalOutFunc key_out_marshaller;
+ PyGIMarshalOutFunc value_out_marshaller;
+
+ PyGIArgCache *key_arg_cache;
+ PyGIArgCache *value_arg_cache;
+ PyGIHashCache *hash_cache = (PyGIHashCache *)arg_cache;
+
+ GIArgument key_arg;
+ GIArgument value_arg;
+
+ PyObject *py_obj = NULL;
+
+ hash_ = arg->v_pointer;
+
+ if (hash_ == NULL) {
+ py_obj = Py_None;
+ Py_INCREF (py_obj);
+ return py_obj;
+ }
+
+ py_obj = PyDict_New ();
+ if (py_obj == NULL)
+ return NULL;
+
+ key_arg_cache = hash_cache->key_cache;
+ key_out_marshaller = key_arg_cache->out_marshaller;
+
+ value_arg_cache = hash_cache->value_cache;
+ value_out_marshaller = value_arg_cache->out_marshaller;
+
+ g_hash_table_iter_init (&hash_table_iter, hash_);
+ while (g_hash_table_iter_next (&hash_table_iter,
+ &key_arg.v_pointer,
+ &value_arg.v_pointer)) {
+ PyObject *py_key;
+ PyObject *py_value;
+ int retval;
+
+ py_key = key_out_marshaller ( state,
+ callable_cache,
+ key_arg_cache,
+ &key_arg);
+
+ if (py_key == NULL) {
+ Py_CLEAR (py_obj);
+ return NULL;
+ }
+
+ py_value = value_out_marshaller ( state,
+ callable_cache,
+ value_arg_cache,
+ &value_arg);
+
+ if (py_value == NULL) {
+ Py_CLEAR (py_obj);
+ Py_DECREF(py_key);
+ return NULL;
+ }
+
+ retval = PyDict_SetItem (py_obj, py_key, py_value);
+
+ Py_DECREF (py_key);
+ Py_DECREF (py_value);
+
+ if (retval < 0) {
+ Py_CLEAR (py_obj);
+ return NULL;
+ }
+ }
+
+ return py_obj;
+}
+
+PyObject *
+_pygi_marshal_out_gerror (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ GIArgument *arg)
+{
+ PyObject *py_obj = NULL;
+
+ PyErr_Format (PyExc_NotImplementedError,
+ "Marshalling for gerror out is not implemented");
+ return py_obj;
+}
+
+PyObject *
+_pygi_marshal_out_interface_callback (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ GIArgument *arg)
+{
+ PyObject *py_obj = NULL;
+
+ PyErr_Format (PyExc_NotImplementedError,
+ "Callback out values are not supported");
+ return py_obj;
+}
+
+PyObject *
+_pygi_marshal_out_interface_enum (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ GIArgument *arg)
+{
+ PyObject *py_obj = NULL;
+ PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)arg_cache;
+
+ if (iface_cache->g_type == G_TYPE_NONE) {
+ py_obj = PyObject_CallFunction (iface_cache->py_type, "l", arg->v_long);
+ } else {
+ py_obj = pyg_enum_from_gtype (iface_cache->g_type, arg->v_long);
+ }
+ return py_obj;
+}
+
+PyObject *
+_pygi_marshal_out_interface_flags (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ GIArgument *arg)
+{
+ PyObject *py_obj = NULL;
+ PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)arg_cache;
+
+ if (iface_cache->g_type == G_TYPE_NONE) {
+ /* An enum with a GType of None is an enum without GType */
+
+ PyObject *py_type = _pygi_type_import_by_gi_info (iface_cache->interface_info);
+ PyObject *py_args = NULL;
+
+ if (!py_type)
+ return NULL;
+
+ py_args = PyTuple_New (1);
+ if (PyTuple_SetItem (py_args, 0, PyLong_FromLong (arg->v_long)) != 0) {
+ Py_DECREF (py_args);
+ Py_DECREF (py_type);
+ return NULL;
+ }
+
+ py_obj = PyObject_CallFunction (py_type, "l", arg->v_long);
+
+ Py_DECREF (py_args);
+ Py_DECREF (py_type);
+ } else {
+ py_obj = pyg_flags_from_gtype (iface_cache->g_type, arg->v_long);
+ }
+
+ return py_obj;
+}
+
+PyObject *
+_pygi_marshal_out_interface_struct (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ GIArgument *arg)
+{
+ PyObject *py_obj = NULL;
+ PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)arg_cache;
+ GType type = iface_cache->g_type;
+
+ if (arg->v_pointer == NULL) {
+ py_obj = Py_None;
+ Py_INCREF (py_obj);
+ return py_obj;
+ }
+
+ if (g_type_is_a (type, G_TYPE_VALUE)) {
+ py_obj = pyg_value_as_pyobject (arg->v_pointer, FALSE);
+ } else if (iface_cache->is_foreign) {
+ py_obj = pygi_struct_foreign_convert_from_g_argument (iface_cache->interface_info,
+ arg->v_pointer);
+ } else if (g_type_is_a (type, G_TYPE_BOXED)) {
+ py_obj = _pygi_boxed_new ( (PyTypeObject *)iface_cache->py_type, arg->v_pointer,
+ arg_cache->transfer == GI_TRANSFER_EVERYTHING);
+ } else if (g_type_is_a (type, G_TYPE_POINTER)) {
+ if (iface_cache->py_type == NULL ||
+ !PyType_IsSubtype ( (PyTypeObject *)iface_cache->py_type, &PyGIStruct_Type)) {
+ g_warn_if_fail(arg_cache->transfer == GI_TRANSFER_NOTHING);
+ py_obj = pyg_pointer_new (type, arg->v_pointer);
+ } else {
+ py_obj = _pygi_struct_new ( (PyTypeObject *)iface_cache->py_type, arg->v_pointer,
+ arg_cache->transfer == GI_TRANSFER_EVERYTHING);
+ }
+ } else if (g_type_is_a (type, G_TYPE_VARIANT)) {
+ g_variant_ref_sink (arg->v_pointer);
+ py_obj = _pygi_struct_new ( (PyTypeObject *)iface_cache->py_type, arg->v_pointer,
+ FALSE);
+ } else if (type == G_TYPE_NONE && iface_cache->is_foreign) {
+ py_obj = pygi_struct_foreign_convert_from_g_argument (iface_cache->interface_info, arg->v_pointer);
+ } else if (type == G_TYPE_NONE) {
+ py_obj = _pygi_struct_new ( (PyTypeObject *) iface_cache->py_type, arg->v_pointer,
+ arg_cache->transfer == GI_TRANSFER_EVERYTHING);
+ } else {
+ PyErr_Format (PyExc_NotImplementedError,
+ "structure type '%s' is not supported yet",
+ g_type_name (type));
+ }
+
+ return py_obj;
+}
+
+PyObject *
+_pygi_marshal_out_interface_interface (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ GIArgument *arg)
+{
+ PyObject *py_obj = NULL;
+
+ PyErr_Format (PyExc_NotImplementedError,
+ "Marshalling for this type is not implemented yet");
+ return py_obj;
+}
+
+PyObject *
+_pygi_marshal_out_interface_boxed (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ GIArgument *arg)
+{
+ PyObject *py_obj = NULL;
+
+ PyErr_Format (PyExc_NotImplementedError,
+ "Marshalling for this type is not implemented yet");
+ return py_obj;
+}
+
+PyObject *
+_pygi_marshal_out_interface_object (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ GIArgument *arg)
+{
+ PyObject *py_obj;
+
+ if (arg->v_pointer == NULL) {
+ py_obj = Py_None;
+ Py_INCREF (py_obj);
+ return py_obj;
+ }
+
+ py_obj = pygobject_new (arg->v_pointer);
+
+ if (arg_cache->transfer == GI_TRANSFER_EVERYTHING)
+ g_object_unref (arg->v_pointer);
+
+ return py_obj;
+}
+
+PyObject *
+_pygi_marshal_out_interface_union (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ GIArgument *arg)
+{
+ PyObject *py_obj = NULL;
+
+ PyErr_Format (PyExc_NotImplementedError,
+ "Marshalling for this type is not implemented yet");
+ return py_obj;
+}
diff --git a/gi/pygi-marshal-out.h b/gi/pygi-marshal-out.h
new file mode 100644
index 00000000..db6bcfed
--- /dev/null
+++ b/gi/pygi-marshal-out.h
@@ -0,0 +1,144 @@
+/* -*- Mode: C; c-basic-offset: 4 -*-
+ * vim: tabstop=4 shiftwidth=4 expandtab
+ *
+ * Copyright (C) 2011 John (J5) Palmieri <johnp@redhat.com>, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#ifndef __PYGI_MARSHAL_OUT_H__
+#define __PYGI_MARSHAL_OUT_H__
+
+PyObject *_pygi_marshal_out_void (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ GIArgument *arg);
+PyObject *_pygi_marshal_out_boolean (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ GIArgument *arg);
+PyObject *_pygi_marshal_out_int8 (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ GIArgument *arg);
+PyObject *_pygi_marshal_out_uint8 (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ GIArgument *arg);
+PyObject *_pygi_marshal_out_int16 (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ GIArgument *arg);
+PyObject *_pygi_marshal_out_uint16 (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ GIArgument *arg);
+PyObject *_pygi_marshal_out_int32 (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ GIArgument *arg);
+PyObject *_pygi_marshal_out_uint32 (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ GIArgument *arg);
+PyObject *_pygi_marshal_out_int64 (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ GIArgument *arg);
+PyObject *_pygi_marshal_out_uint64 (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ GIArgument *arg);
+PyObject *_pygi_marshal_out_float (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ GIArgument *arg);
+PyObject *_pygi_marshal_out_double (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ GIArgument *arg);
+PyObject *_pygi_marshal_out_unichar (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ GIArgument *arg);
+PyObject *_pygi_marshal_out_gtype (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ GIArgument *arg);
+PyObject *_pygi_marshal_out_utf8 (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ GIArgument *arg);
+PyObject *_pygi_marshal_out_filename (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ GIArgument *arg);
+PyObject *_pygi_marshal_out_array (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ GIArgument *arg);
+PyObject *_pygi_marshal_out_glist (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ GIArgument *arg);
+PyObject *_pygi_marshal_out_gslist (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ GIArgument *arg);
+PyObject *_pygi_marshal_out_ghash (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ GIArgument *arg);
+PyObject *_pygi_marshal_out_gerror (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ GIArgument *arg);
+PyObject *_pygi_marshal_out_interface_callback(PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ GIArgument *arg);
+PyObject *_pygi_marshal_out_interface_enum (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ GIArgument *arg);
+PyObject *_pygi_marshal_out_interface_flags (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ GIArgument *arg);
+PyObject *_pygi_marshal_out_interface_struct (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ GIArgument *arg);
+PyObject *_pygi_marshal_out_interface_interface(PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ GIArgument *arg);
+PyObject *_pygi_marshal_out_interface_boxed (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ GIArgument *arg);
+PyObject *_pygi_marshal_out_interface_object (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ GIArgument *arg);
+PyObject *_pygi_marshal_out_interface_union (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ GIArgument *arg);
+
+G_END_DECLS
+
+#endif /* __PYGI_MARSHAL_OUT_H__ */
diff --git a/gi/pygi-private.h b/gi/pygi-private.h
index efe62c85..8b277788 100644
--- a/gi/pygi-private.h
+++ b/gi/pygi-private.h
@@ -27,9 +27,13 @@
#include "pygi-foreign.h"
#include "pygi-closure.h"
#include "pygi-callbacks.h"
-#include "pygi-invoke.h"
#include "pygi-property.h"
#include "pygi-signal-closure.h"
+#include "pygi-invoke.h"
+
+#ifdef ENABLE_INVOKE_NG
+ #include "pygi-cache.h"
+#endif
G_BEGIN_DECLS
#if PY_VERSION_HEX >= 0x03000000
diff --git a/gi/pygi.h b/gi/pygi.h
index c9a3fec6..c23ab9b9 100644
--- a/gi/pygi.h
+++ b/gi/pygi.h
@@ -32,6 +32,7 @@
#if ENABLE_INTROSPECTION
#include <girepository.h>
+#include "pygi-cache.h"
typedef struct {
PyObject_HEAD
@@ -42,6 +43,9 @@ typedef struct {
PyObject_HEAD
GIBaseInfo *info;
PyObject *inst_weakreflist;
+#ifdef ENABLE_INVOKE_NG
+ PyGICallableCache *cache;
+#endif
} PyGIBaseInfo;
typedef struct {
diff --git a/gobject/pygtype.c b/gobject/pygtype.c
index 63ac1c66..ffd99a55 100644
--- a/gobject/pygtype.c
+++ b/gobject/pygtype.c
@@ -743,11 +743,12 @@ int
pyg_value_from_pyobject(GValue *value, PyObject *obj)
{
PyObject *tmp;
+ GType value_type = G_VALUE_TYPE(value);
- switch (G_TYPE_FUNDAMENTAL(G_VALUE_TYPE(value))) {
+ switch (G_TYPE_FUNDAMENTAL(value_type)) {
case G_TYPE_INTERFACE:
/* we only handle interface types that have a GObject prereq */
- if (g_type_is_a(G_VALUE_TYPE(value), G_TYPE_OBJECT)) {
+ if (g_type_is_a(value_type, G_TYPE_OBJECT)) {
if (obj == Py_None)
g_value_set_object(value, NULL);
else {
@@ -755,7 +756,7 @@ pyg_value_from_pyobject(GValue *value, PyObject *obj)
return -1;
}
if (!G_TYPE_CHECK_INSTANCE_TYPE(pygobject_get(obj),
- G_VALUE_TYPE(value))) {
+ value_type)) {
return -1;
}
g_value_set_object(value, pygobject_get(obj));
diff --git a/tests/test_gi.py b/tests/test_gi.py
index 6990225c..0436a6ec 100644
--- a/tests/test_gi.py
+++ b/tests/test_gi.py
@@ -742,7 +742,6 @@ class TestArray(unittest.TestCase):
def test_gstrv_inout(self):
self.assertEquals(['-1', '0', '1', '2'], GIMarshallingTests.gstrv_inout(['0', '1', '2']))
-
class TestGArray(unittest.TestCase):
def test_garray_int_none_return(self):
@@ -786,6 +785,48 @@ class TestGArray(unittest.TestCase):
def test_garray_utf8_full_inout(self):
self.assertEquals(['-2', '-1','0', '1'], GIMarshallingTests.garray_utf8_full_inout(['0', '1', '2']))
+class TestGPtrArray(unittest.TestCase):
+
+ def test_gptrarray_int_none_return(self):
+ self.assertEquals([0, 1, 2, 3], GIMarshallingTests.gptrarray_int_none_return())
+
+ def test_gptrarray_utf8_none_return(self):
+ self.assertEquals(['0', '1', '2'], GIMarshallingTests.gptrarray_utf8_none_return())
+
+ def test_gptrarray_utf8_container_return(self):
+ self.assertEquals(['0', '1', '2'], GIMarshallingTests.gptrarray_utf8_container_return())
+
+ def test_gptrarray_utf8_full_return(self):
+ self.assertEquals(['0', '1', '2'], GIMarshallingTests.gptrarray_utf8_full_return())
+
+ def test_gptrarray_int_none_in(self):
+ GIMarshallingTests.gptrarray_int_none_in(Sequence([0, 1, 2, 3]))
+
+ self.assertRaises(TypeError, GIMarshallingTests.gptrarray_int_none_in, Sequence([-1, '0', 1, 2]))
+
+ self.assertRaises(TypeError, GIMarshallingTests.gptrarray_int_none_in, 42)
+ self.assertRaises(TypeError, GIMarshallingTests.gptrarray_int_none_in, None)
+
+ def test_gptrarray_utf8_none_in(self):
+ GIMarshallingTests.gptrarray_utf8_none_in(Sequence(['0', '1', '2']))
+
+ def test_gptrarray_utf8_none_out(self):
+ self.assertEquals(['0', '1', '2'], GIMarshallingTests.gptrarray_utf8_none_out())
+
+ def test_gptrarray_utf8_container_out(self):
+ self.assertEquals(['0', '1', '2'], GIMarshallingTests.gptrarray_utf8_container_out())
+
+ def test_gptrarray_utf8_full_out(self):
+ self.assertEquals(['0', '1', '2'], GIMarshallingTests.gptrarray_utf8_full_out())
+
+ def test_gptrarray_utf8_none_inout(self):
+ self.assertEquals(['-2', '-1', '0', '1'], GIMarshallingTests.gptrarray_utf8_none_inout(Sequence(('0', '1', '2'))))
+
+ def test_gptrarray_utf8_container_inout(self):
+ self.assertEquals(['-2', '-1','0', '1'], GIMarshallingTests.gptrarray_utf8_container_inout(['0', '1', '2']))
+
+ def test_gptrarray_utf8_full_inout(self):
+ self.assertEquals(['-2', '-1','0', '1'], GIMarshallingTests.gptrarray_utf8_full_inout(['0', '1', '2']))
class TestGList(unittest.TestCase):
diff --git a/tests/test_overrides.py b/tests/test_overrides.py
index fe1fe98f..3e46b335 100644
--- a/tests/test_overrides.py
+++ b/tests/test_overrides.py
@@ -248,8 +248,7 @@ class TestGLib(unittest.TestCase):
self.assertEqual(res, (-1, 'hello'))
# array
- vb = GLib.VariantBuilder()
- vb.init(gi._gi.variant_type_from_string('ai'))
+ vb = GLib.VariantBuilder.new(gi._gi.variant_type_from_string('ai'))
vb.add_value(GLib.Variant.new_int32(-1))
vb.add_value(GLib.Variant.new_int32(3))
res = vb.end().unpack()
@@ -261,8 +260,7 @@ class TestGLib(unittest.TestCase):
def test_gvariant_iteration(self):
# array index access
- vb = GLib.VariantBuilder()
- vb.init(gi._gi.variant_type_from_string('ai'))
+ vb = GLib.VariantBuilder.new(gi._gi.variant_type_from_string('ai'))
vb.add_value(GLib.Variant.new_int32(-1))
vb.add_value(GLib.Variant.new_int32(3))
v = vb.end()
@@ -709,6 +707,7 @@ class TestGtk(unittest.TestCase):
tree_store = Gtk.TreeStore(int,
'gchararray',
TestGtk.TestClass,
+ GObject.TYPE_PYOBJECT,
object,
object,
object,
@@ -728,6 +727,7 @@ class TestGtk(unittest.TestCase):
parent = tree_store.append(parent, (i,
label,
testobj,
+ testobj,
test_pyobj,
test_pydict,
test_pylist,
@@ -756,31 +756,33 @@ class TestGtk(unittest.TestCase):
s = tree_store.get_value(treeiter, 1)
obj = tree_store.get_value(treeiter, 2)
obj.check(i, s)
+ obj2 = tree_store.get_value(treeiter, 3)
+ self.assertEquals(obj, obj2);
- pyobj = tree_store.get_value(treeiter, 3)
+ pyobj = tree_store.get_value(treeiter, 4)
self.assertEquals(pyobj, test_pyobj)
- pydict = tree_store.get_value(treeiter, 4)
+ pydict = tree_store.get_value(treeiter, 5)
self.assertEquals(pydict, test_pydict)
- pylist = tree_store.get_value(treeiter, 5)
+ pylist = tree_store.get_value(treeiter, 6)
self.assertEquals(pylist, test_pylist)
- bool_1 = tree_store.get_value(treeiter, 6)
- bool_2 = tree_store.get_value(treeiter, 7)
+ bool_1 = tree_store.get_value(treeiter, 7)
+ bool_2 = tree_store.get_value(treeiter, 8)
self.assertEquals(bool_1, bool_2)
self.assertTrue(isinstance(bool_1, bool))
self.assertTrue(isinstance(bool_2, bool))
- uint_ = tree_store.get_value(treeiter, 8)
+ uint_ = tree_store.get_value(treeiter, 9)
self.assertEquals(uint_, i)
- ulong_ = tree_store.get_value(treeiter, 9)
+ ulong_ = tree_store.get_value(treeiter, 10)
self.assertEquals(ulong_, GObject.G_MAXULONG)
- int64_ = tree_store.get_value(treeiter, 10)
+ int64_ = tree_store.get_value(treeiter, 11)
self.assertEquals(int64_, GObject.G_MININT64)
- uint64_ = tree_store.get_value(treeiter, 11)
+ uint64_ = tree_store.get_value(treeiter, 12)
self.assertEquals(uint64_, 0xffffffffffffffff)
- uchar_ = tree_store.get_value(treeiter, 12)
+ uchar_ = tree_store.get_value(treeiter, 13)
self.assertEquals(ord(uchar_), 254)
- char_ = tree_store.get_value(treeiter, 13)
+ char_ = tree_store.get_value(treeiter, 14)
self.assertEquals(char_, 'a')
parent = treeiter
@@ -797,7 +799,7 @@ class TestGtk(unittest.TestCase):
test_pylist = [1,"2", "3"]
list_store = Gtk.ListStore(int, str, 'GIOverrideTreeAPITest', object, object, object, bool, bool)
- for i in range(93):
+ for i in range(1, 93):
label = 'this is row #%d' % i
testobj = TestGtk.TestClass(self, i, label)
parent = list_store.append((i,
@@ -821,6 +823,17 @@ class TestGtk(unittest.TestCase):
list_store.set_value(treeiter, 6, 1)
list_store.set_value(treeiter, 7, True)
+ # test prepend
+ label = 'this is row #0'
+ list_store.prepend((0,
+ label,
+ TestGtk.TestClass(self, 0, label),
+ test_pyobj,
+ test_pydict,
+ test_pylist,
+ 0,
+ False))
+
# test automatic unicode->str conversion
i = 94
label = _unicode('this is row #94')