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
;
41 PyDoc_STRVAR(Watch_fileno__doc__
,
43 "Return the watched file descriptor.\n");
45 Watch_fileno(Watch
*self
, PyObject
*unused UNUSED
)
50 DBG("Attempted fileno() on broken Watch at %p", self
);
51 PyErr_SetString(PyExc_ValueError
, "FD watch is no longer valid");
54 fd
= dbus_watch_get_fd(self
->watch
);
55 DBG("Watch at %p (wrapping DBusWatch at %p) has fileno %d", self
,
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");
64 Watch_get_flags(Watch
*self
, PyObject
*unused UNUSED
)
69 DBG("Attempted get_flags() on broken Watch at %p", self
);
70 PyErr_SetString(PyExc_ValueError
, "FD watch is no longer valid");
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");
84 Watch_get_enabled(Watch
*self
, PyObject
*unused UNUSED
)
89 DBG("Attempted get_enabled() on broken Watch at %p", self
);
90 PyErr_SetString(PyExc_ValueError
, "FD watch is no longer valid");
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__
,
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()).");
105 Watch_handle(Watch
*self
, PyObject
*args
)
109 DBG("Attempted handle() on broken Watch at %p", self
);
110 PyErr_SetString(PyExc_ValueError
, "FD watch is no longer valid");
113 if (!PyArg_ParseTuple(args
, "i", &flags
)) {
114 DBG("Python passed junk to <Watch at %p>.handle()", self
);
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
);
126 /* Arranges for the watch to be referenced by its corresponding DBusWatch.
127 * Returns a borrowed reference, or NULL with a Python exception.
130 Watch_BorrowFromDBusWatch(DBusWatch
*watch
, PyObject
*mainloop
)
132 Watch
*self
= (Watch
*)dbus_watch_get_data(watch
);
135 return (PyObject
*)self
;
137 PyErr_SetString(PyExc_AssertionError
,
138 "Attempted to use a non-added watch");
142 self
= PyObject_New(Watch
, &Watch_Type
);
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
)
171 static PyTypeObject Watch_Type
= {
172 PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type
))
174 "_dbus_bindings.Watch",
177 Watch_tp_dealloc
, /* tp_dealloc */
183 0, /* tp_as_number */
184 0, /* tp_as_sequence */
185 0, /* tp_as_mapping */
186 dbus_py_tp_hash_by_pointer
, /* tp_hash */
191 0, /* tp_as_buffer */
192 Py_TPFLAGS_DEFAULT
, /* tp_flags */
193 Watch_tp_doc
, /* tp_doc */
196 dbus_py_tp_richcompare_by_pointer
, /* tp_richcompare */
197 0, /* tp_weaklistoffset */
200 Watch_tp_methods
, /* tp_methods */
205 0, /* tp_descr_get */
206 0, /* tp_descr_set */
207 0, /* tp_dictoffset */
210 /* deliberately not callable! */
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
)
227 DBusTimeout
*timeout
;
230 PyDoc_STRVAR(Timeout_get_interval__doc__
,
231 "get_interval() -> float\n\n"
232 "Return the interval in seconds.\n");
234 Timeout_get_interval(Timeout
*self
, PyObject
*unused UNUSED
)
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");
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");
252 Timeout_get_enabled(Timeout
*self
, PyObject
*unused UNUSED
)
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");
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__
,
269 "To be called when timeout occurs.\n");
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");
278 DBG("Timeout_handle() with self->timeout=%p", self
->timeout
);
279 Py_BEGIN_ALLOW_THREADS
280 dbus_timeout_handle(self
->timeout
);
285 /* Returns a borrowed reference */
287 Timeout_BorrowFromDBusTimeout(DBusTimeout
*timeout
, PyObject
*mainloop
)
289 Timeout
*self
= (Timeout
*)dbus_timeout_get_data(timeout
);
291 return (PyObject
*)self
;
293 PyErr_SetString(PyExc_AssertionError
,
294 "Attempted to use a non-added timeout");
298 self
= PyObject_New(Timeout
, &Timeout_Type
);
302 self
->timeout
= timeout
;
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
)
325 static PyTypeObject Timeout_Type
= {
326 PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type
))
328 "_dbus_bindings.Timeout",
331 Timeout_tp_dealloc
, /* tp_dealloc */
337 0, /* tp_as_number */
338 0, /* tp_as_sequence */
339 0, /* tp_as_mapping */
340 dbus_py_tp_hash_by_pointer
, /* tp_hash */
345 0, /* tp_as_buffer */
346 Py_TPFLAGS_DEFAULT
, /* tp_flags */
347 Timeout_tp_doc
, /* tp_doc */
350 dbus_py_tp_richcompare_by_pointer
, /* tp_richcompare */
351 0, /* tp_weaklistoffset */
354 Timeout_tp_methods
, /* tp_methods */
359 0, /* tp_descr_get */
360 0, /* tp_descr_set */
361 0, /* tp_dictoffset */
364 /* deliberately not callable! */
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
)
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. Must not touch the exception state (use
385 * PyErr_Fetch and PyErr_Restore if necessary). */
386 void (*free_cb
)(void *);
390 static void NativeMainLoop_tp_dealloc(NativeMainLoop
*self
)
392 if (self
->data
&& self
->free_cb
) {
393 (self
->free_cb
)(self
->data
);
395 PyObject_Del((PyObject
*)self
);
398 static PyTypeObject NativeMainLoop_Type
= {
399 PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type
))
401 "dbus.mainloop.NativeMainLoop",
402 sizeof(NativeMainLoop
),
404 (destructor
)NativeMainLoop_tp_dealloc
, /* tp_dealloc */
410 0, /* tp_as_number */
411 0, /* tp_as_sequence */
412 0, /* tp_as_mapping */
418 0, /* tp_as_buffer */
419 Py_TPFLAGS_DEFAULT
, /* tp_flags */
420 NativeMainLoop_tp_doc
, /* tp_doc */
423 0, /* tp_richcompare */
424 0, /* tp_weaklistoffset */
432 0, /* tp_descr_get */
433 0, /* tp_descr_set */
434 0, /* tp_dictoffset */
437 /* deliberately not callable! */
441 /* Internal C API for Connection, Bus, Server ======================= */
444 dbus_py_check_mainloop_sanity(PyObject
*mainloop
)
446 if (NativeMainLoop_Check(mainloop
)) {
449 PyErr_SetString(PyExc_TypeError
,
450 "A dbus.mainloop.NativeMainLoop instance is required");
455 dbus_py_set_up_connection(PyObject
*conn
, PyObject
*mainloop
)
457 if (NativeMainLoop_Check(mainloop
)) {
458 /* Native mainloops are allowed to do arbitrary strange things */
459 NativeMainLoop
*nml
= (NativeMainLoop
*)mainloop
;
460 DBusConnection
*dbc
= DBusPyConnection_BorrowDBusConnection(conn
);
465 return (nml
->set_up_connection_cb
)(dbc
, nml
->data
);
467 PyErr_SetString(PyExc_TypeError
,
468 "A dbus.mainloop.NativeMainLoop instance is required");
472 /* C API ============================================================ */
475 DBusPyNativeMainLoop_New4(dbus_bool_t (*conn_cb
)(DBusConnection
*, void *),
476 dbus_bool_t (*server_cb
)(DBusServer
*, void *),
477 void (*free_cb
)(void *),
480 NativeMainLoop
*self
= PyObject_New(NativeMainLoop
, &NativeMainLoop_Type
);
483 self
->free_cb
= free_cb
;
484 self
->set_up_connection_cb
= conn_cb
;
485 self
->set_up_server_cb
= server_cb
;
487 return (PyObject
*)self
;
490 /* Null mainloop implementation ===================================== */
493 noop_main_loop_cb(void *conn_or_server UNUSED
, void *data UNUSED
)
498 #define noop_conn_cb ((dbus_bool_t (*)(DBusConnection *, void *))(noop_main_loop_cb))
499 #define noop_server_cb ((dbus_bool_t (*)(DBusServer *, void *))(noop_main_loop_cb))
501 /* Initialization =================================================== */
504 dbus_py_init_mainloop(void)
506 if (PyType_Ready (&Watch_Type
) < 0) return 0;
507 if (PyType_Ready (&Timeout_Type
) < 0) return 0;
508 if (PyType_Ready (&NativeMainLoop_Type
) < 0) return 0;
510 /* placate -Wunused */
511 (void)&Watch_BorrowFromDBusWatch
;
512 (void)&Timeout_BorrowFromDBusTimeout
;
518 dbus_py_insert_mainloop_types(PyObject
*this_module
)
520 PyObject
*null_main_loop
= DBusPyNativeMainLoop_New4(noop_conn_cb
,
524 if (!null_main_loop
) return 0;
526 if (PyModule_AddObject (this_module
, "Watch",
527 (PyObject
*)&Watch_Type
) < 0) return 0;
528 if (PyModule_AddObject (this_module
, "Timeout",
529 (PyObject
*)&Timeout_Type
) < 0) return 0;
530 if (PyModule_AddObject (this_module
, "NativeMainLoop",
531 (PyObject
*)&NativeMainLoop_Type
) < 0) return 0;
532 if (PyModule_AddObject (this_module
, "NULL_MAIN_LOOP",
533 null_main_loop
) < 0) return 0;
537 /* vim:set ft=c cino< sw=4 sts=4 et: */