summaryrefslogtreecommitdiff
path: root/gi
diff options
context:
space:
mode:
authorDongHun Kwak <dh0128.kwak@samsung.com>2017-07-12 08:42:37 +0900
committerDongHun Kwak <dh0128.kwak@samsung.com>2017-07-12 08:42:41 +0900
commit87757999f26315ef84be29236bef8a1ba4e4af76 (patch)
tree716215f025890e99a84fe46b5431ee0399313ee5 /gi
parentc20b00fa62305380031ec383e1d7f7c548cdfe44 (diff)
downloadpygobject2-87757999f26315ef84be29236bef8a1ba4e4af76.tar.gz
pygobject2-87757999f26315ef84be29236bef8a1ba4e4af76.tar.bz2
pygobject2-87757999f26315ef84be29236bef8a1ba4e4af76.zip
Imported Upstream version 3.13.92
Change-Id: Ic195bab5260fd866ffc9d377f9efdcba5bffe014 Signed-off-by: DongHun Kwak <dh0128.kwak@samsung.com>
Diffstat (limited to 'gi')
-rw-r--r--gi/pygi-argument.c11
-rw-r--r--gi/pygi-array.c1
-rw-r--r--gi/pygi-boxed.c20
-rw-r--r--gi/pygi-boxed.h2
-rw-r--r--gi/pygi-marshal-cleanup.c13
-rw-r--r--gi/pygi-signal-closure.c43
-rw-r--r--gi/pygi-struct-marshal.c7
7 files changed, 81 insertions, 16 deletions
diff --git a/gi/pygi-argument.c b/gi/pygi-argument.c
index 3d643fe..d63520d 100644
--- a/gi/pygi-argument.c
+++ b/gi/pygi-argument.c
@@ -1036,6 +1036,8 @@ array_success:
{
GType g_type;
PyObject *py_type;
+ gboolean is_foreign = (info_type == GI_INFO_TYPE_STRUCT) &&
+ (g_struct_info_is_foreign ((GIStructInfo *) info));
g_type = g_registered_type_info_get_g_type ( (GIRegisteredTypeInfo *) info);
py_type = _pygi_type_import_by_gi_info ( (GIBaseInfo *) info);
@@ -1055,7 +1057,7 @@ array_success:
py_type,
transfer,
FALSE, /*copy_reference*/
- g_struct_info_is_foreign (info),
+ is_foreign,
g_type_info_is_pointer (type_info));
Py_DECREF (py_type);
@@ -1382,6 +1384,8 @@ _pygi_argument_to_object (GIArgument *arg,
{
PyObject *py_type;
GType g_type = g_registered_type_info_get_g_type ( (GIRegisteredTypeInfo *) info);
+ gboolean is_foreign = (info_type == GI_INFO_TYPE_STRUCT) &&
+ (g_struct_info_is_foreign ((GIStructInfo *) info));
/* Special case variant and none to force loading from py module. */
if (g_type == G_TYPE_VARIANT || g_type == G_TYPE_NONE) {
@@ -1396,7 +1400,7 @@ _pygi_argument_to_object (GIArgument *arg,
py_type,
transfer,
FALSE, /*is_allocated*/
- g_struct_info_is_foreign (info));
+ is_foreign);
Py_XDECREF (py_type);
break;
@@ -1703,7 +1707,8 @@ _pygi_argument_release (GIArgument *arg,
if (direction == GI_DIRECTION_IN && transfer == GI_TRANSFER_NOTHING) {
g_closure_unref (arg->v_pointer);
}
- } else if (g_struct_info_is_foreign ( (GIStructInfo*) info)) {
+ } else if (info_type == GI_INFO_TYPE_STRUCT &&
+ g_struct_info_is_foreign ((GIStructInfo*) info)) {
if (direction == GI_DIRECTION_OUT && transfer == GI_TRANSFER_EVERYTHING) {
pygi_struct_foreign_release (info, arg->v_pointer);
}
diff --git a/gi/pygi-array.c b/gi/pygi-array.c
index 4cfbd17..e2598cd 100644
--- a/gi/pygi-array.c
+++ b/gi/pygi-array.c
@@ -803,6 +803,7 @@ pygi_arg_garray_len_arg_setup (PyGIArgCache *arg_cache,
child_cache->direction = direction;
child_cache->to_py_marshaller = _pygi_marshal_to_py_basic_type_cache_adapter;
child_cache->from_py_marshaller = _pygi_marshal_from_py_basic_type_cache_adapter;
+ child_cache->py_arg_index = -1;
/* ugly edge case code:
*
diff --git a/gi/pygi-boxed.c b/gi/pygi-boxed.c
index a1494b6..d5faeb1 100644
--- a/gi/pygi-boxed.c
+++ b/gi/pygi-boxed.c
@@ -206,6 +206,26 @@ _pygi_boxed_get_free_on_dealloc(PyGIBoxed *self, void *closure)
return PyBool_FromLong( ((PyGBoxed *)self)->free_on_dealloc );
}
+/**
+ * _pygi_boxed_copy_in_place:
+ *
+ * Replace the boxed pointer held by this wrapper with a boxed copy
+ * freeing the previously held pointer (when free_on_dealloc is TRUE).
+ * This can be used in cases where Python is passed a reference which
+ * it does not own and the wrapper is held by the Python program
+ * longer than the duration of a callback it was passed to.
+ */
+void
+_pygi_boxed_copy_in_place (PyGIBoxed *self)
+{
+ PyGBoxed *pygboxed = (PyGBoxed *)self;
+ gpointer copy = g_boxed_copy (pygboxed->gtype, pyg_boxed_get_ptr (self));
+
+ boxed_del (self);
+ pyg_boxed_set_ptr (pygboxed, copy);
+ pygboxed->free_on_dealloc = TRUE;
+}
+
static PyGetSetDef pygi_boxed_getsets[] = {
{ "_free_on_dealloc", (getter)_pygi_boxed_get_free_on_dealloc, (setter)0 },
{ NULL, 0, 0 }
diff --git a/gi/pygi-boxed.h b/gi/pygi-boxed.h
index 189a02c..c8f40b7 100644
--- a/gi/pygi-boxed.h
+++ b/gi/pygi-boxed.h
@@ -34,6 +34,8 @@ PyObject * _pygi_boxed_new (PyTypeObject *pytype,
void * _pygi_boxed_alloc (GIBaseInfo *info,
gsize *size);
+void _pygi_boxed_copy_in_place (PyGIBoxed *self);
+
void _pygi_boxed_register_types (PyObject *m);
G_END_DECLS
diff --git a/gi/pygi-marshal-cleanup.c b/gi/pygi-marshal-cleanup.c
index 4ba6159..b0ec05a 100644
--- a/gi/pygi-marshal-cleanup.c
+++ b/gi/pygi-marshal-cleanup.c
@@ -95,8 +95,6 @@ pygi_marshal_cleanup_args_from_py_marshal_success (PyGIInvokeState *state,
for (i = 0; i < _pygi_callable_cache_args_len (cache); i++) {
PyGIArgCache *arg_cache = _pygi_callable_cache_get_arg (cache, i);
PyGIMarshalCleanupFunc cleanup_func = arg_cache->from_py_cleanup;
- PyObject *py_arg = PyTuple_GET_ITEM (state->py_in_args,
- arg_cache->py_arg_index);
gpointer cleanup_data = state->args_cleanup_data[i];
/* Only cleanup using args_cleanup_data when available.
@@ -105,8 +103,9 @@ pygi_marshal_cleanup_args_from_py_marshal_success (PyGIInvokeState *state,
* PyGIInvokeState.args_cleanup_data stores this data (via _invoke_marshal_in_args)
* for the duration of the invoke up until this point.
*/
- if (cleanup_func && cleanup_data != NULL &&
+ if (cleanup_func && cleanup_data != NULL && arg_cache->py_arg_index >= 0 &&
arg_cache->direction & PYGI_DIRECTION_FROM_PYTHON) {
+ PyObject *py_arg = PyTuple_GET_ITEM (state->py_in_args, arg_cache->py_arg_index);
cleanup_func (state, arg_cache, py_arg, cleanup_data, TRUE);
state->args_cleanup_data[i] = NULL;
}
@@ -167,8 +166,12 @@ pygi_marshal_cleanup_args_from_py_parameter_fail (PyGIInvokeState *state,
PyGIArgCache *arg_cache = _pygi_callable_cache_get_arg (cache, i);
PyGIMarshalCleanupFunc cleanup_func = arg_cache->from_py_cleanup;
gpointer cleanup_data = state->args_cleanup_data[i];
- PyObject *py_arg = PyTuple_GET_ITEM (state->py_in_args,
- arg_cache->py_arg_index);
+ PyObject *py_arg = NULL;
+
+ if (arg_cache->py_arg_index < 0) {
+ continue;
+ }
+ py_arg = PyTuple_GET_ITEM (state->py_in_args, arg_cache->py_arg_index);
if (cleanup_func && cleanup_data != NULL &&
arg_cache->direction == PYGI_DIRECTION_FROM_PYTHON) {
diff --git a/gi/pygi-signal-closure.c b/gi/pygi-signal-closure.c
index 3cf8486..652ac99 100644
--- a/gi/pygi-signal-closure.c
+++ b/gi/pygi-signal-closure.c
@@ -79,6 +79,8 @@ pygi_signal_closure_marshal(GClosure *closure,
GISignalInfo *signal_info;
gint n_sig_info_args;
gint sig_info_highest_arg;
+ GSList *list_item = NULL;
+ GSList *pass_by_ref_structs = NULL;
state = PyGILState_Ensure();
@@ -131,20 +133,28 @@ pygi_signal_closure_marshal(GClosure *closure,
&free_array);
}
- /* Hack to ensure struct output args are passed-by-reference allowing
+ /* Hack to ensure struct arguments are passed-by-reference allowing
* callback implementors to modify the struct values. This is needed
* for keeping backwards compatibility and should be removed in future
* versions which support signal output arguments as return values.
* See: https://bugzilla.gnome.org/show_bug.cgi?id=735486
+ *
+ * Note the logic here must match the logic path taken in _pygi_argument_to_object.
*/
- if (type_tag == GI_TYPE_TAG_INTERFACE &&
- g_arg_info_get_direction (&arg_info) == GI_DIRECTION_OUT) {
+ if (type_tag == GI_TYPE_TAG_INTERFACE) {
GIBaseInfo *info = g_type_info_get_interface (&type_info);
GIInfoType info_type = g_base_info_get_type (info);
- if (info_type == GI_INFO_TYPE_STRUCT) {
+ if (info_type == GI_INFO_TYPE_STRUCT ||
+ info_type == GI_INFO_TYPE_BOXED ||
+ info_type == GI_INFO_TYPE_UNION) {
+
GType gtype = g_registered_type_info_get_g_type ((GIRegisteredTypeInfo *) info);
- if (g_type_is_a (gtype, G_TYPE_BOXED)) {
+ gboolean is_foreign = (info_type == GI_INFO_TYPE_STRUCT) &&
+ (g_struct_info_is_foreign ((GIStructInfo *) info));
+
+ if (!is_foreign && !g_type_is_a (gtype, G_TYPE_VALUE) &&
+ g_type_is_a (gtype, G_TYPE_BOXED)) {
pass_struct_by_ref = TRUE;
}
}
@@ -153,8 +163,12 @@ pygi_signal_closure_marshal(GClosure *closure,
}
if (pass_struct_by_ref) {
+ /* transfer everything will ensure the struct is not copied when wrapped. */
item = _pygi_argument_to_object (&arg, &type_info, GI_TRANSFER_EVERYTHING);
- ((PyGBoxed *)item)->free_on_dealloc = FALSE;
+ if (item && PyObject_IsInstance (item, (PyObject *) &PyGIBoxed_Type)) {
+ ((PyGBoxed *)item)->free_on_dealloc = FALSE;
+ pass_by_ref_structs = g_slist_prepend (pass_by_ref_structs, item);
+ }
} else {
item = _pygi_argument_to_object (&arg, &type_info, GI_TRANSFER_NOTHING);
@@ -196,7 +210,24 @@ pygi_signal_closure_marshal(GClosure *closure,
}
Py_DECREF(ret);
+ /* Run through the list of structs which have been passed by reference and
+ * check if they are being held longer than the duration of the callback
+ * execution. This is determined if the ref count is greater than 1.
+ * A single ref is held by the argument list and any more would mean the callback
+ * stored a ref somewhere else. In this case we make an internal copy of
+ * the boxed struct so Python can own the memory to it.
+ */
+ list_item = pass_by_ref_structs;
+ while (list_item) {
+ PyObject *item = list_item->data;
+ if (item->ob_refcnt > 1) {
+ _pygi_boxed_copy_in_place ((PyGIBoxed *)item);
+ }
+ list_item = g_slist_next (list_item);
+ }
+
out:
+ g_slist_free (pass_by_ref_structs);
Py_DECREF(params);
PyGILState_Release(state);
}
diff --git a/gi/pygi-struct-marshal.c b/gi/pygi-struct-marshal.c
index 5068064..9bf3b54 100644
--- a/gi/pygi-struct-marshal.c
+++ b/gi/pygi-struct-marshal.c
@@ -528,7 +528,6 @@ arg_struct_from_py_setup (PyGIArgCache *arg_cache,
GITransfer transfer)
{
PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)arg_cache;
- iface_cache->is_foreign = g_struct_info_is_foreign ( (GIStructInfo*)iface_info);
if (g_struct_info_is_gtype_struct ((GIStructInfo*)iface_info)) {
arg_cache->from_py_marshaller = arg_type_class_from_py_marshal;
@@ -560,7 +559,6 @@ arg_struct_to_py_setup (PyGIArgCache *arg_cache,
GIArgInfo *arg_info)
{
PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)arg_cache;
- iface_cache->is_foreign = g_struct_info_is_foreign ( (GIStructInfo*)iface_info);
/* HACK to force GtkTreeModel:iter_next() and iter_previous() vfunc implementations
* to receive their Gtk.TreeIter argument as pass-by-reference. We create a new
@@ -615,6 +613,7 @@ pygi_arg_struct_new_from_info (GITypeInfo *type_info,
GIInterfaceInfo *iface_info)
{
PyGIArgCache *cache = NULL;
+ PyGIInterfaceCache *iface_cache;
cache = pygi_arg_interface_new_from_info (type_info,
arg_info,
@@ -624,6 +623,10 @@ pygi_arg_struct_new_from_info (GITypeInfo *type_info,
if (cache == NULL)
return NULL;
+ iface_cache = (PyGIInterfaceCache *)cache;
+ iface_cache->is_foreign = (g_base_info_get_type ((GIBaseInfo *) iface_info) == GI_INFO_TYPE_STRUCT) &&
+ (g_struct_info_is_foreign ((GIStructInfo*) iface_info));
+
if (direction & PYGI_DIRECTION_FROM_PYTHON) {
arg_struct_from_py_setup (cache, iface_info, transfer);
}