aboutsummaryrefslogtreecommitdiff
path: root/swaybar/tray/dbus.c
diff options
context:
space:
mode:
authorCalvin Lee <cyrus296@gmail.com>2017-06-07 16:45:28 -0700
committerCalvin Lee <cyrus296@gmail.com>2017-06-07 17:49:16 -0700
commit843ad38b3c427adb0bf319e9613d9813c8d9246c (patch)
treee02a5b06e2b6923371fd53724791c147c18a1fa4 /swaybar/tray/dbus.c
parentfd47a30e75cccfc3789eafa4bfabd66f4696099b (diff)
Implement Tray Icons
This commit implements the StatusNotifierItem protocol, and enables swaybar to show tray icons. It also uses `xembedsniproxy` in order to communicate with xembed applications. The tray is completely optional, and can be disabled on compile time with the `enable-tray` option. Or on runtime with the bar config option `tray_output none`. Overview of changes: In swaybar very little is changed outside the tray subfolder except that all events are now polled in `event_loop.c`, this creates no functional difference. Six bar configuration options were added, these are detailed in sway-bar(5) The tray subfolder is where all protocol implementation takes place and is organised as follows: tray/sni_watcher.c: This file contains the StatusNotifierWatcher. It keeps track of items and hosts and reports when they come or go. tray/tray.c This file contains the StatusNotifierHost. It keeps track of sway's version of the items and represents the tray itself. tray/sni.c This file contains the StatusNotifierItem struct and all communication with individual items. tray/icon.c This file implements the icon theme protocol. It allows for finding icons by name, rather than by pixmap. tray/dbus.c This file allows for asynchronous DBus communication. See #986 #343
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 @@
+#define _XOPEN_SOURCE 500
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <poll.h>
+#include <signal.h>
+#include <time.h>
+#include <dbus/dbus.h>
+#include "swaybar/tray/dbus.h"
+#include "swaybar/event_loop.h"
+#include "log.h"
+
+DBusConnection *conn = NULL;
+
+static void dispatch_watch(int fd, short mask, void *data) {
+ sway_log(L_DEBUG, "Dispatching watch");
+ DBusWatch *watch = data;
+
+ if (!dbus_watch_get_enabled(watch)) {
+ return;
+ }
+
+ uint32_t flags = 0;
+
+ if (mask & POLLIN) {
+ flags |= DBUS_WATCH_READABLE;
+ } if (mask & POLLOUT) {
+ flags |= DBUS_WATCH_WRITABLE;
+ } if (mask & POLLHUP) {
+ flags |= DBUS_WATCH_HANGUP;
+ } if (mask & POLLERR) {
+ flags |= DBUS_WATCH_ERROR;
+ }
+
+ dbus_watch_handle(watch, flags);
+}
+
+static dbus_bool_t add_watch(DBusWatch *watch, void *_data) {
+ if (!dbus_watch_get_enabled(watch)) {
+ // Watch should not be polled
+ return TRUE;
+ }
+
+ short mask = 0;
+ uint32_t flags = dbus_watch_get_flags(watch);
+
+ if (flags & DBUS_WATCH_READABLE) {
+ mask |= POLLIN;
+ } if (flags & DBUS_WATCH_WRITABLE) {
+ mask |= POLLOUT;
+ }
+
+ int fd = dbus_watch_get_unix_fd(watch);
+
+ sway_log(L_DEBUG, "Adding DBus watch fd: %d", fd);
+ add_event(fd, mask, dispatch_watch, watch);
+
+ return TRUE;
+}
+
+static void remove_watch(DBusWatch *watch, void *_data) {
+ int fd = dbus_watch_get_unix_fd(watch);
+
+ remove_event(fd);
+}
+
+static void dispatch_timeout(timer_t timer, void *data) {
+ sway_log(L_DEBUG, "Dispatching DBus timeout");
+ DBusTimeout *timeout = data;
+
+ if (dbus_timeout_get_enabled(timeout)) {
+ dbus_timeout_handle(timeout);
+ }
+}
+
+static dbus_bool_t add_timeout(DBusTimeout *timeout, void *_data) {
+ if (!dbus_timeout_get_enabled(timeout)) {
+ return TRUE;
+ }
+
+ timer_t *timer = malloc(sizeof(timer_t));
+ if (!timer) {
+ sway_log(L_ERROR, "Cannot allocate memory");
+ return FALSE;
+ }
+ struct sigevent ev = {
+ .sigev_notify = SIGEV_NONE,
+ };
+
+ if (timer_create(CLOCK_MONOTONIC, &ev, timer)) {
+ sway_log(L_ERROR, "Could not create DBus timer");
+ return FALSE;
+ }
+
+ int interval = dbus_timeout_get_interval(timeout);
+ int interval_sec = interval / 1000;
+ int interval_msec = (interval_sec * 1000) - interval;
+
+ struct timespec period = {
+ (time_t) interval_sec,
+ ((long) interval_msec) * 1000 * 1000,
+ };
+ struct itimerspec time = {
+ period,
+ period,
+ };
+
+ timer_settime(*timer, 0, &time, NULL);
+
+ dbus_timeout_set_data(timeout, timer, free);
+
+ sway_log(L_DEBUG, "Adding DBus timeout. Interval: %ds %dms", interval_sec, interval_msec);
+ add_timer(*timer, dispatch_timeout, timeout);
+
+ return TRUE;
+}
+static void remove_timeout(DBusTimeout *timeout, void *_data) {
+ timer_t *timer = (timer_t *) dbus_timeout_get_data(timeout);
+ sway_log(L_DEBUG, "Removing DBus timeout.");
+
+ if (timer) {
+ remove_timer(*timer);
+ }
+}
+
+static bool should_dispatch = true;
+
+static void dispatch_status(DBusConnection *connection, DBusDispatchStatus new_status,
+ void *_data) {
+ if (new_status == DBUS_DISPATCH_DATA_REMAINS) {
+ should_dispatch = true;
+ }
+}
+
+/* Public functions below */
+
+void dispatch_dbus() {
+ if (!should_dispatch) {
+ return;
+ }
+
+ DBusDispatchStatus status;
+
+ do {
+ status = dbus_connection_dispatch(conn);
+ } while (status == DBUS_DISPATCH_DATA_REMAINS);
+
+ if (status != DBUS_DISPATCH_COMPLETE) {
+ sway_log(L_ERROR, "Cannot dispatch dbus events: %d", status);
+ }
+
+ should_dispatch = false;
+}
+
+int dbus_init() {
+ DBusError error;
+ dbus_error_init(&error);
+
+ conn = dbus_bus_get(DBUS_BUS_SESSION, &error);
+ dbus_connection_set_exit_on_disconnect(conn, FALSE);
+ if (dbus_error_is_set(&error)) {
+ sway_log(L_ERROR, "Cannot get bus connection: %s\n", error.message);
+ conn = NULL;
+ return -1;
+ }
+
+ sway_log(L_INFO, "Unique name: %s\n", dbus_bus_get_unique_name(conn));
+
+ // Will be called if dispatch status changes
+ dbus_connection_set_dispatch_status_function(conn, dispatch_status, NULL, NULL);
+
+ if (!dbus_connection_set_watch_functions(conn, add_watch, remove_watch,
+ NULL, NULL, NULL)) {
+ dbus_connection_set_watch_functions(conn, NULL, NULL, NULL, NULL, NULL);
+ sway_log(L_ERROR, "Failed to activate DBUS watch functions");
+ return -1;
+ }
+
+ if (!dbus_connection_set_timeout_functions(conn, add_timeout, remove_timeout,
+ NULL, NULL, NULL)) {
+ dbus_connection_set_watch_functions(conn, NULL, NULL, NULL, NULL, NULL);
+ dbus_connection_set_timeout_functions(conn, NULL, NULL, NULL, NULL, NULL);
+ sway_log(L_ERROR, "Failed to activate DBUS timeout functions");
+ return -1;
+ }
+
+ return 0;
+}