summaryrefslogtreecommitdiffstats
path: root/swaybar/tray/dbus.c
diff options
context:
space:
mode:
Diffstat (limited to 'swaybar/tray/dbus.c')
-rw-r--r--swaybar/tray/dbus.c189
1 files changed, 189 insertions, 0 deletions
diff --git a/swaybar/tray/dbus.c b/swaybar/tray/dbus.c
new file mode 100644
index 00000000..333d398e
--- /dev/null
+++ b/swaybar/tray/dbus.c
@@ -0,0 +1,189 @@
1#define _XOPEN_SOURCE 500
2#include <stdio.h>
3#include <stdlib.h>
4#include <stdint.h>
5#include <stdbool.h>
6#include <poll.h>
7#include <signal.h>
8#include <time.h>
9#include <dbus/dbus.h>
10#include "swaybar/tray/dbus.h"
11#include "swaybar/event_loop.h"
12#include "log.h"
13
14DBusConnection *conn = NULL;
15
16static void dispatch_watch(int fd, short mask, void *data) {
17 sway_log(L_DEBUG, "Dispatching watch");
18 DBusWatch *watch = data;
19
20 if (!dbus_watch_get_enabled(watch)) {
21 return;
22 }
23
24 uint32_t flags = 0;
25
26 if (mask & POLLIN) {
27 flags |= DBUS_WATCH_READABLE;
28 } if (mask & POLLOUT) {
29 flags |= DBUS_WATCH_WRITABLE;
30 } if (mask & POLLHUP) {
31 flags |= DBUS_WATCH_HANGUP;
32 } if (mask & POLLERR) {
33 flags |= DBUS_WATCH_ERROR;
34 }
35
36 dbus_watch_handle(watch, flags);
37}
38
39static dbus_bool_t add_watch(DBusWatch *watch, void *_data) {
40 if (!dbus_watch_get_enabled(watch)) {
41 // Watch should not be polled
42 return TRUE;
43 }
44
45 short mask = 0;
46 uint32_t flags = dbus_watch_get_flags(watch);
47
48 if (flags & DBUS_WATCH_READABLE) {
49 mask |= POLLIN;
50 } if (flags & DBUS_WATCH_WRITABLE) {
51 mask |= POLLOUT;
52 }
53
54 int fd = dbus_watch_get_unix_fd(watch);
55
56 sway_log(L_DEBUG, "Adding DBus watch fd: %d", fd);
57 add_event(fd, mask, dispatch_watch, watch);
58
59 return TRUE;
60}
61
62static void remove_watch(DBusWatch *watch, void *_data) {
63 int fd = dbus_watch_get_unix_fd(watch);
64
65 remove_event(fd);
66}
67
68static void dispatch_timeout(timer_t timer, void *data) {
69 sway_log(L_DEBUG, "Dispatching DBus timeout");
70 DBusTimeout *timeout = data;
71
72 if (dbus_timeout_get_enabled(timeout)) {
73 dbus_timeout_handle(timeout);
74 }
75}
76
77static dbus_bool_t add_timeout(DBusTimeout *timeout, void *_data) {
78 if (!dbus_timeout_get_enabled(timeout)) {
79 return TRUE;
80 }
81
82 timer_t *timer = malloc(sizeof(timer_t));
83 if (!timer) {
84 sway_log(L_ERROR, "Cannot allocate memory");
85 return FALSE;
86 }
87 struct sigevent ev = {
88 .sigev_notify = SIGEV_NONE,
89 };
90
91 if (timer_create(CLOCK_MONOTONIC, &ev, timer)) {
92 sway_log(L_ERROR, "Could not create DBus timer");
93 return FALSE;
94 }
95
96 int interval = dbus_timeout_get_interval(timeout);
97 int interval_sec = interval / 1000;
98 int interval_msec = (interval_sec * 1000) - interval;
99
100 struct timespec period = {
101 (time_t) interval_sec,
102 ((long) interval_msec) * 1000 * 1000,
103 };
104 struct itimerspec time = {
105 period,
106 period,
107 };
108
109 timer_settime(*timer, 0, &time, NULL);
110
111 dbus_timeout_set_data(timeout, timer, free);
112
113 sway_log(L_DEBUG, "Adding DBus timeout. Interval: %ds %dms", interval_sec, interval_msec);
114 add_timer(*timer, dispatch_timeout, timeout);
115
116 return TRUE;
117}
118static void remove_timeout(DBusTimeout *timeout, void *_data) {
119 timer_t *timer = (timer_t *) dbus_timeout_get_data(timeout);
120 sway_log(L_DEBUG, "Removing DBus timeout.");
121
122 if (timer) {
123 remove_timer(*timer);
124 }
125}
126
127static bool should_dispatch = true;
128
129static void dispatch_status(DBusConnection *connection, DBusDispatchStatus new_status,
130 void *_data) {
131 if (new_status == DBUS_DISPATCH_DATA_REMAINS) {
132 should_dispatch = true;
133 }
134}
135
136/* Public functions below */
137
138void dispatch_dbus() {
139 if (!should_dispatch) {
140 return;
141 }
142
143 DBusDispatchStatus status;
144
145 do {
146 status = dbus_connection_dispatch(conn);
147 } while (status == DBUS_DISPATCH_DATA_REMAINS);
148
149 if (status != DBUS_DISPATCH_COMPLETE) {
150 sway_log(L_ERROR, "Cannot dispatch dbus events: %d", status);
151 }
152
153 should_dispatch = false;
154}
155
156int dbus_init() {
157 DBusError error;
158 dbus_error_init(&error);
159
160 conn = dbus_bus_get(DBUS_BUS_SESSION, &error);
161 dbus_connection_set_exit_on_disconnect(conn, FALSE);
162 if (dbus_error_is_set(&error)) {
163 sway_log(L_ERROR, "Cannot get bus connection: %s\n", error.message);
164 conn = NULL;
165 return -1;
166 }
167
168 sway_log(L_INFO, "Unique name: %s\n", dbus_bus_get_unique_name(conn));
169
170 // Will be called if dispatch status changes
171 dbus_connection_set_dispatch_status_function(conn, dispatch_status, NULL, NULL);
172
173 if (!dbus_connection_set_watch_functions(conn, add_watch, remove_watch,
174 NULL, NULL, NULL)) {
175 dbus_connection_set_watch_functions(conn, NULL, NULL, NULL, NULL, NULL);
176 sway_log(L_ERROR, "Failed to activate DBUS watch functions");
177 return -1;
178 }
179
180 if (!dbus_connection_set_timeout_functions(conn, add_timeout, remove_timeout,
181 NULL, NULL, NULL)) {
182 dbus_connection_set_watch_functions(conn, NULL, NULL, NULL, NULL, NULL);
183 dbus_connection_set_timeout_functions(conn, NULL, NULL, NULL, NULL, NULL);
184 sway_log(L_ERROR, "Failed to activate DBUS timeout functions");
185 return -1;
186 }
187
188 return 0;
189}