1 /* Implementation of main-loop integration for dbus-python.
3 * Copyright (C) 2006 Collabora Ltd.
5 * Licensed under the Academic Free License version 2.1
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 #include "dbus_bindings-internal.h"
27 /* Watch ============================================================ */
29 PyDoc_STRVAR(Watch_tp_doc,
30 "Object representing a watched file descriptor.\n"
31 "Cannot be instantiated from Python.\n"
34 static PyTypeObject Watch_Type;
43 PyDoc_STRVAR(Watch_fileno__doc__,
45 "Return the watched file descriptor.\n");
47 Watch_fileno(Watch *self, PyObject *unused UNUSED)
52 DBG("Attempted fileno() on broken Watch at %p", self);
53 PyErr_SetString(PyExc_ValueError, "FD watch is no longer valid");
56 fd = dbus_watch_get_fd(self->watch);
57 DBG("Watch at %p (wrapping DBusWatch at %p) has fileno %d", self,
59 return PyInt_FromLong(fd);
62 PyDoc_STRVAR(Watch_get_flags__doc__,
63 "get_flags() -> int\n\n"
64 "Return 0, WATCH_READABLE, WATCH_WRITABLE or WATCH_READABLE|WATCH_WRITABLE.\n");
66 Watch_get_flags(Watch *self, PyObject *unused UNUSED)
71 DBG("Attempted get_flags() on broken Watch at %p", self);
72 PyErr_SetString(PyExc_ValueError, "FD watch is no longer valid");
75 flags = dbus_watch_get_flags(self->watch);
76 DBG("Watch at %p (wrapping DBusWatch at %p) has flags 0x%x (%s,%s)",
77 self, self->watch, flags, flags & DBUS_WATCH_READABLE ? "read" : ".",
78 flags & DBUS_WATCH_WRITABLE ? "write" : ".");
79 return PyInt_FromLong((long)flags);
82 PyDoc_STRVAR(Watch_get_enabled__doc__,
83 "get_enabled() -> bool\n\n"
84 "Return True if this watch is currently active.\n");
86 Watch_get_enabled(Watch *self, PyObject *unused UNUSED)
91 DBG("Attempted get_enabled() on broken Watch at %p", self);
92 PyErr_SetString(PyExc_ValueError, "FD watch is no longer valid");
95 enabled = dbus_watch_get_enabled(self->watch);
96 DBG("Watch at %p (wrapping DBusWatch at %p) is %s", self,
97 self->watch, enabled ? "enabled" : "disabled");
98 return PyBool_FromLong(enabled);
101 PyDoc_STRVAR(Watch_handle__doc__,
103 "To be called when the file descriptor is closed or reports error,\n"
104 "or enters a readable/writable state for which notification is required\n"
105 "(according to get_flags()).");
107 Watch_handle(Watch *self, PyObject *args)
111 DBG("Attempted handle() on broken Watch at %p", self);
112 PyErr_SetString(PyExc_ValueError, "FD watch is no longer valid");
115 if (!PyArg_ParseTuple(args, "i", &flags)) {
116 DBG("Python passed junk to <Watch at %p>.handle()", self);
119 DBG("Watch at %p (wrapping DBusWatch at %p) handle(0x%x) (%s,%s)",
120 self, self->watch, flags, flags & DBUS_WATCH_READABLE ? "read" : ".",
121 flags & DBUS_WATCH_WRITABLE ? "write" : ".");
122 Py_BEGIN_ALLOW_THREADS
123 dbus_watch_handle(self->watch, (unsigned int)flags);
128 /* Arranges for the watch to be referenced by its corresponding DBusWatch.
129 * Returns a borrowed reference, or NULL with a Python exception.
132 Watch_BorrowFromDBusWatch(DBusWatch *watch, PyObject *mainloop)
134 Watch *self = (Watch *)dbus_watch_get_data(watch);
137 return (PyObject *)self;
139 PyErr_SetString(PyExc_AssertionError,
140 "Attempted to use a non-added watch");
144 self = PyObject_New(Watch, &Watch_Type);
151 dbus_watch_set_data(watch, self,
152 (DBusFreeFunction)dbus_py_take_gil_and_xdecref);
153 return (PyObject *)self;
156 static PyMethodDef Watch_tp_methods[] = {
157 {"fileno", (PyCFunction)Watch_fileno, METH_NOARGS,
158 Watch_fileno__doc__},
159 {"get_flags", (PyCFunction)Watch_get_flags, METH_NOARGS,
160 Watch_get_flags__doc__},
161 {"handle", (PyCFunction)Watch_handle, METH_VARARGS,
162 Watch_handle__doc__},
163 {"get_enabled", (PyCFunction)Watch_get_enabled, METH_NOARGS,
164 Watch_get_enabled__doc__},
165 {NULL, NULL, 0, NULL}
168 static void Watch_tp_dealloc(PyObject *self)
173 static PyTypeObject Watch_Type = {
174 PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type))
176 "_dbus_bindings.Watch",
179 Watch_tp_dealloc, /* tp_dealloc */
185 0, /* tp_as_number */
186 0, /* tp_as_sequence */
187 0, /* tp_as_mapping */
188 dbus_py_tp_hash_by_pointer, /* tp_hash */
193 0, /* tp_as_buffer */
194 Py_TPFLAGS_DEFAULT, /* tp_flags */
195 Watch_tp_doc, /* tp_doc */
198 dbus_py_tp_richcompare_by_pointer, /* tp_richcompare */
199 0, /* tp_weaklistoffset */
202 Watch_tp_methods, /* tp_methods */
207 0, /* tp_descr_get */
208 0, /* tp_descr_set */
209 0, /* tp_dictoffset */
212 /* deliberately not callable! */
216 /* Timeout ========================================================== */
218 PyDoc_STRVAR(Timeout_tp_doc,
219 "Object representing a watched file descriptor.\n"
220 "Cannot be instantiated from Python.\n"
223 static PyTypeObject Timeout_Type;
225 DEFINE_CHECK(Timeout)
229 DBusTimeout *timeout;
232 PyDoc_STRVAR(Timeout_get_interval__doc__,
233 "get_interval() -> float\n\n"
234 "Return the interval in seconds.\n");
236 Timeout_get_interval(Timeout *self, PyObject *unused UNUSED)
239 if (!self->timeout) {
240 DBG("Attempted get_interval() on broken Timeout at %p", self);
241 PyErr_SetString(PyExc_ValueError, "Timeout object is no longer valid");
244 interval = ((double)dbus_timeout_get_interval(self->timeout)) / 1000.0;
245 DBG("Timeout at %p (wrapping DBusTimeout at %p) has interval %f s", self,
246 self->timeout, interval);
247 return PyFloat_FromDouble(interval);
250 PyDoc_STRVAR(Timeout_get_enabled__doc__,
251 "get_enabled() -> bool\n\n"
252 "Return True if this timeout is currently active.\n");
254 Timeout_get_enabled(Timeout *self, PyObject *unused UNUSED)
258 if (!self->timeout) {
259 DBG("Attempted get_enabled() on broken Timeout at %p", self);
260 PyErr_SetString(PyExc_ValueError, "Timeout object is no longer valid");
263 enabled = dbus_timeout_get_enabled(self->timeout);
264 DBG("Timeout at %p (wrapping DBusTimeout at %p) is %s", self,
265 self->timeout, enabled ? "enabled" : "disabled");
266 return PyBool_FromLong(enabled);
269 PyDoc_STRVAR(Timeout_handle__doc__,
271 "To be called when timeout occurs.\n");
273 Timeout_handle(Timeout *self, PyObject *unused UNUSED)
275 if (!self->timeout) {
276 DBG("Attempted handle() on broken Timeout at %p", self);
277 PyErr_SetString(PyExc_ValueError, "Timeout object is no longer valid");
280 DBG("Timeout_handle() with self->timeout=%p", self->timeout);
281 Py_BEGIN_ALLOW_THREADS
282 dbus_timeout_handle(self->timeout);
287 /* Returns a borrowed reference */
289 Timeout_BorrowFromDBusTimeout(DBusTimeout *timeout, PyObject *mainloop)
291 Timeout *self = (Timeout *)dbus_timeout_get_data(timeout);
293 return (PyObject *)self;
295 PyErr_SetString(PyExc_AssertionError,
296 "Attempted to use a non-added timeout");
300 self = PyObject_New(Timeout, &Timeout_Type);
304 self->timeout = timeout;
307 dbus_timeout_set_data(timeout, self,
308 (DBusFreeFunction)dbus_py_take_gil_and_xdecref);
309 return (PyObject *)self;
312 static PyMethodDef Timeout_tp_methods[] = {
313 {"get_interval", (PyCFunction)Timeout_get_interval, METH_NOARGS,
314 Timeout_get_interval__doc__},
315 {"handle", (PyCFunction)Timeout_handle, METH_NOARGS,
316 Timeout_handle__doc__},
317 {"get_enabled", (PyCFunction)Timeout_get_enabled, METH_NOARGS,
318 Timeout_get_enabled__doc__},
319 {NULL, NULL, 0, NULL}
322 static void Timeout_tp_dealloc(PyObject *self)
327 static PyTypeObject Timeout_Type = {
328 PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type))
330 "_dbus_bindings.Timeout",
333 Timeout_tp_dealloc, /* tp_dealloc */
339 0, /* tp_as_number */
340 0, /* tp_as_sequence */
341 0, /* tp_as_mapping */
342 dbus_py_tp_hash_by_pointer, /* tp_hash */
347 0, /* tp_as_buffer */
348 Py_TPFLAGS_DEFAULT, /* tp_flags */
349 Timeout_tp_doc, /* tp_doc */
352 dbus_py_tp_richcompare_by_pointer, /* tp_richcompare */
353 0, /* tp_weaklistoffset */
356 Timeout_tp_methods, /* tp_methods */
361 0, /* tp_descr_get */
362 0, /* tp_descr_set */
363 0, /* tp_dictoffset */
366 /* deliberately not callable! */
370 /* Native mainloop wrapper ========================================= */
372 PyDoc_STRVAR(NativeMainLoop_tp_doc,
373 "Object representing D-Bus main loop integration done in native code.\n"
374 "Cannot be instantiated directly.\n"
377 static PyTypeObject NativeMainLoop_Type;
379 DEFINE_CHECK(NativeMainLoop)
383 /* Called with the GIL held, should set a Python exception on error */
384 dbus_bool_t (*set_up_connection_cb)(DBusConnection *, void *);
385 dbus_bool_t (*set_up_server_cb)(DBusServer *, void *);
386 /* Called in a destructor. */
387 void (*free_cb)(void *);
391 static void NativeMainLoop_tp_dealloc(NativeMainLoop *self)
393 if (self->data && self->free_cb) {
394 (self->free_cb)(self->data);
396 PyObject_Del((PyObject *)self);
399 static PyTypeObject NativeMainLoop_Type = {
400 PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type))
402 "dbus.mainloop.NativeMainLoop",
403 sizeof(NativeMainLoop),
405 (destructor)NativeMainLoop_tp_dealloc, /* tp_dealloc */
411 0, /* tp_as_number */
412 0, /* tp_as_sequence */
413 0, /* tp_as_mapping */
419 0, /* tp_as_buffer */
420 Py_TPFLAGS_DEFAULT, /* tp_flags */
421 NativeMainLoop_tp_doc, /* tp_doc */
424 0, /* tp_richcompare */
425 0, /* tp_weaklistoffset */
433 0, /* tp_descr_get */
434 0, /* tp_descr_set */
435 0, /* tp_dictoffset */
438 /* deliberately not callable! */
442 /* Internal C API for Connection, Bus, Server ======================= */
445 dbus_py_check_mainloop_sanity(PyObject *mainloop)
447 if (NativeMainLoop_Check(mainloop)) {
450 PyErr_SetString(PyExc_TypeError,
451 "A dbus.mainloop.NativeMainLoop instance is required");
456 dbus_py_set_up_connection(PyObject *conn, PyObject *mainloop)
458 if (NativeMainLoop_Check(mainloop)) {
459 /* Native mainloops are allowed to do arbitrary strange things */
460 NativeMainLoop *nml = (NativeMainLoop *)mainloop;
461 DBusConnection *dbc = DBusPyConnection_BorrowDBusConnection(conn);
466 return (nml->set_up_connection_cb)(dbc, nml->data);
468 PyErr_SetString(PyExc_TypeError,
469 "A dbus.mainloop.NativeMainLoop instance is required");
473 /* C API ============================================================ */
476 DBusPyNativeMainLoop_New4(dbus_bool_t (*conn_cb)(DBusConnection *, void *),
477 dbus_bool_t (*server_cb)(DBusServer *, void *),
478 void (*free_cb)(void *),
481 NativeMainLoop *self = PyObject_New(NativeMainLoop, &NativeMainLoop_Type);
484 self->free_cb = free_cb;
485 self->set_up_connection_cb = conn_cb;
486 self->set_up_server_cb = server_cb;
488 return (PyObject *)self;
491 /* Null mainloop implementation ===================================== */
494 noop_main_loop_cb(void *conn_or_server UNUSED, void *data UNUSED)
499 #define noop_conn_cb ((dbus_bool_t (*)(DBusConnection *, void *))(noop_main_loop_cb))
500 #define noop_server_cb ((dbus_bool_t (*)(DBusServer *, void *))(noop_main_loop_cb))
502 /* Initialization =================================================== */
505 dbus_py_init_mainloop(void)
507 if (PyType_Ready (&Watch_Type) < 0) return 0;
508 if (PyType_Ready (&Timeout_Type) < 0) return 0;
509 if (PyType_Ready (&NativeMainLoop_Type) < 0) return 0;
511 /* placate -Wunused */
512 (void)&Watch_BorrowFromDBusWatch;
513 (void)&Timeout_BorrowFromDBusTimeout;
519 dbus_py_insert_mainloop_types(PyObject *this_module)
521 PyObject *null_main_loop = DBusPyNativeMainLoop_New4(noop_conn_cb,
525 if (!null_main_loop) return 0;
527 if (PyModule_AddObject (this_module, "Watch",
528 (PyObject *)&Watch_Type) < 0) return 0;
529 if (PyModule_AddObject (this_module, "Timeout",
530 (PyObject *)&Timeout_Type) < 0) return 0;
531 if (PyModule_AddObject (this_module, "NativeMainLoop",
532 (PyObject *)&NativeMainLoop_Type) < 0) return 0;
533 if (PyModule_AddObject (this_module, "NULL_MAIN_LOOP",
534 null_main_loop) < 0) return 0;
538 /* vim:set ft=c cino< sw=4 sts=4 et: */