+/* Return the file descriptor for WATCH, -1 if not found. */
+static int
+xd_find_watch_fd (DBusWatch *watch)
+{
+#if HAVE_DBUS_WATCH_GET_UNIX_FD
+ /* TODO: Reverse these on Win32, which prefers the opposite. */
+ int fd = dbus_watch_get_unix_fd (watch);
+ if (fd == -1)
+ fd = dbus_watch_get_socket (watch);
+#else
+ int fd = dbus_watch_get_fd (watch);
+#endif
+ return fd;
+}
+
+/* Prototype. */
+static void
+xd_read_queued_messages (int fd, void *data, int for_read);
+
+/* Start monitoring WATCH for possible I/O. */
+static dbus_bool_t
+xd_add_watch (DBusWatch *watch, void *data)
+{
+ unsigned int flags = dbus_watch_get_flags (watch);
+ int fd = xd_find_watch_fd (watch);
+
+ XD_DEBUG_MESSAGE ("fd %d, write %d, enabled %d",
+ fd, flags & DBUS_WATCH_WRITABLE,
+ dbus_watch_get_enabled (watch));
+
+ if (fd == -1)
+ return FALSE;
+
+ if (dbus_watch_get_enabled (watch))
+ {
+ if (flags & DBUS_WATCH_WRITABLE)
+ add_write_fd (fd, xd_read_queued_messages, data);
+ if (flags & DBUS_WATCH_READABLE)
+ add_read_fd (fd, xd_read_queued_messages, data);
+ }
+ return TRUE;
+}
+
+/* Stop monitoring WATCH for possible I/O.
+ DATA is the used bus, either a string or QCdbus_system_bus or
+ QCdbus_session_bus. */
+static void
+xd_remove_watch (DBusWatch *watch, void *data)
+{
+ unsigned int flags = dbus_watch_get_flags (watch);
+ int fd = xd_find_watch_fd (watch);
+
+ XD_DEBUG_MESSAGE ("fd %d", fd);
+
+ if (fd == -1)
+ return;
+
+ /* Unset session environment. */
+ if (data != NULL && data == (void*) XHASH (QCdbus_session_bus))
+ {
+ XD_DEBUG_MESSAGE ("unsetenv DBUS_SESSION_BUS_ADDRESS");
+ unsetenv ("DBUS_SESSION_BUS_ADDRESS");
+ }
+
+ if (flags & DBUS_WATCH_WRITABLE)
+ delete_write_fd (fd);
+ if (flags & DBUS_WATCH_READABLE)
+ delete_read_fd (fd);
+}
+
+/* Toggle monitoring WATCH for possible I/O. */
+static void
+xd_toggle_watch (DBusWatch *watch, void *data)
+{
+ if (dbus_watch_get_enabled (watch))
+ xd_add_watch (watch, data);
+ else
+ xd_remove_watch (watch, data);
+}
+
+DEFUN ("dbus-init-bus", Fdbus_init_bus, Sdbus_init_bus, 1, 1, 0,
+ doc: /* Initialize connection to D-Bus BUS. */)
+ (Lisp_Object bus)
+{
+ DBusConnection *connection;
+
+ /* Open a connection to the bus. */
+ connection = xd_initialize (bus, TRUE);
+
+ /* Add the watch functions. We pass also the bus as data, in order
+ to distinguish between the busses in xd_remove_watch. */
+ if (!dbus_connection_set_watch_functions (connection,
+ xd_add_watch,
+ xd_remove_watch,
+ xd_toggle_watch,
+ (void*) XHASH (bus), NULL))
+ XD_SIGNAL1 (build_string ("Cannot add watch functions"));
+
+ /* Add bus to list of registered buses. */
+ Vdbus_registered_buses = Fcons (bus, Vdbus_registered_buses);
+
+ /* We do not want to abort. */
+ putenv ("DBUS_FATAL_WARNINGS=0");
+
+ /* Return. */
+ return Qnil;
+}
+
+DEFUN ("dbus-close-bus", Fdbus_close_bus, Sdbus_close_bus, 1, 1, 0,
+ doc: /* Close connection to D-Bus BUS. */)
+ (Lisp_Object bus)
+{
+ DBusConnection *connection;
+
+ /* Open a connection to the bus. */
+ connection = xd_initialize (bus, TRUE);
+
+ /* Decrement reference count to the bus. */
+ dbus_connection_unref (connection);
+
+ /* Remove bus from list of registered buses. */
+ Vdbus_registered_buses = Fdelete (bus, Vdbus_registered_buses);
+
+ /* Return. */
+ return Qnil;
+}
+