Remove from EXTRA_DIST files we'd already be distributing
[dbus-python-phuang.git] / _dbus_bindings / mainloop.c
blob6e40f36f055d5af2479a146093e04cee5f67bb72
1 /* Implementation of main-loop integration for dbus-python.
2  *
3  * Copyright (C) 2006 Collabora Ltd.
4  *
5  * Licensed under the Academic Free License version 2.1
6  *
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.
13  *
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.
18  *
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
22  *
23  */
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;
55     }
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;
74     }
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;
94     }
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;
114     }
115     if (!PyArg_ParseTuple(args, "i", &flags)) {
116         DBG("Python passed junk to <Watch at %p>.handle()", self);
117         return NULL;
118     }
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.
130  */
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;
142     }
144     self = PyObject_New(Watch, &Watch_Type);
145     if (!self) {
146         return NULL;
147     }
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))
175     0,
176     "_dbus_bindings.Watch",
177     sizeof(Watch),
178     0,
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;
243     }
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;
262     }
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;
279     }
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;
298     }
300     self = PyObject_New(Timeout, &Timeout_Type);
301     if (!self) {
302         return NULL;
303     }
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))
329     0,
330     "_dbus_bindings.Timeout",
331     sizeof(Timeout),
332     0,
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);
395     }
396     PyObject_Del((PyObject *)self);
399 static PyTypeObject NativeMainLoop_Type = {
400     PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type))
401     0,
402     "dbus.mainloop.NativeMainLoop",
403     sizeof(NativeMainLoop),
404     0,
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;
449     }
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;
465         }
466         return (nml->set_up_connection_cb)(dbc, nml->data);
467     }
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;
487     }
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: */