aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--swaybar/bar.c18
-rw-r--r--swaybar/event_loop.c42
2 files changed, 38 insertions, 22 deletions
diff --git a/swaybar/bar.c b/swaybar/bar.c
index d51c4ec7..669cb11a 100644
--- a/swaybar/bar.c
+++ b/swaybar/bar.c
@@ -401,24 +401,28 @@ void bar_setup(struct swaybar *bar,
render_all_frames(bar);
}
-static void display_in(int fd, short mask, void *_bar) {
- struct swaybar *bar = (struct swaybar *)_bar;
+static void display_in(int fd, short mask, void *data) {
+ struct swaybar *bar = data;
if (wl_display_dispatch(bar->display) == -1) {
bar_teardown(bar);
exit(0);
}
}
-static void ipc_in(int fd, short mask, void *_bar) {
- struct swaybar *bar = (struct swaybar *)_bar;
+static void ipc_in(int fd, short mask, void *data) {
+ struct swaybar *bar = data;
if (handle_ipc_readable(bar)) {
render_all_frames(bar);
}
}
-static void status_in(int fd, short mask, void *_bar) {
- struct swaybar *bar = (struct swaybar *)_bar;
- if (status_handle_readable(bar->status)) {
+static void status_in(int fd, short mask, void *data) {
+ struct swaybar *bar = data;
+ if (mask & (POLLHUP | POLLERR)) {
+ status_error(bar->status, "[error reading from status command]");
+ render_all_frames(bar);
+ remove_event(fd);
+ } else if (status_handle_readable(bar->status)) {
render_all_frames(bar);
}
}
diff --git a/swaybar/event_loop.c b/swaybar/event_loop.c
index 748372ed..bc4053be 100644
--- a/swaybar/event_loop.c
+++ b/swaybar/event_loop.c
@@ -72,24 +72,18 @@ void add_event(int fd, short mask,
}
bool remove_event(int fd) {
- int index = -1;
+ /*
+ * Instead of removing events immediately, we mark them for deletion
+ * and clean them up later. This is so we can call remove_event inside
+ * an event callback safely.
+ */
for (int i = 0; i < event_loop.fds.length; ++i) {
if (event_loop.fds.items[i].fd == fd) {
- index = i;
+ event_loop.fds.items[i].fd = -1;
+ return true;
}
}
- 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;
- }
+ return false;
}
static int timer_item_timer_cmp(const void *_timer_item, const void *_timer) {
@@ -118,11 +112,29 @@ void event_loop_poll() {
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) {
+ // Always send these events
+ unsigned events = pfd.events | POLLHUP | POLLERR;
+
+ if (pfd.revents & events) {
item->cb(pfd.fd, pfd.revents, item->data);
}
}
+ // Cleanup removed events
+ int end = 0;
+ int length = event_loop.fds.length;
+ for (int i = 0; i < length; ++i) {
+ if (event_loop.fds.items[i].fd == -1) {
+ free(event_loop.items->items[i]);
+ list_del(event_loop.items, i);
+ --event_loop.fds.length;
+ } else if (end != i) {
+ event_loop.fds.items[end++] = event_loop.fds.items[i];
+ } else {
+ end = i + 1;
+ }
+ }
+
// check timers
// not tested, but seems to work
for (int i = 0; i < event_loop.timers->length; ++i) {