From 843ad38b3c427adb0bf319e9613d9813c8d9246c Mon Sep 17 00:00:00 2001 From: Calvin Lee Date: Wed, 7 Jun 2017 16:45:28 -0700 Subject: 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 --- swaybar/event_loop.c | 143 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 143 insertions(+) create mode 100644 swaybar/event_loop.c (limited to 'swaybar/event_loop.c') diff --git a/swaybar/event_loop.c b/swaybar/event_loop.c new file mode 100644 index 00000000..80655d8b --- /dev/null +++ b/swaybar/event_loop.c @@ -0,0 +1,143 @@ +#define _XOPEN_SOURCE 500 +#include +#include +#include +#include +#include +#include "swaybar/bar.h" +#include "swaybar/event_loop.h" +#include "list.h" +#include "log.h" + +struct event_item { + void(*cb)(int fd, short mask, void *data); + void *data; +}; + +struct timer_item { + timer_t timer; + void(*cb)(timer_t timer, void *data); + void *data; +}; + +static struct { + // The order of each must be kept consistent + struct { /* pollfd array */ + struct pollfd *items; + int capacity; + int length; + } fds; + list_t *items; /* event_item list */ + + // Timer list + list_t *timers; +} event_loop; + +void add_timer(timer_t timer, + void(*cb)(timer_t timer, void *data), + void *data) { + + struct timer_item *item = malloc(sizeof(struct timer_item)); + item->timer = timer; + item->cb = cb; + item->data = data; + + list_add(event_loop.timers, item); +} + +void add_event(int fd, short mask, + void(*cb)(int fd, short mask, void *data), void *data) { + + struct pollfd pollfd = { + fd, + mask, + 0, + }; + + // Resize + if (event_loop.fds.length == event_loop.fds.capacity) { + event_loop.fds.capacity += 10; + event_loop.fds.items = realloc(event_loop.fds.items, + sizeof(struct pollfd) * event_loop.fds.capacity); + } + + event_loop.fds.items[event_loop.fds.length++] = pollfd; + + struct event_item *item = malloc(sizeof(struct event_item)); + item->cb = cb; + item->data = data; + + list_add(event_loop.items, item); + + return; +} + +bool remove_event(int fd) { + int index = -1; + for (int i = 0; i < event_loop.fds.length; ++i) { + if (event_loop.fds.items[i].fd == fd) { + index = i; + } + } + if (index != -1) { + free(event_loop.items->items[index]); + + --event_loop.fds.length; + memmove(&event_loop.fds.items[index], &event_loop.fds.items[index + 1], + sizeof(struct pollfd) * event_loop.fds.length - index); + + list_del(event_loop.items, index); + return true; + } else { + return false; + } +} + +static int timer_item_timer_cmp(const void *_timer_item, const void *_timer) { + const struct timer_item *timer_item = _timer_item; + const timer_t *timer = _timer; + if (timer_item->timer == timer) { + return 0; + } else { + return -1; + } +} +bool remove_timer(timer_t timer) { + int index = list_seq_find(event_loop.timers, timer_item_timer_cmp, &timer); + if (index != -1) { + list_del(event_loop.timers, index); + return true; + } + return false; +} + +void event_loop_poll() { + poll(event_loop.fds.items, event_loop.fds.length, -1); + + for (int i = 0; i < event_loop.fds.length; ++i) { + struct pollfd pfd = event_loop.fds.items[i]; + struct event_item *item = (struct event_item *)event_loop.items->items[i]; + + if (pfd.revents & pfd.events) { + item->cb(pfd.fd, pfd.revents, item->data); + } + } + + // check timers + // not tested, but seems to work + for (int i = 0; i < event_loop.timers->length; ++i) { + struct timer_item *item = event_loop.timers->items[i]; + int overrun = timer_getoverrun(item->timer); + if (overrun && overrun != -1) { + item->cb(item->timer, item->data); + } + } +} + +void init_event_loop() { + event_loop.fds.length = 0; + event_loop.fds.capacity = 10; + event_loop.fds.items = malloc(event_loop.fds.capacity * sizeof(struct pollfd)); + event_loop.items = create_list(); + event_loop.timers = create_list(); +} -- cgit v1.2.3