From 894bafef2cae44d4b41845ed900cffe65dd63900 Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Thu, 23 Nov 2006 16:44:21 +0000 Subject: [PATCH] _dbus_bindings/mainloop-impl.h: Add Watch and Timeout types _dbus_bindings/generic-impl.h: Add Glue_tp_hash_by_pointer and Glue_tp_richcompare_by_pointer to support the above --- _dbus_bindings/generic-impl.h | 23 +++ _dbus_bindings/mainloop-impl.h | 354 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 377 insertions(+) diff --git a/_dbus_bindings/generic-impl.h b/_dbus_bindings/generic-impl.h index b9c3129..6043285 100644 --- a/_dbus_bindings/generic-impl.h +++ b/_dbus_bindings/generic-impl.h @@ -44,6 +44,29 @@ static inline int type##_Check (PyObject *o) \ static PyObject *empty_tuple = NULL; +static PyObject * +Glue_tp_richcompare_by_pointer(PyObject *self, + PyObject *other, + int op) +{ + if (op == Py_EQ || op == Py_NE) { + if (self == other) { + return PyInt_FromLong(op == Py_EQ); + } + return PyInt_FromLong(op == Py_NE); + } + PyErr_SetString(PyExc_TypeError, + "Instances of this type are not ordered"); + return NULL; +} + +static long +Glue_tp_hash_by_pointer(PyObject *self) +{ + long hash = (long)self; + return (hash == -1L ? -2L : hash); +} + static int Glue_immutable_setattro(PyObject *obj UNUSED, PyObject *name UNUSED, diff --git a/_dbus_bindings/mainloop-impl.h b/_dbus_bindings/mainloop-impl.h index e910c9a..4634142 100644 --- a/_dbus_bindings/mainloop-impl.h +++ b/_dbus_bindings/mainloop-impl.h @@ -22,6 +22,349 @@ * */ +/* Watch ============================================================ */ + +PyDoc_STRVAR(Watch_tp_doc, +"Object representing a watched file descriptor.\n" +"Cannot be instantiated from Python.\n" +); + +static PyTypeObject WatchType; + +DEFINE_CHECK(Watch) + +typedef struct { + PyObject_HEAD + DBusWatch *watch; +} Watch; + +PyDoc_STRVAR(Watch_fileno__doc__, +"fileno() -> int\n\n" +"Return the watched file descriptor.\n"); +static PyObject * +Watch_fileno(Watch *self, PyObject *unused UNUSED) +{ + int fd; + + if (!self->watch) { + DBG("Attempted fileno() on broken Watch at %p", self); + PyErr_SetString(PyExc_ValueError, "FD watch is no longer valid"); + return NULL; + } + fd = dbus_watch_get_fd(self->watch); + DBG("Watch at %p (wrapping DBusWatch at %p) has fileno %d", self, + self->watch, fd); + return PyInt_FromLong(fd); +} + +PyDoc_STRVAR(Watch_get_flags__doc__, +"get_flags() -> int\n\n" +"Return 0, WATCH_READABLE, WATCH_WRITABLE or WATCH_READABLE|WATCH_WRITABLE.\n"); +static PyObject * +Watch_get_flags(Watch *self, PyObject *unused UNUSED) +{ + unsigned int flags; + + if (!self->watch) { + DBG("Attempted get_flags() on broken Watch at %p", self); + PyErr_SetString(PyExc_ValueError, "FD watch is no longer valid"); + return NULL; + } + flags = dbus_watch_get_flags(self->watch); + DBG("Watch at %p (wrapping DBusWatch at %p) has flags 0x%x (%s,%s)", + self, self->watch, flags, flags & WATCH_READABLE ? "read" : ".", + flags & WATCH_WRITABLE ? "write" : "."); + return PyInt_FromLong((long)flags); +} + +PyDoc_STRVAR(Watch_get_enabled__doc__, +"get_enabled() -> bool\n\n" +"Return True if this watch is currently active.\n"); +static PyObject * +Watch_get_enabled(Watch *self, PyObject *unused UNUSED) +{ + dbus_bool_t enabled; + + if (!self->watch) { + DBG("Attempted get_enabled() on broken Watch at %p", self); + PyErr_SetString(PyExc_ValueError, "FD watch is no longer valid"); + return NULL; + } + enabled = dbus_watch_get_enabled(self->watch); + DBG("Watch at %p (wrapping DBusWatch at %p) is %s", self, + self->watch, enabled ? "enabled" : "disabled"); + return PyBool_FromLong(enabled); +} + +PyDoc_STRVAR(Watch_handle__doc__, +"handle(flags)\n\n" +"To be called when the file descriptor is closed or reports error,\n" +"or enters a readable/writable state for which notification is required\n" +"(according to get_flags())."); +static PyObject * +Watch_handle(Watch *self, PyObject *args) +{ + unsigned int flags; + if (!self->watch) { + DBG("Attempted handle() on broken Watch at %p", self); + PyErr_SetString(PyExc_ValueError, "FD watch is no longer valid"); + return NULL; + } + if (!PyArg_ParseTuple(args, "i", &flags)) { + DBG("Python passed junk to .handle()", self); + return NULL; + } + DBG("Watch at %p (wrapping DBusWatch at %p) handle(0x%x) (%s,%s)", + self, self->watch, flags, flags & WATCH_READABLE ? "read" : ".", + flags & WATCH_WRITABLE ? "write" : "."); + Py_BEGIN_ALLOW_THREADS + dbus_watch_handle(self->watch, (unsigned int)flags); + Py_END_ALLOW_THREADS + Py_RETURN_NONE; +} + +/* Arranges for the watch to be referenced by its corresponding DBusWatch. + * Returns a borrowed reference, or NULL with a Python exception. + */ +static PyObject * +Watch_BorrowFromDBusWatch(DBusWatch *watch, PyObject *mainloop) +{ + Watch *self = (Watch *)dbus_watch_get_data(watch); + + if (self) + return (PyObject *)self; + if (!mainloop) { + PyErr_SetString(PyExc_AssertionError, + "Attempted to use a non-added watch"); + return NULL; + } + + self = PyObject_New(Watch, &WatchType); + if (!self) { + return NULL; + } + self->watch = watch; + + Py_INCREF(self); + dbus_watch_set_data(watch, self, + (DBusFreeFunction)Glue_TakeGILAndXDecref); + return (PyObject *)self; +} + +static PyMethodDef Watch_tp_methods[] = { + {"fileno", (PyCFunction)Watch_fileno, METH_NOARGS, + Watch_fileno__doc__}, + {"get_flags", (PyCFunction)Watch_get_flags, METH_NOARGS, + Watch_get_flags__doc__}, + {"handle", (PyCFunction)Watch_handle, METH_VARARGS, + Watch_handle__doc__}, + {"get_enabled", (PyCFunction)Watch_get_enabled, METH_NOARGS, + Watch_get_enabled__doc__}, + {NULL, NULL, 0, NULL} +}; + +static void Watch_tp_dealloc(PyObject *self) +{ + PyObject_Del(self); +} + +static PyTypeObject WatchType = { + PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type)) + 0, + "_dbus_bindings.Watch", + sizeof(Watch), + 0, + Watch_tp_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + Glue_tp_hash_by_pointer, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + Watch_tp_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + Glue_tp_richcompare_by_pointer, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + Watch_tp_methods, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + /* deliberately not callable! */ + 0, /* tp_new */ +}; + +/* Timeout ========================================================== */ + +PyDoc_STRVAR(Timeout_tp_doc, +"Object representing a watched file descriptor.\n" +"Cannot be instantiated from Python.\n" +); + +static PyTypeObject TimeoutType; + +DEFINE_CHECK(Timeout) + +typedef struct { + PyObject_HEAD + DBusTimeout *timeout; +} Timeout; + +PyDoc_STRVAR(Timeout_get_interval__doc__, +"get_interval() -> float\n\n" +"Return the interval in seconds.\n"); +static PyObject * +Timeout_get_interval(Timeout *self, PyObject *unused UNUSED) +{ + double interval; + if (!self->timeout) { + DBG("Attempted get_interval() on broken Timeout at %p", self); + PyErr_SetString(PyExc_ValueError, "Timeout object is no longer valid"); + return NULL; + } + interval = ((double)dbus_timeout_get_interval(self->timeout)) / 1000.0; + DBG("Timeout at %p (wrapping DBusTimeout at %p) has interval %f s", self, + self->timeout, interval); + return PyFloat_FromDouble(interval); +} + +PyDoc_STRVAR(Timeout_get_enabled__doc__, +"get_enabled() -> bool\n\n" +"Return True if this timeout is currently active.\n"); +static PyObject * +Timeout_get_enabled(Timeout *self, PyObject *unused UNUSED) +{ + dbus_bool_t enabled; + + if (!self->timeout) { + DBG("Attempted get_enabled() on broken Timeout at %p", self); + PyErr_SetString(PyExc_ValueError, "Timeout object is no longer valid"); + return NULL; + } + enabled = dbus_timeout_get_enabled(self->timeout); + DBG("Timeout at %p (wrapping DBusTimeout at %p) is %s", self, + self->timeout, enabled ? "enabled" : "disabled"); + return PyBool_FromLong(enabled); +} + +PyDoc_STRVAR(Timeout_handle__doc__, +"handle()\n\n" +"To be called when timeout occurs.\n"); +static PyObject * +Timeout_handle(Timeout *self, PyObject *unused UNUSED) +{ + if (!self->timeout) { + DBG("Attempted handle() on broken Timeout at %p", self); + PyErr_SetString(PyExc_ValueError, "Timeout object is no longer valid"); + return NULL; + } + DBG("Timeout_handle() with self->timeout=%p", self->timeout); + Py_BEGIN_ALLOW_THREADS + dbus_timeout_handle(self->timeout); + Py_END_ALLOW_THREADS + Py_RETURN_NONE; +} + +/* Returns a borrowed reference */ +static PyObject * +Timeout_BorrowFromDBusTimeout(DBusTimeout *timeout, PyObject *mainloop) +{ + Timeout *self = (Timeout *)dbus_timeout_get_data(timeout); + if (self) + return (PyObject *)self; + if (!mainloop) { + PyErr_SetString(PyExc_AssertionError, + "Attempted to use a non-added timeout"); + return NULL; + } + + self = PyObject_New(Timeout, &TimeoutType); + if (!self) { + return NULL; + } + self->timeout = timeout; + + Py_INCREF(self); + dbus_timeout_set_data(timeout, self, + (DBusFreeFunction)Glue_TakeGILAndXDecref); + return (PyObject *)self; +} + +static PyMethodDef Timeout_tp_methods[] = { + {"get_interval", (PyCFunction)Timeout_get_interval, METH_NOARGS, + Timeout_get_interval__doc__}, + {"handle", (PyCFunction)Timeout_handle, METH_NOARGS, + Timeout_handle__doc__}, + {"get_enabled", (PyCFunction)Timeout_get_enabled, METH_NOARGS, + Timeout_get_enabled__doc__}, + {NULL, NULL, 0, NULL} +}; + +static void Timeout_tp_dealloc(PyObject *self) +{ + PyObject_Del(self); +} + +static PyTypeObject TimeoutType = { + PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type)) + 0, + "_dbus_bindings.Timeout", + sizeof(Timeout), + 0, + Timeout_tp_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + Glue_tp_hash_by_pointer, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + Timeout_tp_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + Glue_tp_richcompare_by_pointer, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + Timeout_tp_methods, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + /* deliberately not callable! */ + 0, /* tp_new */ +}; + /* Native mainloop wrapper ========================================= */ PyDoc_STRVAR(NativeMainLoop_tp_doc, @@ -152,7 +495,14 @@ noop_main_loop_cb(void *conn_or_server UNUSED, void *data UNUSED) static inline int init_mainloop (void) { + if (PyType_Ready (&WatchType) < 0) return 0; + if (PyType_Ready (&TimeoutType) < 0) return 0; if (PyType_Ready (&NativeMainLoopType) < 0) return 0; + + /* placate -Wunused */ + (void)&Watch_BorrowFromDBusWatch; + (void)&Timeout_BorrowFromDBusTimeout; + return 1; } @@ -165,6 +515,10 @@ insert_mainloop_types (PyObject *this_module) NULL); if (!null_main_loop) return 0; + if (PyModule_AddObject (this_module, "Watch", + (PyObject *)&WatchType) < 0) return 0; + if (PyModule_AddObject (this_module, "Timeout", + (PyObject *)&TimeoutType) < 0) return 0; if (PyModule_AddObject (this_module, "NativeMainLoop", (PyObject *)&NativeMainLoopType) < 0) return 0; if (PyModule_AddObject (this_module, "NULL_MAIN_LOOP", -- 2.11.4.GIT