aboutsummaryrefslogtreecommitdiffstats
path: root/dbus.c
diff options
context:
space:
mode:
authorNikita Langer <nikitalanger@icloud.com>2026-08-22 18:23:18 +0200
committerNikita Langer <nikitalanger@icloud.com>2026-08-22 18:23:18 +0200
commit98f342c73911d1ba4afcdcd36bd5b4fb9cade224 (patch)
tree1dd0db18d76f5af51e161f919179e84142c3cc25 /dbus.c
parent960d0661f6ed5ab6fd9c371c53a5f5b137864da1 (diff)
downloaddwl-master.tar.gz
dwl-master.tar.bz2
dwl-master.tar.xz
dwl-master.zip
systrayHEADmaster
Diffstat (limited to 'dbus.c')
-rw-r--r--dbus.c242
1 files changed, 242 insertions, 0 deletions
diff --git a/dbus.c b/dbus.c
new file mode 100644
index 0000000..d4e9727
--- /dev/null
+++ b/dbus.c
@@ -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);
+}