.gitignore: ignore patch(1) cruft, and detached signatures for the release tarballs
[dbus-python-phuang.git] / _dbus_bindings / mainloop.c
blob7b94f13e572a5bd751580c6c2ce6e7a19c9aa88e
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 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include "config.h"
25 #include "dbus_bindings-internal.h"
27 #ifndef HAVE_DBUS_WATCH_GET_UNIX_FD
28 # define dbus_watch_get_unix_fd dbus_watch_get_fd
29 #endif
31 /* Watch ============================================================ */
33 PyDoc_STRVAR(Watch_tp_doc,
34 "Object representing a watched file descriptor.\n"
35 "Cannot be instantiated from Python.\n"
38 static PyTypeObject Watch_Type;
40 DEFINE_CHECK(Watch)
42 typedef struct {
43 PyObject_HEAD
44 DBusWatch *watch;
45 } Watch;
47 PyDoc_STRVAR(Watch_fileno__doc__,
48 "fileno() -> int\n\n"
49 "Return the watched file descriptor.\n");
50 static PyObject *
51 Watch_fileno(Watch *self, PyObject *unused UNUSED)
53 int fd;
55 if (!self->watch) {
56 DBG("Attempted fileno() on broken Watch at %p", self);
57 PyErr_SetString(PyExc_ValueError, "FD watch is no longer valid");
58 return NULL;
60 fd = dbus_watch_get_unix_fd(self->watch);
61 DBG("Watch at %p (wrapping DBusWatch at %p) has fileno %d", self,
62 self->watch, fd);
63 return PyInt_FromLong(fd);
66 PyDoc_STRVAR(Watch_get_flags__doc__,
67 "get_flags() -> int\n\n"
68 "Return 0, WATCH_READABLE, WATCH_WRITABLE or WATCH_READABLE|WATCH_WRITABLE.\n");
69 static PyObject *
70 Watch_get_flags(Watch *self, PyObject *unused UNUSED)
72 unsigned int flags;
74 if (!self->watch) {
75 DBG("Attempted get_flags() on broken Watch at %p", self);
76 PyErr_SetString(PyExc_ValueError, "FD watch is no longer valid");
77 return NULL;
79 flags = dbus_watch_get_flags(self->watch);
80 DBG("Watch at %p (wrapping DBusWatch at %p) has flags 0x%x (%s,%s)",
81 self, self->watch, flags, flags & DBUS_WATCH_READABLE ? "read" : ".",
82 flags & DBUS_WATCH_WRITABLE ? "write" : ".");
83 return PyInt_FromLong((long)flags);
86 PyDoc_STRVAR(Watch_get_enabled__doc__,
87 "get_enabled() -> bool\n\n"
88 "Return True if this watch is currently active.\n");
89 static PyObject *
90 Watch_get_enabled(Watch *self, PyObject *unused UNUSED)
92 dbus_bool_t enabled;
94 if (!self->watch) {
95 DBG("Attempted get_enabled() on broken Watch at %p", self);
96 PyErr_SetString(PyExc_ValueError, "FD watch is no longer valid");
97 return NULL;
99 enabled = dbus_watch_get_enabled(self->watch);
100 DBG("Watch at %p (wrapping DBusWatch at %p) is %s", self,
101 self->watch, enabled ? "enabled" : "disabled");
102 return PyBool_FromLong(enabled);
105 PyDoc_STRVAR(Watch_handle__doc__,
106 "handle(flags)\n\n"
107 "To be called when the file descriptor is closed or reports error,\n"
108 "or enters a readable/writable state for which notification is required\n"
109 "(according to get_flags()).");
110 static PyObject *
111 Watch_handle(Watch *self, PyObject *args)
113 unsigned int flags;
114 if (!self->watch) {
115 DBG("Attempted handle() on broken Watch at %p", self);
116 PyErr_SetString(PyExc_ValueError, "FD watch is no longer valid");
117 return NULL;
119 if (!PyArg_ParseTuple(args, "i", &flags)) {
120 DBG("Python passed junk to <Watch at %p>.handle()", self);
121 return NULL;
123 DBG("Watch at %p (wrapping DBusWatch at %p) handle(0x%x) (%s,%s)",
124 self, self->watch, flags, flags & DBUS_WATCH_READABLE ? "read" : ".",
125 flags & DBUS_WATCH_WRITABLE ? "write" : ".");
126 Py_BEGIN_ALLOW_THREADS
127 dbus_watch_handle(self->watch, (unsigned int)flags);
128 Py_END_ALLOW_THREADS
129 Py_RETURN_NONE;
132 /* Arranges for the watch to be referenced by its corresponding DBusWatch.
133 * Returns a borrowed reference, or NULL with a Python exception.
135 static PyObject *
136 Watch_BorrowFromDBusWatch(DBusWatch *watch, PyObject *mainloop)
138 Watch *self = (Watch *)dbus_watch_get_data(watch);
140 if (self)
141 return (PyObject *)self;
142 if (!mainloop) {
143 PyErr_SetString(PyExc_AssertionError,
144 "Attempted to use a non-added watch");
145 return NULL;
148 self = PyObject_New(Watch, &Watch_Type);
149 if (!self) {
150 return NULL;
152 self->watch = watch;
154 Py_INCREF(self);
155 dbus_watch_set_data(watch, self,
156 (DBusFreeFunction)dbus_py_take_gil_and_xdecref);
157 return (PyObject *)self;
160 static PyMethodDef Watch_tp_methods[] = {
161 {"fileno", (PyCFunction)Watch_fileno, METH_NOARGS,
162 Watch_fileno__doc__},
163 {"get_flags", (PyCFunction)Watch_get_flags, METH_NOARGS,
164 Watch_get_flags__doc__},
165 {"handle", (PyCFunction)Watch_handle, METH_VARARGS,
166 Watch_handle__doc__},
167 {"get_enabled", (PyCFunction)Watch_get_enabled, METH_NOARGS,
168 Watch_get_enabled__doc__},
169 {NULL, NULL, 0, NULL}
172 static void Watch_tp_dealloc(PyObject *self)
174 PyObject_Del(self);
177 static PyTypeObject Watch_Type = {
178 PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type))
180 "_dbus_bindings.Watch",
181 sizeof(Watch),
183 Watch_tp_dealloc, /* tp_dealloc */
184 0, /* tp_print */
185 0, /* tp_getattr */
186 0, /* tp_setattr */
187 0, /* tp_compare */
188 0, /* tp_repr */
189 0, /* tp_as_number */
190 0, /* tp_as_sequence */
191 0, /* tp_as_mapping */
192 dbus_py_tp_hash_by_pointer, /* tp_hash */
193 0, /* tp_call */
194 0, /* tp_str */
195 0, /* tp_getattro */
196 0, /* tp_setattro */
197 0, /* tp_as_buffer */
198 Py_TPFLAGS_DEFAULT, /* tp_flags */
199 Watch_tp_doc, /* tp_doc */
200 0, /* tp_traverse */
201 0, /* tp_clear */
202 dbus_py_tp_richcompare_by_pointer, /* tp_richcompare */
203 0, /* tp_weaklistoffset */
204 0, /* tp_iter */
205 0, /* tp_iternext */
206 Watch_tp_methods, /* tp_methods */
207 0, /* tp_members */
208 0, /* tp_getset */
209 0, /* tp_base */
210 0, /* tp_dict */
211 0, /* tp_descr_get */
212 0, /* tp_descr_set */
213 0, /* tp_dictoffset */
214 0, /* tp_init */
215 0, /* tp_alloc */
216 /* deliberately not callable! */
217 0, /* tp_new */
220 /* Timeout ========================================================== */
222 PyDoc_STRVAR(Timeout_tp_doc,
223 "Object representing a watched file descriptor.\n"
224 "Cannot be instantiated from Python.\n"
227 static PyTypeObject Timeout_Type;
229 DEFINE_CHECK(Timeout)
231 typedef struct {
232 PyObject_HEAD
233 DBusTimeout *timeout;
234 } Timeout;
236 PyDoc_STRVAR(Timeout_get_interval__doc__,
237 "get_interval() -> float\n\n"
238 "Return the interval in seconds.\n");
239 static PyObject *
240 Timeout_get_interval(Timeout *self, PyObject *unused UNUSED)
242 double interval;
243 if (!self->timeout) {
244 DBG("Attempted get_interval() on broken Timeout at %p", self);
245 PyErr_SetString(PyExc_ValueError, "Timeout object is no longer valid");
246 return NULL;
248 interval = ((double)dbus_timeout_get_interval(self->timeout)) / 1000.0;
249 DBG("Timeout at %p (wrapping DBusTimeout at %p) has interval %f s", self,
250 self->timeout, interval);
251 return PyFloat_FromDouble(interval);
254 PyDoc_STRVAR(Timeout_get_enabled__doc__,
255 "get_enabled() -> bool\n\n"
256 "Return True if this timeout is currently active.\n");
257 static PyObject *
258 Timeout_get_enabled(Timeout *self, PyObject *unused UNUSED)
260 dbus_bool_t enabled;
262 if (!self->timeout) {
263 DBG("Attempted get_enabled() on broken Timeout at %p", self);
264 PyErr_SetString(PyExc_ValueError, "Timeout object is no longer valid");
265 return NULL;
267 enabled = dbus_timeout_get_enabled(self->timeout);
268 DBG("Timeout at %p (wrapping DBusTimeout at %p) is %s", self,
269 self->timeout, enabled ? "enabled" : "disabled");
270 return PyBool_FromLong(enabled);
273 PyDoc_STRVAR(Timeout_handle__doc__,
274 "handle()\n\n"
275 "To be called when timeout occurs.\n");
276 static PyObject *
277 Timeout_handle(Timeout *self, PyObject *unused UNUSED)
279 if (!self->timeout) {
280 DBG("Attempted handle() on broken Timeout at %p", self);
281 PyErr_SetString(PyExc_ValueError, "Timeout object is no longer valid");
282 return NULL;
284 DBG("Timeout_handle() with self->timeout=%p", self->timeout);
285 Py_BEGIN_ALLOW_THREADS
286 dbus_timeout_handle(self->timeout);
287 Py_END_ALLOW_THREADS
288 Py_RETURN_NONE;
291 /* Returns a borrowed reference */
292 static PyObject *
293 Timeout_BorrowFromDBusTimeout(DBusTimeout *timeout, PyObject *mainloop)
295 Timeout *self = (Timeout *)dbus_timeout_get_data(timeout);
296 if (self)
297 return (PyObject *)self;
298 if (!mainloop) {
299 PyErr_SetString(PyExc_AssertionError,
300 "Attempted to use a non-added timeout");
301 return NULL;
304 self = PyObject_New(Timeout, &Timeout_Type);
305 if (!self) {
306 return NULL;
308 self->timeout = timeout;
310 Py_INCREF(self);
311 dbus_timeout_set_data(timeout, self,
312 (DBusFreeFunction)dbus_py_take_gil_and_xdecref);
313 return (PyObject *)self;
316 static PyMethodDef Timeout_tp_methods[] = {
317 {"get_interval", (PyCFunction)Timeout_get_interval, METH_NOARGS,
318 Timeout_get_interval__doc__},
319 {"handle", (PyCFunction)Timeout_handle, METH_NOARGS,
320 Timeout_handle__doc__},
321 {"get_enabled", (PyCFunction)Timeout_get_enabled, METH_NOARGS,
322 Timeout_get_enabled__doc__},
323 {NULL, NULL, 0, NULL}
326 static void Timeout_tp_dealloc(PyObject *self)
328 PyObject_Del(self);
331 static PyTypeObject Timeout_Type = {
332 PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type))
334 "_dbus_bindings.Timeout",
335 sizeof(Timeout),
337 Timeout_tp_dealloc, /* tp_dealloc */
338 0, /* tp_print */
339 0, /* tp_getattr */
340 0, /* tp_setattr */
341 0, /* tp_compare */
342 0, /* tp_repr */
343 0, /* tp_as_number */
344 0, /* tp_as_sequence */
345 0, /* tp_as_mapping */
346 dbus_py_tp_hash_by_pointer, /* tp_hash */
347 0, /* tp_call */
348 0, /* tp_str */
349 0, /* tp_getattro */
350 0, /* tp_setattro */
351 0, /* tp_as_buffer */
352 Py_TPFLAGS_DEFAULT, /* tp_flags */
353 Timeout_tp_doc, /* tp_doc */
354 0, /* tp_traverse */
355 0, /* tp_clear */
356 dbus_py_tp_richcompare_by_pointer, /* tp_richcompare */
357 0, /* tp_weaklistoffset */
358 0, /* tp_iter */
359 0, /* tp_iternext */
360 Timeout_tp_methods, /* tp_methods */
361 0, /* tp_members */
362 0, /* tp_getset */
363 0, /* tp_base */
364 0, /* tp_dict */
365 0, /* tp_descr_get */
366 0, /* tp_descr_set */
367 0, /* tp_dictoffset */
368 0, /* tp_init */
369 0, /* tp_alloc */
370 /* deliberately not callable! */
371 0, /* tp_new */
374 /* Native mainloop wrapper ========================================= */
376 PyDoc_STRVAR(NativeMainLoop_tp_doc,
377 "Object representing D-Bus main loop integration done in native code.\n"
378 "Cannot be instantiated directly.\n"
381 static PyTypeObject NativeMainLoop_Type;
383 DEFINE_CHECK(NativeMainLoop)
385 typedef struct {
386 PyObject_HEAD
387 /* Called with the GIL held, should set a Python exception on error */
388 dbus_bool_t (*set_up_connection_cb)(DBusConnection *, void *);
389 dbus_bool_t (*set_up_server_cb)(DBusServer *, void *);
390 /* Called in a destructor. Must not touch the exception state (use
391 * PyErr_Fetch and PyErr_Restore if necessary). */
392 void (*free_cb)(void *);
393 void *data;
394 } NativeMainLoop;
396 static void NativeMainLoop_tp_dealloc(NativeMainLoop *self)
398 if (self->data && self->free_cb) {
399 (self->free_cb)(self->data);
401 PyObject_Del((PyObject *)self);
404 static PyTypeObject NativeMainLoop_Type = {
405 PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type))
407 "dbus.mainloop.NativeMainLoop",
408 sizeof(NativeMainLoop),
410 (destructor)NativeMainLoop_tp_dealloc, /* tp_dealloc */
411 0, /* tp_print */
412 0, /* tp_getattr */
413 0, /* tp_setattr */
414 0, /* tp_compare */
415 0, /* tp_repr */
416 0, /* tp_as_number */
417 0, /* tp_as_sequence */
418 0, /* tp_as_mapping */
419 0, /* tp_hash */
420 0, /* tp_call */
421 0, /* tp_str */
422 0, /* tp_getattro */
423 0, /* tp_setattro */
424 0, /* tp_as_buffer */
425 Py_TPFLAGS_DEFAULT, /* tp_flags */
426 NativeMainLoop_tp_doc, /* tp_doc */
427 0, /* tp_traverse */
428 0, /* tp_clear */
429 0, /* tp_richcompare */
430 0, /* tp_weaklistoffset */
431 0, /* tp_iter */
432 0, /* tp_iternext */
433 0, /* tp_methods */
434 0, /* tp_members */
435 0, /* tp_getset */
436 0, /* tp_base */
437 0, /* tp_dict */
438 0, /* tp_descr_get */
439 0, /* tp_descr_set */
440 0, /* tp_dictoffset */
441 0, /* tp_init */
442 0, /* tp_alloc */
443 /* deliberately not callable! */
444 0, /* tp_new */
447 /* Internal C API for Connection, Bus, Server ======================= */
449 dbus_bool_t
450 dbus_py_check_mainloop_sanity(PyObject *mainloop)
452 if (NativeMainLoop_Check(mainloop)) {
453 return TRUE;
455 PyErr_SetString(PyExc_TypeError,
456 "A dbus.mainloop.NativeMainLoop instance is required");
457 return FALSE;
460 dbus_bool_t
461 dbus_py_set_up_connection(PyObject *conn, PyObject *mainloop)
463 if (NativeMainLoop_Check(mainloop)) {
464 /* Native mainloops are allowed to do arbitrary strange things */
465 NativeMainLoop *nml = (NativeMainLoop *)mainloop;
466 DBusConnection *dbc = DBusPyConnection_BorrowDBusConnection(conn);
468 if (!dbc) {
469 return FALSE;
471 return (nml->set_up_connection_cb)(dbc, nml->data);
473 PyErr_SetString(PyExc_TypeError,
474 "A dbus.mainloop.NativeMainLoop instance is required");
475 return FALSE;
478 /* C API ============================================================ */
480 PyObject *
481 DBusPyNativeMainLoop_New4(dbus_bool_t (*conn_cb)(DBusConnection *, void *),
482 dbus_bool_t (*server_cb)(DBusServer *, void *),
483 void (*free_cb)(void *),
484 void *data)
486 NativeMainLoop *self = PyObject_New(NativeMainLoop, &NativeMainLoop_Type);
487 if (self) {
488 self->data = data;
489 self->free_cb = free_cb;
490 self->set_up_connection_cb = conn_cb;
491 self->set_up_server_cb = server_cb;
493 return (PyObject *)self;
496 /* Null mainloop implementation ===================================== */
498 static dbus_bool_t
499 noop_main_loop_cb(void *conn_or_server UNUSED, void *data UNUSED)
501 return TRUE;
504 #define noop_conn_cb ((dbus_bool_t (*)(DBusConnection *, void *))(noop_main_loop_cb))
505 #define noop_server_cb ((dbus_bool_t (*)(DBusServer *, void *))(noop_main_loop_cb))
507 /* Initialization =================================================== */
509 dbus_bool_t
510 dbus_py_init_mainloop(void)
512 if (PyType_Ready (&Watch_Type) < 0) return 0;
513 if (PyType_Ready (&Timeout_Type) < 0) return 0;
514 if (PyType_Ready (&NativeMainLoop_Type) < 0) return 0;
516 /* placate -Wunused */
517 (void)&Watch_BorrowFromDBusWatch;
518 (void)&Timeout_BorrowFromDBusTimeout;
520 return 1;
523 dbus_bool_t
524 dbus_py_insert_mainloop_types(PyObject *this_module)
526 PyObject *null_main_loop = DBusPyNativeMainLoop_New4(noop_conn_cb,
527 noop_server_cb,
528 NULL,
529 NULL);
530 if (!null_main_loop) return 0;
532 if (PyModule_AddObject (this_module, "Watch",
533 (PyObject *)&Watch_Type) < 0) return 0;
534 if (PyModule_AddObject (this_module, "Timeout",
535 (PyObject *)&Timeout_Type) < 0) return 0;
536 if (PyModule_AddObject (this_module, "NativeMainLoop",
537 (PyObject *)&NativeMainLoop_Type) < 0) return 0;
538 if (PyModule_AddObject (this_module, "NULL_MAIN_LOOP",
539 null_main_loop) < 0) return 0;
540 return 1;
543 /* vim:set ft=c cino< sw=4 sts=4 et: */