[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Emacs-diffs] Changes to emacs/src/dbusbind.c,v
From: |
Michael Albinus |
Subject: |
[Emacs-diffs] Changes to emacs/src/dbusbind.c,v |
Date: |
Thu, 31 Jul 2008 18:56:15 +0000 |
CVSROOT: /sources/emacs
Module name: emacs
Changes by: Michael Albinus <albinus> 08/07/31 18:56:15
Index: dbusbind.c
===================================================================
RCS file: /sources/emacs/emacs/src/dbusbind.c,v
retrieving revision 1.28
retrieving revision 1.29
diff -u -b -r1.28 -r1.29
--- dbusbind.c 21 Jul 2008 04:27:38 -0000 1.28
+++ dbusbind.c 31 Jul 2008 18:56:15 -0000 1.29
@@ -31,7 +31,9 @@
/* Subroutines. */
Lisp_Object Qdbus_get_unique_name;
Lisp_Object Qdbus_call_method;
+Lisp_Object Qdbus_call_method_asynchronously;
Lisp_Object Qdbus_method_return_internal;
+Lisp_Object Qdbus_method_error_internal;
Lisp_Object Qdbus_send_signal;
Lisp_Object Qdbus_register_signal;
Lisp_Object Qdbus_register_method;
@@ -920,6 +922,163 @@
RETURN_UNGCPRO (Fnreverse (result));
}
+DEFUN ("dbus-call-method-asynchronously", Fdbus_call_method_asynchronously,
+ 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'.
+
+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
+offered by SERVICE. It must provide METHOD.
+
+HANDLER is a Lisp function, which is called when the corresponding
+return message has arrived.
+
+If the parameter `:timeout' is given, the following integer TIMEOUT
+specifies the maximun number of milliseconds the method call must
+return. The default value is 25.000. If the method call doesn't
+return in time, a D-Bus error is raised.
+
+All other arguments ARGS are passed to METHOD as arguments. They are
+converted into D-Bus types via the following rules:
+
+ t and nil => DBUS_TYPE_BOOLEAN
+ number => DBUS_TYPE_UINT32
+ integer => DBUS_TYPE_INT32
+ float => DBUS_TYPE_DOUBLE
+ string => DBUS_TYPE_STRING
+ list => DBUS_TYPE_ARRAY
+
+All arguments can be preceded by a type symbol. For details about
+type symbols, see Info node `(dbus)Type Conversion'.
+
+The function returns a key into the hash table
+`dbus-registered-functions-table'. The corresponding entry in the
+hash table is removed, when the return message has been arrived, and
+HANDLER is called.
+
+Example:
+
+\(dbus-call-method-asynchronously
+ :system "org.freedesktop.Hal" "/org/freedesktop/Hal/devices/computer"
+ "org.freedesktop.Hal.Device" "GetPropertyString" 'message
+ "system.kernel.machine")
+
+ => (:system 2)
+
+ -| i686
+
+usage: (dbus-call-method-asynchronously
+ BUS SERVICE PATH INTERFACE METHOD HANDLER
+ &optional :timeout TIMEOUT &rest ARGS) */)
+ (nargs, args)
+ int nargs;
+ register Lisp_Object *args;
+{
+ Lisp_Object bus, service, path, interface, method, handler;
+ Lisp_Object result;
+ struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5, gcpro6;
+ DBusConnection *connection;
+ DBusMessage *dmessage;
+ DBusMessageIter iter;
+ unsigned int dtype;
+ int timeout = -1;
+ int i = 6;
+ char signature[DBUS_MAXIMUM_SIGNATURE_LENGTH];
+
+ /* Check parameters. */
+ bus = args[0];
+ service = args[1];
+ path = args[2];
+ interface = args[3];
+ method = args[4];
+ handler = args[5];
+
+ CHECK_SYMBOL (bus);
+ CHECK_STRING (service);
+ CHECK_STRING (path);
+ CHECK_STRING (interface);
+ CHECK_STRING (method);
+ if (!FUNCTIONP (handler))
+ wrong_type_argument (intern ("functionp"), handler);
+ GCPRO6 (bus, service, path, interface, method, handler);
+
+ XD_DEBUG_MESSAGE ("%s %s %s %s",
+ SDATA (service),
+ SDATA (path),
+ SDATA (interface),
+ SDATA (method));
+
+ /* Open a connection to the bus. */
+ connection = xd_initialize (bus);
+
+ /* Create the message. */
+ dmessage = dbus_message_new_method_call (SDATA (service),
+ SDATA (path),
+ SDATA (interface),
+ SDATA (method));
+ if (dmessage == NULL)
+ xsignal1 (Qdbus_error, build_string ("Unable to create a new message"));
+
+ /* Check for timeout parameter. */
+ if ((i+2 <= nargs) && (EQ ((args[i]), QCdbus_timeout)))
+ {
+ CHECK_NATNUM (args[i+1]);
+ timeout = XUINT (args[i+1]);
+ i = i+2;
+ }
+
+ /* Initialize parameter list of message. */
+ dbus_message_iter_init_append (dmessage, &iter);
+
+ /* Append parameters to the message. */
+ for (; i < nargs; ++i)
+ {
+ dtype = XD_OBJECT_TO_DBUS_TYPE (args[i]);
+ if (XD_DBUS_TYPE_P (args[i]))
+ {
+ XD_DEBUG_VALID_LISP_OBJECT_P (args[i]);
+ XD_DEBUG_VALID_LISP_OBJECT_P (args[i+1]);
+ XD_DEBUG_MESSAGE ("Parameter%d %s %s", i-4,
+ SDATA (format2 ("%s", args[i], Qnil)),
+ SDATA (format2 ("%s", args[i+1], Qnil)));
+ ++i;
+ }
+ else
+ {
+ XD_DEBUG_VALID_LISP_OBJECT_P (args[i]);
+ XD_DEBUG_MESSAGE ("Parameter%d %s", i-4,
+ SDATA (format2 ("%s", args[i], Qnil)));
+ }
+
+ /* Check for valid signature. We use DBUS_TYPE_INVALID as
+ indication that there is no parent type. */
+ xd_signature (signature, dtype, DBUS_TYPE_INVALID, args[i]);
+
+ xd_append_arg (dtype, args[i], &iter);
+ }
+
+ /* Send the message. The message is just added to the outgoing
+ message queue. */
+ if (!dbus_connection_send_with_reply (connection, dmessage, NULL, timeout))
+ xsignal1 (Qdbus_error, build_string ("Cannot send message"));
+
+ XD_DEBUG_MESSAGE ("Message sent");
+
+ /* The result is the key in Vdbus_registered_functions_table. */
+ result = (list2 (bus, make_number (dbus_message_get_serial (dmessage))));
+
+ /* Create a hash table entry. */
+ Fputhash (result, handler, Vdbus_registered_functions_table);
+
+ /* Cleanup. */
+ dbus_message_unref (dmessage);
+
+ /* Return the result. */
+ RETURN_UNGCPRO (result);
+}
+
DEFUN ("dbus-method-return-internal", Fdbus_method_return_internal,
Sdbus_method_return_internal,
3, MANY, 0,
@@ -1015,6 +1174,102 @@
return Qt;
}
+DEFUN ("dbus-method-error-internal", Fdbus_method_error_internal,
+ Sdbus_method_error_internal,
+ 3, MANY, 0,
+ doc: /* Return error message for message SERIAL on the D-Bus BUS.
+This is an internal function, it shall not be used outside dbus.el.
+
+usage: (dbus-method-error-internal BUS SERIAL SERVICE &rest ARGS) */)
+ (nargs, args)
+ int nargs;
+ register Lisp_Object *args;
+{
+ Lisp_Object bus, serial, service;
+ struct gcpro gcpro1, gcpro2, gcpro3;
+ DBusConnection *connection;
+ DBusMessage *dmessage;
+ DBusMessageIter iter;
+ unsigned int dtype;
+ int i;
+ char signature[DBUS_MAXIMUM_SIGNATURE_LENGTH];
+
+ /* Check parameters. */
+ bus = args[0];
+ serial = args[1];
+ service = args[2];
+
+ CHECK_SYMBOL (bus);
+ CHECK_NUMBER (serial);
+ CHECK_STRING (service);
+ GCPRO3 (bus, serial, service);
+
+ XD_DEBUG_MESSAGE ("%d %s ", XUINT (serial), SDATA (service));
+
+ /* Open a connection to the bus. */
+ connection = xd_initialize (bus);
+
+ /* Create the message. */
+ dmessage = dbus_message_new (DBUS_MESSAGE_TYPE_ERROR);
+ if ((dmessage == NULL)
+ || (!dbus_message_set_error_name (dmessage, DBUS_ERROR_FAILED))
+ || (!dbus_message_set_reply_serial (dmessage, XUINT (serial)))
+ || (!dbus_message_set_destination (dmessage, SDATA (service))))
+ {
+ UNGCPRO;
+ xsignal1 (Qdbus_error,
+ build_string ("Unable to create a error message"));
+ }
+
+ UNGCPRO;
+
+ /* Initialize parameter list of message. */
+ dbus_message_iter_init_append (dmessage, &iter);
+
+ /* Append parameters to the message. */
+ for (i = 3; i < nargs; ++i)
+ {
+ dtype = XD_OBJECT_TO_DBUS_TYPE (args[i]);
+ if (XD_DBUS_TYPE_P (args[i]))
+ {
+ XD_DEBUG_VALID_LISP_OBJECT_P (args[i]);
+ XD_DEBUG_VALID_LISP_OBJECT_P (args[i+1]);
+ XD_DEBUG_MESSAGE ("Parameter%d %s %s", i-2,
+ SDATA (format2 ("%s", args[i], Qnil)),
+ SDATA (format2 ("%s", args[i+1], Qnil)));
+ ++i;
+ }
+ else
+ {
+ XD_DEBUG_VALID_LISP_OBJECT_P (args[i]);
+ XD_DEBUG_MESSAGE ("Parameter%d %s", i-2,
+ SDATA (format2 ("%s", args[i], Qnil)));
+ }
+
+ /* Check for valid signature. We use DBUS_TYPE_INVALID as
+ indication that there is no parent type. */
+ xd_signature (signature, dtype, DBUS_TYPE_INVALID, args[i]);
+
+ xd_append_arg (dtype, args[i], &iter);
+ }
+
+ /* Send the message. The message is just added to the outgoing
+ message queue. */
+ if (!dbus_connection_send (connection, dmessage, NULL))
+ xsignal1 (Qdbus_error, build_string ("Cannot send message"));
+
+ /* Flush connection to ensure the message is handled. */
+ dbus_connection_flush (connection);
+
+ XD_DEBUG_MESSAGE ("Message sent");
+
+ /* Cleanup. */
+ dbus_message_unref (dmessage);
+
+ /* Return. */
+ return Qt;
+}
+
DEFUN ("dbus-send-signal", Fdbus_send_signal, Sdbus_send_signal, 5, MANY, 0,
doc: /* Send signal SIGNAL on the D-Bus BUS.
@@ -1148,7 +1403,7 @@
DBusMessage *dmessage;
DBusMessageIter iter;
unsigned int dtype;
- int mtype;
+ int mtype, serial;
const char *uname, *path, *interface, *member;
/* Open a connection to the bus. */
@@ -1179,21 +1434,56 @@
args = Fnreverse (args);
}
- /* Read message type, unique name, object path, interface and member
- from the message. */
+ /* Read message type, message serial, unique name, object path,
+ interface and member from the message. */
mtype = dbus_message_get_type (dmessage);
+ serial = (mtype == DBUS_MESSAGE_TYPE_METHOD_RETURN ?
+ dbus_message_get_reply_serial (dmessage) :
+ dbus_message_get_serial (dmessage));
uname = dbus_message_get_sender (dmessage);
path = dbus_message_get_path (dmessage);
interface = dbus_message_get_interface (dmessage);
member = dbus_message_get_member (dmessage);
- /* Vdbus_registered_functions_table requires non-nil interface and member.
*/
- if ((NULL == interface) || (NULL == member))
+ XD_DEBUG_MESSAGE ("Event received: %s %d %s %s %s %s %s",
+ (mtype == DBUS_MESSAGE_TYPE_INVALID) ?
+ "DBUS_MESSAGE_TYPE_INVALID" :
+ (mtype == DBUS_MESSAGE_TYPE_METHOD_CALL) ?
+ "DBUS_MESSAGE_TYPE_METHOD_CALL" :
+ (mtype == DBUS_MESSAGE_TYPE_METHOD_RETURN) ?
+ "DBUS_MESSAGE_TYPE_METHOD_RETURN" :
+ (mtype == DBUS_MESSAGE_TYPE_ERROR) ?
+ "DBUS_MESSAGE_TYPE_METHOD_ERROR" :
+ "DBUS_MESSAGE_TYPE_METHOD_SIGNAL",
+ serial, uname, path, interface, member,
+ SDATA (format2 ("%s", args, Qnil)));
+
+ if (mtype == DBUS_MESSAGE_TYPE_METHOD_RETURN)
+ {
+ /* Search for a registered function of the message. */
+ key = list2 (bus, make_number (serial));
+ value = Fgethash (key, Vdbus_registered_functions_table, Qnil);
+
+ /* There shall be exactly one entry. Construct an event. */
+ if (NILP (value))
goto cleanup;
- XD_DEBUG_MESSAGE ("Event received: %d %s %s %s %s %s",
- mtype, uname, path, interface, member,
- SDATA (format2 ("%s", args, Qnil)));
+ /* Remove the entry. */
+ Fremhash (key, Vdbus_registered_functions_table);
+
+ /* Construct an event. */
+ EVENT_INIT (event);
+ event.kind = DBUS_EVENT;
+ event.frame_or_window = Qnil;
+ event.arg = Fcons (value, args);
+ }
+
+ else /* (mtype != DBUS_MESSAGE_TYPE_METHOD_RETURN) */
+ {
+ /* Vdbus_registered_functions_table requires non-nil interface
+ and member. */
+ if ((interface == NULL) || (member == NULL))
+ goto cleanup;
/* Search for a registered function of the message. */
key = list3 (bus, build_string (interface), build_string (member));
@@ -1209,7 +1499,8 @@
|| (strcmp (uname, SDATA (CAR_SAFE (key))) == 0))
&& ((path == NULL)
|| (NILP (CAR_SAFE (CDR_SAFE (CDR_SAFE (key)))))
- || (strcmp (path, SDATA (CAR_SAFE (CDR_SAFE (CDR_SAFE (key)))))
+ || (strcmp (path,
+ SDATA (CAR_SAFE (CDR_SAFE (CDR_SAFE (key)))))
== 0))
&& (!NILP (CAR_SAFE (CDR_SAFE (CDR_SAFE (CDR_SAFE (key)))))))
{
@@ -1218,29 +1509,35 @@
event.frame_or_window = Qnil;
event.arg = Fcons (CAR_SAFE (CDR_SAFE (CDR_SAFE (CDR_SAFE (key)))),
args);
+ break;
+ }
+ value = CDR_SAFE (value);
+ }
+
+ if (NILP (value))
+ goto cleanup;
+ }
- /* Add uname, path, interface and member to the event. */
- event.arg = Fcons (build_string (member), event.arg);
- event.arg = Fcons (build_string (interface), event.arg);
+ /* Add type, serial, uname, path, interface and member to the event. */
+ event.arg = Fcons ((member == NULL ? Qnil : build_string (member)),
+ event.arg);
+ event.arg = Fcons ((interface == NULL ? Qnil : build_string (interface)),
+ event.arg);
event.arg = Fcons ((path == NULL ? Qnil : build_string (path)),
event.arg);
event.arg = Fcons ((uname == NULL ? Qnil : build_string (uname)),
event.arg);
-
- /* Add the message serial if needed, or nil. */
- event.arg = Fcons ((mtype == DBUS_MESSAGE_TYPE_METHOD_CALL
- ? make_number (dbus_message_get_serial (dmessage))
- : Qnil),
- event.arg);
+ event.arg = Fcons (make_number (serial), event.arg);
+ event.arg = Fcons (make_number (mtype), event.arg);
/* Add the bus symbol to the event. */
event.arg = Fcons (bus, event.arg);
/* Store it into the input event queue. */
kbd_buffer_store_event (&event);
- }
- value = CDR_SAFE (value);
- }
+
+ XD_DEBUG_MESSAGE ("Event stored: %s",
+ SDATA (format2 ("%s", event.arg, Qnil)));
cleanup:
dbus_message_unref (dmessage);
@@ -1481,10 +1778,18 @@
staticpro (&Qdbus_call_method);
defsubr (&Sdbus_call_method);
+ Qdbus_call_method_asynchronously = intern
("dbus-call-method-asynchronously");
+ staticpro (&Qdbus_call_method_asynchronously);
+ defsubr (&Sdbus_call_method_asynchronously);
+
Qdbus_method_return_internal = intern ("dbus-method-return-internal");
staticpro (&Qdbus_method_return_internal);
defsubr (&Sdbus_method_return_internal);
+ Qdbus_method_error_internal = intern ("dbus-method-error-internal");
+ staticpro (&Qdbus_method_error_internal);
+ defsubr (&Sdbus_method_error_internal);
+
Qdbus_send_signal = intern ("dbus-send-signal");
staticpro (&Qdbus_send_signal);
defsubr (&Sdbus_send_signal);
@@ -1564,11 +1869,15 @@
DEFVAR_LISP ("dbus-registered-functions-table",
&Vdbus_registered_functions_table,
doc: /* Hash table of registered functions for D-Bus.
-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 or a signal INTERFACE is offering. All arguments but
-BUS must not be nil.
+There are two different uses of the hash table: for calling registered
+functions, 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 or a signal 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 HANDLER) (UNAME SERVICE PATH HANDLER) ...).
@@ -1576,7 +1885,14 @@
unique name. PATH is the object path of the sending object. All of
them can be nil, which means a wildcard then. HANDLER is the function
to be called when a D-Bus message, which matches the key criteria,
-arrives. */);
+arrives.
+
+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_functions_table in dbus.el,
because we need to define a hash table function first. */
Vdbus_registered_functions_table = Qnil;