aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--common/loop.c105
-rw-r--r--common/meson.build1
-rw-r--r--include/loop.h47
-rw-r--r--include/swaybar/bar.h5
-rw-r--r--include/swaybar/event_loop.h26
-rw-r--r--include/swaybar/status_line.h2
-rw-r--r--swaybar/bar.c17
-rw-r--r--swaybar/event_loop.c156
-rw-r--r--swaybar/meson.build1
-rw-r--r--swaybar/status_line.c4
10 files changed, 172 insertions, 192 deletions
diff --git a/common/loop.c b/common/loop.c
new file mode 100644
index 00000000..bfbfd5a6
--- /dev/null
+++ b/common/loop.c
@@ -0,0 +1,105 @@
1#include <string.h>
2#include <stdbool.h>
3#include <stdlib.h>
4#include <stdio.h>
5#include <poll.h>
6#include <sys/timerfd.h>
7#include <unistd.h>
8#include "list.h"
9#include "log.h"
10#include "loop.h"
11
12struct loop_event {
13 void (*callback)(int fd, short mask, void *data);
14 void *data;
15};
16
17struct loop {
18 struct pollfd *fds;
19 int fd_length;
20 int fd_capacity;
21
22 list_t *events; // struct loop_event
23};
24
25struct loop *loop_create(void) {
26 struct loop *loop = calloc(1, sizeof(struct loop));
27 if (!loop) {
28 wlr_log(WLR_ERROR, "Unable to allocate memory for loop");
29 return NULL;
30 }
31 loop->fd_capacity = 10;
32 loop->fds = malloc(sizeof(struct pollfd) * loop->fd_capacity);
33 loop->events = create_list();
34 return loop;
35}
36
37void loop_destroy(struct loop *loop) {
38 list_foreach(loop->events, free);
39 list_free(loop->events);
40 free(loop);
41}
42
43void loop_poll(struct loop *loop) {
44 poll(loop->fds, loop->fd_length, -1);
45
46 for (int i = 0; i < loop->fd_length; ++i) {
47 struct pollfd pfd = loop->fds[i];
48 struct loop_event *event = loop->events->items[i];
49
50 // Always send these events
51 unsigned events = pfd.events | POLLHUP | POLLERR;
52
53 if (pfd.revents & events) {
54 event->callback(pfd.fd, pfd.revents, event->data);
55 }
56 }
57}
58
59struct loop_event *loop_add_fd(struct loop *loop, int fd, short mask,
60 void (*callback)(int fd, short mask, void *data), void *data) {
61 struct pollfd pfd = {fd, mask, 0};
62
63 if (loop->fd_length == loop->fd_capacity) {
64 loop->fd_capacity += 10;
65 loop->fds = realloc(loop->fds, sizeof(struct pollfd) * loop->fd_capacity);
66 }
67
68 loop->fds[loop->fd_length++] = pfd;
69
70 struct loop_event *event = calloc(1, sizeof(struct loop_event));
71 event->callback = callback;
72 event->data = data;
73
74 list_add(loop->events, event);
75
76 return event;
77}
78
79struct loop_event *loop_add_timer(struct loop *loop, int ms,
80 void (*callback)(int fd, short mask, void *data), void *data) {
81 int fd = timerfd_create(CLOCK_MONOTONIC, 0);
82 struct itimerspec its;
83 its.it_interval.tv_sec = 0;
84 its.it_interval.tv_nsec = 0;
85 its.it_value.tv_sec = ms / 1000000000;
86 its.it_value.tv_nsec = (ms * 1000000) % 1000000000;
87 timerfd_settime(fd, 0, &its, NULL);
88
89 return loop_add_fd(loop, fd, POLLIN, callback, data);
90}
91
92bool loop_remove_event(struct loop *loop, struct loop_event *event) {
93 for (int i = 0; i < loop->events->length; ++i) {
94 if (loop->events->items[i] == event) {
95 list_del(loop->events, i);
96
97 loop->fd_length--;
98 memmove(&loop->fds[i], &loop->fds[i + 1], sizeof(void*) * (loop->fd_length - i));
99
100 free(event);
101 return true;
102 }
103 }
104 return false;
105}
diff --git a/common/meson.build b/common/meson.build
index 44a29508..224a9c3f 100644
--- a/common/meson.build
+++ b/common/meson.build
@@ -5,6 +5,7 @@ lib_sway_common = static_library(
5 'cairo.c', 5 'cairo.c',
6 'ipc-client.c', 6 'ipc-client.c',
7 'log.c', 7 'log.c',
8 'loop.c',
8 'list.c', 9 'list.c',
9 'pango.c', 10 'pango.c',
10 'readline.c', 11 'readline.c',
diff --git a/include/loop.h b/include/loop.h
new file mode 100644
index 00000000..7c151785
--- /dev/null
+++ b/include/loop.h
@@ -0,0 +1,47 @@
1#ifndef _SWAY_LOOP_H
2#define _SWAY_LOOP_H
3#include <stdbool.h>
4
5/**
6 * This is an event loop system designed for sway clients, not sway itself.
7 *
8 * It uses pollfds to block on multiple file descriptors at once, and provides
9 * an easy way to set timers. Typically the Wayland display's fd will be one of
10 * the fds in the loop.
11 */
12
13struct loop;
14
15/**
16 * Create an event loop.
17 */
18struct loop *loop_create(void);
19
20/**
21 * Destroy the event loop (eg. on program termination).
22 */
23void loop_destroy(struct loop *loop);
24
25/**
26 * Poll the event loop. This will block until one of the fds has data.
27 */
28void loop_poll(struct loop *loop);
29
30/**
31 * Add an fd to the loop.
32 */
33struct loop_event *loop_add_fd(struct loop *loop, int fd, short mask,
34 void (*func)(int fd, short mask, void *data), void *data);
35
36/**
37 * Add a timer to the loop.
38 */
39struct loop_event *loop_add_timer(struct loop *loop, int ms,
40 void (*callback)(int fd, short mask, void *data), void *data);
41
42/**
43 * Remove an event from the loop.
44 */
45bool loop_remove_event(struct loop *loop, struct loop_event *event);
46
47#endif
diff --git a/include/swaybar/bar.h b/include/swaybar/bar.h
index 9ff3fe7b..d61da5dc 100644
--- a/include/swaybar/bar.h
+++ b/include/swaybar/bar.h
@@ -8,6 +8,8 @@
8struct swaybar_config; 8struct swaybar_config;
9struct swaybar_output; 9struct swaybar_output;
10struct swaybar_workspace; 10struct swaybar_workspace;
11struct loop;
12struct loop_event;
11 13
12struct swaybar_pointer { 14struct swaybar_pointer {
13 struct wl_pointer *pointer; 15 struct wl_pointer *pointer;
@@ -66,6 +68,9 @@ struct swaybar {
66 struct swaybar_pointer pointer; 68 struct swaybar_pointer pointer;
67 struct status_line *status; 69 struct status_line *status;
68 70
71 struct loop *eventloop;
72 struct loop_event *status_event;
73
69 int ipc_event_socketfd; 74 int ipc_event_socketfd;
70 int ipc_socketfd; 75 int ipc_socketfd;
71 76
diff --git a/include/swaybar/event_loop.h b/include/swaybar/event_loop.h
deleted file mode 100644
index 47be5b79..00000000
--- a/include/swaybar/event_loop.h
+++ /dev/null
@@ -1,26 +0,0 @@
1#ifndef _SWAYBAR_EVENT_LOOP_H
2#define _SWAYBAR_EVENT_LOOP_H
3#include <stdbool.h>
4#include <time.h>
5
6void add_event(int fd, short mask,
7 void(*cb)(int fd, short mask, void *data),
8 void *data);
9
10// Not guaranteed to notify cb immediately
11void add_timer(timer_t timer,
12 void(*cb)(timer_t timer, void *data),
13 void *data);
14
15// Returns false if nothing exists, true otherwise
16bool remove_event(int fd);
17
18// Returns false if nothing exists, true otherwise
19bool remove_timer(timer_t timer);
20
21// Blocks and returns after sending callbacks
22void event_loop_poll(void);
23
24void init_event_loop(void);
25
26#endif
diff --git a/include/swaybar/status_line.h b/include/swaybar/status_line.h
index 5e7e8771..957a808e 100644
--- a/include/swaybar/status_line.h
+++ b/include/swaybar/status_line.h
@@ -14,6 +14,8 @@ enum status_protocol {
14}; 14};
15 15
16struct status_line { 16struct status_line {
17 struct swaybar *bar;
18
17 pid_t pid; 19 pid_t pid;
18 int read_fd, write_fd; 20 int read_fd, write_fd;
19 FILE *read, *write; 21 FILE *read, *write;
diff --git a/swaybar/bar.c b/swaybar/bar.c
index 9f72c94c..8e89c9a8 100644
--- a/swaybar/bar.c
+++ b/swaybar/bar.c
@@ -18,7 +18,6 @@
18#endif 18#endif
19#include "swaybar/bar.h" 19#include "swaybar/bar.h"
20#include "swaybar/config.h" 20#include "swaybar/config.h"
21#include "swaybar/event_loop.h"
22#include "swaybar/i3bar.h" 21#include "swaybar/i3bar.h"
23#include "swaybar/ipc.h" 22#include "swaybar/ipc.h"
24#include "swaybar/status_line.h" 23#include "swaybar/status_line.h"
@@ -26,6 +25,7 @@
26#include "ipc-client.h" 25#include "ipc-client.h"
27#include "list.h" 26#include "list.h"
28#include "log.h" 27#include "log.h"
28#include "loop.h"
29#include "pool-buffer.h" 29#include "pool-buffer.h"
30#include "wlr-layer-shell-unstable-v1-client-protocol.h" 30#include "wlr-layer-shell-unstable-v1-client-protocol.h"
31#include "xdg-output-unstable-v1-client-protocol.h" 31#include "xdg-output-unstable-v1-client-protocol.h"
@@ -573,7 +573,7 @@ static void set_bar_dirty(struct swaybar *bar) {
573 573
574bool bar_setup(struct swaybar *bar, const char *socket_path) { 574bool bar_setup(struct swaybar *bar, const char *socket_path) {
575 bar_init(bar); 575 bar_init(bar);
576 init_event_loop(); 576 bar->eventloop = loop_create();
577 577
578 bar->ipc_socketfd = ipc_open_socket(socket_path); 578 bar->ipc_socketfd = ipc_open_socket(socket_path);
579 bar->ipc_event_socketfd = ipc_open_socket(socket_path); 579 bar->ipc_event_socketfd = ipc_open_socket(socket_path);
@@ -582,6 +582,7 @@ bool bar_setup(struct swaybar *bar, const char *socket_path) {
582 } 582 }
583 if (bar->config->status_command) { 583 if (bar->config->status_command) {
584 bar->status = status_line_init(bar->config->status_command); 584 bar->status = status_line_init(bar->config->status_command);
585 bar->status->bar = bar;
585 } 586 }
586 587
587 bar->display = wl_display_connect(NULL); 588 bar->display = wl_display_connect(NULL);
@@ -646,21 +647,23 @@ static void status_in(int fd, short mask, void *data) {
646 if (mask & (POLLHUP | POLLERR)) { 647 if (mask & (POLLHUP | POLLERR)) {
647 status_error(bar->status, "[error reading from status command]"); 648 status_error(bar->status, "[error reading from status command]");
648 set_bar_dirty(bar); 649 set_bar_dirty(bar);
649 remove_event(fd); 650 loop_remove_event(bar->eventloop, bar->status_event);
650 } else if (status_handle_readable(bar->status)) { 651 } else if (status_handle_readable(bar->status)) {
651 set_bar_dirty(bar); 652 set_bar_dirty(bar);
652 } 653 }
653} 654}
654 655
655void bar_run(struct swaybar *bar) { 656void bar_run(struct swaybar *bar) {
656 add_event(wl_display_get_fd(bar->display), POLLIN, display_in, bar); 657 loop_add_fd(bar->eventloop, wl_display_get_fd(bar->display), POLLIN,
657 add_event(bar->ipc_event_socketfd, POLLIN, ipc_in, bar); 658 display_in, bar);
659 loop_add_fd(bar->eventloop, bar->ipc_event_socketfd, POLLIN, ipc_in, bar);
658 if (bar->status) { 660 if (bar->status) {
659 add_event(bar->status->read_fd, POLLIN, status_in, bar); 661 bar->status_event = loop_add_fd(
662 bar->eventloop, bar->status->read_fd, POLLIN, status_in, bar);
660 } 663 }
661 while (1) { 664 while (1) {
662 wl_display_flush(bar->display); 665 wl_display_flush(bar->display);
663 event_loop_poll(); 666 loop_poll(bar->eventloop);
664 } 667 }
665} 668}
666 669
diff --git a/swaybar/event_loop.c b/swaybar/event_loop.c
deleted file mode 100644
index 686b9962..00000000
--- a/swaybar/event_loop.c
+++ /dev/null
@@ -1,156 +0,0 @@
1#define _XOPEN_SOURCE 700
2#include <stdlib.h>
3#include <stdbool.h>
4#include <string.h>
5#include <strings.h>
6#include <poll.h>
7#include <time.h>
8#include "swaybar/event_loop.h"
9#include "list.h"
10
11struct event_item {
12 void (*cb)(int fd, short mask, void *data);
13 void *data;
14};
15
16struct timer_item {
17 timer_t timer;
18 void (*cb)(timer_t timer, void *data);
19 void *data;
20};
21
22static struct {
23 // The order of each must be kept consistent
24 struct { /* pollfd array */
25 struct pollfd *items;
26 int capacity;
27 int length;
28 } fds;
29 list_t *items; /* event_item list */
30
31 // Timer list
32 list_t *timers;
33} event_loop;
34
35void add_timer(timer_t timer,
36 void(*cb)(timer_t timer, void *data),
37 void *data) {
38
39 struct timer_item *item = malloc(sizeof(struct timer_item));
40 item->timer = timer;
41 item->cb = cb;
42 item->data = data;
43
44 list_add(event_loop.timers, item);
45}
46
47void add_event(int fd, short mask,
48 void(*cb)(int fd, short mask, void *data), void *data) {
49
50 struct pollfd pollfd = {
51 fd,
52 mask,
53 0,
54 };
55
56 // Resize
57 if (event_loop.fds.length == event_loop.fds.capacity) {
58 event_loop.fds.capacity += 10;
59 event_loop.fds.items = realloc(event_loop.fds.items,
60 sizeof(struct pollfd) * event_loop.fds.capacity);
61 }
62
63 event_loop.fds.items[event_loop.fds.length++] = pollfd;
64
65 struct event_item *item = malloc(sizeof(struct event_item));
66 item->cb = cb;
67 item->data = data;
68
69 list_add(event_loop.items, item);
70
71 return;
72}
73
74bool remove_event(int fd) {
75 /*
76 * Instead of removing events immediately, we mark them for deletion
77 * and clean them up later. This is so we can call remove_event inside
78 * an event callback safely.
79 */
80 for (int i = 0; i < event_loop.fds.length; ++i) {
81 if (event_loop.fds.items[i].fd == fd) {
82 event_loop.fds.items[i].fd = -1;
83 return true;
84 }
85 }
86 return false;
87}
88
89static int timer_item_timer_cmp(const void *_timer_item, const void *_timer) {
90 const struct timer_item *timer_item = _timer_item;
91 const timer_t *timer = _timer;
92 if (timer_item->timer == *timer) {
93 return 0;
94 } else {
95 return -1;
96 }
97}
98bool remove_timer(timer_t timer) {
99 int index = list_seq_find(event_loop.timers, timer_item_timer_cmp, &timer);
100 if (index != -1) {
101 free(event_loop.timers->items[index]);
102 list_del(event_loop.timers, index);
103 return true;
104 }
105 return false;
106}
107
108void event_loop_poll(void) {
109 poll(event_loop.fds.items, event_loop.fds.length, -1);
110
111 for (int i = 0; i < event_loop.fds.length; ++i) {
112 struct pollfd pfd = event_loop.fds.items[i];
113 struct event_item *item = (struct event_item *)event_loop.items->items[i];
114
115 // Always send these events
116 unsigned events = pfd.events | POLLHUP | POLLERR;
117
118 if (pfd.revents & events) {
119 item->cb(pfd.fd, pfd.revents, item->data);
120 }
121 }
122
123 // Cleanup removed events
124 int end = 0;
125 int length = event_loop.fds.length;
126 for (int i = 0; i < length; ++i) {
127 if (event_loop.fds.items[i].fd == -1) {
128 free(event_loop.items->items[i]);
129 list_del(event_loop.items, i);
130 --event_loop.fds.length;
131 } else if (end != i) {
132 event_loop.fds.items[end++] = event_loop.fds.items[i];
133 } else {
134 end = i + 1;
135 }
136 }
137
138 // check timers
139 // not tested, but seems to work
140 for (int i = 0; i < event_loop.timers->length; ++i) {
141 struct timer_item *item = event_loop.timers->items[i];
142 int overrun = timer_getoverrun(item->timer);
143 if (overrun && overrun != -1) {
144 item->cb(item->timer, item->data);
145 }
146 }
147}
148
149void init_event_loop(void) {
150 event_loop.fds.length = 0;
151 event_loop.fds.capacity = 10;
152 event_loop.fds.items = malloc(
153 event_loop.fds.capacity * sizeof(struct pollfd));
154 event_loop.items = create_list();
155 event_loop.timers = create_list();
156}
diff --git a/swaybar/meson.build b/swaybar/meson.build
index 7a02a33f..0c116172 100644
--- a/swaybar/meson.build
+++ b/swaybar/meson.build
@@ -2,7 +2,6 @@ executable(
2 'swaybar', [ 2 'swaybar', [
3 'bar.c', 3 'bar.c',
4 'config.c', 4 'config.c',
5 'event_loop.c',
6 'i3bar.c', 5 'i3bar.c',
7 'ipc.c', 6 'ipc.c',
8 'main.c', 7 'main.c',
diff --git a/swaybar/status_line.c b/swaybar/status_line.c
index 000609ce..3f7a386f 100644
--- a/swaybar/status_line.c
+++ b/swaybar/status_line.c
@@ -7,16 +7,16 @@
7#include <stdio.h> 7#include <stdio.h>
8#include <unistd.h> 8#include <unistd.h>
9#include <wlr/util/log.h> 9#include <wlr/util/log.h>
10#include "loop.h"
10#include "swaybar/bar.h" 11#include "swaybar/bar.h"
11#include "swaybar/config.h" 12#include "swaybar/config.h"
12#include "swaybar/i3bar.h" 13#include "swaybar/i3bar.h"
13#include "swaybar/event_loop.h"
14#include "swaybar/status_line.h" 14#include "swaybar/status_line.h"
15#include "readline.h" 15#include "readline.h"
16 16
17static void status_line_close_fds(struct status_line *status) { 17static void status_line_close_fds(struct status_line *status) {
18 if (status->read_fd != -1) { 18 if (status->read_fd != -1) {
19 remove_event(status->read_fd); 19 loop_remove_event(status->bar->eventloop, status->bar->status_event);
20 close(status->read_fd); 20 close(status->read_fd);
21 status->read_fd = -1; 21 status->read_fd = -1;
22 } 22 }