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