1 /* -*- Mode: C; c-basic-offset: 4 -*-
2 * vim: tabstop=4 shiftwidth=4 expandtab
4 * pygi-callbacks.c: PyGI C Callback Functions and Helpers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
22 #include "pygi-private.h"
24 static PyGICClosure *global_destroy_notify;
27 _pygi_destroy_notify_callback_closure (ffi_cif *cif,
32 PyGICClosure *info = * (void**) (args[0]);
36 _pygi_invoke_closure_free (info);
41 _pygi_destroy_notify_create (void)
43 if (!global_destroy_notify) {
45 PyGICClosure *destroy_notify = g_slice_new0 (PyGICClosure);
47 g_assert (destroy_notify);
49 GIBaseInfo* glib_destroy_notify = g_irepository_find_by_name (NULL, "GLib", "DestroyNotify");
50 g_assert (glib_destroy_notify != NULL);
51 g_assert (g_base_info_get_type (glib_destroy_notify) == GI_INFO_TYPE_CALLBACK);
53 destroy_notify->closure = g_callable_info_prepare_closure ( (GICallableInfo*) glib_destroy_notify,
55 _pygi_destroy_notify_callback_closure,
58 global_destroy_notify = destroy_notify;
61 return global_destroy_notify;
66 _pygi_scan_for_callbacks (GIFunctionInfo *function_info,
68 guint8 *callback_index,
69 guint8 *user_data_index,
70 guint8 *destroy_notify_index)
74 *callback_index = G_MAXUINT8;
75 *user_data_index = G_MAXUINT8;
76 *destroy_notify_index = G_MAXUINT8;
78 n_args = g_callable_info_get_n_args ( (GICallableInfo *) function_info);
79 for (i = 0; i < n_args; i++) {
80 GIDirection direction;
82 GITypeInfo *type_info;
83 guint8 destroy, closure;
86 arg_info = g_callable_info_get_arg ( (GICallableInfo*) function_info, i);
87 type_info = g_arg_info_get_type (arg_info);
88 type_tag = g_type_info_get_tag (type_info);
90 if (type_tag == GI_TYPE_TAG_INTERFACE) {
91 GIBaseInfo* interface_info;
92 GIInfoType interface_type;
94 interface_info = g_type_info_get_interface (type_info);
95 interface_type = g_base_info_get_type (interface_info);
96 if (interface_type == GI_INFO_TYPE_CALLBACK &&
97 ! (strcmp (g_base_info_get_namespace ( (GIBaseInfo*) interface_info), "GLib") == 0 &&
98 (strcmp (g_base_info_get_name ( (GIBaseInfo*) interface_info), "DestroyNotify") == 0 ||
99 (strcmp (g_base_info_get_name ( (GIBaseInfo*) interface_info), "FreeFunc") == 0)))) {
100 if (*callback_index != G_MAXUINT8) {
101 PyErr_Format (PyExc_TypeError, "Function %s.%s has multiple callbacks, not supported",
102 g_base_info_get_namespace ( (GIBaseInfo*) function_info),
103 g_base_info_get_name ( (GIBaseInfo*) function_info));
104 g_base_info_unref (interface_info);
109 g_base_info_unref (interface_info);
111 destroy = g_arg_info_get_destroy (arg_info);
113 closure = g_arg_info_get_closure (arg_info);
114 direction = g_arg_info_get_direction (arg_info);
116 if (destroy > 0 && destroy < n_args) {
117 if (*destroy_notify_index != G_MAXUINT8) {
118 PyErr_Format (PyExc_TypeError, "Function %s has multiple GDestroyNotify, not supported",
119 g_base_info_get_name ( (GIBaseInfo*) function_info));
122 *destroy_notify_index = destroy;
125 if (closure > 0 && closure < n_args) {
126 if (*user_data_index != G_MAXUINT8) {
127 PyErr_Format (PyExc_TypeError, "Function %s has multiple user_data arguments, not supported",
128 g_base_info_get_name ( (GIBaseInfo*) function_info));
131 *user_data_index = closure;
134 g_base_info_unref ( (GIBaseInfo*) arg_info);
135 g_base_info_unref ( (GIBaseInfo*) type_info);
142 _pygi_create_callback (GIBaseInfo *function_info,
144 gboolean is_constructor,
148 guint8 callback_index,
149 guint8 user_data_index,
150 guint8 destroy_notify_index,
151 PyGICClosure **closure_out)
153 GIArgInfo *callback_arg;
154 GITypeInfo *callback_type;
155 GICallbackInfo *callback_info;
157 gboolean found_py_function;
158 PyObject *py_function;
159 guint8 i, py_argv_pos;
160 PyObject *py_user_data;
163 callback_arg = g_callable_info_get_arg ( (GICallableInfo*) function_info, callback_index);
164 scope = g_arg_info_get_scope (callback_arg);
165 allow_none = g_arg_info_may_be_null (callback_arg);
167 callback_type = g_arg_info_get_type (callback_arg);
168 g_assert (g_type_info_get_tag (callback_type) == GI_TYPE_TAG_INTERFACE);
170 callback_info = (GICallbackInfo*) g_type_info_get_interface (callback_type);
171 g_assert (g_base_info_get_type ( (GIBaseInfo*) callback_info) == GI_INFO_TYPE_CALLBACK);
173 /* Find the Python function passed for the callback */
174 found_py_function = FALSE;
175 py_function = Py_None;
178 /* if its a method then we need to skip over 'self' */
179 if (is_method || is_constructor)
184 for (i = 0; i < n_args && i < py_argc; i++) {
185 if (i == callback_index) {
186 py_function = PyTuple_GetItem (py_argv, py_argv_pos);
187 /* if we allow none then set the closure to NULL and return */
188 if (allow_none && py_function == Py_None) {
192 found_py_function = TRUE;
193 } else if (i == user_data_index) {
194 py_user_data = PyTuple_GetItem (py_argv, py_argv_pos);
199 if (!found_py_function
200 || (py_function == Py_None || !PyCallable_Check (py_function))) {
201 PyErr_Format (PyExc_TypeError, "Error invoking %s.%s: Unexpected value "
203 g_base_info_get_namespace ( (GIBaseInfo*) function_info),
204 g_base_info_get_name ( (GIBaseInfo*) function_info),
205 g_base_info_get_name ( (GIBaseInfo*) callback_arg));
206 g_base_info_unref ( (GIBaseInfo*) callback_info);
207 g_base_info_unref ( (GIBaseInfo*) callback_type);
211 /** Now actually build the closure **/
212 *closure_out = _pygi_make_native_closure ( (GICallableInfo *) callback_info,
213 g_arg_info_get_scope (callback_arg),
217 g_base_info_unref ( (GIBaseInfo*) callback_info);
218 g_base_info_unref ( (GIBaseInfo*) callback_type);