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, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
21 #include "pygi-private.h"
23 /* Copied from glib */
25 canonicalize_key (gchar *key)
29 for (p = key; *p != 0; p++)
34 (c < '0' || c > '9') &&
35 (c < 'A' || c > 'Z') &&
42 _pygi_lookup_signal_from_g_type (GType g_type,
43 const gchar *signal_name)
45 GIRepository *repository;
51 repository = g_irepository_get_default();
52 info = g_irepository_find_by_gtype (repository, g_type);
54 n_infos = g_object_info_get_n_signals ( (GIObjectInfo *) info);
55 for (i = 0; i < n_infos; i++) {
56 GISignalInfo *signal_info;
58 signal_info = g_object_info_get_signal ( (GIObjectInfo *) info, i);
59 g_assert (info != NULL);
61 if (strcmp (signal_name, g_base_info_get_name (signal_info)) == 0) {
62 g_base_info_unref (info);
66 g_base_info_unref (signal_info);
69 g_base_info_unref (info);
72 parent = g_type_parent (g_type);
74 return _pygi_lookup_signal_from_g_type (parent, signal_name);
80 pygi_signal_closure_invalidate(gpointer data,
83 PyGClosure *pc = (PyGClosure *)closure;
84 PyGILState_STATE state;
86 state = PyGILState_Ensure();
87 Py_XDECREF(pc->callback);
88 Py_XDECREF(pc->extra_args);
89 Py_XDECREF(pc->swap_data);
90 PyGILState_Release(state);
93 pc->extra_args = NULL;
96 g_base_info_unref (((PyGISignalClosure *) pc)->signal_info);
97 ((PyGISignalClosure *) pc)->signal_info = NULL;
101 pygi_signal_closure_marshal(GClosure *closure,
102 GValue *return_value,
103 guint n_param_values,
104 const GValue *param_values,
105 gpointer invocation_hint,
106 gpointer marshal_data)
108 PyGILState_STATE state;
109 PyGClosure *pc = (PyGClosure *)closure;
110 PyObject *params, *ret = NULL;
112 GISignalInfo *signal_info;
113 gint n_sig_info_args;
114 gint sig_info_highest_arg;
116 state = PyGILState_Ensure();
118 signal_info = ((PyGISignalClosure *)closure)->signal_info;
119 n_sig_info_args = g_callable_info_get_n_args(signal_info);
120 /* the first argument to a signal callback is instance,
121 but instance is not counted in the introspection data */
122 sig_info_highest_arg = n_sig_info_args + 1;
123 g_assert_cmpint(sig_info_highest_arg, ==, n_param_values);
125 /* construct Python tuple for the parameter values */
126 params = PyTuple_New(n_param_values);
127 for (i = 0; i < n_param_values; i++) {
128 /* swap in a different initial data for connect_object() */
129 if (i == 0 && G_CCLOSURE_SWAP_DATA(closure)) {
130 g_return_if_fail(pc->swap_data != NULL);
131 Py_INCREF(pc->swap_data);
132 PyTuple_SetItem(params, 0, pc->swap_data);
135 PyObject *item = pyg_value_as_pyobject(¶m_values[i], FALSE);
140 PyTuple_SetItem(params, i, item);
142 } else if (i < sig_info_highest_arg) {
144 GITypeInfo type_info;
146 GIArgument arg = { 0, };
147 PyObject *item = NULL;
149 g_callable_info_load_arg(signal_info, i - 1, &arg_info);
150 g_arg_info_load_type(&arg_info, &type_info);
151 transfer = g_arg_info_get_ownership_transfer(&arg_info);
153 arg = _pygi_argument_from_g_value(¶m_values[i], &type_info);
154 item = _pygi_argument_to_object(&arg, &type_info, transfer);
159 PyTuple_SetItem(params, i, item);
162 /* params passed to function may have extra arguments */
163 if (pc->extra_args) {
164 PyObject *tuple = params;
165 params = PySequence_Concat(tuple, pc->extra_args);
168 ret = PyObject_CallObject(pc->callback, params);
170 if (pc->exception_handler)
171 pc->exception_handler(return_value, n_param_values, param_values);
177 if (return_value && pyg_value_from_pyobject(return_value, ret) != 0) {
178 PyErr_SetString(PyExc_TypeError,
179 "can't convert return value to desired type");
181 if (pc->exception_handler)
182 pc->exception_handler(return_value, n_param_values, param_values);
190 PyGILState_Release(state);
194 pygi_signal_closure_new_real (PyGObject *instance,
195 const gchar *sig_name,
197 PyObject *extra_args,
200 GClosure *closure = NULL;
201 PyGISignalClosure *pygi_closure = NULL;
203 GISignalInfo *signal_info = NULL;
204 char *signal_name = g_strdup (sig_name);
206 g_return_val_if_fail(callback != NULL, NULL);
208 canonicalize_key(signal_name);
210 g_type = pyg_type_from_object ((PyObject *)instance);
211 signal_info = _pygi_lookup_signal_from_g_type (g_type, signal_name);
213 if (signal_info == NULL)
216 closure = g_closure_new_simple(sizeof(PyGISignalClosure), NULL);
217 g_closure_add_invalidate_notifier(closure, NULL, pygi_signal_closure_invalidate);
218 g_closure_set_marshal(closure, pygi_signal_closure_marshal);
220 pygi_closure = (PyGISignalClosure *)closure;
222 pygi_closure->signal_info = signal_info;
224 pygi_closure->pyg_closure.callback = callback;
226 if (extra_args != NULL && extra_args != Py_None) {
227 Py_INCREF(extra_args);
228 if (!PyTuple_Check(extra_args)) {
229 PyObject *tmp = PyTuple_New(1);
230 PyTuple_SetItem(tmp, 0, extra_args);
233 pygi_closure->pyg_closure.extra_args = extra_args;
236 Py_INCREF(swap_data);
237 pygi_closure->pyg_closure.swap_data = swap_data;
238 closure->derivative_flag = TRUE;
242 g_free (signal_name);