#include "dbus.h" #include "util.h" #include #include #include #include #include #include #include #include static void close_pipe(void *data) { int *pipefd = data; close(pipefd[0]); close(pipefd[1]); free(pipefd); } static int dwl_dbus_dispatch(int fd, unsigned int mask, void *data) { DBusConnection *conn = data; int pending; DBusDispatchStatus oldstatus, newstatus; oldstatus = dbus_connection_get_dispatch_status(conn); newstatus = dbus_connection_dispatch(conn); /* Don't clear pending flag if status didn't change */ if (oldstatus == newstatus) return 0; if (read(fd, &pending, sizeof(int)) < 0) { perror("read"); die("Error in dbus dispatch"); } return 0; } static int dwl_dbus_watch_handle(int fd, uint32_t mask, void *data) { DBusWatch *watch = data; uint32_t flags = 0; if (!dbus_watch_get_enabled(watch)) return 0; if (mask & WL_EVENT_READABLE) flags |= DBUS_WATCH_READABLE; if (mask & WL_EVENT_WRITABLE) flags |= DBUS_WATCH_WRITABLE; if (mask & WL_EVENT_HANGUP) flags |= DBUS_WATCH_HANGUP; if (mask & WL_EVENT_ERROR) flags |= DBUS_WATCH_ERROR; dbus_watch_handle(watch, flags); return 0; } static dbus_bool_t dwl_dbus_add_watch(DBusWatch *watch, void *data) { struct wl_event_loop *loop = data; int fd; struct wl_event_source *watch_source; uint32_t mask = 0, flags; if (!dbus_watch_get_enabled(watch)) return TRUE; flags = dbus_watch_get_flags(watch); if (flags & DBUS_WATCH_READABLE) mask |= WL_EVENT_READABLE; if (flags & DBUS_WATCH_WRITABLE) mask |= WL_EVENT_WRITABLE; fd = dbus_watch_get_unix_fd(watch); watch_source = wl_event_loop_add_fd(loop, fd, mask, dwl_dbus_watch_handle, watch); dbus_watch_set_data(watch, watch_source, NULL); return TRUE; } static void dwl_dbus_remove_watch(DBusWatch *watch, void *data) { struct wl_event_source *watch_source = dbus_watch_get_data(watch); if (watch_source) wl_event_source_remove(watch_source); } static int dwl_dbus_timeout_handle(void *data) { DBusTimeout *timeout = data; if (dbus_timeout_get_enabled(timeout)) dbus_timeout_handle(timeout); return 0; } static dbus_bool_t dwl_dbus_add_timeout(DBusTimeout *timeout, void *data) { struct wl_event_loop *loop = data; int r, interval; struct wl_event_source *timeout_source; if (!dbus_timeout_get_enabled(timeout)) return TRUE; interval = dbus_timeout_get_interval(timeout); timeout_source = wl_event_loop_add_timer(loop, dwl_dbus_timeout_handle, timeout); r = wl_event_source_timer_update(timeout_source, interval); if (r < 0) { wl_event_source_remove(timeout_source); return FALSE; } dbus_timeout_set_data(timeout, timeout_source, NULL); return TRUE; } static void dwl_dbus_remove_timeout(DBusTimeout *timeout, void *data) { struct wl_event_source *timeout_source; timeout_source = dbus_timeout_get_data(timeout); if (timeout_source) { wl_event_source_timer_update(timeout_source, 0); wl_event_source_remove(timeout_source); } } static void dwl_dbus_dispatch_status(DBusConnection *conn, DBusDispatchStatus status, void *data) { int *pipefd = data; if (status != DBUS_DISPATCH_COMPLETE) { int pending = 1; if (write(pipefd[1], &pending, sizeof(int)) < 0) { perror("write"); die("Error in dispatch status"); } } } struct wl_event_source * startbus(DBusConnection *conn, struct wl_event_loop *loop) { int *pipefd; int pending = 1, flags; struct wl_event_source *bus_source = NULL; pipefd = ecalloc(2, sizeof(int)); /* * Libdbus forbids calling dbus_connection_dispatch from the * DBusDispatchStatusFunction directly. Notify the event loop of * updates via a self-pipe. */ if (pipe(pipefd) < 0) goto fail; if (((flags = fcntl(pipefd[0], F_GETFD)) < 0) || fcntl(pipefd[0], F_SETFD, flags | FD_CLOEXEC) < 0 || ((flags = fcntl(pipefd[1], F_GETFD)) < 0) || fcntl(pipefd[1], F_SETFD, flags | FD_CLOEXEC) < 0) { goto fail; } dbus_connection_set_exit_on_disconnect(conn, FALSE); bus_source = wl_event_loop_add_fd(loop, pipefd[0], WL_EVENT_READABLE, dwl_dbus_dispatch, conn); if (!bus_source) goto fail; dbus_connection_set_dispatch_status_function(conn, dwl_dbus_dispatch_status, pipefd, close_pipe); if (!dbus_connection_set_watch_functions(conn, dwl_dbus_add_watch, dwl_dbus_remove_watch, NULL, loop, NULL)) { goto fail; } if (!dbus_connection_set_timeout_functions(conn, dwl_dbus_add_timeout, dwl_dbus_remove_timeout, NULL, loop, NULL)) { goto fail; } if (dbus_connection_get_dispatch_status(conn) != DBUS_DISPATCH_COMPLETE) if (write(pipefd[1], &pending, sizeof(int)) < 0) goto fail; return bus_source; fail: if (bus_source) wl_event_source_remove(bus_source); dbus_connection_set_timeout_functions(conn, NULL, NULL, NULL, NULL, NULL); dbus_connection_set_watch_functions(conn, NULL, NULL, NULL, NULL, NULL); dbus_connection_set_dispatch_status_function(conn, NULL, NULL, NULL); return NULL; } void stopbus(DBusConnection *conn, struct wl_event_source *bus_source) { wl_event_source_remove(bus_source); dbus_connection_set_watch_functions(conn, NULL, NULL, NULL, NULL, NULL); dbus_connection_set_timeout_functions(conn, NULL, NULL, NULL, NULL, NULL); dbus_connection_set_dispatch_status_function(conn, NULL, NULL, NULL); }