* lisp/emacs-lisp/cl-macs.el (cl-transform-lambda): Don't add spurious
[bpt/emacs.git] / src / dbusbind.c
CommitLineData
033b73e2 1/* Elisp bindings for D-Bus.
acaf905b 2 Copyright (C) 2007-2012 Free Software Foundation, Inc.
033b73e2
MA
3
4This file is part of GNU Emacs.
5
9ec0b715 6GNU Emacs is free software: you can redistribute it and/or modify
033b73e2 7it under the terms of the GNU General Public License as published by
9ec0b715
GM
8the Free Software Foundation, either version 3 of the License, or
9(at your option) any later version.
033b73e2
MA
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
9ec0b715 17along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
033b73e2 18
08a494a3 19#include <config.h>
033b73e2
MA
20
21#ifdef HAVE_DBUS
f5306ca3 22#include <stdio.h>
033b73e2 23#include <dbus/dbus.h>
d7306fe6 24#include <setjmp.h>
033b73e2
MA
25#include "lisp.h"
26#include "frame.h"
27#include "termhooks.h"
28#include "keyboard.h"
3fad2ad2 29#include "process.h"
033b73e2 30
dcbf5805
MA
31#ifndef DBUS_NUM_MESSAGE_TYPES
32#define DBUS_NUM_MESSAGE_TYPES 5
33#endif
34
033b73e2
MA
35\f
36/* Subroutines. */
955cbe7b 37static Lisp_Object Qdbus_init_bus;
955cbe7b 38static Lisp_Object Qdbus_get_unique_name;
dcbf5805 39static Lisp_Object Qdbus_message_internal;
033b73e2
MA
40
41/* D-Bus error symbol. */
955cbe7b 42static Lisp_Object Qdbus_error;
033b73e2
MA
43
44/* Lisp symbols of the system and session buses. */
955cbe7b 45static Lisp_Object QCdbus_system_bus, QCdbus_session_bus;
033b73e2 46
90b3fc84 47/* Lisp symbol for method call timeout. */
955cbe7b 48static Lisp_Object QCdbus_timeout;
90b3fc84 49
54371585 50/* Lisp symbols of D-Bus types. */
955cbe7b
PE
51static Lisp_Object QCdbus_type_byte, QCdbus_type_boolean;
52static Lisp_Object QCdbus_type_int16, QCdbus_type_uint16;
53static Lisp_Object QCdbus_type_int32, QCdbus_type_uint32;
54static Lisp_Object QCdbus_type_int64, QCdbus_type_uint64;
55static Lisp_Object QCdbus_type_double, QCdbus_type_string;
56static Lisp_Object QCdbus_type_object_path, QCdbus_type_signature;
da1fec2b 57#ifdef DBUS_TYPE_UNIX_FD
b4289b64 58static Lisp_Object QCdbus_type_unix_fd;
da1fec2b 59#endif
955cbe7b
PE
60static Lisp_Object QCdbus_type_array, QCdbus_type_variant;
61static Lisp_Object QCdbus_type_struct, QCdbus_type_dict_entry;
54371585 62
dcbf5805
MA
63/* Lisp symbols of objects in `dbus-registered-objects-table'. */
64static Lisp_Object QCdbus_registered_serial, QCdbus_registered_method;
65static Lisp_Object QCdbus_registered_signal;
66
5cb67954
MA
67/* Alist of D-Bus buses we are polling for messages.
68 The key is the symbol or string of the bus, and the value is the
69 connection address. */
70static Lisp_Object xd_registered_buses;
71
1dae9197 72/* Whether we are reading a D-Bus event. */
16390cd2 73static int xd_in_read_queued_messages = 0;
1dae9197 74
033b73e2
MA
75\f
76/* We use "xd_" and "XD_" as prefix for all internal symbols, because
77 we don't want to poison other namespaces with "dbus_". */
78
1dae9197
MA
79/* Raise a signal. If we are reading events, we cannot signal; we
80 throw to xd_read_queued_messages then. */
81#define XD_SIGNAL1(arg) \
82 do { \
83 if (xd_in_read_queued_messages) \
84 Fthrow (Qdbus_error, Qnil); \
85 else \
86 xsignal1 (Qdbus_error, arg); \
87 } while (0)
88
89#define XD_SIGNAL2(arg1, arg2) \
90 do { \
91 if (xd_in_read_queued_messages) \
92 Fthrow (Qdbus_error, Qnil); \
93 else \
94 xsignal2 (Qdbus_error, arg1, arg2); \
95 } while (0)
96
97#define XD_SIGNAL3(arg1, arg2, arg3) \
98 do { \
99 if (xd_in_read_queued_messages) \
100 Fthrow (Qdbus_error, Qnil); \
101 else \
102 xsignal3 (Qdbus_error, arg1, arg2, arg3); \
103 } while (0)
104
54371585 105/* Raise a Lisp error from a D-Bus ERROR. */
033b73e2 106#define XD_ERROR(error) \
17bc8f94 107 do { \
033b73e2 108 /* Remove the trailing newline. */ \
573f4b54
PE
109 char const *mess = error.message; \
110 char const *nl = strchr (mess, '\n'); \
111 Lisp_Object err = make_string (mess, nl ? nl - mess : strlen (mess)); \
112 dbus_error_free (&error); \
113 XD_SIGNAL1 (err); \
17bc8f94 114 } while (0)
033b73e2
MA
115
116/* Macros for debugging. In order to enable them, build with
dcbf5805 117 "env MYCPPFLAGS='-DDBUS_DEBUG -Wall' make". */
033b73e2 118#ifdef DBUS_DEBUG
9a4b36f8
MA
119#define XD_DEBUG_MESSAGE(...) \
120 do { \
121 char s[1024]; \
122 snprintf (s, sizeof s, __VA_ARGS__); \
123 if (!noninteractive) \
124 printf ("%s: %s\n", __func__, s); \
125 message ("%s: %s", __func__, s); \
17bc8f94 126 } while (0)
033b73e2 127#define XD_DEBUG_VALID_LISP_OBJECT_P(object) \
17bc8f94
MA
128 do { \
129 if (!valid_lisp_object_p (object)) \
130 { \
131 XD_DEBUG_MESSAGE ("%d Assertion failure", __LINE__); \
1dae9197 132 XD_SIGNAL1 (build_string ("Assertion failure")); \
17bc8f94
MA
133 } \
134 } while (0)
033b73e2
MA
135
136#else /* !DBUS_DEBUG */
17bc8f94
MA
137#define XD_DEBUG_MESSAGE(...) \
138 do { \
139 if (!NILP (Vdbus_debug)) \
140 { \
141 char s[1024]; \
dcbf5805 142 snprintf (s, sizeof s, __VA_ARGS__); \
17bc8f94 143 message ("%s: %s", __func__, s); \
80f9d13b 144 } \
17bc8f94 145 } while (0)
033b73e2
MA
146#define XD_DEBUG_VALID_LISP_OBJECT_P(object)
147#endif
148
87cf1a39 149/* Check whether TYPE is a basic DBusType. */
da1fec2b
MA
150#ifdef DBUS_TYPE_UNIX_FD
151#define XD_BASIC_DBUS_TYPE(type) \
152 ((type == DBUS_TYPE_BYTE) \
153 || (type == DBUS_TYPE_BOOLEAN) \
154 || (type == DBUS_TYPE_INT16) \
155 || (type == DBUS_TYPE_UINT16) \
156 || (type == DBUS_TYPE_INT32) \
157 || (type == DBUS_TYPE_UINT32) \
158 || (type == DBUS_TYPE_INT64) \
159 || (type == DBUS_TYPE_UINT64) \
160 || (type == DBUS_TYPE_DOUBLE) \
161 || (type == DBUS_TYPE_STRING) \
162 || (type == DBUS_TYPE_OBJECT_PATH) \
01768686 163 || (type == DBUS_TYPE_SIGNATURE) \
da1fec2b
MA
164 || (type == DBUS_TYPE_UNIX_FD))
165#else
87cf1a39
MA
166#define XD_BASIC_DBUS_TYPE(type) \
167 ((type == DBUS_TYPE_BYTE) \
168 || (type == DBUS_TYPE_BOOLEAN) \
169 || (type == DBUS_TYPE_INT16) \
170 || (type == DBUS_TYPE_UINT16) \
171 || (type == DBUS_TYPE_INT32) \
172 || (type == DBUS_TYPE_UINT32) \
173 || (type == DBUS_TYPE_INT64) \
174 || (type == DBUS_TYPE_UINT64) \
175 || (type == DBUS_TYPE_DOUBLE) \
176 || (type == DBUS_TYPE_STRING) \
177 || (type == DBUS_TYPE_OBJECT_PATH) \
178 || (type == DBUS_TYPE_SIGNATURE))
da1fec2b 179#endif
87cf1a39 180
78c38319 181/* This was a macro. On Solaris 2.11 it was said to compile for
e1dbe924 182 hours, when optimization is enabled. So we have transferred it into
78c38319 183 a function. */
54371585
MA
184/* Determine the DBusType of a given Lisp symbol. OBJECT must be one
185 of the predefined D-Bus type symbols. */
78c38319 186static int
971de7fb 187xd_symbol_to_dbus_type (Lisp_Object object)
78c38319
MA
188{
189 return
190 ((EQ (object, QCdbus_type_byte)) ? DBUS_TYPE_BYTE
191 : (EQ (object, QCdbus_type_boolean)) ? DBUS_TYPE_BOOLEAN
192 : (EQ (object, QCdbus_type_int16)) ? DBUS_TYPE_INT16
193 : (EQ (object, QCdbus_type_uint16)) ? DBUS_TYPE_UINT16
194 : (EQ (object, QCdbus_type_int32)) ? DBUS_TYPE_INT32
195 : (EQ (object, QCdbus_type_uint32)) ? DBUS_TYPE_UINT32
196 : (EQ (object, QCdbus_type_int64)) ? DBUS_TYPE_INT64
197 : (EQ (object, QCdbus_type_uint64)) ? DBUS_TYPE_UINT64
198 : (EQ (object, QCdbus_type_double)) ? DBUS_TYPE_DOUBLE
199 : (EQ (object, QCdbus_type_string)) ? DBUS_TYPE_STRING
200 : (EQ (object, QCdbus_type_object_path)) ? DBUS_TYPE_OBJECT_PATH
201 : (EQ (object, QCdbus_type_signature)) ? DBUS_TYPE_SIGNATURE
da1fec2b
MA
202#ifdef DBUS_TYPE_UNIX_FD
203 : (EQ (object, QCdbus_type_unix_fd)) ? DBUS_TYPE_UNIX_FD
204#endif
78c38319
MA
205 : (EQ (object, QCdbus_type_array)) ? DBUS_TYPE_ARRAY
206 : (EQ (object, QCdbus_type_variant)) ? DBUS_TYPE_VARIANT
207 : (EQ (object, QCdbus_type_struct)) ? DBUS_TYPE_STRUCT
208 : (EQ (object, QCdbus_type_dict_entry)) ? DBUS_TYPE_DICT_ENTRY
209 : DBUS_TYPE_INVALID);
210}
87cf1a39
MA
211
212/* Check whether a Lisp symbol is a predefined D-Bus type symbol. */
213#define XD_DBUS_TYPE_P(object) \
78c38319 214 (SYMBOLP (object) && ((xd_symbol_to_dbus_type (object) != DBUS_TYPE_INVALID)))
54371585
MA
215
216/* Determine the DBusType of a given Lisp OBJECT. It is used to
033b73e2
MA
217 convert Lisp objects, being arguments of `dbus-call-method' or
218 `dbus-send-signal', into corresponding C values appended as
219 arguments to a D-Bus message. */
87cf1a39
MA
220#define XD_OBJECT_TO_DBUS_TYPE(object) \
221 ((EQ (object, Qt) || EQ (object, Qnil)) ? DBUS_TYPE_BOOLEAN \
222 : (NATNUMP (object)) ? DBUS_TYPE_UINT32 \
223 : (INTEGERP (object)) ? DBUS_TYPE_INT32 \
224 : (FLOATP (object)) ? DBUS_TYPE_DOUBLE \
225 : (STRINGP (object)) ? DBUS_TYPE_STRING \
78c38319 226 : (XD_DBUS_TYPE_P (object)) ? xd_symbol_to_dbus_type (object) \
07a4cb03
MA
227 : (CONSP (object)) \
228 ? ((XD_DBUS_TYPE_P (CAR_SAFE (object))) \
78c38319 229 ? ((XD_BASIC_DBUS_TYPE (xd_symbol_to_dbus_type (CAR_SAFE (object)))) \
07a4cb03 230 ? DBUS_TYPE_ARRAY \
78c38319 231 : xd_symbol_to_dbus_type (CAR_SAFE (object))) \
07a4cb03 232 : DBUS_TYPE_ARRAY) \
87cf1a39
MA
233 : DBUS_TYPE_INVALID)
234
235/* Return a list pointer which does not have a Lisp symbol as car. */
a8e72f4f 236#define XD_NEXT_VALUE(object) \
5125905e 237 ((XD_DBUS_TYPE_P (CAR_SAFE (object))) ? CDR_SAFE (object) : object)
87cf1a39 238
dcbf5805
MA
239/* Transform the message type to its string representation for debug
240 messages. */
241#define XD_MESSAGE_TYPE_TO_STRING(mtype) \
242 ((mtype == DBUS_MESSAGE_TYPE_INVALID) \
243 ? "DBUS_MESSAGE_TYPE_INVALID" \
244 : (mtype == DBUS_MESSAGE_TYPE_METHOD_CALL) \
245 ? "DBUS_MESSAGE_TYPE_METHOD_CALL" \
246 : (mtype == DBUS_MESSAGE_TYPE_METHOD_RETURN) \
247 ? "DBUS_MESSAGE_TYPE_METHOD_RETURN" \
248 : (mtype == DBUS_MESSAGE_TYPE_ERROR) \
249 ? "DBUS_MESSAGE_TYPE_ERROR" \
250 : "DBUS_MESSAGE_TYPE_SIGNAL")
251
252/* Transform the object to its string representation for debug
253 messages. */
254#define XD_OBJECT_TO_STRING(object) \
255 SDATA (format2 ("%s", object, Qnil))
256
08686060
PE
257/* Check whether X is a valid dbus serial number. If valid, set
258 SERIAL to its value. Otherwise, signal an error. */
dcbf5805
MA
259#define XD_CHECK_DBUS_SERIAL(x, serial) \
260 do { \
261 dbus_uint32_t DBUS_SERIAL_MAX = -1; \
262 if (NATNUMP (x) && XINT (x) <= DBUS_SERIAL_MAX) \
263 serial = XINT (x); \
264 else if (MOST_POSITIVE_FIXNUM < DBUS_SERIAL_MAX \
265 && FLOATP (x) \
266 && 0 <= XFLOAT_DATA (x) \
267 && XFLOAT_DATA (x) <= DBUS_SERIAL_MAX) \
268 serial = XFLOAT_DATA (x); \
269 else \
270 XD_SIGNAL2 (build_string ("Invalid dbus serial"), x); \
271 } while (0)
272
273#define XD_DBUS_VALIDATE_BUS_ADDRESS(bus) \
274 do { \
275 if (STRINGP (bus)) \
276 { \
277 DBusAddressEntry **entries; \
278 int len; \
279 DBusError derror; \
280 dbus_error_init (&derror); \
281 if (!dbus_parse_address (SSDATA (bus), &entries, &len, &derror)) \
282 XD_ERROR (derror); \
283 /* Cleanup. */ \
284 dbus_error_free (&derror); \
285 dbus_address_entries_free (entries); \
286 } \
287 \
288 else \
289 { \
290 CHECK_SYMBOL (bus); \
291 if (!(EQ (bus, QCdbus_system_bus) || EQ (bus, QCdbus_session_bus))) \
292 XD_SIGNAL2 (build_string ("Wrong bus name"), bus); \
293 /* We do not want to have an autolaunch for the session bus. */ \
294 if (EQ (bus, QCdbus_session_bus) \
295 && getenv ("DBUS_SESSION_BUS_ADDRESS") == NULL) \
296 XD_SIGNAL2 (build_string ("No connection to bus"), bus); \
297 } \
298 } while (0)
299
de85e130
PE
300#if (HAVE_DBUS_VALIDATE_BUS_NAME || HAVE_DBUS_VALIDATE_PATH \
301 || XD_DBUS_VALIDATE_OBJECT || HAVE_DBUS_VALIDATE_MEMBER)
dcbf5805
MA
302#define XD_DBUS_VALIDATE_OBJECT(object, func) \
303 do { \
304 if (!NILP (object)) \
305 { \
306 DBusError derror; \
307 CHECK_STRING (object); \
308 dbus_error_init (&derror); \
309 if (!func (SSDATA (object), &derror)) \
310 XD_ERROR (derror); \
311 /* Cleanup. */ \
312 dbus_error_free (&derror); \
313 } \
314 } while (0)
de85e130 315#endif
dcbf5805
MA
316
317#if HAVE_DBUS_VALIDATE_BUS_NAME
318#define XD_DBUS_VALIDATE_BUS_NAME(bus_name) \
319 XD_DBUS_VALIDATE_OBJECT(bus_name, dbus_validate_bus_name);
320#else
321#define XD_DBUS_VALIDATE_BUS_NAME(bus_name) \
322 if (!NILP (bus_name)) CHECK_STRING (bus_name);
323#endif
324
325#if HAVE_DBUS_VALIDATE_PATH
326#define XD_DBUS_VALIDATE_PATH(path) \
327 XD_DBUS_VALIDATE_OBJECT(path, dbus_validate_path);
328#else
329#define XD_DBUS_VALIDATE_PATH(path) \
330 if (!NILP (path)) CHECK_STRING (path);
331#endif
332
333#if HAVE_DBUS_VALIDATE_INTERFACE
334#define XD_DBUS_VALIDATE_INTERFACE(interface) \
335 XD_DBUS_VALIDATE_OBJECT(interface, dbus_validate_interface);
336#else
337#define XD_DBUS_VALIDATE_INTERFACE(interface) \
338 if (!NILP (interface)) CHECK_STRING (interface);
339#endif
340
341#if HAVE_DBUS_VALIDATE_MEMBER
342#define XD_DBUS_VALIDATE_MEMBER(member) \
343 XD_DBUS_VALIDATE_OBJECT(member, dbus_validate_member);
344#else
345#define XD_DBUS_VALIDATE_MEMBER(member) \
346 if (!NILP (member)) CHECK_STRING (member);
347#endif
08686060 348
e936e76e 349/* Append to SIGNATURE a copy of X, making sure SIGNATURE does
2be7d702
PE
350 not become too long. */
351static void
ecfc0a49 352xd_signature_cat (char *signature, char const *x)
2be7d702
PE
353{
354 ptrdiff_t siglen = strlen (signature);
355 ptrdiff_t xlen = strlen (x);
356 if (DBUS_MAXIMUM_SIGNATURE_LENGTH - xlen <= siglen)
357 string_overflow ();
358 strcat (signature, x);
359}
360
87cf1a39
MA
361/* Compute SIGNATURE of OBJECT. It must have a form that it can be
362 used in dbus_message_iter_open_container. DTYPE is the DBusType
363 the object is related to. It is passed as argument, because it
364 cannot be detected in basic type objects, when they are preceded by
365 a type symbol. PARENT_TYPE is the DBusType of a container this
366 signature is embedded, or DBUS_TYPE_INVALID. It is needed for the
367 check that DBUS_TYPE_DICT_ENTRY occurs only as array element. */
78c38319 368static void
971de7fb 369xd_signature (char *signature, unsigned int dtype, unsigned int parent_type, Lisp_Object object)
033b73e2 370{
87cf1a39
MA
371 unsigned int subtype;
372 Lisp_Object elt;
2ea16b89 373 char const *subsig;
8666506e 374 int subsiglen;
87cf1a39
MA
375 char x[DBUS_MAXIMUM_SIGNATURE_LENGTH];
376
377 elt = object;
033b73e2 378
033b73e2
MA
379 switch (dtype)
380 {
54371585
MA
381 case DBUS_TYPE_BYTE:
382 case DBUS_TYPE_UINT16:
54371585 383 CHECK_NATNUM (object);
87cf1a39 384 sprintf (signature, "%c", dtype);
54371585 385 break;
87cf1a39 386
54371585
MA
387 case DBUS_TYPE_BOOLEAN:
388 if (!EQ (object, Qt) && !EQ (object, Qnil))
389 wrong_type_argument (intern ("booleanp"), object);
87cf1a39 390 sprintf (signature, "%c", dtype);
54371585 391 break;
87cf1a39 392
54371585 393 case DBUS_TYPE_INT16:
54371585 394 CHECK_NUMBER (object);
87cf1a39 395 sprintf (signature, "%c", dtype);
54371585 396 break;
87cf1a39 397
dcbf5805
MA
398 case DBUS_TYPE_UINT32:
399 case DBUS_TYPE_UINT64:
400#ifdef DBUS_TYPE_UNIX_FD
401 case DBUS_TYPE_UNIX_FD:
402#endif
403 case DBUS_TYPE_INT32:
404 case DBUS_TYPE_INT64:
033b73e2 405 case DBUS_TYPE_DOUBLE:
dcbf5805 406 CHECK_NUMBER_OR_FLOAT (object);
87cf1a39 407 sprintf (signature, "%c", dtype);
54371585 408 break;
87cf1a39 409
033b73e2 410 case DBUS_TYPE_STRING:
54371585
MA
411 case DBUS_TYPE_OBJECT_PATH:
412 case DBUS_TYPE_SIGNATURE:
413 CHECK_STRING (object);
87cf1a39 414 sprintf (signature, "%c", dtype);
54371585 415 break;
87cf1a39 416
54371585 417 case DBUS_TYPE_ARRAY:
9af5078b 418 /* Check that all list elements have the same D-Bus type. For
87cf1a39
MA
419 complex element types, we just check the container type, not
420 the whole element's signature. */
54371585 421 CHECK_CONS (object);
87cf1a39 422
5125905e
MA
423 /* Type symbol is optional. */
424 if (EQ (QCdbus_type_array, CAR_SAFE (elt)))
87cf1a39 425 elt = XD_NEXT_VALUE (elt);
5125905e
MA
426
427 /* If the array is empty, DBUS_TYPE_STRING is the default
428 element type. */
429 if (NILP (elt))
430 {
431 subtype = DBUS_TYPE_STRING;
2ea16b89 432 subsig = DBUS_TYPE_STRING_AS_STRING;
5125905e
MA
433 }
434 else
435 {
436 subtype = XD_OBJECT_TO_DBUS_TYPE (CAR_SAFE (elt));
437 xd_signature (x, subtype, dtype, CAR_SAFE (XD_NEXT_VALUE (elt)));
2ea16b89 438 subsig = x;
5125905e
MA
439 }
440
441 /* If the element type is DBUS_TYPE_SIGNATURE, and this is the
dcbf5805
MA
442 only element, the value of this element is used as the
443 array's element signature. */
5125905e
MA
444 if ((subtype == DBUS_TYPE_SIGNATURE)
445 && STRINGP (CAR_SAFE (XD_NEXT_VALUE (elt)))
446 && NILP (CDR_SAFE (XD_NEXT_VALUE (elt))))
2ea16b89 447 subsig = SSDATA (CAR_SAFE (XD_NEXT_VALUE (elt)));
87cf1a39
MA
448
449 while (!NILP (elt))
450 {
5125905e
MA
451 if (subtype != XD_OBJECT_TO_DBUS_TYPE (CAR_SAFE (elt)))
452 wrong_type_argument (intern ("D-Bus"), CAR_SAFE (elt));
453 elt = CDR_SAFE (XD_NEXT_VALUE (elt));
87cf1a39
MA
454 }
455
8666506e
PE
456 subsiglen = snprintf (signature, DBUS_MAXIMUM_SIGNATURE_LENGTH,
457 "%c%s", dtype, subsig);
458 if (! (0 <= subsiglen && subsiglen < DBUS_MAXIMUM_SIGNATURE_LENGTH))
2ea16b89 459 string_overflow ();
54371585 460 break;
87cf1a39 461
54371585 462 case DBUS_TYPE_VARIANT:
9af5078b 463 /* Check that there is exactly one list element. */
54371585 464 CHECK_CONS (object);
87cf1a39
MA
465
466 elt = XD_NEXT_VALUE (elt);
5125905e
MA
467 subtype = XD_OBJECT_TO_DBUS_TYPE (CAR_SAFE (elt));
468 xd_signature (x, subtype, dtype, CAR_SAFE (XD_NEXT_VALUE (elt)));
87cf1a39 469
5125905e 470 if (!NILP (CDR_SAFE (XD_NEXT_VALUE (elt))))
87cf1a39 471 wrong_type_argument (intern ("D-Bus"),
5125905e 472 CAR_SAFE (CDR_SAFE (XD_NEXT_VALUE (elt))));
87cf1a39 473
a271e124 474 sprintf (signature, "%c", dtype);
54371585 475 break;
87cf1a39 476
54371585 477 case DBUS_TYPE_STRUCT:
9af5078b
MA
478 /* A struct list might contain any number of elements with
479 different types. No further check needed. */
87cf1a39
MA
480 CHECK_CONS (object);
481
482 elt = XD_NEXT_VALUE (elt);
483
484 /* Compose the signature from the elements. It is enclosed by
485 parentheses. */
486 sprintf (signature, "%c", DBUS_STRUCT_BEGIN_CHAR );
487 while (!NILP (elt))
488 {
5125905e
MA
489 subtype = XD_OBJECT_TO_DBUS_TYPE (CAR_SAFE (elt));
490 xd_signature (x, subtype, dtype, CAR_SAFE (XD_NEXT_VALUE (elt)));
ecfc0a49 491 xd_signature_cat (signature, x);
5125905e 492 elt = CDR_SAFE (XD_NEXT_VALUE (elt));
87cf1a39 493 }
ecfc0a49 494 xd_signature_cat (signature, DBUS_STRUCT_END_CHAR_AS_STRING);
54371585 495 break;
54371585 496
87cf1a39 497 case DBUS_TYPE_DICT_ENTRY:
9af5078b
MA
498 /* Check that there are exactly two list elements, and the first
499 one is of basic type. The dictionary entry itself must be an
500 element of an array. */
87cf1a39 501 CHECK_CONS (object);
54371585 502
9af5078b 503 /* Check the parent object type. */
87cf1a39
MA
504 if (parent_type != DBUS_TYPE_ARRAY)
505 wrong_type_argument (intern ("D-Bus"), object);
54371585 506
87cf1a39
MA
507 /* Compose the signature from the elements. It is enclosed by
508 curly braces. */
509 sprintf (signature, "%c", DBUS_DICT_ENTRY_BEGIN_CHAR);
54371585 510
87cf1a39
MA
511 /* First element. */
512 elt = XD_NEXT_VALUE (elt);
5125905e
MA
513 subtype = XD_OBJECT_TO_DBUS_TYPE (CAR_SAFE (elt));
514 xd_signature (x, subtype, dtype, CAR_SAFE (XD_NEXT_VALUE (elt)));
ecfc0a49 515 xd_signature_cat (signature, x);
54371585 516
87cf1a39 517 if (!XD_BASIC_DBUS_TYPE (subtype))
5125905e 518 wrong_type_argument (intern ("D-Bus"), CAR_SAFE (XD_NEXT_VALUE (elt)));
54371585 519
87cf1a39 520 /* Second element. */
5125905e
MA
521 elt = CDR_SAFE (XD_NEXT_VALUE (elt));
522 subtype = XD_OBJECT_TO_DBUS_TYPE (CAR_SAFE (elt));
523 xd_signature (x, subtype, dtype, CAR_SAFE (XD_NEXT_VALUE (elt)));
ecfc0a49 524 xd_signature_cat (signature, x);
54371585 525
5125905e 526 if (!NILP (CDR_SAFE (XD_NEXT_VALUE (elt))))
87cf1a39 527 wrong_type_argument (intern ("D-Bus"),
5125905e 528 CAR_SAFE (CDR_SAFE (XD_NEXT_VALUE (elt))));
54371585 529
87cf1a39 530 /* Closing signature. */
ecfc0a49 531 xd_signature_cat (signature, DBUS_DICT_ENTRY_END_CHAR_AS_STRING);
87cf1a39 532 break;
54371585 533
87cf1a39
MA
534 default:
535 wrong_type_argument (intern ("D-Bus"), object);
54371585
MA
536 }
537
87cf1a39
MA
538 XD_DEBUG_MESSAGE ("%s", signature);
539}
54371585 540
87cf1a39
MA
541/* Append C value, extracted from Lisp OBJECT, to iteration ITER.
542 DTYPE must be a valid DBusType. It is used to convert Lisp
543 objects, being arguments of `dbus-call-method' or
544 `dbus-send-signal', into corresponding C values appended as
545 arguments to a D-Bus message. */
78c38319 546static void
971de7fb 547xd_append_arg (unsigned int dtype, Lisp_Object object, DBusMessageIter *iter)
87cf1a39 548{
87cf1a39
MA
549 char signature[DBUS_MAXIMUM_SIGNATURE_LENGTH];
550 DBusMessageIter subiter;
87cf1a39
MA
551
552 if (XD_BASIC_DBUS_TYPE (dtype))
17bc8f94
MA
553 switch (dtype)
554 {
555 case DBUS_TYPE_BYTE:
2d1fc3c7 556 CHECK_NATNUM (object);
54371585 557 {
2d1fc3c7 558 unsigned char val = XFASTINT (object) & 0xFF;
3478ec45 559 XD_DEBUG_MESSAGE ("%c %u", dtype, val);
17bc8f94 560 if (!dbus_message_iter_append_basic (iter, dtype, &val))
1dae9197 561 XD_SIGNAL2 (build_string ("Unable to append argument"), object);
17bc8f94
MA
562 return;
563 }
87cf1a39 564
17bc8f94
MA
565 case DBUS_TYPE_BOOLEAN:
566 {
567 dbus_bool_t val = (NILP (object)) ? FALSE : TRUE;
568 XD_DEBUG_MESSAGE ("%c %s", dtype, (val == FALSE) ? "false" : "true");
569 if (!dbus_message_iter_append_basic (iter, dtype, &val))
1dae9197 570 XD_SIGNAL2 (build_string ("Unable to append argument"), object);
17bc8f94
MA
571 return;
572 }
87cf1a39 573
17bc8f94 574 case DBUS_TYPE_INT16:
e454a4a3 575 CHECK_NUMBER (object);
17bc8f94
MA
576 {
577 dbus_int16_t val = XINT (object);
3478ec45
PE
578 int pval = val;
579 XD_DEBUG_MESSAGE ("%c %d", dtype, pval);
17bc8f94 580 if (!dbus_message_iter_append_basic (iter, dtype, &val))
1dae9197 581 XD_SIGNAL2 (build_string ("Unable to append argument"), object);
17bc8f94
MA
582 return;
583 }
87cf1a39 584
17bc8f94 585 case DBUS_TYPE_UINT16:
2d1fc3c7 586 CHECK_NATNUM (object);
17bc8f94 587 {
2d1fc3c7 588 dbus_uint16_t val = XFASTINT (object);
3478ec45
PE
589 unsigned int pval = val;
590 XD_DEBUG_MESSAGE ("%c %u", dtype, pval);
17bc8f94 591 if (!dbus_message_iter_append_basic (iter, dtype, &val))
1dae9197 592 XD_SIGNAL2 (build_string ("Unable to append argument"), object);
17bc8f94
MA
593 return;
594 }
87cf1a39 595
17bc8f94
MA
596 case DBUS_TYPE_INT32:
597 {
dcbf5805 598 dbus_int32_t val = extract_float (object);
3478ec45
PE
599 int pval = val;
600 XD_DEBUG_MESSAGE ("%c %d", dtype, pval);
17bc8f94 601 if (!dbus_message_iter_append_basic (iter, dtype, &val))
1dae9197 602 XD_SIGNAL2 (build_string ("Unable to append argument"), object);
17bc8f94
MA
603 return;
604 }
87cf1a39 605
17bc8f94 606 case DBUS_TYPE_UINT32:
da1fec2b
MA
607#ifdef DBUS_TYPE_UNIX_FD
608 case DBUS_TYPE_UNIX_FD:
609#endif
17bc8f94 610 {
dcbf5805 611 dbus_uint32_t val = extract_float (object);
3478ec45
PE
612 unsigned int pval = val;
613 XD_DEBUG_MESSAGE ("%c %u", dtype, pval);
17bc8f94 614 if (!dbus_message_iter_append_basic (iter, dtype, &val))
1dae9197 615 XD_SIGNAL2 (build_string ("Unable to append argument"), object);
17bc8f94
MA
616 return;
617 }
87cf1a39 618
17bc8f94
MA
619 case DBUS_TYPE_INT64:
620 {
dcbf5805 621 dbus_int64_t val = extract_float (object);
3478ec45
PE
622 printmax_t pval = val;
623 XD_DEBUG_MESSAGE ("%c %"pMd, dtype, pval);
17bc8f94 624 if (!dbus_message_iter_append_basic (iter, dtype, &val))
1dae9197 625 XD_SIGNAL2 (build_string ("Unable to append argument"), object);
17bc8f94
MA
626 return;
627 }
87cf1a39 628
17bc8f94
MA
629 case DBUS_TYPE_UINT64:
630 {
dcbf5805 631 dbus_uint64_t val = extract_float (object);
3478ec45
PE
632 uprintmax_t pval = val;
633 XD_DEBUG_MESSAGE ("%c %"pMu, dtype, pval);
17bc8f94 634 if (!dbus_message_iter_append_basic (iter, dtype, &val))
1dae9197 635 XD_SIGNAL2 (build_string ("Unable to append argument"), object);
17bc8f94 636 return;
54371585 637 }
87cf1a39 638
17bc8f94 639 case DBUS_TYPE_DOUBLE:
f601cdf3 640 {
dcbf5805 641 double val = extract_float (object);
f601cdf3
KR
642 XD_DEBUG_MESSAGE ("%c %f", dtype, val);
643 if (!dbus_message_iter_append_basic (iter, dtype, &val))
644 XD_SIGNAL2 (build_string ("Unable to append argument"), object);
645 return;
646 }
17bc8f94
MA
647
648 case DBUS_TYPE_STRING:
649 case DBUS_TYPE_OBJECT_PATH:
650 case DBUS_TYPE_SIGNATURE:
e454a4a3 651 CHECK_STRING (object);
17bc8f94 652 {
e454a4a3
SM
653 /* We need to send a valid UTF-8 string. We could encode `object'
654 but by not encoding it, we guarantee it's valid utf-8, even if
655 it contains eight-bit-bytes. Of course, you can still send
656 manually-crafted junk by passing a unibyte string. */
59d6fe83 657 char *val = SSDATA (object);
17bc8f94
MA
658 XD_DEBUG_MESSAGE ("%c %s", dtype, val);
659 if (!dbus_message_iter_append_basic (iter, dtype, &val))
1dae9197 660 XD_SIGNAL2 (build_string ("Unable to append argument"), object);
17bc8f94
MA
661 return;
662 }
663 }
87cf1a39
MA
664
665 else /* Compound types. */
666 {
667
668 /* All compound types except array have a type symbol. For
669 array, it is optional. Skip it. */
5125905e 670 if (!XD_BASIC_DBUS_TYPE (XD_OBJECT_TO_DBUS_TYPE (CAR_SAFE (object))))
87cf1a39
MA
671 object = XD_NEXT_VALUE (object);
672
673 /* Open new subiteration. */
674 switch (dtype)
675 {
676 case DBUS_TYPE_ARRAY:
5125905e
MA
677 /* An array has only elements of the same type. So it is
678 sufficient to check the first element's signature
679 only. */
680
681 if (NILP (object))
682 /* If the array is empty, DBUS_TYPE_STRING is the default
683 element type. */
684 strcpy (signature, DBUS_TYPE_STRING_AS_STRING);
685
686 else
687 /* If the element type is DBUS_TYPE_SIGNATURE, and this is
688 the only element, the value of this element is used as
689 the array's element signature. */
690 if ((XD_OBJECT_TO_DBUS_TYPE (CAR_SAFE (object))
691 == DBUS_TYPE_SIGNATURE)
692 && STRINGP (CAR_SAFE (XD_NEXT_VALUE (object)))
693 && NILP (CDR_SAFE (XD_NEXT_VALUE (object))))
694 {
59d6fe83 695 strcpy (signature, SSDATA (CAR_SAFE (XD_NEXT_VALUE (object))));
5125905e
MA
696 object = CDR_SAFE (XD_NEXT_VALUE (object));
697 }
698
699 else
700 xd_signature (signature,
701 XD_OBJECT_TO_DBUS_TYPE (CAR_SAFE (object)),
702 dtype, CAR_SAFE (XD_NEXT_VALUE (object)));
703
704 XD_DEBUG_MESSAGE ("%c %s %s", dtype, signature,
dcbf5805 705 XD_OBJECT_TO_STRING (object));
5125905e
MA
706 if (!dbus_message_iter_open_container (iter, dtype,
707 signature, &subiter))
1dae9197
MA
708 XD_SIGNAL3 (build_string ("Cannot open container"),
709 make_number (dtype), build_string (signature));
5125905e
MA
710 break;
711
87cf1a39 712 case DBUS_TYPE_VARIANT:
5125905e
MA
713 /* A variant has just one element. */
714 xd_signature (signature, XD_OBJECT_TO_DBUS_TYPE (CAR_SAFE (object)),
715 dtype, CAR_SAFE (XD_NEXT_VALUE (object)));
716
87cf1a39 717 XD_DEBUG_MESSAGE ("%c %s %s", dtype, signature,
dcbf5805 718 XD_OBJECT_TO_STRING (object));
87cf1a39
MA
719 if (!dbus_message_iter_open_container (iter, dtype,
720 signature, &subiter))
1dae9197
MA
721 XD_SIGNAL3 (build_string ("Cannot open container"),
722 make_number (dtype), build_string (signature));
87cf1a39
MA
723 break;
724
725 case DBUS_TYPE_STRUCT:
726 case DBUS_TYPE_DICT_ENTRY:
9af5078b 727 /* These containers do not require a signature. */
dcbf5805 728 XD_DEBUG_MESSAGE ("%c %s", dtype, XD_OBJECT_TO_STRING (object));
87cf1a39 729 if (!dbus_message_iter_open_container (iter, dtype, NULL, &subiter))
1dae9197
MA
730 XD_SIGNAL2 (build_string ("Cannot open container"),
731 make_number (dtype));
87cf1a39
MA
732 break;
733 }
734
735 /* Loop over list elements. */
736 while (!NILP (object))
737 {
5125905e 738 dtype = XD_OBJECT_TO_DBUS_TYPE (CAR_SAFE (object));
87cf1a39
MA
739 object = XD_NEXT_VALUE (object);
740
5125905e 741 xd_append_arg (dtype, CAR_SAFE (object), &subiter);
87cf1a39 742
5125905e 743 object = CDR_SAFE (object);
87cf1a39
MA
744 }
745
9af5078b 746 /* Close the subiteration. */
87cf1a39 747 if (!dbus_message_iter_close_container (iter, &subiter))
1dae9197
MA
748 XD_SIGNAL2 (build_string ("Cannot close container"),
749 make_number (dtype));
87cf1a39 750 }
033b73e2
MA
751}
752
753/* Retrieve C value from a DBusMessageIter structure ITER, and return
754 a converted Lisp object. The type DTYPE of the argument of the
9af5078b
MA
755 D-Bus message must be a valid DBusType. Compound D-Bus types
756 result always in a Lisp list. */
78c38319 757static Lisp_Object
971de7fb 758xd_retrieve_arg (unsigned int dtype, DBusMessageIter *iter)
033b73e2
MA
759{
760
761 switch (dtype)
762 {
9af5078b 763 case DBUS_TYPE_BYTE:
9af5078b 764 {
17bc8f94 765 unsigned int val;
9af5078b 766 dbus_message_iter_get_basic (iter, &val);
17bc8f94 767 val = val & 0xFF;
3478ec45 768 XD_DEBUG_MESSAGE ("%c %u", dtype, val);
9af5078b
MA
769 return make_number (val);
770 }
771
033b73e2
MA
772 case DBUS_TYPE_BOOLEAN:
773 {
774 dbus_bool_t val;
775 dbus_message_iter_get_basic (iter, &val);
87cf1a39 776 XD_DEBUG_MESSAGE ("%c %s", dtype, (val == FALSE) ? "false" : "true");
033b73e2
MA
777 return (val == FALSE) ? Qnil : Qt;
778 }
87cf1a39 779
17bc8f94 780 case DBUS_TYPE_INT16:
1cae01f7
AS
781 {
782 dbus_int16_t val;
3478ec45 783 int pval;
1cae01f7 784 dbus_message_iter_get_basic (iter, &val);
3478ec45
PE
785 pval = val;
786 XD_DEBUG_MESSAGE ("%c %d", dtype, pval);
1cae01f7
AS
787 return make_number (val);
788 }
789
17bc8f94
MA
790 case DBUS_TYPE_UINT16:
791 {
792 dbus_uint16_t val;
3478ec45 793 int pval;
17bc8f94 794 dbus_message_iter_get_basic (iter, &val);
3478ec45
PE
795 pval = val;
796 XD_DEBUG_MESSAGE ("%c %d", dtype, pval);
17bc8f94
MA
797 return make_number (val);
798 }
799
033b73e2 800 case DBUS_TYPE_INT32:
1cae01f7
AS
801 {
802 dbus_int32_t val;
3478ec45 803 int pval;
1cae01f7 804 dbus_message_iter_get_basic (iter, &val);
3478ec45
PE
805 pval = val;
806 XD_DEBUG_MESSAGE ("%c %d", dtype, pval);
1cae01f7
AS
807 return make_fixnum_or_float (val);
808 }
809
033b73e2 810 case DBUS_TYPE_UINT32:
da1fec2b
MA
811#ifdef DBUS_TYPE_UNIX_FD
812 case DBUS_TYPE_UNIX_FD:
813#endif
033b73e2
MA
814 {
815 dbus_uint32_t val;
3478ec45 816 unsigned int pval = val;
033b73e2 817 dbus_message_iter_get_basic (iter, &val);
3478ec45
PE
818 pval = val;
819 XD_DEBUG_MESSAGE ("%c %u", dtype, pval);
1cae01f7 820 return make_fixnum_or_float (val);
9af5078b
MA
821 }
822
823 case DBUS_TYPE_INT64:
1cae01f7
AS
824 {
825 dbus_int64_t val;
3478ec45 826 printmax_t pval;
1cae01f7 827 dbus_message_iter_get_basic (iter, &val);
3478ec45
PE
828 pval = val;
829 XD_DEBUG_MESSAGE ("%c %"pMd, dtype, pval);
1cae01f7
AS
830 return make_fixnum_or_float (val);
831 }
832
9af5078b
MA
833 case DBUS_TYPE_UINT64:
834 {
835 dbus_uint64_t val;
3478ec45 836 uprintmax_t pval;
9af5078b 837 dbus_message_iter_get_basic (iter, &val);
3478ec45
PE
838 pval = val;
839 XD_DEBUG_MESSAGE ("%c %"pMd, dtype, pval);
9af5078b
MA
840 return make_fixnum_or_float (val);
841 }
842
843 case DBUS_TYPE_DOUBLE:
844 {
845 double val;
846 dbus_message_iter_get_basic (iter, &val);
847 XD_DEBUG_MESSAGE ("%c %f", dtype, val);
848 return make_float (val);
033b73e2 849 }
87cf1a39 850
033b73e2
MA
851 case DBUS_TYPE_STRING:
852 case DBUS_TYPE_OBJECT_PATH:
9af5078b 853 case DBUS_TYPE_SIGNATURE:
033b73e2
MA
854 {
855 char *val;
856 dbus_message_iter_get_basic (iter, &val);
87cf1a39 857 XD_DEBUG_MESSAGE ("%c %s", dtype, val);
033b73e2
MA
858 return build_string (val);
859 }
87cf1a39 860
033b73e2
MA
861 case DBUS_TYPE_ARRAY:
862 case DBUS_TYPE_VARIANT:
863 case DBUS_TYPE_STRUCT:
864 case DBUS_TYPE_DICT_ENTRY:
865 {
866 Lisp_Object result;
867 struct gcpro gcpro1;
033b73e2
MA
868 DBusMessageIter subiter;
869 int subtype;
fa8e045a
MA
870 result = Qnil;
871 GCPRO1 (result);
033b73e2
MA
872 dbus_message_iter_recurse (iter, &subiter);
873 while ((subtype = dbus_message_iter_get_arg_type (&subiter))
874 != DBUS_TYPE_INVALID)
875 {
876 result = Fcons (xd_retrieve_arg (subtype, &subiter), result);
877 dbus_message_iter_next (&subiter);
878 }
dcbf5805 879 XD_DEBUG_MESSAGE ("%c %s", dtype, XD_OBJECT_TO_STRING (result));
033b73e2
MA
880 RETURN_UNGCPRO (Fnreverse (result));
881 }
87cf1a39 882
033b73e2 883 default:
87cf1a39 884 XD_DEBUG_MESSAGE ("DBusType '%c' not supported", dtype);
033b73e2
MA
885 return Qnil;
886 }
887}
888
dcbf5805
MA
889/* Return the number of references of the shared CONNECTION. */
890static int
891xd_get_connection_references (DBusConnection *connection)
892{
893 ptrdiff_t *refcount;
de85e130 894
dcbf5805
MA
895 /* We cannot access the DBusConnection structure, it is not public.
896 But we know, that the reference counter is the first field in
897 that structure. */
898 refcount = (void *) &connection;
899 refcount = (void *) *refcount;
900 return *refcount;
901}
902
903/* Return D-Bus connection address. BUS is either a Lisp symbol,
904 :system or :session, or a string denoting the bus address. */
78c38319 905static DBusConnection *
dcbf5805 906xd_get_connection_address (Lisp_Object bus)
033b73e2
MA
907{
908 DBusConnection *connection;
dcbf5805 909 Lisp_Object val;
3f56d3c6 910
5cb67954 911 val = CDR_SAFE (Fassoc (bus, xd_registered_buses));
dcbf5805
MA
912 if (NILP (val))
913 XD_SIGNAL2 (build_string ("No connection to bus"), bus);
033b73e2 914 else
3478ec45 915 connection = (DBusConnection *) (intptr_t) XFASTINT (val);
033b73e2 916
dcbf5805 917 if (!dbus_connection_get_is_connected (connection))
3f56d3c6 918 XD_SIGNAL2 (build_string ("No connection to bus"), bus);
033b73e2 919
033b73e2
MA
920 return connection;
921}
922
3fad2ad2 923/* Return the file descriptor for WATCH, -1 if not found. */
3fad2ad2
J
924static int
925xd_find_watch_fd (DBusWatch *watch)
058ed861 926{
eb4c6ace 927#if HAVE_DBUS_WATCH_GET_UNIX_FD
3fad2ad2
J
928 /* TODO: Reverse these on Win32, which prefers the opposite. */
929 int fd = dbus_watch_get_unix_fd (watch);
930 if (fd == -1)
931 fd = dbus_watch_get_socket (watch);
3f56d3c6 932#else
3fad2ad2 933 int fd = dbus_watch_get_fd (watch);
3f56d3c6 934#endif
3fad2ad2
J
935 return fd;
936}
3f56d3c6 937
08609ffd
MA
938/* Prototype. */
939static void
940xd_read_queued_messages (int fd, void *data, int for_read);
058ed861 941
3fad2ad2 942/* Start monitoring WATCH for possible I/O. */
3fad2ad2
J
943static dbus_bool_t
944xd_add_watch (DBusWatch *watch, void *data)
945{
946 unsigned int flags = dbus_watch_get_flags (watch);
947 int fd = xd_find_watch_fd (watch);
948
949 XD_DEBUG_MESSAGE ("fd %d, write %d, enabled %d",
dcbf5805
MA
950 fd, flags & DBUS_WATCH_WRITABLE,
951 dbus_watch_get_enabled (watch));
3fad2ad2
J
952
953 if (fd == -1)
954 return FALSE;
955
956 if (dbus_watch_get_enabled (watch))
957 {
958 if (flags & DBUS_WATCH_WRITABLE)
08609ffd 959 add_write_fd (fd, xd_read_queued_messages, data);
3fad2ad2 960 if (flags & DBUS_WATCH_READABLE)
08609ffd 961 add_read_fd (fd, xd_read_queued_messages, data);
3fad2ad2 962 }
058ed861
MA
963 return TRUE;
964}
965
3fad2ad2
J
966/* Stop monitoring WATCH for possible I/O.
967 DATA is the used bus, either a string or QCdbus_system_bus or
0c372655 968 QCdbus_session_bus. */
3fad2ad2 969static void
971de7fb 970xd_remove_watch (DBusWatch *watch, void *data)
058ed861 971{
3fad2ad2
J
972 unsigned int flags = dbus_watch_get_flags (watch);
973 int fd = xd_find_watch_fd (watch);
3f56d3c6 974
3fad2ad2
J
975 XD_DEBUG_MESSAGE ("fd %d", fd);
976
08609ffd
MA
977 if (fd == -1)
978 return;
777013f2 979
3fad2ad2 980 /* Unset session environment. */
b4289b64 981 if (XSYMBOL (QCdbus_session_bus) == data)
3fad2ad2 982 {
dcbf5805
MA
983 // XD_DEBUG_MESSAGE ("unsetenv DBUS_SESSION_BUS_ADDRESS");
984 // unsetenv ("DBUS_SESSION_BUS_ADDRESS");
058ed861
MA
985 }
986
3fad2ad2
J
987 if (flags & DBUS_WATCH_WRITABLE)
988 delete_write_fd (fd);
989 if (flags & DBUS_WATCH_READABLE)
990 delete_read_fd (fd);
991}
992
993/* Toggle monitoring WATCH for possible I/O. */
3fad2ad2
J
994static void
995xd_toggle_watch (DBusWatch *watch, void *data)
996{
997 if (dbus_watch_get_enabled (watch))
998 xd_add_watch (watch, data);
999 else
1000 xd_remove_watch (watch, data);
058ed861
MA
1001}
1002
dcbf5805
MA
1003/* Close connection to D-Bus BUS. */
1004static void
1005xd_close_bus (Lisp_Object bus)
1006{
1007 DBusConnection *connection;
1008 Lisp_Object val;
1009
1010 /* Check whether we are connected. */
5cb67954 1011 val = Fassoc (bus, xd_registered_buses);
dcbf5805
MA
1012 if (NILP (val))
1013 return;
1014
1015 /* Retrieve bus address. */
1016 connection = xd_get_connection_address (bus);
1017
1018 /* Close connection, if there isn't another shared application. */
1019 if (xd_get_connection_references (connection) == 1)
1020 {
1021 XD_DEBUG_MESSAGE ("Close connection to bus %s",
1022 XD_OBJECT_TO_STRING (bus));
1023 dbus_connection_close (connection);
1024 }
1025
1026 /* Decrement reference count. */
1027 dbus_connection_unref (connection);
1028
1029 /* Remove bus from list of registered buses. */
5cb67954 1030 xd_registered_buses = Fdelete (val, xd_registered_buses);
dcbf5805
MA
1031
1032 /* Return. */
1033 return;
1034}
1035
1036DEFUN ("dbus-init-bus", Fdbus_init_bus, Sdbus_init_bus, 1, 2, 0,
1037 doc: /* Establish the connection to D-Bus BUS.
1038
1039BUS can be either the symbol `:system' or the symbol `:session', or it
1040can be a string denoting the address of the corresponding bus. For
1041the system and session buses, this function is called when loading
1042`dbus.el', there is no need to call it again.
1043
1044The function returns a number, which counts the connections this Emacs
1045session has established to the BUS under the same unique name (see
1046`dbus-get-unique-name'). It depends on the libraries Emacs is linked
1047with, and on the environment Emacs is running. For example, if Emacs
1048is linked with the gtk toolkit, and it runs in a GTK-aware environment
1049like Gnome, another connection might already be established.
1050
1051When PRIVATE is non-nil, a new connection is established instead of
1052reusing an existing one. It results in a new unique name at the bus.
1053This can be used, if it is necessary to distinguish from another
1054connection used in the same Emacs process, like the one established by
1055GTK+. It should be used with care for at least the `:system' and
1056`:session' buses, because other Emacs Lisp packages might already use
1057this connection to those buses. */)
1058 (Lisp_Object bus, Lisp_Object private)
058ed861
MA
1059{
1060 DBusConnection *connection;
dcbf5805
MA
1061 DBusError derror;
1062 Lisp_Object val;
1063 int refcount;
058ed861 1064
b4289b64 1065 /* Check parameter. */
dcbf5805
MA
1066 XD_DBUS_VALIDATE_BUS_ADDRESS (bus);
1067
1068 /* Close bus if it is already open. */
1069 xd_close_bus (bus);
1070
1071 /* Initialize. */
1072 dbus_error_init (&derror);
1073
1074 /* Open the connection. */
1075 if (STRINGP (bus))
1076 if (NILP (private))
1077 connection = dbus_connection_open (SSDATA (bus), &derror);
1078 else
1079 connection = dbus_connection_open_private (SSDATA (bus), &derror);
1080
1081 else
1082 if (NILP (private))
1083 connection = dbus_bus_get (EQ (bus, QCdbus_system_bus)
1084 ? DBUS_BUS_SYSTEM : DBUS_BUS_SESSION,
1085 &derror);
1086 else
1087 connection = dbus_bus_get_private (EQ (bus, QCdbus_system_bus)
1088 ? DBUS_BUS_SYSTEM : DBUS_BUS_SESSION,
1089 &derror);
1090
1091 if (dbus_error_is_set (&derror))
1092 XD_ERROR (derror);
1093
1094 if (connection == NULL)
1095 XD_SIGNAL2 (build_string ("No connection to bus"), bus);
1096
1097 /* If it is not the system or session bus, we must register
1098 ourselves. Otherwise, we have called dbus_bus_get, which has
1099 configured us to exit if the connection closes - we undo this
1100 setting. */
1101 if (STRINGP (bus))
1102 dbus_bus_register (connection, &derror);
b4289b64 1103 else
dcbf5805 1104 dbus_connection_set_exit_on_disconnect (connection, FALSE);
371cac43 1105
dcbf5805
MA
1106 if (dbus_error_is_set (&derror))
1107 XD_ERROR (derror);
058ed861 1108
777013f2 1109 /* Add the watch functions. We pass also the bus as data, in order
301b181a 1110 to distinguish between the buses in xd_remove_watch. */
058ed861
MA
1111 if (!dbus_connection_set_watch_functions (connection,
1112 xd_add_watch,
1113 xd_remove_watch,
3fad2ad2 1114 xd_toggle_watch,
dcbf5805
MA
1115 SYMBOLP (bus)
1116 ? (void *) XSYMBOL (bus)
1117 : (void *) XSTRING (bus),
1118 NULL))
058ed861
MA
1119 XD_SIGNAL1 (build_string ("Cannot add watch functions"));
1120
0c372655 1121 /* Add bus to list of registered buses. */
3478ec45 1122 XSETFASTINT (val, (intptr_t) connection);
5cb67954 1123 xd_registered_buses = Fcons (Fcons (bus, val), xd_registered_buses);
0c372655 1124
a79b0f28 1125 /* We do not want to abort. */
78320123 1126 putenv ((char *) "DBUS_FATAL_WARNINGS=0");
a79b0f28 1127
dcbf5805
MA
1128 /* Cleanup. */
1129 dbus_error_free (&derror);
0c372655 1130
dcbf5805
MA
1131 /* Return reference counter. */
1132 refcount = xd_get_connection_references (connection);
1133 XD_DEBUG_MESSAGE ("Bus %s, Reference counter %d",
1134 XD_OBJECT_TO_STRING (bus), refcount);
1135 return make_number (refcount);
058ed861
MA
1136}
1137
033b73e2
MA
1138DEFUN ("dbus-get-unique-name", Fdbus_get_unique_name, Sdbus_get_unique_name,
1139 1, 1, 0,
5125905e 1140 doc: /* Return the unique name of Emacs registered at D-Bus BUS. */)
5842a27b 1141 (Lisp_Object bus)
033b73e2
MA
1142{
1143 DBusConnection *connection;
48f7d213 1144 const char *name;
033b73e2 1145
dcbf5805
MA
1146 /* Check parameter. */
1147 XD_DBUS_VALIDATE_BUS_ADDRESS (bus);
1148
1149 /* Retrieve bus address. */
1150 connection = xd_get_connection_address (bus);
033b73e2
MA
1151
1152 /* Request the name. */
48f7d213 1153 name = dbus_bus_get_unique_name (connection);
033b73e2 1154 if (name == NULL)
1dae9197 1155 XD_SIGNAL1 (build_string ("No unique name available"));
033b73e2
MA
1156
1157 /* Return. */
1158 return build_string (name);
1159}
1160
dcbf5805
MA
1161DEFUN ("dbus-message-internal", Fdbus_message_internal, Sdbus_message_internal,
1162 4, MANY, 0,
1163 doc: /* Send a D-Bus message.
1164This is an internal function, it shall not be used outside dbus.el.
1165
1166The following usages are expected:
1167
1168`dbus-call-method', `dbus-call-method-asynchronously':
1169 \(dbus-message-internal
1170 dbus-message-type-method-call BUS SERVICE PATH INTERFACE METHOD HANDLER
1171 &optional :timeout TIMEOUT &rest ARGS)
1172
1173`dbus-send-signal':
1174 \(dbus-message-internal
1175 dbus-message-type-signal BUS SERVICE PATH INTERFACE SIGNAL &rest ARGS)
1176
1177`dbus-method-return-internal':
1178 \(dbus-message-internal
1179 dbus-message-type-method-return BUS SERVICE SERIAL &rest ARGS)
1180
1181`dbus-method-error-internal':
1182 \(dbus-message-internal
1183 dbus-message-type-error BUS SERVICE SERIAL &rest ARGS)
1184
1185usage: (dbus-message-internal &rest REST) */)
f66c7cf8 1186 (ptrdiff_t nargs, Lisp_Object *args)
033b73e2 1187{
dcbf5805
MA
1188 Lisp_Object message_type, bus, service, handler;
1189 Lisp_Object path = Qnil;
1190 Lisp_Object interface = Qnil;
1191 Lisp_Object member = Qnil;
033b73e2 1192 Lisp_Object result;
dcbf5805 1193 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5, gcpro6;
033b73e2
MA
1194 DBusConnection *connection;
1195 DBusMessage *dmessage;
033b73e2 1196 DBusMessageIter iter;
eb7c7bf5 1197 unsigned int dtype;
dcbf5805
MA
1198 unsigned int mtype;
1199 dbus_uint32_t serial = 0;
3478ec45 1200 unsigned int ui_serial;
90b3fc84 1201 int timeout = -1;
dcbf5805 1202 ptrdiff_t count;
87cf1a39 1203 char signature[DBUS_MAXIMUM_SIGNATURE_LENGTH];
033b73e2 1204
dcbf5805
MA
1205 /* Initialize parameters. */
1206 message_type = args[0];
1207 bus = args[1];
1208 service = args[2];
1209 handler = Qnil;
1210
1211 CHECK_NATNUM (message_type);
1212 mtype = XFASTINT (message_type);
1213 if ((mtype <= DBUS_MESSAGE_TYPE_INVALID) || (mtype >= DBUS_NUM_MESSAGE_TYPES))
1214 XD_SIGNAL2 (build_string ("Invalid message type"), message_type);
1215
1216 if ((mtype == DBUS_MESSAGE_TYPE_METHOD_CALL)
1217 || (mtype == DBUS_MESSAGE_TYPE_SIGNAL))
1218 {
1219 path = args[3];
1220 interface = args[4];
1221 member = args[5];
1222 if (mtype == DBUS_MESSAGE_TYPE_METHOD_CALL)
1223 handler = args[6];
1224 count = (mtype == DBUS_MESSAGE_TYPE_METHOD_CALL) ? 7 : 6;
1225 }
1226 else /* DBUS_MESSAGE_TYPE_METHOD_RETURN, DBUS_MESSAGE_TYPE_ERROR */
1227 {
1228 XD_CHECK_DBUS_SERIAL (args[3], serial);
1229 count = 4;
1230 }
1231
033b73e2 1232 /* Check parameters. */
dcbf5805
MA
1233 XD_DBUS_VALIDATE_BUS_ADDRESS (bus);
1234 XD_DBUS_VALIDATE_BUS_NAME (service);
1235 if (nargs < count)
1236 xsignal2 (Qwrong_number_of_arguments,
1237 Qdbus_message_internal,
1238 make_number (nargs));
1239
1240 if ((mtype == DBUS_MESSAGE_TYPE_METHOD_CALL)
1241 || (mtype == DBUS_MESSAGE_TYPE_SIGNAL))
1242 {
1243 XD_DBUS_VALIDATE_PATH (path);
1244 XD_DBUS_VALIDATE_INTERFACE (interface);
1245 XD_DBUS_VALIDATE_MEMBER (member);
1246 if (!NILP (handler) && (!FUNCTIONP (handler)))
1247 wrong_type_argument (Qinvalid_function, handler);
1248 }
90b3fc84 1249
dcbf5805
MA
1250 /* Protect Lisp variables. */
1251 GCPRO6 (bus, service, path, interface, member, handler);
1252
1253 /* Trace parameters. */
1254 switch (mtype)
033b73e2 1255 {
dcbf5805
MA
1256 case DBUS_MESSAGE_TYPE_METHOD_CALL:
1257 XD_DEBUG_MESSAGE ("%s %s %s %s %s %s %s",
1258 XD_MESSAGE_TYPE_TO_STRING (mtype),
1259 XD_OBJECT_TO_STRING (bus),
1260 XD_OBJECT_TO_STRING (service),
1261 XD_OBJECT_TO_STRING (path),
1262 XD_OBJECT_TO_STRING (interface),
1263 XD_OBJECT_TO_STRING (member),
1264 XD_OBJECT_TO_STRING (handler));
1265 break;
1266 case DBUS_MESSAGE_TYPE_SIGNAL:
1267 XD_DEBUG_MESSAGE ("%s %s %s %s %s %s",
1268 XD_MESSAGE_TYPE_TO_STRING (mtype),
1269 XD_OBJECT_TO_STRING (bus),
1270 XD_OBJECT_TO_STRING (service),
1271 XD_OBJECT_TO_STRING (path),
1272 XD_OBJECT_TO_STRING (interface),
1273 XD_OBJECT_TO_STRING (member));
1274 break;
1275 default: /* DBUS_MESSAGE_TYPE_METHOD_RETURN, DBUS_MESSAGE_TYPE_ERROR */
3478ec45 1276 ui_serial = serial;
dcbf5805
MA
1277 XD_DEBUG_MESSAGE ("%s %s %s %u",
1278 XD_MESSAGE_TYPE_TO_STRING (mtype),
1279 XD_OBJECT_TO_STRING (bus),
1280 XD_OBJECT_TO_STRING (service),
3478ec45 1281 ui_serial);
033b73e2
MA
1282 }
1283
dcbf5805
MA
1284 /* Retrieve bus address. */
1285 connection = xd_get_connection_address (bus);
54371585 1286
dcbf5805
MA
1287 /* Create the D-Bus message. */
1288 dmessage = dbus_message_new (mtype);
1289 if (dmessage == NULL)
1290 {
1291 UNGCPRO;
1292 XD_SIGNAL1 (build_string ("Unable to create a new message"));
1293 }
1294
1295 if (STRINGP (service))
033b73e2 1296 {
dcbf5805
MA
1297 if (mtype != DBUS_MESSAGE_TYPE_SIGNAL)
1298 /* Set destination. */
8c7a4ac5 1299 {
dcbf5805
MA
1300 if (!dbus_message_set_destination (dmessage, SSDATA (service)))
1301 {
1302 UNGCPRO;
1303 XD_SIGNAL2 (build_string ("Unable to set the destination"),
1304 service);
1305 }
8c7a4ac5 1306 }
dcbf5805 1307
8c7a4ac5 1308 else
dcbf5805 1309 /* Set destination for unicast signals. */
8c7a4ac5 1310 {
dcbf5805 1311 Lisp_Object uname;
033b73e2 1312
dcbf5805
MA
1313 /* If it is the same unique name as we are registered at the
1314 bus or an unknown name, we regard it as broadcast message
1315 due to backward compatibility. */
1316 if (dbus_bus_name_has_owner (connection, SSDATA (service), NULL))
1317 uname = call2 (intern ("dbus-get-name-owner"), bus, service);
1318 else
1319 uname = Qnil;
87cf1a39 1320
dcbf5805
MA
1321 if (STRINGP (uname)
1322 && (strcmp (dbus_bus_get_unique_name (connection), SSDATA (uname))
1323 != 0)
1324 && (!dbus_message_set_destination (dmessage, SSDATA (service))))
1325 {
1326 UNGCPRO;
1327 XD_SIGNAL2 (build_string ("Unable to set signal destination"),
1328 service);
1329 }
1330 }
033b73e2
MA
1331 }
1332
dcbf5805
MA
1333 /* Set message parameters. */
1334 if ((mtype == DBUS_MESSAGE_TYPE_METHOD_CALL)
1335 || (mtype == DBUS_MESSAGE_TYPE_SIGNAL))
033b73e2 1336 {
dcbf5805
MA
1337 if ((!dbus_message_set_path (dmessage, SSDATA (path)))
1338 || (!dbus_message_set_interface (dmessage, SSDATA (interface)))
1339 || (!dbus_message_set_member (dmessage, SSDATA (member))))
2c3a8b27 1340 {
dcbf5805
MA
1341 UNGCPRO;
1342 XD_SIGNAL1 (build_string ("Unable to set the message parameter"));
2c3a8b27 1343 }
033b73e2 1344 }
13ecc6dc 1345
dcbf5805
MA
1346 else /* DBUS_MESSAGE_TYPE_METHOD_RETURN, DBUS_MESSAGE_TYPE_ERROR */
1347 {
1348 if (!dbus_message_set_reply_serial (dmessage, serial))
1349 {
1350 UNGCPRO;
1351 XD_SIGNAL1 (build_string ("Unable to create a return message"));
1352 }
13ecc6dc 1353
dcbf5805
MA
1354 if ((mtype == DBUS_MESSAGE_TYPE_ERROR)
1355 && (!dbus_message_set_error_name (dmessage, DBUS_ERROR_FAILED)))
1356 {
1357 UNGCPRO;
1358 XD_SIGNAL1 (build_string ("Unable to create a error message"));
1359 }
1360 }
13ecc6dc
MA
1361
1362 /* Check for timeout parameter. */
dcbf5805 1363 if ((count+2 <= nargs) && (EQ ((args[count]), QCdbus_timeout)))
13ecc6dc 1364 {
dcbf5805
MA
1365 CHECK_NATNUM (args[count+1]);
1366 timeout = XFASTINT (args[count+1]);
1367 count = count+2;
13ecc6dc
MA
1368 }
1369
1370 /* Initialize parameter list of message. */
1371 dbus_message_iter_init_append (dmessage, &iter);
1372
1373 /* Append parameters to the message. */
dcbf5805 1374 for (; count < nargs; ++count)
13ecc6dc 1375 {
dcbf5805
MA
1376 dtype = XD_OBJECT_TO_DBUS_TYPE (args[count]);
1377 if (XD_DBUS_TYPE_P (args[count]))
13ecc6dc 1378 {
dcbf5805
MA
1379 XD_DEBUG_VALID_LISP_OBJECT_P (args[count]);
1380 XD_DEBUG_VALID_LISP_OBJECT_P (args[count+1]);
1381 XD_DEBUG_MESSAGE ("Parameter%"pD"d %s %s", count - 4,
1382 XD_OBJECT_TO_STRING (args[count]),
1383 XD_OBJECT_TO_STRING (args[count+1]));
1384 ++count;
13ecc6dc
MA
1385 }
1386 else
1387 {
dcbf5805
MA
1388 XD_DEBUG_VALID_LISP_OBJECT_P (args[count]);
1389 XD_DEBUG_MESSAGE ("Parameter%"pD"d %s", count - 4,
1390 XD_OBJECT_TO_STRING (args[count]));
13ecc6dc
MA
1391 }
1392
1393 /* Check for valid signature. We use DBUS_TYPE_INVALID as
1394 indication that there is no parent type. */
dcbf5805 1395 xd_signature (signature, dtype, DBUS_TYPE_INVALID, args[count]);
13ecc6dc 1396
dcbf5805 1397 xd_append_arg (dtype, args[count], &iter);
13ecc6dc
MA
1398 }
1399
ca4f31ea
MA
1400 if (!NILP (handler))
1401 {
1402 /* Send the message. The message is just added to the outgoing
1403 message queue. */
1404 if (!dbus_connection_send_with_reply (connection, dmessage,
1405 NULL, timeout))
dcbf5805
MA
1406 {
1407 UNGCPRO;
1408 XD_SIGNAL1 (build_string ("Cannot send message"));
1409 }
1410
f04bb9b2 1411 /* The result is the key in Vdbus_registered_objects_table. */
08686060 1412 serial = dbus_message_get_serial (dmessage);
dcbf5805
MA
1413 result = list3 (QCdbus_registered_serial,
1414 bus, make_fixnum_or_float (serial));
13ecc6dc 1415
ca4f31ea 1416 /* Create a hash table entry. */
f04bb9b2 1417 Fputhash (result, handler, Vdbus_registered_objects_table);
ca4f31ea
MA
1418 }
1419 else
1420 {
1421 /* Send the message. The message is just added to the outgoing
1422 message queue. */
1423 if (!dbus_connection_send (connection, dmessage, NULL))
dcbf5805
MA
1424 {
1425 UNGCPRO;
1426 XD_SIGNAL1 (build_string ("Cannot send message"));
1427 }
13ecc6dc 1428
ca4f31ea
MA
1429 result = Qnil;
1430 }
1431
dcbf5805 1432 XD_DEBUG_MESSAGE ("Message sent: %s", XD_OBJECT_TO_STRING (result));
13ecc6dc
MA
1433
1434 /* Cleanup. */
1435 dbus_message_unref (dmessage);
1436
1437 /* Return the result. */
1438 RETURN_UNGCPRO (result);
1439}
1440
3fad2ad2
J
1441/* Read one queued incoming message of the D-Bus BUS.
1442 BUS is either a Lisp symbol, :system or :session, or a string denoting
1443 the bus address. */
3fad2ad2
J
1444static void
1445xd_read_message_1 (DBusConnection *connection, Lisp_Object bus)
033b73e2 1446{
a31d47c7 1447 Lisp_Object args, key, value;
033b73e2 1448 struct gcpro gcpro1;
15f16c1b 1449 struct input_event event;
033b73e2
MA
1450 DBusMessage *dmessage;
1451 DBusMessageIter iter;
eb7c7bf5 1452 unsigned int dtype;
dcbf5805 1453 unsigned int mtype;
30217ff0 1454 dbus_uint32_t serial;
08686060 1455 unsigned int ui_serial;
a8e72f4f 1456 const char *uname, *path, *interface, *member;
39abdd4a 1457
033b73e2
MA
1458 dmessage = dbus_connection_pop_message (connection);
1459
1460 /* Return if there is no queued message. */
1461 if (dmessage == NULL)
3fad2ad2 1462 return;
033b73e2
MA
1463
1464 /* Collect the parameters. */
a31d47c7
MA
1465 args = Qnil;
1466 GCPRO1 (args);
033b73e2 1467
033b73e2 1468 /* Loop over the resulting parameters. Construct a list. */
17bc8f94 1469 if (dbus_message_iter_init (dmessage, &iter))
033b73e2 1470 {
17bc8f94
MA
1471 while ((dtype = dbus_message_iter_get_arg_type (&iter))
1472 != DBUS_TYPE_INVALID)
1473 {
1474 args = Fcons (xd_retrieve_arg (dtype, &iter), args);
1475 dbus_message_iter_next (&iter);
1476 }
1477 /* The arguments are stored in reverse order. Reorder them. */
1478 args = Fnreverse (args);
033b73e2
MA
1479 }
1480
13ecc6dc
MA
1481 /* Read message type, message serial, unique name, object path,
1482 interface and member from the message. */
367ea173 1483 mtype = dbus_message_get_type (dmessage);
08686060 1484 ui_serial = serial =
367ea173
MA
1485 ((mtype == DBUS_MESSAGE_TYPE_METHOD_RETURN)
1486 || (mtype == DBUS_MESSAGE_TYPE_ERROR))
1487 ? dbus_message_get_reply_serial (dmessage)
1488 : dbus_message_get_serial (dmessage);
1489 uname = dbus_message_get_sender (dmessage);
1490 path = dbus_message_get_path (dmessage);
a8e72f4f 1491 interface = dbus_message_get_interface (dmessage);
367ea173 1492 member = dbus_message_get_member (dmessage);
a8e72f4f 1493
30217ff0 1494 XD_DEBUG_MESSAGE ("Event received: %s %u %s %s %s %s %s",
dcbf5805 1495 XD_MESSAGE_TYPE_TO_STRING (mtype),
08686060 1496 ui_serial, uname, path, interface, member,
dcbf5805 1497 XD_OBJECT_TO_STRING (args));
17bc8f94 1498
dcbf5805
MA
1499 if (mtype == DBUS_MESSAGE_TYPE_INVALID)
1500 goto cleanup;
1501
1502 else if ((mtype == DBUS_MESSAGE_TYPE_METHOD_RETURN)
1503 || (mtype == DBUS_MESSAGE_TYPE_ERROR))
13ecc6dc
MA
1504 {
1505 /* Search for a registered function of the message. */
dcbf5805
MA
1506 key = list3 (QCdbus_registered_serial, bus,
1507 make_fixnum_or_float (serial));
f04bb9b2 1508 value = Fgethash (key, Vdbus_registered_objects_table, Qnil);
13ecc6dc
MA
1509
1510 /* There shall be exactly one entry. Construct an event. */
1511 if (NILP (value))
1512 goto cleanup;
1513
1514 /* Remove the entry. */
f04bb9b2 1515 Fremhash (key, Vdbus_registered_objects_table);
13ecc6dc
MA
1516
1517 /* Construct an event. */
1518 EVENT_INIT (event);
1519 event.kind = DBUS_EVENT;
1520 event.frame_or_window = Qnil;
1521 event.arg = Fcons (value, args);
1522 }
a31d47c7 1523
dcbf5805 1524 else /* DBUS_MESSAGE_TYPE_METHOD_CALL, DBUS_MESSAGE_TYPE_SIGNAL. */
a31d47c7 1525 {
f04bb9b2
MA
1526 /* Vdbus_registered_objects_table requires non-nil interface and
1527 member. */
13ecc6dc
MA
1528 if ((interface == NULL) || (member == NULL))
1529 goto cleanup;
1530
1531 /* Search for a registered function of the message. */
dcbf5805
MA
1532 key = list4 ((mtype == DBUS_MESSAGE_TYPE_METHOD_CALL)
1533 ? QCdbus_registered_method
1534 : QCdbus_registered_signal,
1535 bus, build_string (interface), build_string (member));
f04bb9b2 1536 value = Fgethash (key, Vdbus_registered_objects_table, Qnil);
13ecc6dc
MA
1537
1538 /* Loop over the registered functions. Construct an event. */
1539 while (!NILP (value))
a31d47c7 1540 {
13ecc6dc
MA
1541 key = CAR_SAFE (value);
1542 /* key has the structure (UNAME SERVICE PATH HANDLER). */
1543 if (((uname == NULL)
1544 || (NILP (CAR_SAFE (key)))
59d6fe83 1545 || (strcmp (uname, SSDATA (CAR_SAFE (key))) == 0))
13ecc6dc
MA
1546 && ((path == NULL)
1547 || (NILP (CAR_SAFE (CDR_SAFE (CDR_SAFE (key)))))
1548 || (strcmp (path,
59d6fe83 1549 SSDATA (CAR_SAFE (CDR_SAFE (CDR_SAFE (key)))))
13ecc6dc
MA
1550 == 0))
1551 && (!NILP (CAR_SAFE (CDR_SAFE (CDR_SAFE (CDR_SAFE (key)))))))
1552 {
1553 EVENT_INIT (event);
1554 event.kind = DBUS_EVENT;
1555 event.frame_or_window = Qnil;
b4289b64
MA
1556 event.arg
1557 = Fcons (CAR_SAFE (CDR_SAFE (CDR_SAFE (CDR_SAFE (key)))), args);
13ecc6dc
MA
1558 break;
1559 }
1560 value = CDR_SAFE (value);
a31d47c7 1561 }
13ecc6dc
MA
1562
1563 if (NILP (value))
1564 goto cleanup;
a31d47c7 1565 }
033b73e2 1566
13ecc6dc
MA
1567 /* Add type, serial, uname, path, interface and member to the event. */
1568 event.arg = Fcons ((member == NULL ? Qnil : build_string (member)),
1569 event.arg);
1570 event.arg = Fcons ((interface == NULL ? Qnil : build_string (interface)),
1571 event.arg);
1572 event.arg = Fcons ((path == NULL ? Qnil : build_string (path)),
1573 event.arg);
1574 event.arg = Fcons ((uname == NULL ? Qnil : build_string (uname)),
1575 event.arg);
08686060 1576 event.arg = Fcons (make_fixnum_or_float (serial), event.arg);
13ecc6dc
MA
1577 event.arg = Fcons (make_number (mtype), event.arg);
1578
1579 /* Add the bus symbol to the event. */
1580 event.arg = Fcons (bus, event.arg);
1581
1582 /* Store it into the input event queue. */
1583 kbd_buffer_store_event (&event);
1584
dcbf5805 1585 XD_DEBUG_MESSAGE ("Event stored: %s", XD_OBJECT_TO_STRING (event.arg));
13ecc6dc 1586
c1d5ce94 1587 /* Cleanup. */
a8e72f4f 1588 cleanup:
033b73e2 1589 dbus_message_unref (dmessage);
c1d5ce94 1590
3fad2ad2
J
1591 UNGCPRO;
1592}
1593
1594/* Read queued incoming messages of the D-Bus BUS.
1595 BUS is either a Lisp symbol, :system or :session, or a string denoting
1596 the bus address. */
3fad2ad2
J
1597static Lisp_Object
1598xd_read_message (Lisp_Object bus)
1599{
dcbf5805
MA
1600 /* Retrieve bus address. */
1601 DBusConnection *connection = xd_get_connection_address (bus);
3fad2ad2
J
1602
1603 /* Non blocking read of the next available message. */
1604 dbus_connection_read_write (connection, 0);
1605
1606 while (dbus_connection_get_dispatch_status (connection)
1607 != DBUS_DISPATCH_COMPLETE)
1608 xd_read_message_1 (connection, bus);
1609 return Qnil;
033b73e2
MA
1610}
1611
08609ffd
MA
1612/* Callback called when something is ready to read or write. */
1613static void
1614xd_read_queued_messages (int fd, void *data, int for_read)
033b73e2 1615{
5cb67954 1616 Lisp_Object busp = xd_registered_buses;
08609ffd 1617 Lisp_Object bus = Qnil;
dcbf5805 1618 Lisp_Object key;
96faeb40 1619
08609ffd
MA
1620 /* Find bus related to fd. */
1621 if (data != NULL)
1622 while (!NILP (busp))
1623 {
dcbf5805
MA
1624 key = CAR_SAFE (CAR_SAFE (busp));
1625 if ((SYMBOLP (key) && XSYMBOL (key) == data)
1626 || (STRINGP (key) && XSTRING (key) == data))
1627 bus = key;
08609ffd
MA
1628 busp = CDR_SAFE (busp);
1629 }
1630
5e617bc2 1631 if (NILP (bus))
08609ffd
MA
1632 return;
1633
1634 /* We ignore all Lisp errors during the call. */
0c372655 1635 xd_in_read_queued_messages = 1;
08609ffd 1636 internal_catch (Qdbus_error, xd_read_message, bus);
0c372655 1637 xd_in_read_queued_messages = 0;
033b73e2
MA
1638}
1639
033b73e2
MA
1640\f
1641void
971de7fb 1642syms_of_dbusbind (void)
033b73e2
MA
1643{
1644
cd3520a4 1645 DEFSYM (Qdbus_init_bus, "dbus-init-bus");
058ed861
MA
1646 defsubr (&Sdbus_init_bus);
1647
cd3520a4 1648 DEFSYM (Qdbus_get_unique_name, "dbus-get-unique-name");
033b73e2
MA
1649 defsubr (&Sdbus_get_unique_name);
1650
dcbf5805
MA
1651 DEFSYM (Qdbus_message_internal, "dbus-message-internal");
1652 defsubr (&Sdbus_message_internal);
17bc8f94 1653
cd3520a4 1654 DEFSYM (Qdbus_error, "dbus-error");
033b73e2
MA
1655 Fput (Qdbus_error, Qerror_conditions,
1656 list2 (Qdbus_error, Qerror));
1657 Fput (Qdbus_error, Qerror_message,
d67b4f80 1658 make_pure_c_string ("D-Bus error"));
033b73e2 1659
cd3520a4
JB
1660 DEFSYM (QCdbus_system_bus, ":system");
1661 DEFSYM (QCdbus_session_bus, ":session");
cd3520a4
JB
1662 DEFSYM (QCdbus_timeout, ":timeout");
1663 DEFSYM (QCdbus_type_byte, ":byte");
1664 DEFSYM (QCdbus_type_boolean, ":boolean");
1665 DEFSYM (QCdbus_type_int16, ":int16");
1666 DEFSYM (QCdbus_type_uint16, ":uint16");
1667 DEFSYM (QCdbus_type_int32, ":int32");
1668 DEFSYM (QCdbus_type_uint32, ":uint32");
1669 DEFSYM (QCdbus_type_int64, ":int64");
1670 DEFSYM (QCdbus_type_uint64, ":uint64");
1671 DEFSYM (QCdbus_type_double, ":double");
1672 DEFSYM (QCdbus_type_string, ":string");
1673 DEFSYM (QCdbus_type_object_path, ":object-path");
1674 DEFSYM (QCdbus_type_signature, ":signature");
da1fec2b 1675#ifdef DBUS_TYPE_UNIX_FD
cd3520a4 1676 DEFSYM (QCdbus_type_unix_fd, ":unix-fd");
da1fec2b 1677#endif
cd3520a4
JB
1678 DEFSYM (QCdbus_type_array, ":array");
1679 DEFSYM (QCdbus_type_variant, ":variant");
1680 DEFSYM (QCdbus_type_struct, ":struct");
1681 DEFSYM (QCdbus_type_dict_entry, ":dict-entry");
dcbf5805
MA
1682 DEFSYM (QCdbus_registered_serial, ":serial");
1683 DEFSYM (QCdbus_registered_method, ":method");
1684 DEFSYM (QCdbus_registered_signal, ":signal");
1685
1686 DEFVAR_LISP ("dbus-compiled-version",
1687 Vdbus_compiled_version,
1688 doc: /* The version of D-Bus Emacs is compiled against. */);
1689#ifdef DBUS_VERSION_STRING
1690 Vdbus_compiled_version = make_pure_c_string (DBUS_VERSION_STRING);
1691#else
1692 Vdbus_compiled_version = Qnil;
1693#endif
1694
1695 DEFVAR_LISP ("dbus-runtime-version",
1696 Vdbus_runtime_version,
1697 doc: /* The version of D-Bus Emacs runs with. */);
1698 {
1699#ifdef DBUS_VERSION
1700 int major, minor, micro;
1701 char s[1024];
1702 dbus_get_version (&major, &minor, &micro);
1703 snprintf (s, sizeof s, "%d.%d.%d", major, minor, micro);
1704 Vdbus_runtime_version = make_string (s, strlen (s));
1705#else
1706 Vdbus_runtime_version = Qnil;
1707#endif
1708 }
1709
1710 DEFVAR_LISP ("dbus-message-type-invalid",
1711 Vdbus_message_type_invalid,
1712 doc: /* This value is never a valid message type. */);
1713 Vdbus_message_type_invalid = make_number (DBUS_MESSAGE_TYPE_INVALID);
1714
1715 DEFVAR_LISP ("dbus-message-type-method-call",
1716 Vdbus_message_type_method_call,
1717 doc: /* Message type of a method call message. */);
1718 Vdbus_message_type_method_call = make_number (DBUS_MESSAGE_TYPE_METHOD_CALL);
1719
1720 DEFVAR_LISP ("dbus-message-type-method-return",
1721 Vdbus_message_type_method_return,
1722 doc: /* Message type of a method return message. */);
1723 Vdbus_message_type_method_return
1724 = make_number (DBUS_MESSAGE_TYPE_METHOD_RETURN);
1725
1726 DEFVAR_LISP ("dbus-message-type-error",
1727 Vdbus_message_type_error,
1728 doc: /* Message type of an error reply message. */);
1729 Vdbus_message_type_error = make_number (DBUS_MESSAGE_TYPE_ERROR);
1730
1731 DEFVAR_LISP ("dbus-message-type-signal",
1732 Vdbus_message_type_signal,
1733 doc: /* Message type of a signal message. */);
1734 Vdbus_message_type_signal = make_number (DBUS_MESSAGE_TYPE_SIGNAL);
54371585 1735
f04bb9b2 1736 DEFVAR_LISP ("dbus-registered-objects-table",
29208e82 1737 Vdbus_registered_objects_table,
39abdd4a 1738 doc: /* Hash table of registered functions for D-Bus.
0c372655 1739
f04bb9b2
MA
1740There are two different uses of the hash table: for accessing
1741registered interfaces properties, targeted by signals or method calls,
1742and for calling handlers in case of non-blocking method call returns.
13ecc6dc 1743
dcbf5805
MA
1744In the first case, the key in the hash table is the list (TYPE BUS
1745INTERFACE MEMBER). TYPE is one of the Lisp symbols `:method',
1746`:signal' or `:property'. BUS is either a Lisp symbol, `:system' or
0c372655
MA
1747`:session', or a string denoting the bus address. INTERFACE is a
1748string which denotes a D-Bus interface, and MEMBER, also a string, is
1749either a method, a signal or a property INTERFACE is offering. All
1750arguments but BUS must not be nil.
a31d47c7 1751
dcbf5805
MA
1752The value in the hash table is a list of quadruple lists \((UNAME
1753SERVICE PATH OBJECT [RULE]) ...). SERVICE is the service name as
1754registered, UNAME is the corresponding unique name. In case of
1755registered methods and properties, UNAME is nil. PATH is the object
1756path of the sending object. All of them can be nil, which means a
1757wildcard then. OBJECT is either the handler to be called when a D-Bus
1758message, which matches the key criteria, arrives (TYPE `:method' and
1759`:signal'), or a cons cell containing the value of the property (TYPE
1760`:property').
13ecc6dc 1761
dcbf5805
MA
1762For entries of type `:signal', there is also a fifth element RULE,
1763which keeps the match string the signal is registered with.
a3de0cbd 1764
dcbf5805 1765In the second case, the key in the hash table is the list (:serial BUS
0c372655
MA
1766SERIAL). BUS is either a Lisp symbol, `:system' or `:session', or a
1767string denoting the bus address. SERIAL is the serial number of the
1768non-blocking method call, a reply is expected. Both arguments must
1769not be nil. The value in the hash table is HANDLER, the function to
1770be called when the D-Bus reply message arrives. */);
1771 {
1772 Lisp_Object args[2];
1773 args[0] = QCtest;
1774 args[1] = Qequal;
1775 Vdbus_registered_objects_table = Fmake_hash_table (2, args);
1776 }
033b73e2 1777
29208e82 1778 DEFVAR_LISP ("dbus-debug", Vdbus_debug,
39abdd4a 1779 doc: /* If non-nil, debug messages of D-Bus bindings are raised. */);
033b73e2
MA
1780#ifdef DBUS_DEBUG
1781 Vdbus_debug = Qt;
a79b0f28
MA
1782 /* We can also set environment variable DBUS_VERBOSE=1 in order to
1783 see more traces. This requires libdbus-1 to be configured with
1784 --enable-verbose-mode. */
033b73e2
MA
1785#else
1786 Vdbus_debug = Qnil;
1787#endif
1788
5cb67954
MA
1789 /* Initialize internal objects. */
1790 xd_registered_buses = Qnil;
1791 staticpro (&xd_registered_buses);
1792
d67b4f80 1793 Fprovide (intern_c_string ("dbusbind"), Qnil);
033b73e2
MA
1794
1795}
1796
1797#endif /* HAVE_DBUS */