\f
/* Subroutines. */
Lisp_Object Qdbus_init_bus;
+Lisp_Object Qdbus_close_bus;
Lisp_Object Qdbus_get_unique_name;
Lisp_Object Qdbus_call_method;
Lisp_Object Qdbus_call_method_asynchronously;
Lisp_Object QCdbus_type_array, QCdbus_type_variant;
Lisp_Object QCdbus_type_struct, QCdbus_type_dict_entry;
+/* Registered buses. */
+Lisp_Object Vdbus_registered_buses;
+
/* Hash table which keeps function definitions. */
Lisp_Object Vdbus_registered_objects_table;
} while (0)
/* Macros for debugging. In order to enable them, build with
- "make MYCPPFLAGS='-DDBUS_DEBUG -Wall'". */
+ "MYCPPFLAGS='-DDBUS_DEBUG -Wall' make". */
#ifdef DBUS_DEBUG
#define XD_DEBUG_MESSAGE(...) \
do { \
}
}
-/* Initialize D-Bus connection. BUS is a Lisp symbol, either :system
- or :session. It tells which D-Bus to initialize. If RAISE_ERROR
- is non-zero signal an error when the connection cannot be
- initialized. */
+/* Initialize D-Bus connection. BUS is either a Lisp symbol, :system
+ or :session, or a string denoting the bus address. It tells which
+ D-Bus to initialize. If RAISE_ERROR is non-zero, signal an error
+ when the connection cannot be initialized. */
static DBusConnection *
xd_initialize (Lisp_Object bus, int raise_error)
{
DBusError derror;
/* Parameter check. */
- CHECK_SYMBOL (bus);
- if (!(EQ (bus, QCdbus_system_bus) || EQ (bus, QCdbus_session_bus)))
- if (raise_error)
- XD_SIGNAL2 (build_string ("Wrong bus name"), bus);
- else
- return NULL;
+ if (!STRINGP (bus))
+ {
+ CHECK_SYMBOL (bus);
+ if (!(EQ (bus, QCdbus_system_bus) || EQ (bus, QCdbus_session_bus)))
+ {
+ if (raise_error)
+ XD_SIGNAL2 (build_string ("Wrong bus name"), bus);
+ else
+ return NULL;
+ }
- /* We do not want to have an autolaunch for the session bus. */
- if (EQ (bus, QCdbus_session_bus)
- && getenv ("DBUS_SESSION_BUS_ADDRESS") == NULL)
- if (raise_error)
- XD_SIGNAL2 (build_string ("No connection to bus"), bus);
- else
- return NULL;
+ /* We do not want to have an autolaunch for the session bus. */
+ if (EQ (bus, QCdbus_session_bus)
+ && getenv ("DBUS_SESSION_BUS_ADDRESS") == NULL)
+ {
+ if (raise_error)
+ XD_SIGNAL2 (build_string ("No connection to bus"), bus);
+ else
+ return NULL;
+ }
+ }
/* Open a connection to the bus. */
dbus_error_init (&derror);
- if (EQ (bus, QCdbus_system_bus))
- connection = dbus_bus_get (DBUS_BUS_SYSTEM, &derror);
+ if (STRINGP (bus))
+ connection = dbus_connection_open (SDATA (bus), &derror);
else
- connection = dbus_bus_get (DBUS_BUS_SESSION, &derror);
+ if (EQ (bus, QCdbus_system_bus))
+ connection = dbus_bus_get (DBUS_BUS_SYSTEM, &derror);
+ else
+ connection = dbus_bus_get (DBUS_BUS_SESSION, &derror);
if (dbus_error_is_set (&derror))
- if (raise_error)
- XD_ERROR (derror);
- else
- connection = NULL;
+ {
+ if (raise_error)
+ XD_ERROR (derror);
+ else
+ connection = NULL;
+ }
+
+ /* If it is not the system or session bus, we must register
+ ourselves. Otherwise, we have called dbus_bus_get, which has
+ configured us to exit if the connection closes - we undo this
+ setting. */
+ if (connection != NULL)
+ {
+ if (STRINGP (bus))
+ dbus_bus_register (connection, &derror);
+ else
+ dbus_connection_set_exit_on_disconnect (connection, FALSE);
+ }
+
+ if (dbus_error_is_set (&derror))
+ {
+ if (raise_error)
+ XD_ERROR (derror);
+ else
+ connection = NULL;
+ }
if (connection == NULL && raise_error)
XD_SIGNAL2 (build_string ("No connection to bus"), bus);
}
/* Remove connection file descriptor from input_wait_mask. DATA is
- the used bus, either QCdbus_system_bus or QCdbus_session_bus. */
+ the used bus, either a string or QCdbus_system_bus or
+ QCdbus_session_bus. */
void
xd_remove_watch (DBusWatch *watch, void *data)
{
}
DEFUN ("dbus-init-bus", Fdbus_init_bus, Sdbus_init_bus, 1, 1, 0,
- doc: /* Initialize connection to D-Bus BUS.
-This is an internal function, it shall not be used outside dbus.el. */)
+ doc: /* Initialize connection to D-Bus BUS. */)
(Lisp_Object bus)
{
DBusConnection *connection;
- /* Check parameters. */
- CHECK_SYMBOL (bus);
-
/* Open a connection to the bus. */
connection = xd_initialize (bus, TRUE);
NULL, (void*) XHASH (bus), NULL))
XD_SIGNAL1 (build_string ("Cannot add watch functions"));
+ /* Add bus to list of registered buses. */
+ Vdbus_registered_buses = Fcons (bus, Vdbus_registered_buses);
+
+ /* Return. */
+ return Qnil;
+}
+
+DEFUN ("dbus-close-bus", Fdbus_close_bus, Sdbus_close_bus, 1, 1, 0,
+ doc: /* Close connection to D-Bus BUS. */)
+ (Lisp_Object bus)
+{
+ DBusConnection *connection;
+
+ /* Open a connection to the bus. */
+ connection = xd_initialize (bus, TRUE);
+
+ /* Decrement reference count to the bus. */
+ dbus_connection_unref (connection);
+
+ /* Remove bus from list of registered buses. */
+ Vdbus_registered_buses = Fdelete (bus, Vdbus_registered_buses);
+
/* Return. */
return Qnil;
}
DBusConnection *connection;
const char *name;
- /* Check parameters. */
- CHECK_SYMBOL (bus);
-
/* Open a connection to the bus. */
connection = xd_initialize (bus, TRUE);
DEFUN ("dbus-call-method", Fdbus_call_method, Sdbus_call_method, 5, MANY, 0,
doc: /* Call METHOD on the D-Bus BUS.
-BUS is either the symbol `:system' or the symbol `:session'.
+BUS is either a Lisp symbol, `:system' or `:session', or a string
+denoting the bus address.
SERVICE is the D-Bus service name to be used. PATH is the D-Bus
object path SERVICE is registered at. INTERFACE is an interface
interface = args[3];
method = args[4];
- CHECK_SYMBOL (bus);
CHECK_STRING (service);
CHECK_STRING (path);
CHECK_STRING (interface);
Sdbus_call_method_asynchronously, 6, MANY, 0,
doc: /* Call METHOD on the D-Bus BUS asynchronously.
-BUS is either the symbol `:system' or the symbol `:session'.
+BUS is either a Lisp symbol, `:system' or `:session', or a string
+denoting the bus address.
SERVICE is the D-Bus service name to be used. PATH is the D-Bus
object path SERVICE is registered at. INTERFACE is an interface
method = args[4];
handler = args[5];
- CHECK_SYMBOL (bus);
CHECK_STRING (service);
CHECK_STRING (path);
CHECK_STRING (interface);
serial = args[1];
service = args[2];
- CHECK_SYMBOL (bus);
CHECK_NUMBER (serial);
CHECK_STRING (service);
GCPRO3 (bus, serial, service);
serial = args[1];
service = args[2];
- CHECK_SYMBOL (bus);
CHECK_NUMBER (serial);
CHECK_STRING (service);
GCPRO3 (bus, serial, service);
DEFUN ("dbus-send-signal", Fdbus_send_signal, Sdbus_send_signal, 5, MANY, 0,
doc: /* Send signal SIGNAL on the D-Bus BUS.
-BUS is either the symbol `:system' or the symbol `:session'.
+BUS is either a Lisp symbol, `:system' or `:session', or a string
+denoting the bus address.
SERVICE is the D-Bus service name SIGNAL is sent from. PATH is the
D-Bus object path SERVICE is registered at. INTERFACE is an interface
interface = args[3];
signal = args[4];
- CHECK_SYMBOL (bus);
CHECK_STRING (service);
CHECK_STRING (path);
CHECK_STRING (interface);
}
/* Check, whether there is pending input in the message queue of the
- D-Bus BUS. BUS is a Lisp symbol, either :system or :session. */
+ D-Bus BUS. BUS is either a Lisp symbol, :system or :session, or a
+ string denoting the bus address. */
int
xd_get_dispatch_status (Lisp_Object bus)
{
? TRUE : FALSE;
}
-/* Check for queued incoming messages from the system and session buses. */
+/* Check for queued incoming messages from the buses. */
int
xd_pending_messages (void)
{
+ Lisp_Object busp = Vdbus_registered_buses;
+
+ while (!NILP (busp))
+ {
+ /* We do not want to have an autolaunch for the session bus. */
+ if (EQ ((CAR_SAFE (busp)), QCdbus_session_bus)
+ && getenv ("DBUS_SESSION_BUS_ADDRESS") == NULL)
+ continue;
- /* Vdbus_registered_objects_table will be initialized as hash table
- in dbus.el. When this package isn't loaded yet, it doesn't make
- sense to handle D-Bus messages. */
- return (HASH_TABLE_P (Vdbus_registered_objects_table)
- ? (xd_get_dispatch_status (QCdbus_system_bus)
- || ((getenv ("DBUS_SESSION_BUS_ADDRESS") != NULL)
- ? xd_get_dispatch_status (QCdbus_session_bus)
- : FALSE))
- : FALSE);
+ if (xd_get_dispatch_status (CAR_SAFE (busp)))
+ return TRUE;
+
+ busp = CDR_SAFE (busp);
+ }
+
+ return FALSE;
}
-/* Read queued incoming message of the D-Bus BUS. BUS is a Lisp
- symbol, either :system or :session. */
+/* Read queued incoming message of the D-Bus BUS. BUS is either a
+ Lisp symbol, :system or :session, or a string denoting the bus
+ address. */
static Lisp_Object
xd_read_message (Lisp_Object bus)
{
RETURN_UNGCPRO (Qnil);
}
-/* Read queued incoming messages from the system and session buses. */
+/* Read queued incoming messages from all buses. */
void
xd_read_queued_messages (void)
{
+ Lisp_Object busp = Vdbus_registered_buses;
- /* Vdbus_registered_objects_table will be initialized as hash table
- in dbus.el. When this package isn't loaded yet, it doesn't make
- sense to handle D-Bus messages. Furthermore, we ignore all Lisp
- errors during the call. */
- if (HASH_TABLE_P (Vdbus_registered_objects_table))
+ xd_in_read_queued_messages = 1;
+ while (!NILP (busp))
{
- xd_in_read_queued_messages = 1;
- internal_catch (Qdbus_error, xd_read_message, QCdbus_system_bus);
- internal_catch (Qdbus_error, xd_read_message, QCdbus_session_bus);
- xd_in_read_queued_messages = 0;
+ /* We ignore all Lisp errors during the call. */
+ internal_catch (Qdbus_error, xd_read_message, CAR_SAFE (busp));
+ busp = CDR_SAFE (busp);
}
+ xd_in_read_queued_messages = 0;
}
DEFUN ("dbus-register-signal", Fdbus_register_signal, Sdbus_register_signal,
6, MANY, 0,
doc: /* Register for signal SIGNAL on the D-Bus BUS.
-BUS is either the symbol `:system' or the symbol `:session'.
+BUS is either a Lisp symbol, `:system' or `:session', or a string
+denoting the bus address.
SERVICE is the D-Bus service name used by the sending D-Bus object.
It can be either a known name or the unique name of the D-Bus object
signal = args[4];
handler = args[5];
- CHECK_SYMBOL (bus);
if (!NILP (service)) CHECK_STRING (service);
if (!NILP (path)) CHECK_STRING (path);
CHECK_STRING (interface);
6, 6, 0,
doc: /* Register for method METHOD on the D-Bus BUS.
-BUS is either the symbol `:system' or the symbol `:session'.
+BUS is either a Lisp symbol, `:system' or `:session', or a string
+denoting the bus address.
SERVICE is the D-Bus service name of the D-Bus object METHOD is
registered for. It must be a known name.
DBusError derror;
/* Check parameters. */
- CHECK_SYMBOL (bus);
CHECK_STRING (service);
CHECK_STRING (path);
CHECK_STRING (interface);
staticpro (&Qdbus_init_bus);
defsubr (&Sdbus_init_bus);
+ Qdbus_close_bus = intern_c_string ("dbus-close-bus");
+ staticpro (&Qdbus_close_bus);
+ defsubr (&Sdbus_close_bus);
+
Qdbus_get_unique_name = intern_c_string ("dbus-get-unique-name");
staticpro (&Qdbus_get_unique_name);
defsubr (&Sdbus_get_unique_name);
QCdbus_type_dict_entry = intern_c_string (":dict-entry");
staticpro (&QCdbus_type_dict_entry);
+ DEFVAR_LISP ("dbus-registered-buses",
+ &Vdbus_registered_buses,
+ doc: /* List of D-Bus buses we are polling for messages. */);
+ Vdbus_registered_buses = Qnil;
+
DEFVAR_LISP ("dbus-registered-objects-table",
&Vdbus_registered_objects_table,
doc: /* Hash table of registered functions for D-Bus.
+
There are two different uses of the hash table: for accessing
registered interfaces properties, targeted by signals or method calls,
and for calling handlers in case of non-blocking method call returns.
In the first case, the key in the hash table is the list (BUS
-INTERFACE MEMBER). BUS is either the symbol `:system' or the symbol
-`:session'. INTERFACE is a string which denotes a D-Bus interface,
-and MEMBER, also a string, is either a method, a signal or a property
-INTERFACE is offering. All arguments but BUS must not be nil.
+INTERFACE MEMBER). BUS is either a Lisp symbol, `:system' or
+`:session', or a string denoting the bus address. INTERFACE is a
+string which denotes a D-Bus interface, and MEMBER, also a string, is
+either a method, a signal or a property INTERFACE is offering. All
+arguments but BUS must not be nil.
The value in the hash table is a list of quadruple lists
\((UNAME SERVICE PATH OBJECT) (UNAME SERVICE PATH OBJECT) ...).
arrives (methods and signals), or a cons cell containing the value of
the property.
-In the second case, the key in the hash table is the list (BUS SERIAL).
-BUS is either the symbol `:system' or the symbol `:session'. SERIAL
-is the serial number of the non-blocking method call, a reply is
-expected. Both arguments must not be nil. The value in the hash
-table is HANDLER, the function to be called when the D-Bus reply
-message arrives. */);
- /* We initialize Vdbus_registered_objects_table in dbus.el, because
- we need to define a hash table function first. */
- Vdbus_registered_objects_table = Qnil;
+In the second case, the key in the hash table is the list (BUS
+SERIAL). BUS is either a Lisp symbol, `:system' or `:session', or a
+string denoting the bus address. SERIAL is the serial number of the
+non-blocking method call, a reply is expected. Both arguments must
+not be nil. The value in the hash table is HANDLER, the function to
+be called when the D-Bus reply message arrives. */);
+ {
+ Lisp_Object args[2];
+ args[0] = QCtest;
+ args[1] = Qequal;
+ Vdbus_registered_objects_table = Fmake_hash_table (2, args);
+ }
DEFVAR_LISP ("dbus-debug", &Vdbus_debug,
doc: /* If non-nil, debug messages of D-Bus bindings are raised. */);