summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Drew DeVault <sir@cmpwn.com>2018-02-05 18:11:07 -0500
committerLibravatar GitHub <noreply@github.com>2018-02-05 18:11:07 -0500
commita571506d0e3abae0a8fe05a186cb5a33623bdf94 (patch)
treeab10cd02219ad353a97794139e92e8801ce5871f
parentMerge pull request #1579 from tmccombs/patch-1 (diff)
parentHandle swaybar status line errors (diff)
downloadsway-a571506d0e3abae0a8fe05a186cb5a33623bdf94.tar.gz
sway-a571506d0e3abae0a8fe05a186cb5a33623bdf94.tar.zst
sway-a571506d0e3abae0a8fe05a186cb5a33623bdf94.zip
Merge pull request #1584 from 4e554c4c/no_more_hups
Handle swaybar status line errors
-rw-r--r--include/swaybar/event_loop.h8
-rw-r--r--include/swaybar/status_line.h6
-rw-r--r--swaybar/bar.c10
-rw-r--r--swaybar/event_loop.c53
-rw-r--r--swaybar/status_line.c29
5 files changed, 94 insertions, 12 deletions
diff --git a/include/swaybar/event_loop.h b/include/swaybar/event_loop.h
index a0cde07f..d5089262 100644
--- a/include/swaybar/event_loop.h
+++ b/include/swaybar/event_loop.h
@@ -13,11 +13,11 @@ void add_timer(timer_t timer,
13 void(*cb)(timer_t timer, void *data), 13 void(*cb)(timer_t timer, void *data),
14 void *data); 14 void *data);
15 15
16// Returns false if nothing exists, true otherwise 16// Remove the given event from the event loop
17bool remove_event(int fd); 17void remove_event(int fd);
18 18
19// Returns false if nothing exists, true otherwise 19// Remove the given timer from the event loop
20bool remove_timer(timer_t timer); 20void remove_timer(timer_t timer);
21 21
22// Blocks and returns after sending callbacks 22// Blocks and returns after sending callbacks
23void event_loop_poll(); 23void event_loop_poll();
diff --git a/include/swaybar/status_line.h b/include/swaybar/status_line.h
index 0664ddee..3ec0fcd0 100644
--- a/include/swaybar/status_line.h
+++ b/include/swaybar/status_line.h
@@ -49,6 +49,12 @@ struct status_line *init_status_line();
49bool handle_status_line(struct bar *bar); 49bool handle_status_line(struct bar *bar);
50 50
51/** 51/**
52 * This should be called if statusline input cannot be accessed.
53 * It will set an error statusline instead of using the status command
54 */
55void handle_status_hup(struct status_line *status);
56
57/**
52 * Handle mouse clicks. 58 * Handle mouse clicks.
53 */ 59 */
54bool status_line_mouse_event(struct bar *bar, int x, int y, uint32_t button); 60bool status_line_mouse_event(struct bar *bar, int x, int y, uint32_t button);
diff --git a/swaybar/bar.c b/swaybar/bar.c
index 6db556a8..deddf971 100644
--- a/swaybar/bar.c
+++ b/swaybar/bar.c
@@ -274,6 +274,14 @@ static void respond_ipc(int fd, short mask, void *_bar) {
274 274
275static void respond_command(int fd, short mask, void *_bar) { 275static void respond_command(int fd, short mask, void *_bar) {
276 struct bar *bar = (struct bar *)_bar; 276 struct bar *bar = (struct bar *)_bar;
277 if (mask & POLLHUP) {
278 // Something's wrong with the command
279 handle_status_hup(bar->status);
280 dirty = true;
281 // We will stop watching the status line so swaybar won't
282 // flood the CPU with its HUPs
283 remove_event(fd);
284 }
277 dirty = handle_status_line(bar); 285 dirty = handle_status_line(bar);
278} 286}
279 287
@@ -286,7 +294,7 @@ static void respond_output(int fd, short mask, void *_output) {
286 294
287void bar_run(struct bar *bar) { 295void bar_run(struct bar *bar) {
288 add_event(bar->ipc_event_socketfd, POLLIN, respond_ipc, bar); 296 add_event(bar->ipc_event_socketfd, POLLIN, respond_ipc, bar);
289 add_event(bar->status_read_fd, POLLIN, respond_command, bar); 297 add_event(bar->status_read_fd, POLLIN | POLLHUP, respond_command, bar);
290 298
291 int i; 299 int i;
292 for (i = 0; i < bar->outputs->length; ++i) { 300 for (i = 0; i < bar->outputs->length; ++i) {
diff --git a/swaybar/event_loop.c b/swaybar/event_loop.c
index 0d1be1da..bde8203f 100644
--- a/swaybar/event_loop.c
+++ b/swaybar/event_loop.c
@@ -20,6 +20,19 @@ struct timer_item {
20 void *data; 20 void *data;
21}; 21};
22 22
23enum state_item_flags {
24 ITEM_IS_FD,
25 ITEM_IS_TIMER,
26};
27
28struct state_item {
29 enum state_item_flags flags;
30 union {
31 int fd;
32 timer_t timer;
33 } inner;
34};
35
23static struct { 36static struct {
24 // The order of each must be kept consistent 37 // The order of each must be kept consistent
25 struct { /* pollfd array */ 38 struct { /* pollfd array */
@@ -31,6 +44,9 @@ static struct {
31 44
32 // Timer list 45 // Timer list
33 list_t *timers; 46 list_t *timers;
47
48 // List of state changes at the end of each iteration
49 list_t *state;
34} event_loop; 50} event_loop;
35 51
36void add_timer(timer_t timer, 52void add_timer(timer_t timer,
@@ -72,7 +88,7 @@ void add_event(int fd, short mask,
72 return; 88 return;
73} 89}
74 90
75bool remove_event(int fd) { 91static void _remove_event(int fd) {
76 int index = -1; 92 int index = -1;
77 for (int i = 0; i < event_loop.fds.length; ++i) { 93 for (int i = 0; i < event_loop.fds.length; ++i) {
78 if (event_loop.fds.items[i].fd == fd) { 94 if (event_loop.fds.items[i].fd == fd) {
@@ -87,12 +103,16 @@ bool remove_event(int fd) {
87 sizeof(struct pollfd) * event_loop.fds.length - index); 103 sizeof(struct pollfd) * event_loop.fds.length - index);
88 104
89 list_del(event_loop.items, index); 105 list_del(event_loop.items, index);
90 return true;
91 } else {
92 return false;
93 } 106 }
94} 107}
95 108
109void remove_event(int fd) {
110 struct state_item *item = malloc(sizeof(struct state_item));
111 item->flags = ITEM_IS_FD;
112 item->inner.fd = fd;
113 list_add(event_loop.state, item);
114}
115
96static int timer_item_timer_cmp(const void *_timer_item, const void *_timer) { 116static int timer_item_timer_cmp(const void *_timer_item, const void *_timer) {
97 const struct timer_item *timer_item = _timer_item; 117 const struct timer_item *timer_item = _timer_item;
98 const timer_t *timer = _timer; 118 const timer_t *timer = _timer;
@@ -102,14 +122,19 @@ static int timer_item_timer_cmp(const void *_timer_item, const void *_timer) {
102 return -1; 122 return -1;
103 } 123 }
104} 124}
105bool remove_timer(timer_t timer) { 125static void _remove_timer(timer_t timer) {
106 int index = list_seq_find(event_loop.timers, timer_item_timer_cmp, &timer); 126 int index = list_seq_find(event_loop.timers, timer_item_timer_cmp, &timer);
107 if (index != -1) { 127 if (index != -1) {
108 free(event_loop.timers->items[index]); 128 free(event_loop.timers->items[index]);
109 list_del(event_loop.timers, index); 129 list_del(event_loop.timers, index);
110 return true;
111 } 130 }
112 return false; 131}
132
133void remove_timer(timer_t timer) {
134 struct state_item *item = malloc(sizeof(struct state_item));
135 item->flags = ITEM_IS_TIMER;
136 item->inner.timer = timer;
137 list_add(event_loop.state, item);
113} 138}
114 139
115void event_loop_poll() { 140void event_loop_poll() {
@@ -133,6 +158,19 @@ void event_loop_poll() {
133 item->cb(item->timer, item->data); 158 item->cb(item->timer, item->data);
134 } 159 }
135 } 160 }
161
162 // Remove all requested items from the event loop. We can't do this
163 // during normal operation, as it will cause race conditions.
164 for (int i = 0; i < event_loop.state->length; ++i) {
165 struct state_item *item = event_loop.state->items[i];
166 if (item->flags == ITEM_IS_FD) {
167 _remove_event(item->inner.fd);
168 } else {
169 _remove_timer(item->inner.timer);
170 }
171 free(item);
172 }
173 event_loop.state->length = 0; // reset state list
136} 174}
137 175
138void init_event_loop() { 176void init_event_loop() {
@@ -141,4 +179,5 @@ void init_event_loop() {
141 event_loop.fds.items = malloc(event_loop.fds.capacity * sizeof(struct pollfd)); 179 event_loop.fds.items = malloc(event_loop.fds.capacity * sizeof(struct pollfd));
142 event_loop.items = create_list(); 180 event_loop.items = create_list();
143 event_loop.timers = create_list(); 181 event_loop.timers = create_list();
182 event_loop.state = create_list();
144} 183}
diff --git a/swaybar/status_line.c b/swaybar/status_line.c
index e3cc0bf4..bbb798f1 100644
--- a/swaybar/status_line.c
+++ b/swaybar/status_line.c
@@ -511,6 +511,35 @@ bool handle_status_line(struct bar *bar) {
511 return dirty; 511 return dirty;
512} 512}
513 513
514void handle_status_hup(struct status_line *line) {
515 // This is somewhat hacky, but free all previous status line state and
516 // then create a status block that displays an error string. This is so
517 // we can have pretty error colors.
518 sway_log(L_ERROR, "Replacing statusline with error string, as the status command has failed");
519 if (line->block_line) {
520 list_foreach(line->block_line, free_status_block);
521 list_free(line->block_line);
522 }
523 line->block_line = create_list();
524 struct status_block *new = calloc(1, sizeof(struct status_block));
525 new->full_text = strdup("ERROR: swaybar cannot access the statusline");
526 new->color = 0xff0000ff;
527 new->min_width = 0;
528 new->align = strdup("left");
529 new->markup = false;
530 new->separator = true;
531 new->separator_block_width = 9;
532 new->background = 0x0;
533 new->border = 0x0;
534 new->border_top = 1;
535 new->border_bottom = 1;
536 new->border_left = 1;
537 new->border_right = 1;
538 list_add(line->block_line, new);
539
540 line->protocol = I3BAR;
541}
542
514struct status_line *init_status_line() { 543struct status_line *init_status_line() {
515 struct status_line *line = malloc(sizeof(struct status_line)); 544 struct status_line *line = malloc(sizeof(struct status_line));
516 line->block_line = create_list(); 545 line->block_line = create_list();