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
;
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
, &WatchType
);
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 WatchType
= {
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 Glue_tp_hash_by_pointer
, /* tp_hash */
191 0, /* tp_as_buffer */
192 Py_TPFLAGS_DEFAULT
, /* tp_flags */
193 Watch_tp_doc
, /* tp_doc */
196 Glue_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 TimeoutType
;
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
, &TimeoutType
);
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 TimeoutType
= {
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 Glue_tp_hash_by_pointer
, /* tp_hash */
345 0, /* tp_as_buffer */
346 Py_TPFLAGS_DEFAULT
, /* tp_flags */
347 Timeout_tp_doc
, /* tp_doc */
350 Glue_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 NativeMainLoopType
;
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. */
385 void (*free_cb
)(void *);
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 */
409 0, /* tp_as_number */
410 0, /* tp_as_sequence */
411 0, /* tp_as_mapping */
417 0, /* tp_as_buffer */
418 Py_TPFLAGS_DEFAULT
, /* tp_flags */
419 NativeMainLoop_tp_doc
, /* tp_doc */
422 0, /* tp_richcompare */
423 0, /* tp_weaklistoffset */
431 0, /* tp_descr_get */
432 0, /* tp_descr_set */
433 0, /* tp_dictoffset */
436 /* deliberately not callable! */
440 /* Internal C API for Connection, Bus, Server ======================= */
443 check_mainloop_sanity(PyObject
*mainloop
)
445 if (NativeMainLoop_Check(mainloop
)) {
448 PyErr_SetString(PyExc_TypeError
,
449 "A dbus.mainloop.NativeMainLoop instance is required");
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
);
464 return (nml
->set_up_connection_cb
)(dbc
, nml
->data
);
466 PyErr_SetString(PyExc_TypeError
,
467 "A dbus.mainloop.NativeMainLoop instance is required");
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 */
476 dbus_py_get_default_main_loop(void)
478 if (!default_main_loop
) {
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"
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");
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"
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"
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"
521 set_default_main_loop(PyObject
*always_null UNUSED
,
524 PyObject
*new_loop
, *old_loop
;
526 if (!PyArg_ParseTuple(args
, "O", &new_loop
)) {
529 if (!check_mainloop_sanity(new_loop
)) {
532 old_loop
= default_main_loop
;
534 default_main_loop
= new_loop
;
535 Py_XDECREF(old_loop
);
539 /* C API ============================================================ */
542 DBusPyNativeMainLoop_New4(dbus_bool_t (*conn_cb
)(DBusConnection
*, void *),
543 dbus_bool_t (*server_cb
)(DBusServer
*, void *),
544 void (*free_cb
)(void *),
547 NativeMainLoop
*self
= PyObject_New(NativeMainLoop
, &NativeMainLoopType
);
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 ===================================== */
560 noop_main_loop_cb(void *conn_or_server UNUSED
, void *data UNUSED
)
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 =================================================== */
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
;
587 insert_mainloop_types (PyObject
*this_module
)
589 PyObject
*null_main_loop
= DBusPyNativeMainLoop_New4(noop_conn_cb
,
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;
606 /* vim:set ft=c cino< sw=4 sts=4 et: */