diff options
-rw-r--r-- | common/loop.c | 143 | ||||
-rw-r--r-- | include/loop.h | 25 | ||||
-rw-r--r-- | include/swaybar/bar.h | 1 | ||||
-rw-r--r-- | include/swaylock/swaylock.h | 6 | ||||
-rw-r--r-- | swaybar/bar.c | 6 | ||||
-rw-r--r-- | swaybar/status_line.c | 2 | ||||
-rw-r--r-- | swaylock/password.c | 10 |
7 files changed, 128 insertions, 65 deletions
diff --git a/common/loop.c b/common/loop.c index da3c2142..c358e212 100644 --- a/common/loop.c +++ b/common/loop.c | |||
@@ -1,18 +1,24 @@ | |||
1 | #include <limits.h> | ||
1 | #include <string.h> | 2 | #include <string.h> |
2 | #include <stdbool.h> | 3 | #include <stdbool.h> |
3 | #include <stdlib.h> | 4 | #include <stdlib.h> |
4 | #include <stdio.h> | 5 | #include <stdio.h> |
5 | #include <poll.h> | 6 | #include <poll.h> |
6 | #include <sys/timerfd.h> | 7 | #include <time.h> |
7 | #include <unistd.h> | 8 | #include <unistd.h> |
8 | #include "list.h" | 9 | #include "list.h" |
9 | #include "log.h" | 10 | #include "log.h" |
10 | #include "loop.h" | 11 | #include "loop.h" |
11 | 12 | ||
12 | struct loop_event { | 13 | struct loop_fd_event { |
13 | void (*callback)(int fd, short mask, void *data); | 14 | void (*callback)(int fd, short mask, void *data); |
14 | void *data; | 15 | void *data; |
15 | bool is_timer; | 16 | }; |
17 | |||
18 | struct loop_timer { | ||
19 | void (*callback)(void *data); | ||
20 | void *data; | ||
21 | struct timespec expiry; | ||
16 | }; | 22 | }; |
17 | 23 | ||
18 | struct loop { | 24 | struct loop { |
@@ -20,7 +26,8 @@ struct loop { | |||
20 | int fd_length; | 26 | int fd_length; |
21 | int fd_capacity; | 27 | int fd_capacity; |
22 | 28 | ||
23 | list_t *events; // struct loop_event | 29 | list_t *fd_events; // struct loop_fd_event |
30 | list_t *timers; // struct loop_timer | ||
24 | }; | 31 | }; |
25 | 32 | ||
26 | struct loop *loop_create(void) { | 33 | struct loop *loop_create(void) { |
@@ -31,86 +38,136 @@ struct loop *loop_create(void) { | |||
31 | } | 38 | } |
32 | loop->fd_capacity = 10; | 39 | loop->fd_capacity = 10; |
33 | loop->fds = malloc(sizeof(struct pollfd) * loop->fd_capacity); | 40 | loop->fds = malloc(sizeof(struct pollfd) * loop->fd_capacity); |
34 | loop->events = create_list(); | 41 | loop->fd_events = create_list(); |
42 | loop->timers = create_list(); | ||
35 | return loop; | 43 | return loop; |
36 | } | 44 | } |
37 | 45 | ||
38 | void loop_destroy(struct loop *loop) { | 46 | void loop_destroy(struct loop *loop) { |
39 | list_foreach(loop->events, free); | 47 | list_foreach(loop->fd_events, free); |
40 | list_free(loop->events); | 48 | list_foreach(loop->timers, free); |
49 | list_free(loop->fd_events); | ||
50 | list_free(loop->timers); | ||
41 | free(loop); | 51 | free(loop); |
42 | } | 52 | } |
43 | 53 | ||
44 | void loop_poll(struct loop *loop) { | 54 | void loop_poll(struct loop *loop) { |
45 | poll(loop->fds, loop->fd_length, -1); | 55 | // Calculate next timer in ms |
56 | int ms = INT_MAX; | ||
57 | if (loop->timers->length) { | ||
58 | struct timespec now; | ||
59 | clock_gettime(CLOCK_MONOTONIC, &now); | ||
60 | for (int i = 0; i < loop->timers->length; ++i) { | ||
61 | struct loop_timer *timer = loop->timers->items[i]; | ||
62 | int timer_ms = (timer->expiry.tv_sec - now.tv_sec) * 1000; | ||
63 | timer_ms += (timer->expiry.tv_nsec - now.tv_nsec) / 1000000; | ||
64 | if (timer_ms < ms) { | ||
65 | ms = timer_ms; | ||
66 | } | ||
67 | } | ||
68 | } | ||
46 | 69 | ||
70 | poll(loop->fds, loop->fd_length, ms); | ||
71 | |||
72 | // Dispatch fds | ||
47 | for (int i = 0; i < loop->fd_length; ++i) { | 73 | for (int i = 0; i < loop->fd_length; ++i) { |
48 | struct pollfd pfd = loop->fds[i]; | 74 | struct pollfd pfd = loop->fds[i]; |
49 | struct loop_event *event = loop->events->items[i]; | 75 | struct loop_fd_event *event = loop->fd_events->items[i]; |
50 | 76 | ||
51 | // Always send these events | 77 | // Always send these events |
52 | unsigned events = pfd.events | POLLHUP | POLLERR; | 78 | unsigned events = pfd.events | POLLHUP | POLLERR; |
53 | 79 | ||
54 | if (pfd.revents & events) { | 80 | if (pfd.revents & events) { |
55 | event->callback(pfd.fd, pfd.revents, event->data); | 81 | event->callback(pfd.fd, pfd.revents, event->data); |
82 | } | ||
83 | } | ||
56 | 84 | ||
57 | if (event->is_timer) { | 85 | // Dispatch timers |
58 | loop_remove_event(loop, event); | 86 | if (loop->timers->length) { |
87 | struct timespec now; | ||
88 | clock_gettime(CLOCK_MONOTONIC, &now); | ||
89 | for (int i = 0; i < loop->timers->length; ++i) { | ||
90 | struct loop_timer *timer = loop->timers->items[i]; | ||
91 | bool expired = timer->expiry.tv_sec < now.tv_sec || | ||
92 | (timer->expiry.tv_sec == now.tv_sec && | ||
93 | timer->expiry.tv_nsec < now.tv_nsec); | ||
94 | if (expired) { | ||
95 | timer->callback(timer->data); | ||
96 | loop_remove_timer(loop, timer); | ||
59 | --i; | 97 | --i; |
60 | } | 98 | } |
61 | } | 99 | } |
62 | } | 100 | } |
63 | } | 101 | } |
64 | 102 | ||
65 | struct loop_event *loop_add_fd(struct loop *loop, int fd, short mask, | 103 | void loop_add_fd(struct loop *loop, int fd, short mask, |
66 | void (*callback)(int fd, short mask, void *data), void *data) { | 104 | void (*callback)(int fd, short mask, void *data), void *data) { |
105 | struct loop_fd_event *event = calloc(1, sizeof(struct loop_fd_event)); | ||
106 | if (!event) { | ||
107 | wlr_log(WLR_ERROR, "Unable to allocate memory for event"); | ||
108 | return; | ||
109 | } | ||
110 | event->callback = callback; | ||
111 | event->data = data; | ||
112 | list_add(loop->fd_events, event); | ||
113 | |||
67 | struct pollfd pfd = {fd, mask, 0}; | 114 | struct pollfd pfd = {fd, mask, 0}; |
68 | 115 | ||
69 | if (loop->fd_length == loop->fd_capacity) { | 116 | if (loop->fd_length == loop->fd_capacity) { |
70 | loop->fd_capacity += 10; | 117 | loop->fd_capacity += 10; |
71 | loop->fds = realloc(loop->fds, sizeof(struct pollfd) * loop->fd_capacity); | 118 | loop->fds = realloc(loop->fds, |
119 | sizeof(struct pollfd) * loop->fd_capacity); | ||
72 | } | 120 | } |
73 | 121 | ||
74 | loop->fds[loop->fd_length++] = pfd; | 122 | loop->fds[loop->fd_length++] = pfd; |
123 | } | ||
75 | 124 | ||
76 | struct loop_event *event = calloc(1, sizeof(struct loop_event)); | 125 | struct loop_timer *loop_add_timer(struct loop *loop, int ms, |
77 | event->callback = callback; | 126 | void (*callback)(void *data), void *data) { |
78 | event->data = data; | 127 | struct loop_timer *timer = calloc(1, sizeof(struct loop_timer)); |
128 | if (!timer) { | ||
129 | wlr_log(WLR_ERROR, "Unable to allocate memory for timer"); | ||
130 | return NULL; | ||
131 | } | ||
132 | timer->callback = callback; | ||
133 | timer->data = data; | ||
79 | 134 | ||
80 | list_add(loop->events, event); | 135 | clock_gettime(CLOCK_MONOTONIC, &timer->expiry); |
136 | timer->expiry.tv_sec += ms / 1000; | ||
81 | 137 | ||
82 | return event; | 138 | long int nsec = (ms % 1000) * 1000000; |
83 | } | 139 | if (timer->expiry.tv_nsec + nsec >= 1000000000) { |
140 | timer->expiry.tv_sec++; | ||
141 | nsec -= 1000000000; | ||
142 | } | ||
143 | timer->expiry.tv_nsec += nsec; | ||
84 | 144 | ||
85 | struct loop_event *loop_add_timer(struct loop *loop, int ms, | 145 | list_add(loop->timers, timer); |
86 | void (*callback)(int fd, short mask, void *data), void *data) { | ||
87 | int fd = timerfd_create(CLOCK_MONOTONIC, 0); | ||
88 | struct itimerspec its; | ||
89 | its.it_interval.tv_sec = 0; | ||
90 | its.it_interval.tv_nsec = 0; | ||
91 | its.it_value.tv_sec = ms / 1000; | ||
92 | its.it_value.tv_nsec = (ms % 1000) * 1000000; | ||
93 | timerfd_settime(fd, 0, &its, NULL); | ||
94 | |||
95 | struct loop_event *event = loop_add_fd(loop, fd, POLLIN, callback, data); | ||
96 | event->is_timer = true; | ||
97 | |||
98 | return event; | ||
99 | } | ||
100 | 146 | ||
101 | bool loop_remove_event(struct loop *loop, struct loop_event *event) { | 147 | return timer; |
102 | for (int i = 0; i < loop->events->length; ++i) { | 148 | } |
103 | if (loop->events->items[i] == event) { | ||
104 | list_del(loop->events, i); | ||
105 | 149 | ||
106 | if (event->is_timer) { | 150 | bool loop_remove_fd(struct loop *loop, int fd) { |
107 | close(loop->fds[i].fd); | 151 | for (int i = 0; i < loop->fd_length; ++i) { |
108 | } | 152 | if (loop->fds[i].fd == fd) { |
153 | free(loop->fd_events->items[i]); | ||
154 | list_del(loop->fd_events, i); | ||
109 | 155 | ||
110 | loop->fd_length--; | 156 | loop->fd_length--; |
111 | memmove(&loop->fds[i], &loop->fds[i + 1], sizeof(void*) * (loop->fd_length - i)); | 157 | memmove(&loop->fds[i], &loop->fds[i + 1], |
158 | sizeof(void*) * (loop->fd_length - i)); | ||
159 | |||
160 | return true; | ||
161 | } | ||
162 | } | ||
163 | return false; | ||
164 | } | ||
112 | 165 | ||
113 | free(event); | 166 | bool loop_remove_timer(struct loop *loop, struct loop_timer *timer) { |
167 | for (int i = 0; i < loop->timers->length; ++i) { | ||
168 | if (loop->timers->items[i] == timer) { | ||
169 | list_del(loop->timers, i); | ||
170 | free(timer); | ||
114 | return true; | 171 | return true; |
115 | } | 172 | } |
116 | } | 173 | } |
diff --git a/include/loop.h b/include/loop.h index 7c151785..2f608eda 100644 --- a/include/loop.h +++ b/include/loop.h | |||
@@ -5,12 +5,12 @@ | |||
5 | /** | 5 | /** |
6 | * This is an event loop system designed for sway clients, not sway itself. | 6 | * This is an event loop system designed for sway clients, not sway itself. |
7 | * | 7 | * |
8 | * It uses pollfds to block on multiple file descriptors at once, and provides | 8 | * The loop consists of file descriptors and timers. Typically the Wayland |
9 | * an easy way to set timers. Typically the Wayland display's fd will be one of | 9 | * display's file descriptor will be one of the fds in the loop. |
10 | * the fds in the loop. | ||
11 | */ | 10 | */ |
12 | 11 | ||
13 | struct loop; | 12 | struct loop; |
13 | struct loop_timer; | ||
14 | 14 | ||
15 | /** | 15 | /** |
16 | * Create an event loop. | 16 | * Create an event loop. |
@@ -28,20 +28,27 @@ void loop_destroy(struct loop *loop); | |||
28 | void loop_poll(struct loop *loop); | 28 | void loop_poll(struct loop *loop); |
29 | 29 | ||
30 | /** | 30 | /** |
31 | * Add an fd to the loop. | 31 | * Add a file descriptor to the loop. |
32 | */ | 32 | */ |
33 | struct loop_event *loop_add_fd(struct loop *loop, int fd, short mask, | 33 | void loop_add_fd(struct loop *loop, int fd, short mask, |
34 | void (*func)(int fd, short mask, void *data), void *data); | 34 | void (*func)(int fd, short mask, void *data), void *data); |
35 | 35 | ||
36 | /** | 36 | /** |
37 | * Add a timer to the loop. | 37 | * Add a timer to the loop. |
38 | * | ||
39 | * When the timer expires, the timer will be removed from the loop and freed. | ||
40 | */ | ||
41 | struct loop_timer *loop_add_timer(struct loop *loop, int ms, | ||
42 | void (*callback)(void *data), void *data); | ||
43 | |||
44 | /** | ||
45 | * Remove a file descriptor from the loop. | ||
38 | */ | 46 | */ |
39 | struct loop_event *loop_add_timer(struct loop *loop, int ms, | 47 | bool loop_remove_fd(struct loop *loop, int fd); |
40 | void (*callback)(int fd, short mask, void *data), void *data); | ||
41 | 48 | ||
42 | /** | 49 | /** |
43 | * Remove an event from the loop. | 50 | * Remove a timer from the loop. |
44 | */ | 51 | */ |
45 | bool loop_remove_event(struct loop *loop, struct loop_event *event); | 52 | bool loop_remove_timer(struct loop *loop, struct loop_timer *timer); |
46 | 53 | ||
47 | #endif | 54 | #endif |
diff --git a/include/swaybar/bar.h b/include/swaybar/bar.h index d61da5dc..db2d3d62 100644 --- a/include/swaybar/bar.h +++ b/include/swaybar/bar.h | |||
@@ -69,7 +69,6 @@ struct swaybar { | |||
69 | struct status_line *status; | 69 | struct status_line *status; |
70 | 70 | ||
71 | struct loop *eventloop; | 71 | struct loop *eventloop; |
72 | struct loop_event *status_event; | ||
73 | 72 | ||
74 | int ipc_event_socketfd; | 73 | int ipc_event_socketfd; |
75 | int ipc_socketfd; | 74 | int ipc_socketfd; |
diff --git a/include/swaylock/swaylock.h b/include/swaylock/swaylock.h index e7165b3b..25b41a71 100644 --- a/include/swaylock/swaylock.h +++ b/include/swaylock/swaylock.h | |||
@@ -55,9 +55,9 @@ struct swaylock_password { | |||
55 | 55 | ||
56 | struct swaylock_state { | 56 | struct swaylock_state { |
57 | struct loop *eventloop; | 57 | struct loop *eventloop; |
58 | struct loop_event *clear_indicator_timer; // clears the indicator | 58 | struct loop_timer *clear_indicator_timer; // clears the indicator |
59 | struct loop_event *clear_password_timer; // clears the password buffer | 59 | struct loop_timer *clear_password_timer; // clears the password buffer |
60 | struct loop_event *verify_password_timer; | 60 | struct loop_timer *verify_password_timer; |
61 | struct wl_display *display; | 61 | struct wl_display *display; |
62 | struct wl_compositor *compositor; | 62 | struct wl_compositor *compositor; |
63 | struct zwlr_layer_shell_v1 *layer_shell; | 63 | struct zwlr_layer_shell_v1 *layer_shell; |
diff --git a/swaybar/bar.c b/swaybar/bar.c index 8e89c9a8..be290c18 100644 --- a/swaybar/bar.c +++ b/swaybar/bar.c | |||
@@ -647,7 +647,7 @@ static void status_in(int fd, short mask, void *data) { | |||
647 | if (mask & (POLLHUP | POLLERR)) { | 647 | if (mask & (POLLHUP | POLLERR)) { |
648 | status_error(bar->status, "[error reading from status command]"); | 648 | status_error(bar->status, "[error reading from status command]"); |
649 | set_bar_dirty(bar); | 649 | set_bar_dirty(bar); |
650 | loop_remove_event(bar->eventloop, bar->status_event); | 650 | loop_remove_fd(bar->eventloop, fd); |
651 | } else if (status_handle_readable(bar->status)) { | 651 | } else if (status_handle_readable(bar->status)) { |
652 | set_bar_dirty(bar); | 652 | set_bar_dirty(bar); |
653 | } | 653 | } |
@@ -658,8 +658,8 @@ void bar_run(struct swaybar *bar) { | |||
658 | display_in, bar); | 658 | display_in, bar); |
659 | loop_add_fd(bar->eventloop, bar->ipc_event_socketfd, POLLIN, ipc_in, bar); | 659 | loop_add_fd(bar->eventloop, bar->ipc_event_socketfd, POLLIN, ipc_in, bar); |
660 | if (bar->status) { | 660 | if (bar->status) { |
661 | bar->status_event = loop_add_fd( | 661 | loop_add_fd(bar->eventloop, bar->status->read_fd, POLLIN, |
662 | bar->eventloop, bar->status->read_fd, POLLIN, status_in, bar); | 662 | status_in, bar); |
663 | } | 663 | } |
664 | while (1) { | 664 | while (1) { |
665 | wl_display_flush(bar->display); | 665 | wl_display_flush(bar->display); |
diff --git a/swaybar/status_line.c b/swaybar/status_line.c index 3f7a386f..65d6c052 100644 --- a/swaybar/status_line.c +++ b/swaybar/status_line.c | |||
@@ -16,7 +16,7 @@ | |||
16 | 16 | ||
17 | static void status_line_close_fds(struct status_line *status) { | 17 | static void status_line_close_fds(struct status_line *status) { |
18 | if (status->read_fd != -1) { | 18 | if (status->read_fd != -1) { |
19 | loop_remove_event(status->bar->eventloop, status->bar->status_event); | 19 | loop_remove_fd(status->bar->eventloop, status->read_fd); |
20 | close(status->read_fd); | 20 | close(status->read_fd); |
21 | status->read_fd = -1; | 21 | status->read_fd = -1; |
22 | } | 22 | } |
diff --git a/swaylock/password.c b/swaylock/password.c index 3f9949b2..fecaecbf 100644 --- a/swaylock/password.c +++ b/swaylock/password.c | |||
@@ -40,7 +40,7 @@ static void append_ch(struct swaylock_password *pw, uint32_t codepoint) { | |||
40 | pw->len += utf8_size; | 40 | pw->len += utf8_size; |
41 | } | 41 | } |
42 | 42 | ||
43 | static void clear_indicator(int fd, short mask, void *data) { | 43 | static void clear_indicator(void *data) { |
44 | struct swaylock_state *state = data; | 44 | struct swaylock_state *state = data; |
45 | state->clear_indicator_timer = NULL; | 45 | state->clear_indicator_timer = NULL; |
46 | state->auth_state = AUTH_STATE_IDLE; | 46 | state->auth_state = AUTH_STATE_IDLE; |
@@ -49,13 +49,13 @@ static void clear_indicator(int fd, short mask, void *data) { | |||
49 | 49 | ||
50 | static void schedule_indicator_clear(struct swaylock_state *state) { | 50 | static void schedule_indicator_clear(struct swaylock_state *state) { |
51 | if (state->clear_indicator_timer) { | 51 | if (state->clear_indicator_timer) { |
52 | loop_remove_event(state->eventloop, state->clear_indicator_timer); | 52 | loop_remove_timer(state->eventloop, state->clear_indicator_timer); |
53 | } | 53 | } |
54 | state->clear_indicator_timer = loop_add_timer( | 54 | state->clear_indicator_timer = loop_add_timer( |
55 | state->eventloop, 3000, clear_indicator, state); | 55 | state->eventloop, 3000, clear_indicator, state); |
56 | } | 56 | } |
57 | 57 | ||
58 | static void clear_password(int fd, short mask, void *data) { | 58 | static void clear_password(void *data) { |
59 | struct swaylock_state *state = data; | 59 | struct swaylock_state *state = data; |
60 | state->clear_password_timer = NULL; | 60 | state->clear_password_timer = NULL; |
61 | state->auth_state = AUTH_STATE_CLEAR; | 61 | state->auth_state = AUTH_STATE_CLEAR; |
@@ -66,13 +66,13 @@ static void clear_password(int fd, short mask, void *data) { | |||
66 | 66 | ||
67 | static void schedule_password_clear(struct swaylock_state *state) { | 67 | static void schedule_password_clear(struct swaylock_state *state) { |
68 | if (state->clear_password_timer) { | 68 | if (state->clear_password_timer) { |
69 | loop_remove_event(state->eventloop, state->clear_password_timer); | 69 | loop_remove_timer(state->eventloop, state->clear_password_timer); |
70 | } | 70 | } |
71 | state->clear_password_timer = loop_add_timer( | 71 | state->clear_password_timer = loop_add_timer( |
72 | state->eventloop, 10000, clear_password, state); | 72 | state->eventloop, 10000, clear_password, state); |
73 | } | 73 | } |
74 | 74 | ||
75 | static void handle_preverify_timeout(int fd, short mask, void *data) { | 75 | static void handle_preverify_timeout(void *data) { |
76 | struct swaylock_state *state = data; | 76 | struct swaylock_state *state = data; |
77 | state->verify_password_timer = NULL; | 77 | state->verify_password_timer = NULL; |
78 | } | 78 | } |