1 /* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
3 * Copyright (c) 2011 Laszlo Pandy <lpandy@src.gnome.org>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
19 #include "pygi-signal-closure.h"
20 #include "pygi-value.h"
21 #include "pygi-argument.h"
22 #include "pygi-boxed.h"
25 _pygi_lookup_signal_from_g_type (GType g_type,
26 const gchar *signal_name)
28 GIRepository *repository;
30 GISignalInfo *signal_info = NULL;
32 repository = g_irepository_get_default();
33 info = g_irepository_find_by_gtype (repository, g_type);
37 if (GI_IS_OBJECT_INFO (info))
38 signal_info = g_object_info_find_signal ((GIObjectInfo *) info,
40 else if (GI_IS_INTERFACE_INFO (info))
41 signal_info = g_interface_info_find_signal ((GIInterfaceInfo *) info,
44 g_base_info_unref (info);
49 pygi_signal_closure_invalidate(gpointer data,
52 PyGClosure *pc = (PyGClosure *)closure;
53 PyGILState_STATE state;
55 state = PyGILState_Ensure();
56 Py_XDECREF(pc->callback);
57 Py_XDECREF(pc->extra_args);
58 Py_XDECREF(pc->swap_data);
59 PyGILState_Release(state);
62 pc->extra_args = NULL;
65 g_base_info_unref (((PyGISignalClosure *) pc)->signal_info);
66 ((PyGISignalClosure *) pc)->signal_info = NULL;
70 pygi_signal_closure_marshal(GClosure *closure,
73 const GValue *param_values,
74 gpointer invocation_hint,
75 gpointer marshal_data)
77 PyGILState_STATE state;
78 PyGClosure *pc = (PyGClosure *)closure;
79 PyObject *params, *ret = NULL;
81 GISignalInfo *signal_info;
83 gint sig_info_highest_arg;
84 GSList *list_item = NULL;
85 GSList *pass_by_ref_structs = NULL;
87 state = PyGILState_Ensure();
89 signal_info = ((PyGISignalClosure *)closure)->signal_info;
90 n_sig_info_args = g_callable_info_get_n_args(signal_info);
91 /* the first argument to a signal callback is instance,
92 but instance is not counted in the introspection data */
93 sig_info_highest_arg = n_sig_info_args + 1;
94 g_assert_cmpint(sig_info_highest_arg, ==, n_param_values);
96 /* construct Python tuple for the parameter values */
97 params = PyTuple_New(n_param_values);
98 for (i = 0; i < n_param_values; i++) {
99 /* swap in a different initial data for connect_object() */
100 if (i == 0 && G_CCLOSURE_SWAP_DATA(closure)) {
101 g_return_if_fail(pc->swap_data != NULL);
102 Py_INCREF(pc->swap_data);
103 PyTuple_SetItem(params, 0, pc->swap_data);
106 PyObject *item = pyg_value_as_pyobject(¶m_values[i], FALSE);
111 PyTuple_SetItem(params, i, item);
113 } else if (i < sig_info_highest_arg) {
115 GITypeInfo type_info;
117 GIArgument arg = { 0, };
118 PyObject *item = NULL;
119 gboolean free_array = FALSE;
120 gboolean pass_struct_by_ref = FALSE;
122 g_callable_info_load_arg(signal_info, i - 1, &arg_info);
123 g_arg_info_load_type(&arg_info, &type_info);
125 arg = _pygi_argument_from_g_value(¶m_values[i], &type_info);
127 type_tag = g_type_info_get_tag (&type_info);
128 if (type_tag == GI_TYPE_TAG_ARRAY) {
129 /* Skip the self argument of param_values */
130 arg.v_pointer = _pygi_argument_to_array (&arg,
131 _pygi_argument_array_length_marshal,
132 (void *)(param_values + 1),
138 /* Hack to ensure struct arguments are passed-by-reference allowing
139 * callback implementors to modify the struct values. This is needed
140 * for keeping backwards compatibility and should be removed in future
141 * versions which support signal output arguments as return values.
142 * See: https://bugzilla.gnome.org/show_bug.cgi?id=735486
144 * Note the logic here must match the logic path taken in _pygi_argument_to_object.
146 if (type_tag == GI_TYPE_TAG_INTERFACE) {
147 GIBaseInfo *info = g_type_info_get_interface (&type_info);
148 GIInfoType info_type = g_base_info_get_type (info);
150 if (info_type == GI_INFO_TYPE_STRUCT ||
151 info_type == GI_INFO_TYPE_BOXED ||
152 info_type == GI_INFO_TYPE_UNION) {
154 GType gtype = g_registered_type_info_get_g_type ((GIRegisteredTypeInfo *) info);
155 gboolean is_foreign = (info_type == GI_INFO_TYPE_STRUCT) &&
156 (g_struct_info_is_foreign ((GIStructInfo *) info));
158 if (!is_foreign && !g_type_is_a (gtype, G_TYPE_VALUE) &&
159 g_type_is_a (gtype, G_TYPE_BOXED)) {
160 pass_struct_by_ref = TRUE;
164 g_base_info_unref (info);
167 if (pass_struct_by_ref) {
168 /* transfer everything will ensure the struct is not copied when wrapped. */
169 item = _pygi_argument_to_object (&arg, &type_info, GI_TRANSFER_EVERYTHING);
170 if (item && PyObject_IsInstance (item, (PyObject *) &PyGIBoxed_Type)) {
171 ((PyGBoxed *)item)->free_on_dealloc = FALSE;
172 pass_by_ref_structs = g_slist_prepend (pass_by_ref_structs, item);
176 item = _pygi_argument_to_object (&arg, &type_info, GI_TRANSFER_NOTHING);
180 g_array_free (arg.v_pointer, FALSE);
187 PyTuple_SetItem(params, i, item);
190 /* params passed to function may have extra arguments */
191 if (pc->extra_args) {
192 PyObject *tuple = params;
193 params = PySequence_Concat(tuple, pc->extra_args);
196 ret = PyObject_CallObject(pc->callback, params);
198 if (pc->exception_handler)
199 pc->exception_handler(return_value, n_param_values, param_values);
205 if (G_IS_VALUE(return_value) && pyg_value_from_pyobject(return_value, ret) != 0) {
206 PyErr_SetString(PyExc_TypeError,
207 "can't convert return value to desired type");
209 if (pc->exception_handler)
210 pc->exception_handler(return_value, n_param_values, param_values);
216 /* Run through the list of structs which have been passed by reference and
217 * check if they are being held longer than the duration of the callback
218 * execution. This is determined if the ref count is greater than 1.
219 * A single ref is held by the argument list and any more would mean the callback
220 * stored a ref somewhere else. In this case we make an internal copy of
221 * the boxed struct so Python can own the memory to it.
223 list_item = pass_by_ref_structs;
225 PyObject *item = list_item->data;
226 if (item->ob_refcnt > 1) {
227 _pygi_boxed_copy_in_place ((PyGIBoxed *)item);
229 list_item = g_slist_next (list_item);
233 g_slist_free (pass_by_ref_structs);
235 PyGILState_Release(state);
239 pygi_signal_closure_new (PyGObject *instance,
241 const gchar *signal_name,
243 PyObject *extra_args,
246 GClosure *closure = NULL;
247 PyGISignalClosure *pygi_closure = NULL;
248 GISignalInfo *signal_info = NULL;
250 g_return_val_if_fail(callback != NULL, NULL);
252 signal_info = _pygi_lookup_signal_from_g_type (g_type, signal_name);
253 if (signal_info == NULL)
256 closure = g_closure_new_simple(sizeof(PyGISignalClosure), NULL);
257 g_closure_add_invalidate_notifier(closure, NULL, pygi_signal_closure_invalidate);
258 g_closure_set_marshal(closure, pygi_signal_closure_marshal);
260 pygi_closure = (PyGISignalClosure *)closure;
262 pygi_closure->signal_info = signal_info;
264 pygi_closure->pyg_closure.callback = callback;
266 if (extra_args != NULL && extra_args != Py_None) {
267 Py_INCREF(extra_args);
268 if (!PyTuple_Check(extra_args)) {
269 PyObject *tmp = PyTuple_New(1);
270 PyTuple_SetItem(tmp, 0, extra_args);
273 pygi_closure->pyg_closure.extra_args = extra_args;
276 Py_INCREF(swap_data);
277 pygi_closure->pyg_closure.swap_data = swap_data;
278 closure->derivative_flag = TRUE;