diff options
author | Gustavo J. A. M. Carneiro <gjc@src.gnome.org> | 2006-01-11 16:09:18 +0000 |
---|---|---|
committer | Gustavo J. A. M. Carneiro <gjc@src.gnome.org> | 2006-01-11 16:09:18 +0000 |
commit | e370df75fb2cfdd780188af1e81416a5443cb6e9 (patch) | |
tree | 0e54a2fdc133bc24d05caa5782eb8021efd1d737 /gobject/gobjectmodule.c | |
parent | a4834ddbe8dfe5b0f131ba3c1331de0b05f67a0f (diff) | |
download | pygobject-e370df75fb2cfdd780188af1e81416a5443cb6e9.tar.gz pygobject-e370df75fb2cfdd780188af1e81416a5443cb6e9.tar.xz pygobject-e370df75fb2cfdd780188af1e81416a5443cb6e9.zip |
signal accumulators
Diffstat (limited to 'gobject/gobjectmodule.c')
-rw-r--r-- | gobject/gobjectmodule.c | 100 |
1 files changed, 97 insertions, 3 deletions
diff --git a/gobject/gobjectmodule.c b/gobject/gobjectmodule.c index 06572cd..77008ed 100644 --- a/gobject/gobjectmodule.c +++ b/gobject/gobjectmodule.c @@ -30,6 +30,7 @@ static PyObject *gerror_exc = NULL; static gboolean use_gil_state_api = FALSE; +static PyObject *_pyg_signal_accumulator_true_handled_func; GQuark pyginterface_type_key; GQuark pygobject_class_init_key; @@ -458,6 +459,61 @@ pyg_object_class_init(GObjectClass *class, PyObject *py_class) class->get_property = pyg_object_get_property; } +typedef struct _PyGSignalAccumulatorData { + PyObject *callable; + PyObject *user_data; +} PyGSignalAccumulatorData; + +static gboolean +_pyg_signal_accumulator(GSignalInvocationHint *ihint, + GValue *return_accu, + const GValue *handler_return, + gpointer _data) +{ + PyObject *py_ihint, *py_return_accu, *py_handler_return, *py_detail; + PyObject *py_retval; + gboolean retval = FALSE; + PyGSignalAccumulatorData *data = _data; + PyGILState_STATE state; + + state = pyg_gil_state_ensure(); + if (ihint->detail) + py_detail = PyString_FromString(g_quark_to_string(ihint->detail)); + else { + Py_INCREF(Py_None); + py_detail = Py_None; + } + + py_ihint = Py_BuildValue("lNi", (long int) ihint->signal_id, + py_detail, ihint->run_type); + py_handler_return = pyg_value_as_pyobject(handler_return, TRUE); + py_return_accu = pyg_value_as_pyobject(return_accu, FALSE); + if (data->user_data) + py_retval = PyObject_CallFunction(data->callable, "NNNO", py_ihint, + py_return_accu, py_handler_return, + data->user_data); + else + py_retval = PyObject_CallFunction(data->callable, "NNN", py_ihint, + py_return_accu, py_handler_return); + if (!py_retval) + PyErr_Print(); + else { + if (!PyTuple_Check(py_retval) || PyTuple_Size(py_retval) != 2) { + PyErr_SetString(PyExc_TypeError, "accumulator function must return" + " a (bool, object) tuple"); + PyErr_Print(); + } else { + retval = PyObject_IsTrue(PyTuple_GET_ITEM(py_retval, 0)); + if (pyg_value_from_pyobject(return_accu, PyTuple_GET_ITEM(py_retval, 1))) { + PyErr_Print(); + } + } + Py_DECREF(py_retval); + } + pyg_gil_state_release(state); + return retval; +} + static gboolean create_signal (GType instance_type, const gchar *signal_name, PyObject *tuple) { @@ -467,9 +523,13 @@ create_signal (GType instance_type, const gchar *signal_name, PyObject *tuple) guint n_params, i; GType *param_types; guint signal_id; + GSignalAccumulator accumulator = NULL; + PyGSignalAccumulatorData *accum_data = NULL; + PyObject *py_accum = NULL, *py_accum_data = NULL; - if (!PyArg_ParseTuple(tuple, "iOO", &signal_flags, &py_return_type, - &py_param_types)) { + if (!PyArg_ParseTuple(tuple, "iOO|OO", &signal_flags, &py_return_type, + &py_param_types, &py_accum, &py_accum_data)) + { gchar buf[128]; PyErr_Clear(); @@ -478,6 +538,15 @@ create_signal (GType instance_type, const gchar *signal_name, PyObject *tuple) return FALSE; } + if (py_accum && py_accum != Py_None && !PyCallable_Check(py_accum)) + { + gchar buf[128]; + + g_snprintf(buf, sizeof(buf), "accumulator for __gsignals__['%s'] must be callable", signal_name); + PyErr_SetString(PyExc_TypeError, buf); + return FALSE; + } + return_type = pyg_type_from_object(py_return_type); if (!return_type) return FALSE; @@ -502,9 +571,22 @@ create_signal (GType instance_type, const gchar *signal_name, PyObject *tuple) Py_DECREF(item); } + if (py_accum == _pyg_signal_accumulator_true_handled_func) + accumulator = g_signal_accumulator_true_handled; + else { + if (py_accum != NULL && py_accum != Py_None) { + accum_data = g_new(PyGSignalAccumulatorData, 1); + accum_data->callable = py_accum; + Py_INCREF(py_accum); + accum_data->user_data = py_accum_data; + Py_XINCREF(py_accum_data); + accumulator = _pyg_signal_accumulator; + } + } + signal_id = g_signal_newv(signal_name, instance_type, signal_flags, pyg_signal_class_closure_get(), - (GSignalAccumulator)0, NULL, + accumulator, accum_data, (GSignalCMarshaller)0, return_type, n_params, param_types); g_free(param_types); @@ -2231,6 +2313,14 @@ pyg_main_depth(PyObject *unused) return PyInt_FromLong(g_main_depth()); } +static PyObject * +pyg_signal_accumulator_true_handled(PyObject *unused, PyObject *args) +{ + PyErr_SetString(PyExc_TypeError, "signal_accumulator_true_handled can only" + " be used as accumulator argument when registering signals"); + return NULL; +} + static PyMethodDef pygobject_functions[] = { { "type_name", pyg_type_name, METH_VARARGS }, { "type_from_name", pyg_type_from_name, METH_VARARGS }, @@ -2258,6 +2348,7 @@ static PyMethodDef pygobject_functions[] = { { "markup_escape_text", (PyCFunction)pyg_markup_escape_text, METH_VARARGS|METH_KEYWORDS }, { "get_current_time", (PyCFunction)pyg_get_current_time, METH_NOARGS }, { "main_depth", (PyCFunction)pyg_main_depth, METH_NOARGS }, + { "signal_accumulator_true_handled", (PyCFunction)pyg_signal_accumulator_true_handled, METH_VARARGS }, { NULL, NULL, 0 } }; @@ -2929,4 +3020,7 @@ initgobject(void) g_log_set_handler("GThread", G_LOG_LEVEL_CRITICAL|G_LOG_LEVEL_WARNING, _log_func, warning); + /* signal registration recognizes this special accumulator 'constant' */ + _pyg_signal_accumulator_true_handled_func = \ + PyDict_GetItemString(d, "signal_accumulator_true_handled"); } |