diff options
| author | Nikita Langer <nikitalanger@icloud.com> | 2026-08-22 18:23:18 +0200 |
|---|---|---|
| committer | Nikita Langer <nikitalanger@icloud.com> | 2026-08-22 18:23:18 +0200 |
| commit | 98f342c73911d1ba4afcdcd36bd5b4fb9cade224 (patch) | |
| tree | 1dd0db18d76f5af51e161f919179e84142c3cc25 /dbus.c | |
| parent | 960d0661f6ed5ab6fd9c371c53a5f5b137864da1 (diff) | |
| download | dwl-master.tar.gz dwl-master.tar.bz2 dwl-master.tar.xz dwl-master.zip | |
Diffstat (limited to 'dbus.c')
| -rw-r--r-- | dbus.c | 242 |
1 files changed, 242 insertions, 0 deletions
@@ -0,0 +1,242 @@ +#include "dbus.h" + +#include "util.h" + +#include <dbus/dbus.h> +#include <stdlib.h> +#include <wayland-server-core.h> + +#include <fcntl.h> +#include <stddef.h> +#include <stdint.h> +#include <stdio.h> +#include <unistd.h> + +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); +} |
