diff options
-rw-r--r-- | gobject/pygobject.c | 99 | ||||
-rw-r--r-- | gobject/pygtype.c | 15 | ||||
-rw-r--r-- | tests/test_signal.py | 29 |
3 files changed, 143 insertions, 0 deletions
diff --git a/gobject/pygobject.c b/gobject/pygobject.c index b9a51b1..cbfe269 100644 --- a/gobject/pygobject.c +++ b/gobject/pygobject.c @@ -1630,6 +1630,102 @@ pygobject_chain_from_overridden(PyGObject *self, PyObject *args) return py_ret; } +static PyObject * +pygobject_disconnect_by_func(PyGObject *self, PyObject *args) +{ + PyObject *pyfunc = NULL; + GClosure *closure = NULL; + guint retval; + + CHECK_GOBJECT(self); + + if (!PyArg_ParseTuple(args, "O:GObject.disconnect_by_func", &pyfunc)) + return NULL; + + if (!PyCallable_Check(pyfunc)) { + PyErr_SetString(PyExc_TypeError, "first argument must be callable"); + return NULL; + } + + closure = gclosure_from_pyfunc(self, pyfunc); + if (!closure) { + PyErr_Format(PyExc_TypeError, "nothing connected to %s", + PyString_AsString(PyObject_Repr((PyObject*)pyfunc))); + return NULL; + } + + retval = g_signal_handlers_disconnect_matched(self->obj, + G_SIGNAL_MATCH_CLOSURE, + 0, 0, + closure, + NULL, NULL); + return PyInt_FromLong(retval); +} + +static PyObject * +pygobject_handler_block_by_func(PyGObject *self, PyObject *args) +{ + PyObject *pyfunc = NULL; + GClosure *closure = NULL; + guint retval; + + CHECK_GOBJECT(self); + + if (!PyArg_ParseTuple(args, "O:GObject.handler_block_by_func", &pyfunc)) + return NULL; + + if (!PyCallable_Check(pyfunc)) { + PyErr_SetString(PyExc_TypeError, "first argument must be callable"); + return NULL; + } + + closure = gclosure_from_pyfunc(self, pyfunc); + if (!closure) { + PyErr_Format(PyExc_TypeError, "nothing connected to %s", + PyString_AsString(PyObject_Repr((PyObject*)pyfunc))); + return NULL; + } + + retval = g_signal_handlers_block_matched(self->obj, + G_SIGNAL_MATCH_CLOSURE, + 0, 0, + closure, + NULL, NULL); + return PyInt_FromLong(retval); +} + +static PyObject * +pygobject_handler_unblock_by_func(PyGObject *self, PyObject *args) +{ + PyObject *pyfunc = NULL; + GClosure *closure = NULL; + guint retval; + + CHECK_GOBJECT(self); + + if (!PyArg_ParseTuple(args, "O:GObject.handler_unblock_by_func", &pyfunc)) + return NULL; + + if (!PyCallable_Check(pyfunc)) { + PyErr_SetString(PyExc_TypeError, "first argument must be callable"); + return NULL; + } + + closure = gclosure_from_pyfunc(self, pyfunc); + if (!closure) { + PyErr_Format(PyExc_TypeError, "nothing connected to %s", + PyString_AsString(PyObject_Repr((PyObject*)pyfunc))); + return NULL; + } + + retval = g_signal_handlers_unblock_matched(self->obj, + G_SIGNAL_MATCH_CLOSURE, + 0, 0, + closure, + NULL, NULL); + return PyInt_FromLong(retval); +} + static PyMethodDef pygobject_methods[] = { { "__gobject_init__", (PyCFunction)pygobject__gobject_init__, METH_VARARGS|METH_KEYWORDS }, @@ -1645,10 +1741,13 @@ static PyMethodDef pygobject_methods[] = { { "connect_object", (PyCFunction)pygobject_connect_object, METH_VARARGS }, { "connect_object_after", (PyCFunction)pygobject_connect_object_after, METH_VARARGS }, { "disconnect", (PyCFunction)pygobject_disconnect, METH_VARARGS }, + { "disconnect_by_func", (PyCFunction)pygobject_disconnect_by_func, METH_VARARGS }, { "handler_disconnect", (PyCFunction)pygobject_disconnect, METH_VARARGS }, { "handler_is_connected", (PyCFunction)pygobject_handler_is_connected, METH_VARARGS }, { "handler_block", (PyCFunction)pygobject_handler_block, METH_VARARGS }, { "handler_unblock", (PyCFunction)pygobject_handler_unblock,METH_VARARGS }, + { "handler_block_by_func", (PyCFunction)pygobject_handler_block_by_func, METH_VARARGS }, + { "handler_unblock_by_func", (PyCFunction)pygobject_handler_unblock_by_func, METH_VARARGS }, { "emit", (PyCFunction)pygobject_emit, METH_VARARGS }, { "stop_emission", (PyCFunction)pygobject_stop_emission, METH_VARARGS }, { "emit_stop_by_name", (PyCFunction)pygobject_stop_emission,METH_VARARGS }, diff --git a/gobject/pygtype.c b/gobject/pygtype.c index a1400a0..296f48f 100644 --- a/gobject/pygtype.c +++ b/gobject/pygtype.c @@ -1306,6 +1306,21 @@ pyg_signal_class_closure_get(void) return closure; } +GClosure * +gclosure_from_pyfunc(PyGObject *object, PyObject *func) +{ + GSList *l; + + for (l = object->closures; l; l = l->next) { + PyGClosure *pyclosure = l->data; + if (PyFunction_GetClosure(pyclosure->callback) == + PyFunction_GetClosure(func)) { + return (GClosure*)pyclosure; + } + } + return NULL; +} + /* ----- __doc__ descriptor for GObject and GInterface ----- */ static void diff --git a/tests/test_signal.py b/tests/test_signal.py index f006fae..6cf9313 100644 --- a/tests/test_signal.py +++ b/tests/test_signal.py @@ -168,5 +168,34 @@ class TestEmissionHook(unittest.TestCase): self.assertEqual(e.status, 1) e.status = 3 +class TestClosures(unittest.TestCase): + def setUp(self): + self.count = 0 + + def _callback(self, e): + self.count += 1 + + def testDisconnect(self): + e = E() + e.connect('signal', self._callback) + e.disconnect_by_func(self._callback) + e.emit('signal') + self.assertEqual(self.count, 0) + + def testHandlerBlock(self): + e = E() + e.connect('signal', self._callback) + e.handler_block_by_func(self._callback) + e.emit('signal') + self.assertEqual(self.count, 0) + + def testHandlerUnBlock(self): + e = E() + signal_id = e.connect('signal', self._callback) + e.handler_block(signal_id) + e.handler_unblock_by_func(self._callback) + e.emit('signal') + self.assertEqual(self.count, 1) + if __name__ == '__main__': unittest.main() |