revert requiring mh-acros; remove mh-loaddefs instead
[bpt/emacs.git] / src / dbusbind.c
CommitLineData
033b73e2
MA
1/* Elisp bindings for D-Bus.
2 Copyright (C) 2007 Free Software Foundation, Inc.
3
4This file is part of GNU Emacs.
5
6GNU Emacs is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 3, or (at your option)
9any later version.
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Emacs; see the file COPYING. If not, write to
18the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19Boston, MA 02110-1301, USA. */
20
21#include "config.h"
22
23#ifdef HAVE_DBUS
24#include <stdlib.h>
25#include <dbus/dbus.h>
26#include "lisp.h"
27#include "frame.h"
28#include "termhooks.h"
29#include "keyboard.h"
30
31\f
32/* Subroutines. */
33Lisp_Object Qdbus_get_unique_name;
34Lisp_Object Qdbus_call_method;
35Lisp_Object Qdbus_send_signal;
36Lisp_Object Qdbus_register_signal;
37Lisp_Object Qdbus_unregister_signal;
38
39/* D-Bus error symbol. */
40Lisp_Object Qdbus_error;
41
42/* Lisp symbols of the system and session buses. */
39abdd4a 43Lisp_Object QCdbus_system_bus, QCdbus_session_bus;
033b73e2 44
39abdd4a
MA
45/* Hash table which keeps function definitions. */
46Lisp_Object Vdbus_registered_functions_table;
033b73e2
MA
47
48/* Whether to debug D-Bus. */
49Lisp_Object Vdbus_debug;
50
51\f
52/* We use "xd_" and "XD_" as prefix for all internal symbols, because
53 we don't want to poison other namespaces with "dbus_". */
54
033b73e2
MA
55/* Raise a Lisp error from a D-Bus error. */
56#define XD_ERROR(error) \
57 { \
58 char s[1024]; \
59 strcpy (s, error.message); \
60 dbus_error_free (&error); \
61 /* Remove the trailing newline. */ \
62 if (strchr (s, '\n') != NULL) \
63 s[strlen (s) - 1] = '\0'; \
64 xsignal1 (Qdbus_error, build_string (s)); \
65 }
66
67/* Macros for debugging. In order to enable them, build with
68 "make MYCPPFLAGS='-DDBUS_DEBUG'". */
69#ifdef DBUS_DEBUG
70#define XD_DEBUG_MESSAGE(...) \
71 { \
72 char s[1024]; \
73 sprintf (s, __VA_ARGS__); \
74 printf ("%s: %s\n", __func__, s); \
75 message ("%s: %s", __func__, s); \
76 }
77#define XD_DEBUG_VALID_LISP_OBJECT_P(object) \
78 if (!valid_lisp_object_p (object)) \
79 { \
80 XD_DEBUG_MESSAGE ("%s Assertion failure", __LINE__); \
81 xsignal1 (Qdbus_error, build_string ("Assertion failure")); \
82 }
83
84#else /* !DBUS_DEBUG */
85#define XD_DEBUG_MESSAGE(...) \
86 if (!NILP (Vdbus_debug)) \
87 { \
88 char s[1024]; \
89 sprintf (s, __VA_ARGS__); \
90 message ("%s: %s", __func__, s); \
91 }
92#define XD_DEBUG_VALID_LISP_OBJECT_P(object)
93#endif
94
95/* Determine the DBusType of a given Lisp object. It is used to
96 convert Lisp objects, being arguments of `dbus-call-method' or
97 `dbus-send-signal', into corresponding C values appended as
98 arguments to a D-Bus message. */
99#define XD_LISP_OBJECT_TO_DBUS_TYPE(object) \
100 (EQ (object, Qt) || EQ (object, Qnil)) ? DBUS_TYPE_BOOLEAN : \
101 (NATNUMP (object)) ? DBUS_TYPE_UINT32 : \
102 (INTEGERP (object)) ? DBUS_TYPE_INT32 : \
103 (FLOATP (object)) ? DBUS_TYPE_DOUBLE : \
104 (STRINGP (object)) ? DBUS_TYPE_STRING : \
105 DBUS_TYPE_INVALID
106
107/* Extract C value from Lisp OBJECT. DTYPE must be a valid DBusType,
108 as detected by XD_LISP_OBJECT_TO_DBUS_TYPE. Compound types are not
109 supported (yet). It is used to convert Lisp objects, being
110 arguments of `dbus-call-method' or `dbus-send-signal', into
111 corresponding C values appended as arguments to a D-Bus
112 message. */
113char *
114xd_retrieve_value (dtype, object)
115 uint dtype;
116 Lisp_Object object;
117{
118
119 XD_DEBUG_VALID_LISP_OBJECT_P (object);
120 switch (dtype)
121 {
122 case DBUS_TYPE_BOOLEAN:
123 XD_DEBUG_MESSAGE ("%d %s", dtype, (NILP (object)) ? "false" : "true");
124 return (NILP (object)) ? (char *) FALSE : (char *) TRUE;
125 case DBUS_TYPE_UINT32:
126 XD_DEBUG_MESSAGE ("%d %d", dtype, XUINT (object));
127 return (char *) XUINT (object);
128 case DBUS_TYPE_INT32:
129 XD_DEBUG_MESSAGE ("%d %d", dtype, XINT (object));
130 return (char *) XINT (object);
131 case DBUS_TYPE_DOUBLE:
132 XD_DEBUG_MESSAGE ("%d %d", dtype, XFLOAT (object));
133 return (char *) XFLOAT (object);
134 case DBUS_TYPE_STRING:
135 XD_DEBUG_MESSAGE ("%d %s", dtype, SDATA (object));
136 return SDATA (object);
137 default:
138 XD_DEBUG_MESSAGE ("DBus-Type %d not supported", dtype);
139 return NULL;
140 }
141}
142
143/* Retrieve C value from a DBusMessageIter structure ITER, and return
144 a converted Lisp object. The type DTYPE of the argument of the
145 D-Bus message must be a valid DBusType. Compound D-Bus types are
146 partly supported; they result always in a Lisp list. */
147Lisp_Object
148xd_retrieve_arg (dtype, iter)
149 uint dtype;
150 DBusMessageIter *iter;
151{
152
153 switch (dtype)
154 {
155 case DBUS_TYPE_BOOLEAN:
156 {
157 dbus_bool_t val;
158 dbus_message_iter_get_basic (iter, &val);
159 XD_DEBUG_MESSAGE ("%d %s", dtype, (val == FALSE) ? "false" : "true");
160 return (val == FALSE) ? Qnil : Qt;
161 }
162 case DBUS_TYPE_INT32:
163 case DBUS_TYPE_UINT32:
164 {
165 dbus_uint32_t val;
166 dbus_message_iter_get_basic (iter, &val);
167 XD_DEBUG_MESSAGE ("%d %d", dtype, val);
168 return make_number (val);
169 }
170 case DBUS_TYPE_STRING:
171 case DBUS_TYPE_OBJECT_PATH:
172 {
173 char *val;
174 dbus_message_iter_get_basic (iter, &val);
175 XD_DEBUG_MESSAGE ("%d %s", dtype, val);
176 return build_string (val);
177 }
178 case DBUS_TYPE_ARRAY:
179 case DBUS_TYPE_VARIANT:
180 case DBUS_TYPE_STRUCT:
181 case DBUS_TYPE_DICT_ENTRY:
182 {
183 Lisp_Object result;
184 struct gcpro gcpro1;
185 result = Qnil;
186 GCPRO1 (result);
187 DBusMessageIter subiter;
188 int subtype;
189 dbus_message_iter_recurse (iter, &subiter);
190 while ((subtype = dbus_message_iter_get_arg_type (&subiter))
191 != DBUS_TYPE_INVALID)
192 {
193 result = Fcons (xd_retrieve_arg (subtype, &subiter), result);
194 dbus_message_iter_next (&subiter);
195 }
196 RETURN_UNGCPRO (Fnreverse (result));
197 }
198 default:
199 XD_DEBUG_MESSAGE ("DBusType %d not supported", dtype);
200 return Qnil;
201 }
202}
203
204
205/* Initialize D-Bus connection. BUS is a Lisp symbol, either :system
206 or :session. It tells which D-Bus to be initialized. */
207DBusConnection *
208xd_initialize (bus)
209 Lisp_Object bus;
210{
211 DBusConnection *connection;
212 DBusError derror;
213
214 /* Parameter check. */
215 CHECK_SYMBOL (bus);
39abdd4a 216 if (!((EQ (bus, QCdbus_system_bus)) || (EQ (bus, QCdbus_session_bus))))
033b73e2
MA
217 xsignal2 (Qdbus_error, build_string ("Wrong bus name"), bus);
218
219 /* Open a connection to the bus. */
220 dbus_error_init (&derror);
221
39abdd4a 222 if (EQ (bus, QCdbus_system_bus))
033b73e2
MA
223 connection = dbus_bus_get (DBUS_BUS_SYSTEM, &derror);
224 else
225 connection = dbus_bus_get (DBUS_BUS_SESSION, &derror);
226
227 if (dbus_error_is_set (&derror))
228 XD_ERROR (derror);
229
230 if (connection == NULL)
231 xsignal2 (Qdbus_error, build_string ("No connection"), bus);
232
233 /* Return the result. */
234 return connection;
235}
236
237DEFUN ("dbus-get-unique-name", Fdbus_get_unique_name, Sdbus_get_unique_name,
238 1, 1, 0,
239 doc: /* Return the unique name of Emacs registered at D-Bus BUS as string. */)
240 (bus)
241 Lisp_Object bus;
242{
243 DBusConnection *connection;
244 char name[1024];
245
246 /* Check parameters. */
247 CHECK_SYMBOL (bus);
248
249 /* Open a connection to the bus. */
250 connection = xd_initialize (bus);
251
252 /* Request the name. */
253 strcpy (name, dbus_bus_get_unique_name (connection));
254 if (name == NULL)
255 xsignal1 (Qdbus_error, build_string ("No unique name available"));
256
257 /* Return. */
258 return build_string (name);
259}
260
261DEFUN ("dbus-call-method", Fdbus_call_method, Sdbus_call_method, 5, MANY, 0,
262 doc: /* Call METHOD on the D-Bus BUS.
263
264BUS is either the symbol `:system' or the symbol `:session'.
265
266SERVICE is the D-Bus service name to be used. PATH is the D-Bus
267object path SERVICE is registered at. INTERFACE is an interface
268offered by SERVICE. It must provide METHOD.
269
270All other arguments ARGS are passed to METHOD as arguments. They are
271converted into D-Bus types via the following rules:
272
273 t and nil => DBUS_TYPE_BOOLEAN
274 number => DBUS_TYPE_UINT32
275 integer => DBUS_TYPE_INT32
276 float => DBUS_TYPE_DOUBLE
277 string => DBUS_TYPE_STRING
278
279Other Lisp objects are not supported as input arguments of METHOD.
280
281`dbus-call-method' returns the resulting values of METHOD as a list of
282Lisp objects. The type conversion happens the other direction as for
283input arguments. Additionally to the types supported for input
284arguments, the D-Bus compound types DBUS_TYPE_ARRAY, DBUS_TYPE_VARIANT,
285DBUS_TYPE_STRUCT and DBUS_TYPE_DICT_ENTRY are accepted. All of them
286are converted into a list of Lisp objects which correspond to the
287elements of the D-Bus container. Example:
288
289\(dbus-call-method
290 :session "GetKeyField" "org.gnome.seahorse"
291 "/org/gnome/seahorse/keys/openpgp" "org.gnome.seahorse.Keys"
292 "openpgp:657984B8C7A966DD" "simple-name")
293
294 => (t ("Philip R. Zimmermann"))
295
296If the result of the METHOD call is just one value, the converted Lisp
297object is returned instead of a list containing this single Lisp object.
298
299\(dbus-call-method
300 :system "GetPropertyString" "org.freedesktop.Hal"
301 "/org/freedesktop/Hal/devices/computer" "org.freedesktop.Hal.Device"
302 "system.kernel.machine")
303
304 => "i686"
305
306usage: (dbus-call-method BUS METHOD SERVICE PATH INTERFACE &rest ARGS) */)
307 (nargs, args)
308 int nargs;
309 register Lisp_Object *args;
310{
311 Lisp_Object bus, method, service, path, interface;
312 Lisp_Object result;
313 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
314 DBusConnection *connection;
315 DBusMessage *dmessage;
316 DBusMessage *reply;
317 DBusMessageIter iter;
318 DBusError derror;
319 uint dtype;
320 int i;
321 char *value;
322
323 /* Check parameters. */
324 bus = args[0];
325 method = args[1];
326 service = args[2];
327 path = args[3];
328 interface = args[4];
329
330 CHECK_SYMBOL (bus);
331 CHECK_STRING (method);
332 CHECK_STRING (service);
333 CHECK_STRING (path);
334 CHECK_STRING (interface);
335 GCPRO5 (bus, method, service, path, interface);
336
337 XD_DEBUG_MESSAGE ("%s %s %s %s",
338 SDATA (method),
339 SDATA (service),
340 SDATA (path),
341 SDATA (interface));
342
343 /* Open a connection to the bus. */
344 connection = xd_initialize (bus);
345
346 /* Create the message. */
347 dmessage = dbus_message_new_method_call (SDATA (service),
348 SDATA (path),
349 SDATA (interface),
350 SDATA (method));
351 if (dmessage == NULL)
352 {
353 UNGCPRO;
354 xsignal1 (Qdbus_error, build_string ("Unable to create a new message"));
355 }
356
357 UNGCPRO;
358
359 /* Append parameters to the message. */
360 for (i = 5; i < nargs; ++i)
361 {
362
363 XD_DEBUG_VALID_LISP_OBJECT_P (args[i]);
364 XD_DEBUG_MESSAGE ("Parameter%d %s",
365 i-4,
366 SDATA (format2 ("%s", args[i], Qnil)));
367
368 dtype = XD_LISP_OBJECT_TO_DBUS_TYPE (args[i]);
369 if (dtype == DBUS_TYPE_INVALID)
370 xsignal2 (Qdbus_error, build_string ("Not a valid argument"), args[i]);
371
372 value = (char *) xd_retrieve_value (dtype, args[i]);
373
374 if (!dbus_message_append_args (dmessage,
375 dtype,
376 &value,
377 DBUS_TYPE_INVALID))
378 xsignal2 (Qdbus_error,
379 build_string ("Unable to append argument"), args[i]);
380 }
381
382 /* Send the message. */
383 dbus_error_init (&derror);
384 reply = dbus_connection_send_with_reply_and_block (connection,
385 dmessage,
386 -1,
387 &derror);
388
389 if (dbus_error_is_set (&derror))
390 XD_ERROR (derror);
391
392 if (reply == NULL)
393 xsignal1 (Qdbus_error, build_string ("No reply"));
394
395 XD_DEBUG_MESSAGE ("Message sent");
396
397 /* Collect the results. */
398 result = Qnil;
399 GCPRO1 (result);
400
401 if (!dbus_message_iter_init (reply, &iter))
402 {
403 UNGCPRO;
404 xsignal1 (Qdbus_error, build_string ("Cannot read reply"));
405 }
406
407 /* Loop over the parameters of the D-Bus reply message. Construct a
408 Lisp list, which is returned by `dbus-call-method'. */
409 while ((dtype = dbus_message_iter_get_arg_type (&iter)) != DBUS_TYPE_INVALID)
410 {
411 result = Fcons (xd_retrieve_arg (dtype, &iter), result);
412 dbus_message_iter_next (&iter);
413 }
414
415 /* Cleanup. */
416 dbus_message_unref (dmessage);
417 dbus_message_unref (reply);
418
419 /* Return the result. If there is only one single Lisp object,
420 return it as-it-is, otherwise return the reversed list. */
421 if (XUINT (Flength (result)) == 1)
422 RETURN_UNGCPRO (XCAR (result));
423 else
424 RETURN_UNGCPRO (Fnreverse (result));
425}
426
427DEFUN ("dbus-send-signal", Fdbus_send_signal, Sdbus_send_signal, 5, MANY, 0,
428 doc: /* Send signal SIGNAL on the D-Bus BUS.
429
430BUS is either the symbol `:system' or the symbol `:session'.
431
432SERVICE is the D-Bus service name SIGNAL is sent from. PATH is the
433D-Bus object path SERVICE is registered at. INTERFACE is an interface
434offered by SERVICE. It must provide signal SIGNAL.
435
436All other arguments ARGS are passed to SIGNAL as arguments. They are
437converted into D-Bus types via the following rules:
438
439 t and nil => DBUS_TYPE_BOOLEAN
440 number => DBUS_TYPE_UINT32
441 integer => DBUS_TYPE_INT32
442 float => DBUS_TYPE_DOUBLE
443 string => DBUS_TYPE_STRING
444
445Other Lisp objects are not supported as arguments of SIGNAL.
446
447Example:
448
449\(dbus-send-signal
450 :session "Started" "org.gnu.emacs" "/org/gnu/emacs" "org.gnu.emacs")))
451
452usage: (dbus-send-signal BUS SIGNAL SERVICE PATH INTERFACE &rest ARGS) */)
453 (nargs, args)
454 int nargs;
455 register Lisp_Object *args;
456{
457 Lisp_Object bus, signal, service, path, interface;
458 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
459 DBusConnection *connection;
460 DBusMessage *dmessage;
461 uint dtype;
462 int i;
463 char *value;
464
465 /* Check parameters. */
466 bus = args[0];
467 signal = args[1];
468 service = args[2];
469 path = args[3];
470 interface = args[4];
471
472 CHECK_SYMBOL (bus);
473 CHECK_STRING (signal);
474 CHECK_STRING (service);
475 CHECK_STRING (path);
476 CHECK_STRING (interface);
477 GCPRO5 (bus, signal, service, path, interface);
478
479 XD_DEBUG_MESSAGE ("%s %s %s %s",
480 SDATA (signal),
481 SDATA (service),
482 SDATA (path),
483 SDATA (interface));
484
485 /* Open a connection to the bus. */
486 connection = xd_initialize (bus);
487
488 /* Create the message. */
489 dmessage = dbus_message_new_signal (SDATA (path),
490 SDATA (interface),
491 SDATA (signal));
492 if (dmessage == NULL)
493 {
494 UNGCPRO;
495 xsignal1 (Qdbus_error, build_string ("Unable to create a new message"));
496 }
497
498 UNGCPRO;
499
500 /* Append parameters to the message. */
501 for (i = 5; i < nargs; ++i)
502 {
503 XD_DEBUG_VALID_LISP_OBJECT_P (args[i]);
504 XD_DEBUG_MESSAGE ("Parameter%d %s",
505 i-4,
506 SDATA (format2 ("%s", args[i], Qnil)));
507
508 dtype = XD_LISP_OBJECT_TO_DBUS_TYPE (args[i]);
509 if (dtype == DBUS_TYPE_INVALID)
510 xsignal2 (Qdbus_error, build_string ("Not a valid argument"), args[i]);
511
512 value = (char *) xd_retrieve_value (dtype, args[i]);
513
514 if (!dbus_message_append_args (dmessage,
515 dtype,
516 &value,
517 DBUS_TYPE_INVALID))
518 xsignal2 (Qdbus_error,
519 build_string ("Unable to append argument"), args[i]);
520 }
521
522 /* Send the message. The message is just added to the outgoing
523 message queue. */
524 if (!dbus_connection_send (connection, dmessage, NULL))
525 xsignal1 (Qdbus_error, build_string ("Cannot send message"));
526
527 /* Flush connection to ensure the message is handled. */
528 dbus_connection_flush (connection);
529
530 XD_DEBUG_MESSAGE ("Signal sent");
531
532 /* Cleanup. */
533 dbus_message_unref (dmessage);
534
535 /* Return. */
536 return Qt;
537}
538
539/* Read queued incoming message of the D-Bus BUS. BUS is a Lisp
540 symbol, either :system or :session. */
541void
542xd_read_message (bus)
543 Lisp_Object bus;
544{
39abdd4a 545 Lisp_Object key;
033b73e2
MA
546 struct gcpro gcpro1;
547 static struct input_event event;
548 DBusConnection *connection;
549 DBusMessage *dmessage;
550 DBusMessageIter iter;
551 uint dtype;
39abdd4a
MA
552 char service[1024], path[1024], interface[1024], member[1024];
553
554 /* Vdbus_registered_functions_table will be made as hash table in
555 dbus.el. When it isn't loaded yet, it doesn't make sense to
556 handle D-Bus messages. */
557 if (!HASH_TABLE_P (Vdbus_registered_functions_table))
558 return;
033b73e2
MA
559
560 /* Open a connection to the bus. */
561 connection = xd_initialize (bus);
562
563 /* Non blocking read of the next available message. */
564 dbus_connection_read_write (connection, 0);
565 dmessage = dbus_connection_pop_message (connection);
566
567 /* Return if there is no queued message. */
568 if (dmessage == NULL)
569 return;
570
571 /* There is a message in the queue. Construct the D-Bus event. */
572 XD_DEBUG_MESSAGE ("Event received");
573 EVENT_INIT (event);
574
575 event.kind = DBUS_EVENT;
576 event.frame_or_window = Qnil;
577
578 /* Collect the parameters. */
579 event.arg = Qnil;
580 GCPRO1 (event.arg);
581
582 if (!dbus_message_iter_init (dmessage, &iter))
583 {
584 UNGCPRO;
585 XD_DEBUG_MESSAGE ("Cannot read event");
586 return;
587 }
588
589 /* Loop over the resulting parameters. Construct a list. */
590 while ((dtype = dbus_message_iter_get_arg_type (&iter)) != DBUS_TYPE_INVALID)
591 {
592 event.arg = Fcons (xd_retrieve_arg (dtype, &iter), event.arg);
593 dbus_message_iter_next (&iter);
594 }
595
596 /* The arguments are stored in reverse order. Reorder them. */
597 event.arg = Fnreverse (event.arg);
598
39abdd4a
MA
599 /* Read service, object path interface and member from the
600 message. */
601 strcpy (service, dbus_message_get_sender (dmessage));
602 strcpy (path, dbus_message_get_path (dmessage));
603 strcpy (interface, dbus_message_get_interface (dmessage));
604 strcpy (member, dbus_message_get_member (dmessage));
605
606 /* Add them to the event. */
607 event.arg = Fcons ((member == NULL ? Qnil : build_string (member)),
608 event.arg);
609 event.arg = Fcons ((interface == NULL ? Qnil : build_string (interface)),
610 event.arg);
611 event.arg = Fcons ((path == NULL ? Qnil : build_string (path)),
612 event.arg);
613 event.arg = Fcons ((service == NULL ? Qnil : build_string (service)),
614 event.arg);
615
616 /* Add the bus symbol to the event. */
617 event.arg = Fcons (bus, event.arg);
618
619 /* Add the registered function of the message. */
620 key = list3 (bus,
621 (interface == NULL ? Qnil : build_string (interface)),
622 (member == NULL ? Qnil : build_string (member)));
623 event.arg = Fcons (Fgethash (key, Vdbus_registered_functions_table, Qnil),
624 event.arg);
033b73e2
MA
625
626 /* Store it into the input event queue. */
627 kbd_buffer_store_event (&event);
628
629 /* Cleanup. */
630 dbus_message_unref (dmessage);
631 UNGCPRO;
632}
633
634/* Read queued incoming messages from the system and session buses. */
635void
636xd_read_queued_messages ()
637{
39abdd4a
MA
638 xd_read_message (QCdbus_system_bus);
639 xd_read_message (QCdbus_session_bus);
033b73e2
MA
640}
641
642DEFUN ("dbus-register-signal", Fdbus_register_signal, Sdbus_register_signal,
643 6, 6, 0,
644 doc: /* Register for signal SIGNAL on the D-Bus BUS.
645
646BUS is either the symbol `:system' or the symbol `:session'.
647
39abdd4a
MA
648SERVICE is the D-Bus service name used by the sending D-Bus object.
649It can be either a known name or the unique name of the D-Bus object
650sending the signal. When SERVICE is nil, related signals from all
651D-Bus objects shall be accepted.
033b73e2 652
39abdd4a
MA
653PATH is the D-Bus object path SERVICE is registered. It can also be
654nil if the path name of incoming signals shall not be checked.
033b73e2 655
39abdd4a
MA
656INTERFACE is an interface offered by SERVICE. It must provide SIGNAL.
657HANDLER is a Lisp function to be called when the signal is received.
658It must accept as arguments the values SIGNAL is sending. INTERFACE,
659SIGNAL and HANDLER must not be nil. Example:
033b73e2
MA
660
661\(defun my-signal-handler (device)
662 (message "Device %s added" device))
663
664\(dbus-register-signal
39abdd4a
MA
665 :system "DeviceAdded"
666 (dbus-get-name-owner :system "org.freedesktop.Hal")
033b73e2
MA
667 "/org/freedesktop/Hal/Manager" "org.freedesktop.Hal.Manager"
668 'my-signal-handler)
669
39abdd4a 670 => (:system "org.freedesktop.Hal.Manager" "DeviceAdded")
033b73e2
MA
671
672`dbus-register-signal' returns an object, which can be used in
673`dbus-unregister-signal' for removing the registration. */)
674 (bus, signal, service, path, interface, handler)
675 Lisp_Object bus, signal, service, path, interface, handler;
676{
39abdd4a 677 Lisp_Object key;
033b73e2 678 DBusConnection *connection;
033b73e2 679 char rule[1024];
39abdd4a 680 DBusError derror;
033b73e2
MA
681
682 /* Check parameters. */
683 CHECK_SYMBOL (bus);
684 CHECK_STRING (signal);
39abdd4a
MA
685 if (!NILP (service)) CHECK_STRING (service);
686 if (!NILP (path)) CHECK_STRING (path);
033b73e2
MA
687 CHECK_STRING (interface);
688 CHECK_SYMBOL (handler);
689
690 /* Open a connection to the bus. */
691 connection = xd_initialize (bus);
692
39abdd4a 693 /* Create a rule to receive related signals. */
033b73e2
MA
694 sprintf (rule,
695 "type='signal',interface='%s',member=%s%",
696 SDATA (interface),
697 SDATA (signal));
033b73e2 698
39abdd4a
MA
699 /* Add service and path to the rule if they are non-nil. */
700 if (!NILP (service))
701 sprintf (rule, "%s,sender='%s'%", rule, SDATA (service));
702
703 if (!NILP (path))
704 sprintf (rule, "%s,path='%s'", rule, SDATA (path));
705
706 /* Add the rule to the bus. */
707 dbus_error_init (&derror);
708 dbus_bus_add_match (connection, rule, &derror);
033b73e2
MA
709 if (dbus_error_is_set (&derror))
710 XD_ERROR (derror);
711
712 XD_DEBUG_MESSAGE ("Matching rule \"%s\" created", rule);
713
39abdd4a
MA
714 /* Create a hash table entry. */
715 key = list3 (bus, interface, signal);
716 Fputhash (key, handler, Vdbus_registered_functions_table);
033b73e2 717 XD_DEBUG_MESSAGE ("\"%s\" registered with handler \"%s\"",
39abdd4a
MA
718 SDATA (format2 ("%s", key, Qnil)),
719 SDATA (format2 ("%s", handler, Qnil)));
033b73e2 720
39abdd4a
MA
721 /* Return key. */
722 return key;
033b73e2
MA
723}
724
725DEFUN ("dbus-unregister-signal", Fdbus_unregister_signal, Sdbus_unregister_signal,
726 1, 1, 0,
727 doc: /* Unregister OBJECT from the D-Bus.
728OBJECT must be the result of a preceding `dbus-register-signal' call. */)
729 (object)
730 Lisp_Object object;
731{
732
733 /* Check parameters. */
734 CHECK_SYMBOL (object);
735
736 XD_DEBUG_MESSAGE ("\"%s\" unregistered with handler \"%s\"",
737 SDATA (format2 ("%s", object, Qnil)),
738 SDATA (format2 ("%s", Fsymbol_function (object), Qnil)));
739
740 /* Unintern the signal symbol. */
39abdd4a 741 Fremhash (object, Vdbus_registered_functions_table);
033b73e2
MA
742
743 /* Return. */
744 return Qnil;
745}
746
747\f
748void
749syms_of_dbusbind ()
750{
751
752 Qdbus_get_unique_name = intern ("dbus-get-unique-name");
753 staticpro (&Qdbus_get_unique_name);
754 defsubr (&Sdbus_get_unique_name);
755
756 Qdbus_call_method = intern ("dbus-call-method");
757 staticpro (&Qdbus_call_method);
758 defsubr (&Sdbus_call_method);
759
760 Qdbus_send_signal = intern ("dbus-send-signal");
761 staticpro (&Qdbus_send_signal);
762 defsubr (&Sdbus_send_signal);
763
764 Qdbus_register_signal = intern ("dbus-register-signal");
765 staticpro (&Qdbus_register_signal);
766 defsubr (&Sdbus_register_signal);
767
768 Qdbus_unregister_signal = intern ("dbus-unregister-signal");
769 staticpro (&Qdbus_unregister_signal);
770 defsubr (&Sdbus_unregister_signal);
771
772 Qdbus_error = intern ("dbus-error");
773 staticpro (&Qdbus_error);
774 Fput (Qdbus_error, Qerror_conditions,
775 list2 (Qdbus_error, Qerror));
776 Fput (Qdbus_error, Qerror_message,
777 build_string ("D-Bus error"));
778
39abdd4a
MA
779 QCdbus_system_bus = intern (":system");
780 staticpro (&QCdbus_system_bus);
781
782 QCdbus_session_bus = intern (":session");
783 staticpro (&QCdbus_session_bus);
033b73e2 784
39abdd4a
MA
785 DEFVAR_LISP ("dbus-registered-functions-table", &Vdbus_registered_functions_table,
786 doc: /* Hash table of registered functions for D-Bus.
787The key in the hash table is the list (BUS INTERFACE MEMBER). BUS is
788either the symbol `:system' or the symbol `:session'. INTERFACE is a
789string which denotes a D-Bus interface, and MEMBER, also a string, is
790either a method or a signal INTERFACE is offering.
033b73e2 791
39abdd4a
MA
792The value in the hash table a the function to be called when a D-Bus
793message, which matches the key criteria, arrives. */);
794 /* We initialize Vdbus_registered_functions_table in dbus.el,
795 because we need to define a hash table function first. */
796 Vdbus_registered_functions_table = Qnil;
033b73e2
MA
797
798 DEFVAR_LISP ("dbus-debug", &Vdbus_debug,
39abdd4a 799 doc: /* If non-nil, debug messages of D-Bus bindings are raised. */);
033b73e2
MA
800#ifdef DBUS_DEBUG
801 Vdbus_debug = Qt;
802#else
803 Vdbus_debug = Qnil;
804#endif
805
806 Fprovide (intern ("dbusbind"), Qnil);
807
808}
809
810#endif /* HAVE_DBUS */