1 /* Implementation of the _dbus_bindings Connection type, a Python wrapper
2 * for DBusConnection. See also conn-methods-impl.h.
4 * Copyright (C) 2006 Collabora Ltd. <http://www.collabora.co.uk/>
6 * Licensed under the Academic Free License version 2.1
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 #include "dbus_bindings-internal.h"
27 #include "conn-internal.h"
29 /* Connection definition ============================================ */
31 PyDoc_STRVAR(Connection_tp_doc
,
32 "A D-Bus connection.\n\n"
33 "Connection(address: str, mainloop=None) -> Connection\n"
36 /* D-Bus Connection user data slot, containing an owned reference to either
37 * the Connection, or a weakref to the Connection.
39 static dbus_int32_t _connection_python_slot
;
41 /* C API for main-loop hooks ======================================== */
43 /* Return a borrowed reference to the DBusConnection which underlies this
46 DBusPyConnection_BorrowDBusConnection(PyObject
*self
)
50 if (!DBusPyConnection_Check(self
)) {
51 PyErr_SetString(PyExc_TypeError
, "A dbus.Connection is required");
54 dbc
= ((Connection
*)self
)->conn
;
56 PyErr_SetString(PyExc_RuntimeError
, "Connection is in an invalid "
57 "state: no DBusConnection");
63 /* Internal C API =================================================== */
65 /* Pass a message through a handler. */
67 DBusPyConnection_HandleMessage(Connection
*conn
,
71 PyObject
*obj
= PyObject_CallFunctionObjArgs(callable
, conn
, msg
,
74 DBG("%p: OK, handler %p returned None", conn
, callable
);
76 return DBUS_HANDLER_RESULT_HANDLED
;
78 else if (obj
== Py_NotImplemented
) {
79 DBG("%p: handler %p returned NotImplemented, continuing",
82 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED
;
85 if (PyErr_ExceptionMatches(PyExc_MemoryError
)) {
86 DBG_EXC("%p: handler %p caused OOM", conn
, callable
);
88 return DBUS_HANDLER_RESULT_NEED_MEMORY
;
90 DBG_EXC("%p: handler %p raised exception", conn
, callable
);
91 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED
;
94 long i
= PyInt_AsLong(obj
);
95 DBG("%p: handler %p returned %ld", conn
, callable
, i
);
97 if (i
== -1 && PyErr_Occurred()) {
98 PyErr_SetString(PyExc_TypeError
, "Return from D-Bus message "
99 "handler callback should be None, "
100 "NotImplemented or integer");
101 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED
;
103 else if (i
== DBUS_HANDLER_RESULT_HANDLED
||
104 i
== DBUS_HANDLER_RESULT_NOT_YET_HANDLED
||
105 i
== DBUS_HANDLER_RESULT_NEED_MEMORY
) {
109 PyErr_Format(PyExc_ValueError
, "Integer return from "
110 "D-Bus message handler callback should "
111 "be a DBUS_HANDLER_RESULT_... constant, "
113 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED
;
118 /* On KeyError or if unregistration is in progress, return None. */
120 DBusPyConnection_GetObjectPathHandlers(PyObject
*self
, PyObject
*path
)
122 PyObject
*callbacks
= PyDict_GetItem(((Connection
*)self
)->object_paths
,
125 if (PyErr_ExceptionMatches(PyExc_KeyError
)) {
130 Py_INCREF(callbacks
);
134 /* Return a new reference to a Python Connection or subclass corresponding
135 * to the DBusConnection conn. For use in callbacks.
137 * Raises AssertionError if the DBusConnection does not have a Connection.
140 DBusPyConnection_ExistingFromDBusConnection(DBusConnection
*conn
)
142 PyObject
*self
, *ref
;
144 Py_BEGIN_ALLOW_THREADS
145 ref
= (PyObject
*)dbus_connection_get_data(conn
,
146 _connection_python_slot
);
149 self
= PyWeakref_GetObject(ref
); /* still a borrowed ref */
150 if (self
&& self
!= Py_None
&& DBusPyConnection_Check(self
)) {
156 PyErr_SetString(PyExc_AssertionError
,
157 "D-Bus connection does not have a Connection "
158 "instance associated with it");
162 /* Return a new reference to a Python Connection or subclass (given by cls)
163 * corresponding to the DBusConnection conn, which must have been newly
164 * created. For use by the Connection and Bus constructors.
166 * Raises AssertionError if the DBusConnection already has a Connection.
169 DBusPyConnection_NewConsumingDBusConnection(PyTypeObject
*cls
,
170 DBusConnection
*conn
,
173 Connection
*self
= NULL
;
177 Py_BEGIN_ALLOW_THREADS
178 ref
= (PyObject
*)dbus_connection_get_data(conn
,
179 _connection_python_slot
);
182 self
= (Connection
*)PyWeakref_GetObject(ref
);
184 if (self
&& (PyObject
*)self
!= Py_None
) {
186 PyErr_SetString(PyExc_AssertionError
,
187 "Newly created D-Bus connection already has a "
188 "Connection instance associated with it");
194 if (!mainloop
|| mainloop
== Py_None
) {
195 mainloop
= dbus_py_get_default_main_loop();
196 if (!mainloop
|| mainloop
== Py_None
) {
197 PyErr_SetString(PyExc_ValueError
,
198 "D-Bus connections must be attached to a main "
199 "loop by passing mainloop=... to the constructor "
200 "or calling dbus.Bus.set_default_main_loop(...)");
208 DBG("Constructing Connection from DBusConnection at %p", conn
);
210 self
= (Connection
*)(cls
->tp_alloc(cls
, 0));
214 self
->filters
= PyList_New(0);
215 if (!self
->filters
) goto err
;
216 self
->object_paths
= PyDict_New();
217 if (!self
->object_paths
) goto err
;
219 ref
= PyWeakref_NewRef((PyObject
*)self
, NULL
);
222 Py_BEGIN_ALLOW_THREADS
223 ok
= dbus_connection_set_data(conn
, _connection_python_slot
,
225 (DBusFreeFunction
)dbus_py_take_gil_and_xdecref
);
235 if (!dbus_py_set_up_connection((PyObject
*)self
, mainloop
)) {
241 return (PyObject
*)self
;
244 DBG("Failed to construct Connection from DBusConnection at %p", conn
);
245 Py_XDECREF(mainloop
);
249 Py_BEGIN_ALLOW_THREADS
250 dbus_connection_close(conn
);
251 dbus_connection_unref(conn
);
257 /* Connection type-methods ========================================== */
259 /* "Constructor" (the real constructor is Connection_NewFromDBusConnection,
260 * to which this delegates). */
262 Connection_tp_new(PyTypeObject
*cls
, PyObject
*args
, PyObject
*kwargs
)
264 DBusConnection
*conn
;
267 PyObject
*self
, *mainloop
= NULL
;
268 static char *argnames
[] = {"address", "mainloop", NULL
};
270 if (!PyArg_ParseTupleAndKeywords(args
, kwargs
, "s|O", argnames
,
271 &address
, &mainloop
)) {
275 dbus_error_init(&error
);
277 /* We always open a private connection (at the libdbus level). Sharing
278 * is done in Python, to keep things simple. */
279 Py_BEGIN_ALLOW_THREADS
280 conn
= dbus_connection_open_private(address
, &error
);
284 DBusPyException_ConsumeError(&error
);
287 self
= DBusPyConnection_NewConsumingDBusConnection(cls
, conn
, mainloop
);
293 static void Connection_tp_dealloc(Connection
*self
)
295 DBusConnection
*conn
= self
->conn
;
296 PyObject
*filters
= self
->filters
;
297 PyObject
*object_paths
= self
->object_paths
;
299 DBG("Deallocating Connection at %p (DBusConnection at %p)", self
, conn
);
301 self
->filters
= NULL
;
303 self
->object_paths
= NULL
;
304 Py_XDECREF(object_paths
);
306 /* make sure to do this last to preserve the invariant that
307 * self->conn is always non-NULL for any referenced Connection
308 * (until the filters and object paths were freed, we might have been
309 * in a reference cycle!)
313 Py_BEGIN_ALLOW_THREADS
314 dbus_connection_close(conn
);
317 dbus_connection_unref(conn
);
320 (self
->ob_type
->tp_free
)((PyObject
*)self
);
323 /* Connection type object =========================================== */
325 PyTypeObject DBusPyConnection_Type
= {
326 PyObject_HEAD_INIT(NULL
)
328 "_dbus_bindings.Connection", /*tp_name*/
329 sizeof(Connection
), /*tp_basicsize*/
332 (destructor
)Connection_tp_dealloc
,
339 0, /*tp_as_sequence*/
347 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_HAVE_WEAKREFS
| Py_TPFLAGS_BASETYPE
,
348 Connection_tp_doc
, /*tp_doc*/
351 0, /*tp_richcompare*/
352 offsetof(Connection
, weaklist
), /*tp_weaklistoffset*/
355 DBusPyConnection_tp_methods
, /*tp_methods*/
365 Connection_tp_new
, /*tp_new*/
371 dbus_py_init_conn_types(void)
373 /* Get a slot to store our weakref on DBus Connections */
374 _connection_python_slot
= -1;
375 if (!dbus_connection_allocate_data_slot(&_connection_python_slot
))
377 if (PyType_Ready(&DBusPyConnection_Type
) < 0)
383 dbus_py_insert_conn_types(PyObject
*this_module
)
385 if (PyModule_AddObject(this_module
, "Connection",
386 (PyObject
*)&DBusPyConnection_Type
) < 0) return FALSE
;
390 /* vim:set ft=c cino< sw=4 sts=4 et: */