dbus, _dbus_bindings, _dbus_glib_bindings: remove accidentally duplicated lines in...
[dbus-python-phuang.git] / _dbus_bindings / mainloop.c
blobed486ed6a7b4631818999c572e4822af953695b5
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 "dbus_bindings-internal.h"
25 /* Watch ============================================================ */
27 PyDoc_STRVAR(Watch_tp_doc,
28 "Object representing a watched file descriptor.\n"
29 "Cannot be instantiated from Python.\n"
32 static PyTypeObject Watch_Type;
34 DEFINE_CHECK(Watch)
36 typedef struct {
37 PyObject_HEAD
38 DBusWatch *watch;
39 } Watch;
41 PyDoc_STRVAR(Watch_fileno__doc__,
42 "fileno() -> int\n\n"
43 "Return the watched file descriptor.\n");
44 static PyObject *
45 Watch_fileno(Watch *self, PyObject *unused UNUSED)
47 int fd;
49 if (!self->watch) {
50 DBG("Attempted fileno() on broken Watch at %p", self);
51 PyErr_SetString(PyExc_ValueError, "FD watch is no longer valid");
52 return NULL;
54 fd = dbus_watch_get_fd(self->watch);
55 DBG("Watch at %p (wrapping DBusWatch at %p) has fileno %d", self,
56 self->watch, fd);
57 return PyInt_FromLong(fd);
60 PyDoc_STRVAR(Watch_get_flags__doc__,
61 "get_flags() -> int\n\n"
62 "Return 0, WATCH_READABLE, WATCH_WRITABLE or WATCH_READABLE|WATCH_WRITABLE.\n");
63 static PyObject *
64 Watch_get_flags(Watch *self, PyObject *unused UNUSED)
66 unsigned int flags;
68 if (!self->watch) {
69 DBG("Attempted get_flags() on broken Watch at %p", self);
70 PyErr_SetString(PyExc_ValueError, "FD watch is no longer valid");
71 return NULL;
73 flags = dbus_watch_get_flags(self->watch);
74 DBG("Watch at %p (wrapping DBusWatch at %p) has flags 0x%x (%s,%s)",
75 self, self->watch, flags, flags & DBUS_WATCH_READABLE ? "read" : ".",
76 flags & DBUS_WATCH_WRITABLE ? "write" : ".");
77 return PyInt_FromLong((long)flags);
80 PyDoc_STRVAR(Watch_get_enabled__doc__,
81 "get_enabled() -> bool\n\n"
82 "Return True if this watch is currently active.\n");
83 static PyObject *
84 Watch_get_enabled(Watch *self, PyObject *unused UNUSED)
86 dbus_bool_t enabled;
88 if (!self->watch) {
89 DBG("Attempted get_enabled() on broken Watch at %p", self);
90 PyErr_SetString(PyExc_ValueError, "FD watch is no longer valid");
91 return NULL;
93 enabled = dbus_watch_get_enabled(self->watch);
94 DBG("Watch at %p (wrapping DBusWatch at %p) is %s", self,
95 self->watch, enabled ? "enabled" : "disabled");
96 return PyBool_FromLong(enabled);
99 PyDoc_STRVAR(Watch_handle__doc__,
100 "handle(flags)\n\n"
101 "To be called when the file descriptor is closed or reports error,\n"
102 "or enters a readable/writable state for which notification is required\n"
103 "(according to get_flags()).");
104 static PyObject *
105 Watch_handle(Watch *self, PyObject *args)
107 unsigned int flags;
108 if (!self->watch) {
109 DBG("Attempted handle() on broken Watch at %p", self);
110 PyErr_SetString(PyExc_ValueError, "FD watch is no longer valid");
111 return NULL;
113 if (!PyArg_ParseTuple(args, "i", &flags)) {
114 DBG("Python passed junk to <Watch at %p>.handle()", self);
115 return NULL;
117 DBG("Watch at %p (wrapping DBusWatch at %p) handle(0x%x) (%s,%s)",
118 self, self->watch, flags, flags & DBUS_WATCH_READABLE ? "read" : ".",
119 flags & DBUS_WATCH_WRITABLE ? "write" : ".");
120 Py_BEGIN_ALLOW_THREADS
121 dbus_watch_handle(self->watch, (unsigned int)flags);
122 Py_END_ALLOW_THREADS
123 Py_RETURN_NONE;
126 /* Arranges for the watch to be referenced by its corresponding DBusWatch.
127 * Returns a borrowed reference, or NULL with a Python exception.
129 static PyObject *
130 Watch_BorrowFromDBusWatch(DBusWatch *watch, PyObject *mainloop)
132 Watch *self = (Watch *)dbus_watch_get_data(watch);
134 if (self)
135 return (PyObject *)self;
136 if (!mainloop) {
137 PyErr_SetString(PyExc_AssertionError,
138 "Attempted to use a non-added watch");
139 return NULL;
142 self = PyObject_New(Watch, &Watch_Type);
143 if (!self) {
144 return NULL;
146 self->watch = watch;
148 Py_INCREF(self);
149 dbus_watch_set_data(watch, self,
150 (DBusFreeFunction)dbus_py_take_gil_and_xdecref);
151 return (PyObject *)self;
154 static PyMethodDef Watch_tp_methods[] = {
155 {"fileno", (PyCFunction)Watch_fileno, METH_NOARGS,
156 Watch_fileno__doc__},
157 {"get_flags", (PyCFunction)Watch_get_flags, METH_NOARGS,
158 Watch_get_flags__doc__},
159 {"handle", (PyCFunction)Watch_handle, METH_VARARGS,
160 Watch_handle__doc__},
161 {"get_enabled", (PyCFunction)Watch_get_enabled, METH_NOARGS,
162 Watch_get_enabled__doc__},
163 {NULL, NULL, 0, NULL}
166 static void Watch_tp_dealloc(PyObject *self)
168 PyObject_Del(self);
171 static PyTypeObject Watch_Type = {
172 PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type))
174 "_dbus_bindings.Watch",
175 sizeof(Watch),
177 Watch_tp_dealloc, /* tp_dealloc */
178 0, /* tp_print */
179 0, /* tp_getattr */
180 0, /* tp_setattr */
181 0, /* tp_compare */
182 0, /* tp_repr */
183 0, /* tp_as_number */
184 0, /* tp_as_sequence */
185 0, /* tp_as_mapping */
186 dbus_py_tp_hash_by_pointer, /* tp_hash */
187 0, /* tp_call */
188 0, /* tp_str */
189 0, /* tp_getattro */
190 0, /* tp_setattro */
191 0, /* tp_as_buffer */
192 Py_TPFLAGS_DEFAULT, /* tp_flags */
193 Watch_tp_doc, /* tp_doc */
194 0, /* tp_traverse */
195 0, /* tp_clear */
196 dbus_py_tp_richcompare_by_pointer, /* tp_richcompare */
197 0, /* tp_weaklistoffset */
198 0, /* tp_iter */
199 0, /* tp_iternext */
200 Watch_tp_methods, /* tp_methods */
201 0, /* tp_members */
202 0, /* tp_getset */
203 0, /* tp_base */
204 0, /* tp_dict */
205 0, /* tp_descr_get */
206 0, /* tp_descr_set */
207 0, /* tp_dictoffset */
208 0, /* tp_init */
209 0, /* tp_alloc */
210 /* deliberately not callable! */
211 0, /* tp_new */
214 /* Timeout ========================================================== */
216 PyDoc_STRVAR(Timeout_tp_doc,
217 "Object representing a watched file descriptor.\n"
218 "Cannot be instantiated from Python.\n"
221 static PyTypeObject Timeout_Type;
223 DEFINE_CHECK(Timeout)
225 typedef struct {
226 PyObject_HEAD
227 DBusTimeout *timeout;
228 } Timeout;
230 PyDoc_STRVAR(Timeout_get_interval__doc__,
231 "get_interval() -> float\n\n"
232 "Return the interval in seconds.\n");
233 static PyObject *
234 Timeout_get_interval(Timeout *self, PyObject *unused UNUSED)
236 double interval;
237 if (!self->timeout) {
238 DBG("Attempted get_interval() on broken Timeout at %p", self);
239 PyErr_SetString(PyExc_ValueError, "Timeout object is no longer valid");
240 return NULL;
242 interval = ((double)dbus_timeout_get_interval(self->timeout)) / 1000.0;
243 DBG("Timeout at %p (wrapping DBusTimeout at %p) has interval %f s", self,
244 self->timeout, interval);
245 return PyFloat_FromDouble(interval);
248 PyDoc_STRVAR(Timeout_get_enabled__doc__,
249 "get_enabled() -> bool\n\n"
250 "Return True if this timeout is currently active.\n");
251 static PyObject *
252 Timeout_get_enabled(Timeout *self, PyObject *unused UNUSED)
254 dbus_bool_t enabled;
256 if (!self->timeout) {
257 DBG("Attempted get_enabled() on broken Timeout at %p", self);
258 PyErr_SetString(PyExc_ValueError, "Timeout object is no longer valid");
259 return NULL;
261 enabled = dbus_timeout_get_enabled(self->timeout);
262 DBG("Timeout at %p (wrapping DBusTimeout at %p) is %s", self,
263 self->timeout, enabled ? "enabled" : "disabled");
264 return PyBool_FromLong(enabled);
267 PyDoc_STRVAR(Timeout_handle__doc__,
268 "handle()\n\n"
269 "To be called when timeout occurs.\n");
270 static PyObject *
271 Timeout_handle(Timeout *self, PyObject *unused UNUSED)
273 if (!self->timeout) {
274 DBG("Attempted handle() on broken Timeout at %p", self);
275 PyErr_SetString(PyExc_ValueError, "Timeout object is no longer valid");
276 return NULL;
278 DBG("Timeout_handle() with self->timeout=%p", self->timeout);
279 Py_BEGIN_ALLOW_THREADS
280 dbus_timeout_handle(self->timeout);
281 Py_END_ALLOW_THREADS
282 Py_RETURN_NONE;
285 /* Returns a borrowed reference */
286 static PyObject *
287 Timeout_BorrowFromDBusTimeout(DBusTimeout *timeout, PyObject *mainloop)
289 Timeout *self = (Timeout *)dbus_timeout_get_data(timeout);
290 if (self)
291 return (PyObject *)self;
292 if (!mainloop) {
293 PyErr_SetString(PyExc_AssertionError,
294 "Attempted to use a non-added timeout");
295 return NULL;
298 self = PyObject_New(Timeout, &Timeout_Type);
299 if (!self) {
300 return NULL;
302 self->timeout = timeout;
304 Py_INCREF(self);
305 dbus_timeout_set_data(timeout, self,
306 (DBusFreeFunction)dbus_py_take_gil_and_xdecref);
307 return (PyObject *)self;
310 static PyMethodDef Timeout_tp_methods[] = {
311 {"get_interval", (PyCFunction)Timeout_get_interval, METH_NOARGS,
312 Timeout_get_interval__doc__},
313 {"handle", (PyCFunction)Timeout_handle, METH_NOARGS,
314 Timeout_handle__doc__},
315 {"get_enabled", (PyCFunction)Timeout_get_enabled, METH_NOARGS,
316 Timeout_get_enabled__doc__},
317 {NULL, NULL, 0, NULL}
320 static void Timeout_tp_dealloc(PyObject *self)
322 PyObject_Del(self);
325 static PyTypeObject Timeout_Type = {
326 PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type))
328 "_dbus_bindings.Timeout",
329 sizeof(Timeout),
331 Timeout_tp_dealloc, /* tp_dealloc */
332 0, /* tp_print */
333 0, /* tp_getattr */
334 0, /* tp_setattr */
335 0, /* tp_compare */
336 0, /* tp_repr */
337 0, /* tp_as_number */
338 0, /* tp_as_sequence */
339 0, /* tp_as_mapping */
340 dbus_py_tp_hash_by_pointer, /* tp_hash */
341 0, /* tp_call */
342 0, /* tp_str */
343 0, /* tp_getattro */
344 0, /* tp_setattro */
345 0, /* tp_as_buffer */
346 Py_TPFLAGS_DEFAULT, /* tp_flags */
347 Timeout_tp_doc, /* tp_doc */
348 0, /* tp_traverse */
349 0, /* tp_clear */
350 dbus_py_tp_richcompare_by_pointer, /* tp_richcompare */
351 0, /* tp_weaklistoffset */
352 0, /* tp_iter */
353 0, /* tp_iternext */
354 Timeout_tp_methods, /* tp_methods */
355 0, /* tp_members */
356 0, /* tp_getset */
357 0, /* tp_base */
358 0, /* tp_dict */
359 0, /* tp_descr_get */
360 0, /* tp_descr_set */
361 0, /* tp_dictoffset */
362 0, /* tp_init */
363 0, /* tp_alloc */
364 /* deliberately not callable! */
365 0, /* tp_new */
368 /* Native mainloop wrapper ========================================= */
370 PyDoc_STRVAR(NativeMainLoop_tp_doc,
371 "Object representing D-Bus main loop integration done in native code.\n"
372 "Cannot be instantiated directly.\n"
375 static PyTypeObject NativeMainLoop_Type;
377 DEFINE_CHECK(NativeMainLoop)
379 typedef struct {
380 PyObject_HEAD
381 /* Called with the GIL held, should set a Python exception on error */
382 dbus_bool_t (*set_up_connection_cb)(DBusConnection *, void *);
383 dbus_bool_t (*set_up_server_cb)(DBusServer *, void *);
384 /* Called in a destructor. */
385 void (*free_cb)(void *);
386 void *data;
387 } NativeMainLoop;
389 static void NativeMainLoop_tp_dealloc(NativeMainLoop *self)
391 if (self->data && self->free_cb) {
392 (self->free_cb)(self->data);
394 PyObject_Del((PyObject *)self);
397 static PyTypeObject NativeMainLoop_Type = {
398 PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type))
400 "dbus.mainloop.NativeMainLoop",
401 sizeof(NativeMainLoop),
403 (destructor)NativeMainLoop_tp_dealloc, /* tp_dealloc */
404 0, /* tp_print */
405 0, /* tp_getattr */
406 0, /* tp_setattr */
407 0, /* tp_compare */
408 0, /* tp_repr */
409 0, /* tp_as_number */
410 0, /* tp_as_sequence */
411 0, /* tp_as_mapping */
412 0, /* tp_hash */
413 0, /* tp_call */
414 0, /* tp_str */
415 0, /* tp_getattro */
416 0, /* tp_setattro */
417 0, /* tp_as_buffer */
418 Py_TPFLAGS_DEFAULT, /* tp_flags */
419 NativeMainLoop_tp_doc, /* tp_doc */
420 0, /* tp_traverse */
421 0, /* tp_clear */
422 0, /* tp_richcompare */
423 0, /* tp_weaklistoffset */
424 0, /* tp_iter */
425 0, /* tp_iternext */
426 0, /* tp_methods */
427 0, /* tp_members */
428 0, /* tp_getset */
429 0, /* tp_base */
430 0, /* tp_dict */
431 0, /* tp_descr_get */
432 0, /* tp_descr_set */
433 0, /* tp_dictoffset */
434 0, /* tp_init */
435 0, /* tp_alloc */
436 /* deliberately not callable! */
437 0, /* tp_new */
440 /* Internal C API for Connection, Bus, Server ======================= */
442 dbus_bool_t
443 dbus_py_check_mainloop_sanity(PyObject *mainloop)
445 if (NativeMainLoop_Check(mainloop)) {
446 return TRUE;
448 PyErr_SetString(PyExc_TypeError,
449 "A dbus.mainloop.NativeMainLoop instance is required");
450 return FALSE;
453 dbus_bool_t
454 dbus_py_set_up_connection(PyObject *conn, PyObject *mainloop)
456 if (NativeMainLoop_Check(mainloop)) {
457 /* Native mainloops are allowed to do arbitrary strange things */
458 NativeMainLoop *nml = (NativeMainLoop *)mainloop;
459 DBusConnection *dbc = DBusPyConnection_BorrowDBusConnection(conn);
461 if (!dbc) {
462 return FALSE;
464 return (nml->set_up_connection_cb)(dbc, nml->data);
466 PyErr_SetString(PyExc_TypeError,
467 "A dbus.mainloop.NativeMainLoop instance is required");
468 return FALSE;
471 /* C API ============================================================ */
473 PyObject *
474 DBusPyNativeMainLoop_New4(dbus_bool_t (*conn_cb)(DBusConnection *, void *),
475 dbus_bool_t (*server_cb)(DBusServer *, void *),
476 void (*free_cb)(void *),
477 void *data)
479 NativeMainLoop *self = PyObject_New(NativeMainLoop, &NativeMainLoop_Type);
480 if (self) {
481 self->data = data;
482 self->free_cb = free_cb;
483 self->set_up_connection_cb = conn_cb;
484 self->set_up_server_cb = server_cb;
486 return (PyObject *)self;
489 /* Null mainloop implementation ===================================== */
491 static dbus_bool_t
492 noop_main_loop_cb(void *conn_or_server UNUSED, void *data UNUSED)
494 return TRUE;
497 #define noop_conn_cb ((dbus_bool_t (*)(DBusConnection *, void *))(noop_main_loop_cb))
498 #define noop_server_cb ((dbus_bool_t (*)(DBusServer *, void *))(noop_main_loop_cb))
500 /* Initialization =================================================== */
502 dbus_bool_t
503 dbus_py_init_mainloop(void)
505 if (PyType_Ready (&Watch_Type) < 0) return 0;
506 if (PyType_Ready (&Timeout_Type) < 0) return 0;
507 if (PyType_Ready (&NativeMainLoop_Type) < 0) return 0;
509 /* placate -Wunused */
510 (void)&Watch_BorrowFromDBusWatch;
511 (void)&Timeout_BorrowFromDBusTimeout;
513 return 1;
516 dbus_bool_t
517 dbus_py_insert_mainloop_types(PyObject *this_module)
519 PyObject *null_main_loop = DBusPyNativeMainLoop_New4(noop_conn_cb,
520 noop_server_cb,
521 NULL,
522 NULL);
523 if (!null_main_loop) return 0;
525 if (PyModule_AddObject (this_module, "Watch",
526 (PyObject *)&Watch_Type) < 0) return 0;
527 if (PyModule_AddObject (this_module, "Timeout",
528 (PyObject *)&Timeout_Type) < 0) return 0;
529 if (PyModule_AddObject (this_module, "NativeMainLoop",
530 (PyObject *)&NativeMainLoop_Type) < 0) return 0;
531 if (PyModule_AddObject (this_module, "NULL_MAIN_LOOP",
532 null_main_loop) < 0) return 0;
533 return 1;
536 /* vim:set ft=c cino< sw=4 sts=4 et: */