summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Drew DeVault <sir@cmpwn.com>2018-10-14 16:34:22 +0200
committerLibravatar GitHub <noreply@github.com>2018-10-14 16:34:22 +0200
commit53d90dd6a82205a20c3e97a8a396048588e1b5ef (patch)
tree10f5596fd0d90711af66281c38780c5a1d4d724f
parentUpdate README.MD (and README.*.md) (diff)
parentEvent loop: Fix memmove and remove extraneous declaration (diff)
downloadsway-53d90dd6a82205a20c3e97a8a396048588e1b5ef.tar.gz
sway-53d90dd6a82205a20c3e97a8a396048588e1b5ef.tar.zst
sway-53d90dd6a82205a20c3e97a8a396048588e1b5ef.zip
Merge pull request #2826 from RyanDwyer/common-eventloop
Implement common event loop for swaybar and swaylock
-rw-r--r--common/loop.c179
-rw-r--r--common/meson.build1
-rw-r--r--include/loop.h54
-rw-r--r--include/swaybar/bar.h3
-rw-r--r--include/swaybar/event_loop.h26
-rw-r--r--include/swaybar/status_line.h2
-rw-r--r--include/swaylock/swaylock.h4
-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
-rw-r--r--swaylock/main.c14
-rw-r--r--swaylock/password.c62
13 files changed, 328 insertions, 195 deletions
diff --git a/common/loop.c b/common/loop.c
new file mode 100644
index 00000000..1b174967
--- /dev/null
+++ b/common/loop.c
@@ -0,0 +1,179 @@
1#include <limits.h>
2#include <string.h>
3#include <stdbool.h>
4#include <stdlib.h>
5#include <stdio.h>
6#include <poll.h>
7#include <time.h>
8#include <unistd.h>
9#include "list.h"
10#include "log.h"
11#include "loop.h"
12
13struct loop_fd_event {
14 void (*callback)(int fd, short mask, void *data);
15 void *data;
16};
17
18struct loop_timer {
19 void (*callback)(void *data);
20 void *data;
21 struct timespec expiry;
22};
23
24struct loop {
25 struct pollfd *fds;
26 int fd_length;
27 int fd_capacity;
28
29 list_t *fd_events; // struct loop_fd_event
30 list_t *timers; // struct loop_timer
31};
32
33struct loop *loop_create(void) {
34 struct loop *loop = calloc(1, sizeof(struct loop));
35 if (!loop) {
36 wlr_log(WLR_ERROR, "Unable to allocate memory for loop");
37 return NULL;
38 }
39 loop->fd_capacity = 10;
40 loop->fds = malloc(sizeof(struct pollfd) * loop->fd_capacity);
41 loop->fd_events = create_list();
42 loop->timers = create_list();
43 return loop;
44}
45
46void loop_destroy(struct loop *loop) {
47 list_foreach(loop->fd_events, free);
48 list_foreach(loop->timers, free);
49 list_free(loop->fd_events);
50 list_free(loop->timers);
51 free(loop->fds);
52 free(loop);
53}
54
55void loop_poll(struct loop *loop) {
56 // Calculate next timer in ms
57 int ms = INT_MAX;
58 if (loop->timers->length) {
59 struct timespec now;
60 clock_gettime(CLOCK_MONOTONIC, &now);
61 for (int i = 0; i < loop->timers->length; ++i) {
62 struct loop_timer *timer = loop->timers->items[i];
63 int timer_ms = (timer->expiry.tv_sec - now.tv_sec) * 1000;
64 timer_ms += (timer->expiry.tv_nsec - now.tv_nsec) / 1000000;
65 if (timer_ms < ms) {
66 ms = timer_ms;
67 }
68 }
69 }
70 if (ms < 0) {
71 ms = 0;
72 }
73
74 poll(loop->fds, loop->fd_length, ms);
75
76 // Dispatch fds
77 for (int i = 0; i < loop->fd_length; ++i) {
78 struct pollfd pfd = loop->fds[i];
79 struct loop_fd_event *event = loop->fd_events->items[i];
80
81 // Always send these events
82 unsigned events = pfd.events | POLLHUP | POLLERR;
83
84 if (pfd.revents & events) {
85 event->callback(pfd.fd, pfd.revents, event->data);
86 }
87 }
88
89 // Dispatch timers
90 if (loop->timers->length) {
91 struct timespec now;
92 clock_gettime(CLOCK_MONOTONIC, &now);
93 for (int i = 0; i < loop->timers->length; ++i) {
94 struct loop_timer *timer = loop->timers->items[i];
95 bool expired = timer->expiry.tv_sec < now.tv_sec ||
96 (timer->expiry.tv_sec == now.tv_sec &&
97 timer->expiry.tv_nsec < now.tv_nsec);
98 if (expired) {
99 timer->callback(timer->data);
100 loop_remove_timer(loop, timer);
101 --i;
102 }
103 }
104 }
105}
106
107void loop_add_fd(struct loop *loop, int fd, short mask,
108 void (*callback)(int fd, short mask, void *data), void *data) {
109 struct loop_fd_event *event = calloc(1, sizeof(struct loop_fd_event));
110 if (!event) {
111 wlr_log(WLR_ERROR, "Unable to allocate memory for event");
112 return;
113 }
114 event->callback = callback;
115 event->data = data;
116 list_add(loop->fd_events, event);
117
118 struct pollfd pfd = {fd, mask, 0};
119
120 if (loop->fd_length == loop->fd_capacity) {
121 loop->fd_capacity += 10;
122 loop->fds = realloc(loop->fds,
123 sizeof(struct pollfd) * loop->fd_capacity);
124 }
125
126 loop->fds[loop->fd_length++] = pfd;
127}
128
129struct loop_timer *loop_add_timer(struct loop *loop, int ms,
130 void (*callback)(void *data), void *data) {
131 struct loop_timer *timer = calloc(1, sizeof(struct loop_timer));
132 if (!timer) {
133 wlr_log(WLR_ERROR, "Unable to allocate memory for timer");
134 return NULL;
135 }
136 timer->callback = callback;
137 timer->data = data;
138
139 clock_gettime(CLOCK_MONOTONIC, &timer->expiry);
140 timer->expiry.tv_sec += ms / 1000;
141
142 long int nsec = (ms % 1000) * 1000000;
143 if (timer->expiry.tv_nsec + nsec >= 1000000000) {
144 timer->expiry.tv_sec++;
145 nsec -= 1000000000;
146 }
147 timer->expiry.tv_nsec += nsec;
148
149 list_add(loop->timers, timer);
150
151 return timer;
152}
153
154bool loop_remove_fd(struct loop *loop, int fd) {
155 for (int i = 0; i < loop->fd_length; ++i) {
156 if (loop->fds[i].fd == fd) {
157 free(loop->fd_events->items[i]);
158 list_del(loop->fd_events, i);
159
160 loop->fd_length--;
161 memmove(&loop->fds[i], &loop->fds[i + 1],
162 sizeof(struct pollfd) * (loop->fd_length - i));
163
164 return true;
165 }
166 }
167 return false;
168}
169
170bool loop_remove_timer(struct loop *loop, struct loop_timer *timer) {
171 for (int i = 0; i < loop->timers->length; ++i) {
172 if (loop->timers->items[i] == timer) {
173 list_del(loop->timers, i);
174 free(timer);
175 return true;
176 }
177 }
178 return false;
179}
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..2f608eda
--- /dev/null
+++ b/include/loop.h
@@ -0,0 +1,54 @@
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 * The loop consists of file descriptors and timers. Typically the Wayland
9 * display's file descriptor will be one of the fds in the loop.
10 */
11
12struct loop;
13struct loop_timer;
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 a file descriptor to the loop.
32 */
33void 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 *
39 * When the timer expires, the timer will be removed from the loop and freed.
40 */
41struct 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.
46 */
47bool loop_remove_fd(struct loop *loop, int fd);
48
49/**
50 * Remove a timer from the loop.
51 */
52bool loop_remove_timer(struct loop *loop, struct loop_timer *timer);
53
54#endif
diff --git a/include/swaybar/bar.h b/include/swaybar/bar.h
index 9ff3fe7b..58e2dee6 100644
--- a/include/swaybar/bar.h
+++ b/include/swaybar/bar.h
@@ -8,6 +8,7 @@
8struct swaybar_config; 8struct swaybar_config;
9struct swaybar_output; 9struct swaybar_output;
10struct swaybar_workspace; 10struct swaybar_workspace;
11struct loop;
11 12
12struct swaybar_pointer { 13struct swaybar_pointer {
13 struct wl_pointer *pointer; 14 struct wl_pointer *pointer;
@@ -66,6 +67,8 @@ struct swaybar {
66 struct swaybar_pointer pointer; 67 struct swaybar_pointer pointer;
67 struct status_line *status; 68 struct status_line *status;
68 69
70 struct loop *eventloop;
71
69 int ipc_event_socketfd; 72 int ipc_event_socketfd;
70 int ipc_socketfd; 73 int ipc_socketfd;
71 74
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/include/swaylock/swaylock.h b/include/swaylock/swaylock.h
index fbdd42a8..25b41a71 100644
--- a/include/swaylock/swaylock.h
+++ b/include/swaylock/swaylock.h
@@ -54,6 +54,10 @@ struct swaylock_password {
54}; 54};
55 55
56struct swaylock_state { 56struct swaylock_state {
57 struct loop *eventloop;
58 struct loop_timer *clear_indicator_timer; // clears the indicator
59 struct loop_timer *clear_password_timer; // clears the password buffer
60 struct loop_timer *verify_password_timer;
57 struct wl_display *display; 61 struct wl_display *display;
58 struct wl_compositor *compositor; 62 struct wl_compositor *compositor;
59 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 9f72c94c..be290c18 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_fd(bar->eventloop, fd);
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 loop_add_fd(bar->eventloop, bar->status->read_fd, POLLIN,
662 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..65d6c052 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_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/main.c b/swaylock/main.c
index d1384c6f..27bcfe32 100644
--- a/swaylock/main.c
+++ b/swaylock/main.c
@@ -21,6 +21,7 @@
21#include "pool-buffer.h" 21#include "pool-buffer.h"
22#include "cairo.h" 22#include "cairo.h"
23#include "log.h" 23#include "log.h"
24#include "loop.h"
24#include "readline.h" 25#include "readline.h"
25#include "stringop.h" 26#include "stringop.h"
26#include "util.h" 27#include "util.h"
@@ -844,6 +845,10 @@ static int load_config(char *path, struct swaylock_state *state,
844 845
845static struct swaylock_state state; 846static struct swaylock_state state;
846 847
848static void display_in(int fd, short mask, void *data) {
849 wl_display_dispatch(state.display);
850}
851
847int main(int argc, char **argv) { 852int main(int argc, char **argv) {
848 wlr_log_init(WLR_DEBUG, NULL); 853 wlr_log_init(WLR_DEBUG, NULL);
849 initialize_pw_backend(); 854 initialize_pw_backend();
@@ -946,9 +951,14 @@ int main(int argc, char **argv) {
946 daemonize(); 951 daemonize();
947 } 952 }
948 953
954 state.eventloop = loop_create();
955 loop_add_fd(state.eventloop, wl_display_get_fd(state.display), POLL_IN,
956 display_in, NULL);
957
949 state.run_display = true; 958 state.run_display = true;
950 while (wl_display_dispatch(state.display) != -1 && state.run_display) { 959 while (state.run_display) {
951 // This space intentionally left blank 960 wl_display_flush(state.display);
961 loop_poll(state.eventloop);
952 } 962 }
953 963
954 free(state.args.font); 964 free(state.args.font);
diff --git a/swaylock/password.c b/swaylock/password.c
index 50b81f6b..fecaecbf 100644
--- a/swaylock/password.c
+++ b/swaylock/password.c
@@ -8,6 +8,7 @@
8#include <xkbcommon/xkbcommon.h> 8#include <xkbcommon/xkbcommon.h>
9#include "swaylock/swaylock.h" 9#include "swaylock/swaylock.h"
10#include "swaylock/seat.h" 10#include "swaylock/seat.h"
11#include "loop.h"
11#include "unicode.h" 12#include "unicode.h"
12 13
13void clear_password_buffer(struct swaylock_password *pw) { 14void clear_password_buffer(struct swaylock_password *pw) {
@@ -39,6 +40,43 @@ static void append_ch(struct swaylock_password *pw, uint32_t codepoint) {
39 pw->len += utf8_size; 40 pw->len += utf8_size;
40} 41}
41 42
43static void clear_indicator(void *data) {
44 struct swaylock_state *state = data;
45 state->clear_indicator_timer = NULL;
46 state->auth_state = AUTH_STATE_IDLE;
47 damage_state(state);
48}
49
50static void schedule_indicator_clear(struct swaylock_state *state) {
51 if (state->clear_indicator_timer) {
52 loop_remove_timer(state->eventloop, state->clear_indicator_timer);
53 }
54 state->clear_indicator_timer = loop_add_timer(
55 state->eventloop, 3000, clear_indicator, state);
56}
57
58static void clear_password(void *data) {
59 struct swaylock_state *state = data;
60 state->clear_password_timer = NULL;
61 state->auth_state = AUTH_STATE_CLEAR;
62 clear_password_buffer(&state->password);
63 damage_state(state);
64 schedule_indicator_clear(state);
65}
66
67static void schedule_password_clear(struct swaylock_state *state) {
68 if (state->clear_password_timer) {
69 loop_remove_timer(state->eventloop, state->clear_password_timer);
70 }
71 state->clear_password_timer = loop_add_timer(
72 state->eventloop, 10000, clear_password, state);
73}
74
75static void handle_preverify_timeout(void *data) {
76 struct swaylock_state *state = data;
77 state->verify_password_timer = NULL;
78}
79
42void swaylock_handle_key(struct swaylock_state *state, 80void swaylock_handle_key(struct swaylock_state *state,
43 xkb_keysym_t keysym, uint32_t codepoint) { 81 xkb_keysym_t keysym, uint32_t codepoint) {
44 switch (keysym) { 82 switch (keysym) {
@@ -50,7 +88,18 @@ void swaylock_handle_key(struct swaylock_state *state,
50 88
51 state->auth_state = AUTH_STATE_VALIDATING; 89 state->auth_state = AUTH_STATE_VALIDATING;
52 damage_state(state); 90 damage_state(state);
53 while (wl_display_dispatch(state->display) != -1 && state->run_display) { 91
92 // We generally want to wait until all surfaces are showing the
93 // "verifying" state before we go and verify the password, because
94 // verifying it is a blocking operation. However, if the surface is on
95 // an output with DPMS off then it won't update, so we set a timer.
96 state->verify_password_timer = loop_add_timer(
97 state->eventloop, 50, handle_preverify_timeout, state);
98
99 while (state->run_display && state->verify_password_timer) {
100 wl_display_flush(state->display);
101 loop_poll(state->eventloop);
102
54 bool ok = 1; 103 bool ok = 1;
55 struct swaylock_surface *surface; 104 struct swaylock_surface *surface;
56 wl_list_for_each(surface, &state->surfaces, link) { 105 wl_list_for_each(surface, &state->surfaces, link) {
@@ -70,6 +119,7 @@ void swaylock_handle_key(struct swaylock_state *state,
70 } 119 }
71 state->auth_state = AUTH_STATE_INVALID; 120 state->auth_state = AUTH_STATE_INVALID;
72 damage_state(state); 121 damage_state(state);
122 schedule_indicator_clear(state);
73 break; 123 break;
74 case XKB_KEY_Delete: 124 case XKB_KEY_Delete:
75 case XKB_KEY_BackSpace: 125 case XKB_KEY_BackSpace:
@@ -79,11 +129,14 @@ void swaylock_handle_key(struct swaylock_state *state,
79 state->auth_state = AUTH_STATE_CLEAR; 129 state->auth_state = AUTH_STATE_CLEAR;
80 } 130 }
81 damage_state(state); 131 damage_state(state);
132 schedule_indicator_clear(state);
133 schedule_password_clear(state);
82 break; 134 break;
83 case XKB_KEY_Escape: 135 case XKB_KEY_Escape:
84 clear_password_buffer(&state->password); 136 clear_password_buffer(&state->password);
85 state->auth_state = AUTH_STATE_CLEAR; 137 state->auth_state = AUTH_STATE_CLEAR;
86 damage_state(state); 138 damage_state(state);
139 schedule_indicator_clear(state);
87 break; 140 break;
88 case XKB_KEY_Caps_Lock: 141 case XKB_KEY_Caps_Lock:
89 /* The state is getting active after this 142 /* The state is getting active after this
@@ -91,6 +144,8 @@ void swaylock_handle_key(struct swaylock_state *state,
91 state->xkb.caps_lock = !state->xkb.caps_lock; 144 state->xkb.caps_lock = !state->xkb.caps_lock;
92 state->auth_state = AUTH_STATE_INPUT_NOP; 145 state->auth_state = AUTH_STATE_INPUT_NOP;
93 damage_state(state); 146 damage_state(state);
147 schedule_indicator_clear(state);
148 schedule_password_clear(state);
94 break; 149 break;
95 case XKB_KEY_Shift_L: 150 case XKB_KEY_Shift_L:
96 case XKB_KEY_Shift_R: 151 case XKB_KEY_Shift_R:
@@ -104,12 +159,15 @@ void swaylock_handle_key(struct swaylock_state *state,
104 case XKB_KEY_Super_R: 159 case XKB_KEY_Super_R:
105 state->auth_state = AUTH_STATE_INPUT_NOP; 160 state->auth_state = AUTH_STATE_INPUT_NOP;
106 damage_state(state); 161 damage_state(state);
162 schedule_indicator_clear(state);
163 schedule_password_clear(state);
107 break; 164 break;
108 case XKB_KEY_u: 165 case XKB_KEY_u:
109 if (state->xkb.control) { 166 if (state->xkb.control) {
110 clear_password_buffer(&state->password); 167 clear_password_buffer(&state->password);
111 state->auth_state = AUTH_STATE_CLEAR; 168 state->auth_state = AUTH_STATE_CLEAR;
112 damage_state(state); 169 damage_state(state);
170 schedule_indicator_clear(state);
113 break; 171 break;
114 } 172 }
115 // fallthrough 173 // fallthrough
@@ -118,6 +176,8 @@ void swaylock_handle_key(struct swaylock_state *state,
118 append_ch(&state->password, codepoint); 176 append_ch(&state->password, codepoint);
119 state->auth_state = AUTH_STATE_INPUT; 177 state->auth_state = AUTH_STATE_INPUT;
120 damage_state(state); 178 damage_state(state);
179 schedule_indicator_clear(state);
180 schedule_password_clear(state);
121 } 181 }
122 break; 182 break;
123 } 183 }