_dbus_bindings: split out conn, conn-methods into separate translation units
[dbus-python-phuang.git] / _dbus_bindings / mainloop-impl.h
blob924215452c7f7ef38b239e2e9e6fdde85fffc643
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 /* 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 WatchType;
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, &WatchType);
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 WatchType = {
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 Glue_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 Glue_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 TimeoutType;
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, &TimeoutType);
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 TimeoutType = {
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 Glue_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 Glue_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 NativeMainLoopType;
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 NativeMainLoopType = {
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 static dbus_bool_t
443 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 /* The main loop if none is passed to the constructor */
472 static PyObject *default_main_loop;
474 /* Return a new reference to the default main loop */
475 PyObject *
476 dbus_py_get_default_main_loop(void)
478 if (!default_main_loop) {
479 Py_RETURN_NONE;
481 Py_INCREF(default_main_loop);
482 return default_main_loop;
485 /* Python API ======================================================= */
487 PyDoc_STRVAR(get_default_main_loop__doc__,
488 "get_default_main_loop() -> object\n\n"
489 "Return the global default dbus-python main loop wrapper, which is used\n"
490 "when no main loop wrapper is passed to the Connection constructor.\n"
491 "\n"
492 "If None, there is no default and you must always pass the mainloop\n"
493 "parameter to the constructor. This will be the case until\n"
494 "set_default_main_loop is called.\n");
495 static PyObject *
496 get_default_main_loop(PyObject *always_null UNUSED,
497 PyObject *no_args UNUSED)
499 return dbus_py_get_default_main_loop();
502 PyDoc_STRVAR(set_default_main_loop__doc__,
503 "set_default_main_loop(object)\n\n"
504 "Change the global default dbus-python main loop wrapper, which is used\n"
505 "when no main loop wrapper is passed to the Connection constructor.\n"
506 "\n"
507 "If None, return to the initial situation: there is no default, and you\n"
508 "must always pass the mainloop parameter to the constructor.\n"
509 "\n"
510 "Two types of main loop wrapper are planned in dbus-python.\n"
511 "Native main-loop wrappers are instances of dbus.mainloop.NativeMainLoop\n"
512 "supplied by extension modules like `dbus.mainloop.glib`: they have no\n"
513 "Python API, but connect themselves to ``libdbus`` using native code.\n"
515 "Python main-loop wrappers are not yet implemented. They will be objects\n"
516 "supporting the interface defined by `dbus.mainloop.MainLoop`, with an\n"
517 "API entirely based on Python methods.\n"
518 "\n"
520 static PyObject *
521 set_default_main_loop(PyObject *always_null UNUSED,
522 PyObject *args)
524 PyObject *new_loop, *old_loop;
526 if (!PyArg_ParseTuple(args, "O", &new_loop)) {
527 return NULL;
529 if (!check_mainloop_sanity(new_loop)) {
530 return NULL;
532 old_loop = default_main_loop;
533 Py_INCREF(new_loop);
534 default_main_loop = new_loop;
535 Py_XDECREF(old_loop);
536 Py_RETURN_NONE;
539 /* C API ============================================================ */
541 PyObject *
542 DBusPyNativeMainLoop_New4(dbus_bool_t (*conn_cb)(DBusConnection *, void *),
543 dbus_bool_t (*server_cb)(DBusServer *, void *),
544 void (*free_cb)(void *),
545 void *data)
547 NativeMainLoop *self = PyObject_New(NativeMainLoop, &NativeMainLoopType);
548 if (self) {
549 self->data = data;
550 self->free_cb = free_cb;
551 self->set_up_connection_cb = conn_cb;
552 self->set_up_server_cb = server_cb;
554 return (PyObject *)self;
557 /* Null mainloop implementation ===================================== */
559 static dbus_bool_t
560 noop_main_loop_cb(void *conn_or_server UNUSED, void *data UNUSED)
562 return TRUE;
565 #define noop_conn_cb ((dbus_bool_t (*)(DBusConnection *, void *))(noop_main_loop_cb))
566 #define noop_server_cb ((dbus_bool_t (*)(DBusServer *, void *))(noop_main_loop_cb))
568 /* Initialization =================================================== */
570 static inline int
571 init_mainloop (void)
573 default_main_loop = NULL;
575 if (PyType_Ready (&WatchType) < 0) return 0;
576 if (PyType_Ready (&TimeoutType) < 0) return 0;
577 if (PyType_Ready (&NativeMainLoopType) < 0) return 0;
579 /* placate -Wunused */
580 (void)&Watch_BorrowFromDBusWatch;
581 (void)&Timeout_BorrowFromDBusTimeout;
583 return 1;
586 static inline int
587 insert_mainloop_types (PyObject *this_module)
589 PyObject *null_main_loop = DBusPyNativeMainLoop_New4(noop_conn_cb,
590 noop_server_cb,
591 NULL,
592 NULL);
593 if (!null_main_loop) return 0;
595 if (PyModule_AddObject (this_module, "Watch",
596 (PyObject *)&WatchType) < 0) return 0;
597 if (PyModule_AddObject (this_module, "Timeout",
598 (PyObject *)&TimeoutType) < 0) return 0;
599 if (PyModule_AddObject (this_module, "NativeMainLoop",
600 (PyObject *)&NativeMainLoopType) < 0) return 0;
601 if (PyModule_AddObject (this_module, "NULL_MAIN_LOOP",
602 null_main_loop) < 0) return 0;
603 return 1;
606 /* vim:set ft=c cino< sw=4 sts=4 et: */