Add Makefile target maintainer-update-website to update d.fd.o/doc/dbus-python
[dbus-python-phuang.git] / _dbus_bindings / mainloop.c
blob6e40f36f055d5af2479a146093e04cee5f67bb72
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;
36 DEFINE_CHECK(Watch)
38 typedef struct {
39 PyObject_HEAD
40 DBusWatch *watch;
41 } Watch;
43 PyDoc_STRVAR(Watch_fileno__doc__,
44 "fileno() -> int\n\n"
45 "Return the watched file descriptor.\n");
46 static PyObject *
47 Watch_fileno(Watch *self, PyObject *unused UNUSED)
49 int fd;
51 if (!self->watch) {
52 DBG("Attempted fileno() on broken Watch at %p", self);
53 PyErr_SetString(PyExc_ValueError, "FD watch is no longer valid");
54 return NULL;
56 fd = dbus_watch_get_fd(self->watch);
57 DBG("Watch at %p (wrapping DBusWatch at %p) has fileno %d", self,
58 self->watch, fd);
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");
65 static PyObject *
66 Watch_get_flags(Watch *self, PyObject *unused UNUSED)
68 unsigned int flags;
70 if (!self->watch) {
71 DBG("Attempted get_flags() on broken Watch at %p", self);
72 PyErr_SetString(PyExc_ValueError, "FD watch is no longer valid");
73 return NULL;
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");
85 static PyObject *
86 Watch_get_enabled(Watch *self, PyObject *unused UNUSED)
88 dbus_bool_t enabled;
90 if (!self->watch) {
91 DBG("Attempted get_enabled() on broken Watch at %p", self);
92 PyErr_SetString(PyExc_ValueError, "FD watch is no longer valid");
93 return NULL;
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__,
102 "handle(flags)\n\n"
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()).");
106 static PyObject *
107 Watch_handle(Watch *self, PyObject *args)
109 unsigned int flags;
110 if (!self->watch) {
111 DBG("Attempted handle() on broken Watch at %p", self);
112 PyErr_SetString(PyExc_ValueError, "FD watch is no longer valid");
113 return NULL;
115 if (!PyArg_ParseTuple(args, "i", &flags)) {
116 DBG("Python passed junk to <Watch at %p>.handle()", self);
117 return NULL;
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);
124 Py_END_ALLOW_THREADS
125 Py_RETURN_NONE;
128 /* Arranges for the watch to be referenced by its corresponding DBusWatch.
129 * Returns a borrowed reference, or NULL with a Python exception.
131 static PyObject *
132 Watch_BorrowFromDBusWatch(DBusWatch *watch, PyObject *mainloop)
134 Watch *self = (Watch *)dbus_watch_get_data(watch);
136 if (self)
137 return (PyObject *)self;
138 if (!mainloop) {
139 PyErr_SetString(PyExc_AssertionError,
140 "Attempted to use a non-added watch");
141 return NULL;
144 self = PyObject_New(Watch, &Watch_Type);
145 if (!self) {
146 return NULL;
148 self->watch = watch;
150 Py_INCREF(self);
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)
170 PyObject_Del(self);
173 static PyTypeObject Watch_Type = {
174 PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type))
176 "_dbus_bindings.Watch",
177 sizeof(Watch),
179 Watch_tp_dealloc, /* tp_dealloc */
180 0, /* tp_print */
181 0, /* tp_getattr */
182 0, /* tp_setattr */
183 0, /* tp_compare */
184 0, /* tp_repr */
185 0, /* tp_as_number */
186 0, /* tp_as_sequence */
187 0, /* tp_as_mapping */
188 dbus_py_tp_hash_by_pointer, /* tp_hash */
189 0, /* tp_call */
190 0, /* tp_str */
191 0, /* tp_getattro */
192 0, /* tp_setattro */
193 0, /* tp_as_buffer */
194 Py_TPFLAGS_DEFAULT, /* tp_flags */
195 Watch_tp_doc, /* tp_doc */
196 0, /* tp_traverse */
197 0, /* tp_clear */
198 dbus_py_tp_richcompare_by_pointer, /* tp_richcompare */
199 0, /* tp_weaklistoffset */
200 0, /* tp_iter */
201 0, /* tp_iternext */
202 Watch_tp_methods, /* tp_methods */
203 0, /* tp_members */
204 0, /* tp_getset */
205 0, /* tp_base */
206 0, /* tp_dict */
207 0, /* tp_descr_get */
208 0, /* tp_descr_set */
209 0, /* tp_dictoffset */
210 0, /* tp_init */
211 0, /* tp_alloc */
212 /* deliberately not callable! */
213 0, /* tp_new */
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)
227 typedef struct {
228 PyObject_HEAD
229 DBusTimeout *timeout;
230 } Timeout;
232 PyDoc_STRVAR(Timeout_get_interval__doc__,
233 "get_interval() -> float\n\n"
234 "Return the interval in seconds.\n");
235 static PyObject *
236 Timeout_get_interval(Timeout *self, PyObject *unused UNUSED)
238 double interval;
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");
242 return NULL;
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");
253 static PyObject *
254 Timeout_get_enabled(Timeout *self, PyObject *unused UNUSED)
256 dbus_bool_t enabled;
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");
261 return NULL;
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__,
270 "handle()\n\n"
271 "To be called when timeout occurs.\n");
272 static PyObject *
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");
278 return NULL;
280 DBG("Timeout_handle() with self->timeout=%p", self->timeout);
281 Py_BEGIN_ALLOW_THREADS
282 dbus_timeout_handle(self->timeout);
283 Py_END_ALLOW_THREADS
284 Py_RETURN_NONE;
287 /* Returns a borrowed reference */
288 static PyObject *
289 Timeout_BorrowFromDBusTimeout(DBusTimeout *timeout, PyObject *mainloop)
291 Timeout *self = (Timeout *)dbus_timeout_get_data(timeout);
292 if (self)
293 return (PyObject *)self;
294 if (!mainloop) {
295 PyErr_SetString(PyExc_AssertionError,
296 "Attempted to use a non-added timeout");
297 return NULL;
300 self = PyObject_New(Timeout, &Timeout_Type);
301 if (!self) {
302 return NULL;
304 self->timeout = timeout;
306 Py_INCREF(self);
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)
324 PyObject_Del(self);
327 static PyTypeObject Timeout_Type = {
328 PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type))
330 "_dbus_bindings.Timeout",
331 sizeof(Timeout),
333 Timeout_tp_dealloc, /* tp_dealloc */
334 0, /* tp_print */
335 0, /* tp_getattr */
336 0, /* tp_setattr */
337 0, /* tp_compare */
338 0, /* tp_repr */
339 0, /* tp_as_number */
340 0, /* tp_as_sequence */
341 0, /* tp_as_mapping */
342 dbus_py_tp_hash_by_pointer, /* tp_hash */
343 0, /* tp_call */
344 0, /* tp_str */
345 0, /* tp_getattro */
346 0, /* tp_setattro */
347 0, /* tp_as_buffer */
348 Py_TPFLAGS_DEFAULT, /* tp_flags */
349 Timeout_tp_doc, /* tp_doc */
350 0, /* tp_traverse */
351 0, /* tp_clear */
352 dbus_py_tp_richcompare_by_pointer, /* tp_richcompare */
353 0, /* tp_weaklistoffset */
354 0, /* tp_iter */
355 0, /* tp_iternext */
356 Timeout_tp_methods, /* tp_methods */
357 0, /* tp_members */
358 0, /* tp_getset */
359 0, /* tp_base */
360 0, /* tp_dict */
361 0, /* tp_descr_get */
362 0, /* tp_descr_set */
363 0, /* tp_dictoffset */
364 0, /* tp_init */
365 0, /* tp_alloc */
366 /* deliberately not callable! */
367 0, /* tp_new */
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)
381 typedef struct {
382 PyObject_HEAD
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 *);
388 void *data;
389 } NativeMainLoop;
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 */
406 0, /* tp_print */
407 0, /* tp_getattr */
408 0, /* tp_setattr */
409 0, /* tp_compare */
410 0, /* tp_repr */
411 0, /* tp_as_number */
412 0, /* tp_as_sequence */
413 0, /* tp_as_mapping */
414 0, /* tp_hash */
415 0, /* tp_call */
416 0, /* tp_str */
417 0, /* tp_getattro */
418 0, /* tp_setattro */
419 0, /* tp_as_buffer */
420 Py_TPFLAGS_DEFAULT, /* tp_flags */
421 NativeMainLoop_tp_doc, /* tp_doc */
422 0, /* tp_traverse */
423 0, /* tp_clear */
424 0, /* tp_richcompare */
425 0, /* tp_weaklistoffset */
426 0, /* tp_iter */
427 0, /* tp_iternext */
428 0, /* tp_methods */
429 0, /* tp_members */
430 0, /* tp_getset */
431 0, /* tp_base */
432 0, /* tp_dict */
433 0, /* tp_descr_get */
434 0, /* tp_descr_set */
435 0, /* tp_dictoffset */
436 0, /* tp_init */
437 0, /* tp_alloc */
438 /* deliberately not callable! */
439 0, /* tp_new */
442 /* Internal C API for Connection, Bus, Server ======================= */
444 dbus_bool_t
445 dbus_py_check_mainloop_sanity(PyObject *mainloop)
447 if (NativeMainLoop_Check(mainloop)) {
448 return TRUE;
450 PyErr_SetString(PyExc_TypeError,
451 "A dbus.mainloop.NativeMainLoop instance is required");
452 return FALSE;
455 dbus_bool_t
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);
463 if (!dbc) {
464 return FALSE;
466 return (nml->set_up_connection_cb)(dbc, nml->data);
468 PyErr_SetString(PyExc_TypeError,
469 "A dbus.mainloop.NativeMainLoop instance is required");
470 return FALSE;
473 /* C API ============================================================ */
475 PyObject *
476 DBusPyNativeMainLoop_New4(dbus_bool_t (*conn_cb)(DBusConnection *, void *),
477 dbus_bool_t (*server_cb)(DBusServer *, void *),
478 void (*free_cb)(void *),
479 void *data)
481 NativeMainLoop *self = PyObject_New(NativeMainLoop, &NativeMainLoop_Type);
482 if (self) {
483 self->data = data;
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 ===================================== */
493 static dbus_bool_t
494 noop_main_loop_cb(void *conn_or_server UNUSED, void *data UNUSED)
496 return TRUE;
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 =================================================== */
504 dbus_bool_t
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;
515 return 1;
518 dbus_bool_t
519 dbus_py_insert_mainloop_types(PyObject *this_module)
521 PyObject *null_main_loop = DBusPyNativeMainLoop_New4(noop_conn_cb,
522 noop_server_cb,
523 NULL,
524 NULL);
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;
535 return 1;
538 /* vim:set ft=c cino< sw=4 sts=4 et: */