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
;
43 PyDoc_STRVAR(Watch_fileno__doc__
,
45 "Return the watched file descriptor.\n");
47 Watch_fileno(Watch
*self
, PyObject
*unused UNUSED
)
52 DBG("Attempted fileno() on broken Watch at %p", self
);
53 PyErr_SetString(PyExc_ValueError
, "FD watch is no longer valid");
56 fd
= dbus_watch_get_fd(self
->watch
);
57 DBG("Watch at %p (wrapping DBusWatch at %p) has fileno %d", self
,
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");
66 Watch_get_flags(Watch
*self
, PyObject
*unused UNUSED
)
71 DBG("Attempted get_flags() on broken Watch at %p", self
);
72 PyErr_SetString(PyExc_ValueError
, "FD watch is no longer valid");
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");
86 Watch_get_enabled(Watch
*self
, PyObject
*unused UNUSED
)
91 DBG("Attempted get_enabled() on broken Watch at %p", self
);
92 PyErr_SetString(PyExc_ValueError
, "FD watch is no longer valid");
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__
,
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()).");
107 Watch_handle(Watch
*self
, PyObject
*args
)
111 DBG("Attempted handle() on broken Watch at %p", self
);
112 PyErr_SetString(PyExc_ValueError
, "FD watch is no longer valid");
115 if (!PyArg_ParseTuple(args
, "i", &flags
)) {
116 DBG("Python passed junk to <Watch at %p>.handle()", self
);
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
);
128 /* Arranges for the watch to be referenced by its corresponding DBusWatch.
129 * Returns a borrowed reference, or NULL with a Python exception.
132 Watch_BorrowFromDBusWatch(DBusWatch
*watch
, PyObject
*mainloop
)
134 Watch
*self
= (Watch
*)dbus_watch_get_data(watch
);
137 return (PyObject
*)self
;
139 PyErr_SetString(PyExc_AssertionError
,
140 "Attempted to use a non-added watch");
144 self
= PyObject_New(Watch
, &Watch_Type
);
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
)
173 static PyTypeObject Watch_Type
= {
174 PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type
))
176 "_dbus_bindings.Watch",
179 Watch_tp_dealloc
, /* tp_dealloc */
185 0, /* tp_as_number */
186 0, /* tp_as_sequence */
187 0, /* tp_as_mapping */
188 dbus_py_tp_hash_by_pointer
, /* tp_hash */
193 0, /* tp_as_buffer */
194 Py_TPFLAGS_DEFAULT
, /* tp_flags */
195 Watch_tp_doc
, /* tp_doc */
198 dbus_py_tp_richcompare_by_pointer
, /* tp_richcompare */
199 0, /* tp_weaklistoffset */
202 Watch_tp_methods
, /* tp_methods */
207 0, /* tp_descr_get */
208 0, /* tp_descr_set */
209 0, /* tp_dictoffset */
212 /* deliberately not callable! */
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
)
229 DBusTimeout
*timeout
;
232 PyDoc_STRVAR(Timeout_get_interval__doc__
,
233 "get_interval() -> float\n\n"
234 "Return the interval in seconds.\n");
236 Timeout_get_interval(Timeout
*self
, PyObject
*unused UNUSED
)
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");
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");
254 Timeout_get_enabled(Timeout
*self
, PyObject
*unused UNUSED
)
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");
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__
,
271 "To be called when timeout occurs.\n");
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");
280 DBG("Timeout_handle() with self->timeout=%p", self
->timeout
);
281 Py_BEGIN_ALLOW_THREADS
282 dbus_timeout_handle(self
->timeout
);
287 /* Returns a borrowed reference */
289 Timeout_BorrowFromDBusTimeout(DBusTimeout
*timeout
, PyObject
*mainloop
)
291 Timeout
*self
= (Timeout
*)dbus_timeout_get_data(timeout
);
293 return (PyObject
*)self
;
295 PyErr_SetString(PyExc_AssertionError
,
296 "Attempted to use a non-added timeout");
300 self
= PyObject_New(Timeout
, &Timeout_Type
);
304 self
->timeout
= timeout
;
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
)
327 static PyTypeObject Timeout_Type
= {
328 PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type
))
330 "_dbus_bindings.Timeout",
333 Timeout_tp_dealloc
, /* tp_dealloc */
339 0, /* tp_as_number */
340 0, /* tp_as_sequence */
341 0, /* tp_as_mapping */
342 dbus_py_tp_hash_by_pointer
, /* tp_hash */
347 0, /* tp_as_buffer */
348 Py_TPFLAGS_DEFAULT
, /* tp_flags */
349 Timeout_tp_doc
, /* tp_doc */
352 dbus_py_tp_richcompare_by_pointer
, /* tp_richcompare */
353 0, /* tp_weaklistoffset */
356 Timeout_tp_methods
, /* tp_methods */
361 0, /* tp_descr_get */
362 0, /* tp_descr_set */
363 0, /* tp_dictoffset */
366 /* deliberately not callable! */
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
)
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 *);
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 */
411 0, /* tp_as_number */
412 0, /* tp_as_sequence */
413 0, /* tp_as_mapping */
419 0, /* tp_as_buffer */
420 Py_TPFLAGS_DEFAULT
, /* tp_flags */
421 NativeMainLoop_tp_doc
, /* tp_doc */
424 0, /* tp_richcompare */
425 0, /* tp_weaklistoffset */
433 0, /* tp_descr_get */
434 0, /* tp_descr_set */
435 0, /* tp_dictoffset */
438 /* deliberately not callable! */
442 /* Internal C API for Connection, Bus, Server ======================= */
445 dbus_py_check_mainloop_sanity(PyObject
*mainloop
)
447 if (NativeMainLoop_Check(mainloop
)) {
450 PyErr_SetString(PyExc_TypeError
,
451 "A dbus.mainloop.NativeMainLoop instance is required");
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
);
466 return (nml
->set_up_connection_cb
)(dbc
, nml
->data
);
468 PyErr_SetString(PyExc_TypeError
,
469 "A dbus.mainloop.NativeMainLoop instance is required");
473 /* C API ============================================================ */
476 DBusPyNativeMainLoop_New4(dbus_bool_t (*conn_cb
)(DBusConnection
*, void *),
477 dbus_bool_t (*server_cb
)(DBusServer
*, void *),
478 void (*free_cb
)(void *),
481 NativeMainLoop
*self
= PyObject_New(NativeMainLoop
, &NativeMainLoop_Type
);
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 ===================================== */
494 noop_main_loop_cb(void *conn_or_server UNUSED
, void *data UNUSED
)
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 =================================================== */
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
;
519 dbus_py_insert_mainloop_types(PyObject
*this_module
)
521 PyObject
*null_main_loop
= DBusPyNativeMainLoop_New4(noop_conn_cb
,
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;
538 /* vim:set ft=c cino< sw=4 sts=4 et: */