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 g_assert_cmpint (n_sig_info_args
, >=, 0);
92 /* the first argument to a signal callback is instance,
93 but instance is not counted in the introspection data */
94 sig_info_highest_arg
= n_sig_info_args
+ 1;
95 g_assert_cmpint(sig_info_highest_arg
, ==, n_param_values
);
97 /* construct Python tuple for the parameter values */
98 params
= PyTuple_New(n_param_values
);
99 for (i
= 0; i
< n_param_values
; i
++) {
100 /* swap in a different initial data for connect_object() */
101 if (i
== 0 && G_CCLOSURE_SWAP_DATA(closure
)) {
102 g_return_if_fail(pc
->swap_data
!= NULL
);
103 Py_INCREF(pc
->swap_data
);
104 PyTuple_SetItem(params
, 0, pc
->swap_data
);
107 PyObject
*item
= pyg_value_as_pyobject(¶m_values
[i
], FALSE
);
112 PyTuple_SetItem(params
, i
, item
);
114 } else if (i
< (guint
)sig_info_highest_arg
) {
116 GITypeInfo type_info
;
118 GIArgument arg
= { 0, };
119 PyObject
*item
= NULL
;
120 gboolean free_array
= FALSE
;
121 gboolean pass_struct_by_ref
= FALSE
;
123 g_callable_info_load_arg(signal_info
, i
- 1, &arg_info
);
124 g_arg_info_load_type(&arg_info
, &type_info
);
126 arg
= _pygi_argument_from_g_value(¶m_values
[i
], &type_info
);
128 type_tag
= g_type_info_get_tag (&type_info
);
129 if (type_tag
== GI_TYPE_TAG_ARRAY
) {
130 /* Skip the self argument of param_values */
131 arg
.v_pointer
= _pygi_argument_to_array (&arg
,
132 _pygi_argument_array_length_marshal
,
133 (void *)(param_values
+ 1),
139 /* Hack to ensure struct arguments are passed-by-reference allowing
140 * callback implementors to modify the struct values. This is needed
141 * for keeping backwards compatibility and should be removed in future
142 * versions which support signal output arguments as return values.
143 * See: https://bugzilla.gnome.org/show_bug.cgi?id=735486
145 * Note the logic here must match the logic path taken in _pygi_argument_to_object.
147 if (type_tag
== GI_TYPE_TAG_INTERFACE
) {
148 GIBaseInfo
*info
= g_type_info_get_interface (&type_info
);
149 GIInfoType info_type
= g_base_info_get_type (info
);
151 if (info_type
== GI_INFO_TYPE_STRUCT
||
152 info_type
== GI_INFO_TYPE_BOXED
||
153 info_type
== GI_INFO_TYPE_UNION
) {
155 GType gtype
= g_registered_type_info_get_g_type ((GIRegisteredTypeInfo
*) info
);
156 gboolean is_foreign
= (info_type
== GI_INFO_TYPE_STRUCT
) &&
157 (g_struct_info_is_foreign ((GIStructInfo
*) info
));
159 if (!is_foreign
&& !g_type_is_a (gtype
, G_TYPE_VALUE
) &&
160 g_type_is_a (gtype
, G_TYPE_BOXED
)) {
161 pass_struct_by_ref
= TRUE
;
165 g_base_info_unref (info
);
168 if (pass_struct_by_ref
) {
169 /* transfer everything will ensure the struct is not copied when wrapped. */
170 item
= _pygi_argument_to_object (&arg
, &type_info
, GI_TRANSFER_EVERYTHING
);
171 if (item
&& PyObject_IsInstance (item
, (PyObject
*) &PyGIBoxed_Type
)) {
172 ((PyGBoxed
*)item
)->free_on_dealloc
= FALSE
;
173 pass_by_ref_structs
= g_slist_prepend (pass_by_ref_structs
, item
);
177 item
= _pygi_argument_to_object (&arg
, &type_info
, GI_TRANSFER_NOTHING
);
181 g_array_free (arg
.v_pointer
, FALSE
);
188 PyTuple_SetItem(params
, i
, item
);
191 /* params passed to function may have extra arguments */
192 if (pc
->extra_args
) {
193 PyObject
*tuple
= params
;
194 params
= PySequence_Concat(tuple
, pc
->extra_args
);
197 ret
= PyObject_CallObject(pc
->callback
, params
);
199 if (pc
->exception_handler
)
200 pc
->exception_handler(return_value
, n_param_values
, param_values
);
206 if (G_IS_VALUE(return_value
) && pyg_value_from_pyobject(return_value
, ret
) != 0) {
207 PyErr_SetString(PyExc_TypeError
,
208 "can't convert return value to desired type");
210 if (pc
->exception_handler
)
211 pc
->exception_handler(return_value
, n_param_values
, param_values
);
217 /* Run through the list of structs which have been passed by reference and
218 * check if they are being held longer than the duration of the callback
219 * execution. This is determined if the ref count is greater than 1.
220 * A single ref is held by the argument list and any more would mean the callback
221 * stored a ref somewhere else. In this case we make an internal copy of
222 * the boxed struct so Python can own the memory to it.
224 list_item
= pass_by_ref_structs
;
226 PyObject
*item
= list_item
->data
;
227 if (Py_REFCNT (item
) > 1) {
228 pygi_boxed_copy_in_place ((PyGIBoxed
*)item
);
230 list_item
= g_slist_next (list_item
);
234 g_slist_free (pass_by_ref_structs
);
236 PyGILState_Release(state
);
240 pygi_signal_closure_new (PyGObject
*instance
,
242 const gchar
*signal_name
,
244 PyObject
*extra_args
,
247 GClosure
*closure
= NULL
;
248 PyGISignalClosure
*pygi_closure
= NULL
;
249 GISignalInfo
*signal_info
= NULL
;
251 g_return_val_if_fail(callback
!= NULL
, NULL
);
253 signal_info
= _pygi_lookup_signal_from_g_type (g_type
, signal_name
);
254 if (signal_info
== NULL
)
257 closure
= g_closure_new_simple(sizeof(PyGISignalClosure
), NULL
);
258 g_closure_add_invalidate_notifier(closure
, NULL
, pygi_signal_closure_invalidate
);
259 g_closure_set_marshal(closure
, pygi_signal_closure_marshal
);
261 pygi_closure
= (PyGISignalClosure
*)closure
;
263 pygi_closure
->signal_info
= signal_info
;
265 pygi_closure
->pyg_closure
.callback
= callback
;
267 if (extra_args
!= NULL
&& extra_args
!= Py_None
) {
268 Py_INCREF(extra_args
);
269 if (!PyTuple_Check(extra_args
)) {
270 PyObject
*tmp
= PyTuple_New(1);
271 PyTuple_SetItem(tmp
, 0, extra_args
);
274 pygi_closure
->pyg_closure
.extra_args
= extra_args
;
277 Py_INCREF(swap_data
);
278 pygi_closure
->pyg_closure
.swap_data
= swap_data
;
279 closure
->derivative_flag
= TRUE
;