diff options
author | 2018-09-18 22:52:36 -0400 | |
---|---|---|
committer | 2018-09-18 22:52:36 -0400 | |
commit | cdce604d8e166ae905b394306fece4e7f035cedd (patch) | |
tree | fbbd9612c860fb60bfdee882346f843668b1b8fa /swaybar | |
parent | Merge pull request #2652 from emersion/swaybar-output-names (diff) | |
parent | swaybar: only free tokener when using i3bar protocol (diff) | |
download | sway-cdce604d8e166ae905b394306fece4e7f035cedd.tar.gz sway-cdce604d8e166ae905b394306fece4e7f035cedd.tar.zst sway-cdce604d8e166ae905b394306fece4e7f035cedd.zip |
Merge pull request #2640 from ianyfan/swaybar
Overhaul swaybar protocol handling (+fixes)
Diffstat (limited to 'swaybar')
-rw-r--r-- | swaybar/event_loop.c | 4 | ||||
-rw-r--r-- | swaybar/i3bar.c | 205 | ||||
-rw-r--r-- | swaybar/render.c | 28 | ||||
-rw-r--r-- | swaybar/status_line.c | 144 |
4 files changed, 222 insertions, 159 deletions
diff --git a/swaybar/event_loop.c b/swaybar/event_loop.c index bc4053be..686b9962 100644 --- a/swaybar/event_loop.c +++ b/swaybar/event_loop.c | |||
@@ -105,7 +105,7 @@ bool remove_timer(timer_t timer) { | |||
105 | return false; | 105 | return false; |
106 | } | 106 | } |
107 | 107 | ||
108 | void event_loop_poll() { | 108 | void event_loop_poll(void) { |
109 | poll(event_loop.fds.items, event_loop.fds.length, -1); | 109 | poll(event_loop.fds.items, event_loop.fds.length, -1); |
110 | 110 | ||
111 | for (int i = 0; i < event_loop.fds.length; ++i) { | 111 | for (int i = 0; i < event_loop.fds.length; ++i) { |
@@ -146,7 +146,7 @@ void event_loop_poll() { | |||
146 | } | 146 | } |
147 | } | 147 | } |
148 | 148 | ||
149 | void init_event_loop() { | 149 | void init_event_loop(void) { |
150 | event_loop.fds.length = 0; | 150 | event_loop.fds.length = 0; |
151 | event_loop.fds.capacity = 10; | 151 | event_loop.fds.capacity = 10; |
152 | event_loop.fds.items = malloc( | 152 | event_loop.fds.items = malloc( |
diff --git a/swaybar/i3bar.c b/swaybar/i3bar.c index 0becae5d..88404703 100644 --- a/swaybar/i3bar.c +++ b/swaybar/i3bar.c | |||
@@ -1,6 +1,7 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | 1 | #define _POSIX_C_SOURCE 200809L |
2 | #include <json-c/json.h> | 2 | #include <json-c/json.h> |
3 | #include <linux/input-event-codes.h> | 3 | #include <linux/input-event-codes.h> |
4 | #include <ctype.h> | ||
4 | #include <stdlib.h> | 5 | #include <stdlib.h> |
5 | #include <string.h> | 6 | #include <string.h> |
6 | #include <unistd.h> | 7 | #include <unistd.h> |
@@ -24,24 +25,19 @@ void i3bar_block_unref(struct i3bar_block *block) { | |||
24 | } | 25 | } |
25 | } | 26 | } |
26 | 27 | ||
27 | static bool i3bar_parse_json(struct status_line *status, const char *text) { | 28 | static void i3bar_parse_json(struct status_line *status, |
29 | struct json_object *json_array) { | ||
28 | struct i3bar_block *block, *tmp; | 30 | struct i3bar_block *block, *tmp; |
29 | wl_list_for_each_safe(block, tmp, &status->blocks, link) { | 31 | wl_list_for_each_safe(block, tmp, &status->blocks, link) { |
30 | wl_list_remove(&block->link); | 32 | wl_list_remove(&block->link); |
31 | i3bar_block_unref(block); | 33 | i3bar_block_unref(block); |
32 | } | 34 | } |
33 | json_object *results = json_tokener_parse(text); | 35 | for (size_t i = 0; i < json_object_array_length(json_array); ++i) { |
34 | if (!results) { | ||
35 | status_error(status, "[failed to parse i3bar json]"); | ||
36 | return false; | ||
37 | } | ||
38 | wlr_log(WLR_DEBUG, "Got i3bar json: '%s'", text); | ||
39 | for (size_t i = 0; i < json_object_array_length(results); ++i) { | ||
40 | json_object *full_text, *short_text, *color, *min_width, *align, *urgent; | 36 | json_object *full_text, *short_text, *color, *min_width, *align, *urgent; |
41 | json_object *name, *instance, *separator, *separator_block_width; | 37 | json_object *name, *instance, *separator, *separator_block_width; |
42 | json_object *background, *border, *border_top, *border_bottom; | 38 | json_object *background, *border, *border_top, *border_bottom; |
43 | json_object *border_left, *border_right, *markup; | 39 | json_object *border_left, *border_right, *markup; |
44 | json_object *json = json_object_array_get_idx(results, i); | 40 | json_object *json = json_object_array_get_idx(json_array, i); |
45 | if (!json) { | 41 | if (!json) { |
46 | continue; | 42 | continue; |
47 | } | 43 | } |
@@ -110,96 +106,149 @@ static bool i3bar_parse_json(struct status_line *status, const char *text) { | |||
110 | json_object_get_int(border_right) : 1; | 106 | json_object_get_int(border_right) : 1; |
111 | wl_list_insert(&status->blocks, &block->link); | 107 | wl_list_insert(&status->blocks, &block->link); |
112 | } | 108 | } |
113 | json_object_put(results); | ||
114 | return true; | ||
115 | } | 109 | } |
116 | 110 | ||
117 | bool i3bar_handle_readable(struct status_line *status) { | 111 | bool i3bar_handle_readable(struct status_line *status) { |
118 | struct i3bar_protocol_state *state = &status->i3bar_state; | 112 | while (!status->started) { // look for opening bracket |
119 | 113 | for (size_t c = 0; c < status->buffer_index; ++c) { | |
120 | char *cur = &state->buffer[state->buffer_index]; | 114 | if (status->buffer[c] == '[') { |
121 | ssize_t n = read(status->read_fd, cur, | 115 | status->started = true; |
122 | state->buffer_size - state->buffer_index); | 116 | status->buffer_index -= ++c; |
123 | if (n == -1) { | 117 | memmove(status->buffer, &status->buffer[c], status->buffer_index); |
124 | status_error(status, "[failed to read from status command]"); | 118 | break; |
125 | return false; | 119 | } else if (!isspace(status->buffer[c])) { |
126 | } | 120 | status_error(status, "[invalid json]"); |
121 | return true; | ||
122 | } | ||
123 | } | ||
124 | if (status->started) { | ||
125 | break; | ||
126 | } | ||
127 | 127 | ||
128 | if (n == (ssize_t)(state->buffer_size - state->buffer_index)) { | 128 | errno = 0; |
129 | state->buffer_size = state->buffer_size * 2; | 129 | ssize_t read_bytes = read(status->read_fd, status->buffer, status->buffer_size); |
130 | char *new_buffer = realloc(state->buffer, state->buffer_size); | 130 | if (read_bytes > -1) { |
131 | if (!new_buffer) { | 131 | status->buffer_index = read_bytes; |
132 | free(state->buffer); | 132 | } else if (errno == EAGAIN) { |
133 | status_error(status, "[failed to allocate buffer]"); | 133 | return false; |
134 | } else { | ||
135 | status_error(status, "[error reading from status command]"); | ||
134 | return true; | 136 | return true; |
135 | } | 137 | } |
136 | state->current_node += new_buffer - state->buffer; | ||
137 | cur += new_buffer - state->buffer; | ||
138 | state->buffer = new_buffer; | ||
139 | } | 138 | } |
140 | 139 | ||
141 | cur[n] = '\0'; | 140 | struct json_object *last_object = NULL; |
142 | bool redraw = false; | 141 | struct json_object *test_object; |
143 | while (*cur) { | 142 | size_t buffer_pos = 0; |
144 | if (state->nodes[state->depth] == JSON_NODE_STRING) { | 143 | while (true) { |
145 | if (!state->escape && *cur == '"') { | 144 | // since the incoming stream is an infinite array |
146 | --state->depth; | 145 | // parsing is split into two parts |
146 | // first, attempt to parse the current object, reading more if the | ||
147 | // parser indicates that the current object is incomplete, and failing | ||
148 | // if the parser fails | ||
149 | // second, look for separating comma, ignoring whitespace, failing if | ||
150 | // any other characters are encountered | ||
151 | if (status->expecting_comma) { | ||
152 | for (; buffer_pos < status->buffer_index; ++buffer_pos) { | ||
153 | if (status->buffer[buffer_pos] == ',') { | ||
154 | status->expecting_comma = false; | ||
155 | ++buffer_pos; | ||
156 | break; | ||
157 | } else if (!isspace(status->buffer[buffer_pos])) { | ||
158 | status_error(status, "[invalid i3bar json]"); | ||
159 | return true; | ||
160 | } | ||
161 | } | ||
162 | if (buffer_pos < status->buffer_index) { | ||
163 | continue; // look for new object without reading more input | ||
147 | } | 164 | } |
148 | state->escape = !state->escape && *cur == '\\'; | 165 | buffer_pos = status->buffer_index = 0; |
149 | } else { | 166 | } else { |
150 | switch (*cur) { | 167 | test_object = json_tokener_parse_ex(status->tokener, |
151 | case '[': | 168 | &status->buffer[buffer_pos], status->buffer_index - buffer_pos); |
152 | ++state->depth; | 169 | if (json_tokener_get_error(status->tokener) == json_tokener_success) { |
153 | if (state->depth > | 170 | if (json_object_get_type(test_object) == json_type_array) { |
154 | sizeof(state->nodes) / sizeof(state->nodes[0])) { | 171 | if (last_object) { |
155 | status_error(status, "[i3bar json too deep]"); | 172 | json_object_put(last_object); |
156 | return false; | 173 | } |
157 | } | 174 | last_object = test_object; |
158 | state->nodes[state->depth] = JSON_NODE_ARRAY; | 175 | } else { |
159 | if (state->depth == 1) { | 176 | json_object_put(test_object); |
160 | state->current_node = cur; | ||
161 | } | 177 | } |
162 | break; | 178 | |
163 | case ']': | 179 | // in order to print the json for debugging purposes |
164 | if (state->nodes[state->depth] != JSON_NODE_ARRAY) { | 180 | // the last character is temporarily replaced with a null character |
165 | status_error(status, "[failed to parse i3bar json]"); | 181 | // (the last character is used in case the buffer is full) |
166 | return false; | 182 | char *last_char_pos = |
183 | &status->buffer[buffer_pos + status->tokener->char_offset - 1]; | ||
184 | char last_char = *last_char_pos; | ||
185 | while (isspace(last_char)) { | ||
186 | last_char = *--last_char_pos; | ||
167 | } | 187 | } |
168 | --state->depth; | 188 | *last_char_pos = '\0'; |
169 | if (state->depth == 0) { | 189 | size_t offset = strspn(&status->buffer[buffer_pos], " \f\n\r\t\v"); |
170 | // cur[1] is valid since cur[0] != '\0' | 190 | wlr_log(WLR_DEBUG, "Received i3bar json: '%s%c'", |
171 | char p = cur[1]; | 191 | &status->buffer[buffer_pos + offset], last_char); |
172 | cur[1] = '\0'; | 192 | *last_char_pos = last_char; |
173 | redraw = i3bar_parse_json( | 193 | |
174 | status, state->current_node) || redraw; | 194 | buffer_pos += status->tokener->char_offset; |
175 | cur[1] = p; | 195 | status->expecting_comma = true; |
176 | memmove(state->buffer, cur, | 196 | |
177 | state->buffer_size - (cur - state->buffer)); | 197 | if (buffer_pos < status->buffer_index) { |
178 | cur = state->buffer; | 198 | continue; // look for comma without reading more input |
179 | state->current_node = cur + 1; | ||
180 | } | 199 | } |
181 | break; | 200 | buffer_pos = status->buffer_index = 0; |
182 | case '"': | 201 | } else if (json_tokener_get_error(status->tokener) == json_tokener_continue) { |
183 | ++state->depth; | 202 | if (status->buffer_index < status->buffer_size) { |
184 | if (state->depth > | 203 | // move the object to the start of the buffer |
185 | sizeof(state->nodes) / sizeof(state->nodes[0])) { | 204 | status->buffer_index -= buffer_pos; |
186 | status_error(status, "[i3bar json too deep]"); | 205 | memmove(status->buffer, &status->buffer[buffer_pos], |
187 | return false; | 206 | status->buffer_index); |
207 | } else { | ||
208 | // expand buffer | ||
209 | status->buffer_size *= 2; | ||
210 | char *new_buffer = realloc(status->buffer, status->buffer_size); | ||
211 | if (new_buffer) { | ||
212 | status->buffer = new_buffer; | ||
213 | } else { | ||
214 | free(status->buffer); | ||
215 | status_error(status, "[failed to allocate buffer]"); | ||
216 | return true; | ||
217 | } | ||
188 | } | 218 | } |
189 | state->nodes[state->depth] = JSON_NODE_STRING; | 219 | } else { |
190 | break; | 220 | status_error(status, "[failed to parse i3bar json]"); |
221 | return true; | ||
191 | } | 222 | } |
192 | } | 223 | } |
193 | ++cur; | 224 | |
225 | errno = 0; | ||
226 | ssize_t read_bytes = read(status->read_fd, &status->buffer[status->buffer_index], | ||
227 | status->buffer_size - status->buffer_index); | ||
228 | if (read_bytes > -1) { | ||
229 | status->buffer_index += read_bytes; | ||
230 | } else if (errno == EAGAIN) { | ||
231 | break; | ||
232 | } else { | ||
233 | status_error(status, "[error reading from status command]"); | ||
234 | return true; | ||
235 | } | ||
236 | } | ||
237 | |||
238 | if (last_object) { | ||
239 | wlr_log(WLR_DEBUG, "Rendering last received json"); | ||
240 | i3bar_parse_json(status, last_object); | ||
241 | json_object_put(last_object); | ||
242 | return true; | ||
243 | } else { | ||
244 | return false; | ||
194 | } | 245 | } |
195 | state->buffer_index = cur - state->buffer; | ||
196 | return redraw; | ||
197 | } | 246 | } |
198 | 247 | ||
199 | enum hotspot_event_handling i3bar_block_send_click(struct status_line *status, | 248 | enum hotspot_event_handling i3bar_block_send_click(struct status_line *status, |
200 | struct i3bar_block *block, int x, int y, enum x11_button button) { | 249 | struct i3bar_block *block, int x, int y, enum x11_button button) { |
201 | wlr_log(WLR_DEBUG, "block %s clicked", block->name ? block->name : "(nil)"); | 250 | wlr_log(WLR_DEBUG, "block %s clicked", block->name ? block->name : "(nil)"); |
202 | if (!block->name || !status->i3bar_state.click_events) { | 251 | if (!block->name || !status->click_events) { |
203 | return HOTSPOT_PROCESS; | 252 | return HOTSPOT_PROCESS; |
204 | } | 253 | } |
205 | 254 | ||
@@ -214,7 +263,7 @@ enum hotspot_event_handling i3bar_block_send_click(struct status_line *status, | |||
214 | json_object_object_add(event_json, "button", json_object_new_int(button)); | 263 | json_object_object_add(event_json, "button", json_object_new_int(button)); |
215 | json_object_object_add(event_json, "x", json_object_new_int(x)); | 264 | json_object_object_add(event_json, "x", json_object_new_int(x)); |
216 | json_object_object_add(event_json, "y", json_object_new_int(y)); | 265 | json_object_object_add(event_json, "y", json_object_new_int(y)); |
217 | if (dprintf(status->write_fd, "%s\n", | 266 | if (dprintf(status->write_fd, "%s,\n", |
218 | json_object_to_json_string(event_json)) < 0) { | 267 | json_object_to_json_string(event_json)) < 0) { |
219 | status_error(status, "[failed to write click event]"); | 268 | status_error(status, "[failed to write click event]"); |
220 | } | 269 | } |
diff --git a/swaybar/render.c b/swaybar/render.c index 2d848bfa..97690338 100644 --- a/swaybar/render.c +++ b/swaybar/render.c | |||
@@ -120,14 +120,14 @@ static void i3bar_block_unref_callback(void *data) { | |||
120 | } | 120 | } |
121 | 121 | ||
122 | static uint32_t render_status_block(cairo_t *cairo, | 122 | static uint32_t render_status_block(cairo_t *cairo, |
123 | struct swaybar_config *config, struct swaybar_output *output, | 123 | struct swaybar_output *output, struct i3bar_block *block, double *x, |
124 | struct i3bar_block *block, double *x, | ||
125 | uint32_t surface_height, bool focused, bool edge) { | 124 | uint32_t surface_height, bool focused, bool edge) { |
126 | if (!block->full_text || !*block->full_text) { | 125 | if (!block->full_text || !*block->full_text) { |
127 | return 0; | 126 | return 0; |
128 | } | 127 | } |
129 | 128 | ||
130 | uint32_t height = surface_height * output->scale; | 129 | uint32_t height = surface_height * output->scale; |
130 | struct swaybar_config *config = output->bar->config; | ||
131 | 131 | ||
132 | int text_width, text_height; | 132 | int text_width, text_height; |
133 | get_text_size(cairo, config->font, &text_width, &text_height, NULL, | 133 | get_text_size(cairo, config->font, &text_width, &text_height, NULL, |
@@ -177,16 +177,18 @@ static uint32_t render_status_block(cairo_t *cairo, | |||
177 | *x -= margin; | 177 | *x -= margin; |
178 | } | 178 | } |
179 | 179 | ||
180 | struct swaybar_hotspot *hotspot = calloc(1, sizeof(struct swaybar_hotspot)); | 180 | if (output->bar->status->click_events) { |
181 | hotspot->x = *x; | 181 | struct swaybar_hotspot *hotspot = calloc(1, sizeof(struct swaybar_hotspot)); |
182 | hotspot->y = 0; | 182 | hotspot->x = *x; |
183 | hotspot->width = width; | 183 | hotspot->y = 0; |
184 | hotspot->height = height; | 184 | hotspot->width = width; |
185 | hotspot->callback = block_hotspot_callback; | 185 | hotspot->height = height; |
186 | hotspot->destroy = i3bar_block_unref_callback; | 186 | hotspot->callback = block_hotspot_callback; |
187 | hotspot->data = block; | 187 | hotspot->destroy = i3bar_block_unref_callback; |
188 | block->ref_count++; | 188 | hotspot->data = block; |
189 | wl_list_insert(&output->hotspots, &hotspot->link); | 189 | block->ref_count++; |
190 | wl_list_insert(&output->hotspots, &hotspot->link); | ||
191 | } | ||
190 | 192 | ||
191 | double pos = *x; | 193 | double pos = *x; |
192 | if (block->background) { | 194 | if (block->background) { |
@@ -268,7 +270,7 @@ static uint32_t render_status_line_i3bar(cairo_t *cairo, | |||
268 | bool edge = true; | 270 | bool edge = true; |
269 | struct i3bar_block *block; | 271 | struct i3bar_block *block; |
270 | wl_list_for_each(block, &status->blocks, link) { | 272 | wl_list_for_each(block, &status->blocks, link) { |
271 | uint32_t h = render_status_block(cairo, config, output, | 273 | uint32_t h = render_status_block(cairo, output, |
272 | block, x, surface_height, focused, edge); | 274 | block, x, surface_height, focused, edge); |
273 | max_height = h > max_height ? h : max_height; | 275 | max_height = h > max_height ? h : max_height; |
274 | edge = false; | 276 | edge = false; |
diff --git a/swaybar/status_line.c b/swaybar/status_line.c index 3ba990bd..401bf6f6 100644 --- a/swaybar/status_line.c +++ b/swaybar/status_line.c | |||
@@ -7,86 +7,102 @@ | |||
7 | #include <unistd.h> | 7 | #include <unistd.h> |
8 | #include <wlr/util/log.h> | 8 | #include <wlr/util/log.h> |
9 | #include "swaybar/config.h" | 9 | #include "swaybar/config.h" |
10 | #include "swaybar/event_loop.h" | ||
10 | #include "swaybar/status_line.h" | 11 | #include "swaybar/status_line.h" |
11 | #include "readline.h" | 12 | #include "readline.h" |
12 | 13 | ||
14 | static void status_line_close_fds(struct status_line *status) { | ||
15 | if (status->read_fd != -1) { | ||
16 | remove_event(status->read_fd); | ||
17 | close(status->read_fd); | ||
18 | status->read_fd = -1; | ||
19 | } | ||
20 | if (status->write_fd != -1) { | ||
21 | close(status->write_fd); | ||
22 | status->write_fd = -1; | ||
23 | } | ||
24 | } | ||
25 | |||
13 | void status_error(struct status_line *status, const char *text) { | 26 | void status_error(struct status_line *status, const char *text) { |
14 | close(status->read_fd); | 27 | status_line_close_fds(status); |
15 | close(status->write_fd); | ||
16 | status->protocol = PROTOCOL_ERROR; | 28 | status->protocol = PROTOCOL_ERROR; |
17 | status->text = text; | 29 | status->text = text; |
18 | } | 30 | } |
19 | 31 | ||
20 | bool status_handle_readable(struct status_line *status) { | 32 | bool status_handle_readable(struct status_line *status) { |
21 | char *line; | 33 | ssize_t read_bytes = 1; |
22 | switch (status->protocol) { | 34 | switch (status->protocol) { |
23 | case PROTOCOL_ERROR: | ||
24 | return false; | ||
25 | case PROTOCOL_I3BAR: | ||
26 | if (i3bar_handle_readable(status) > 0) { | ||
27 | return true; | ||
28 | } | ||
29 | break; | ||
30 | case PROTOCOL_TEXT: | ||
31 | line = read_line_buffer(status->read, | ||
32 | status->text_state.buffer, status->text_state.buffer_size); | ||
33 | if (!line) { | ||
34 | status_error(status, "[error reading from status command]"); | ||
35 | } else { | ||
36 | status->text = line; | ||
37 | } | ||
38 | return true; | ||
39 | case PROTOCOL_UNDEF: | 35 | case PROTOCOL_UNDEF: |
40 | line = read_line_buffer(status->read, | 36 | errno = 0; |
41 | status->text_state.buffer, status->text_state.buffer_size); | 37 | read_bytes = getline(&status->buffer, |
42 | if (!line) { | 38 | &status->buffer_size, status->read); |
39 | if (errno == EAGAIN) { | ||
40 | clearerr(status->read); | ||
41 | } else if (errno) { | ||
43 | status_error(status, "[error reading from status command]"); | 42 | status_error(status, "[error reading from status command]"); |
44 | return false; | 43 | return true; |
45 | } | 44 | } |
46 | if (line[0] == '{') { | 45 | |
47 | json_object *proto = json_tokener_parse(line); | 46 | // the header must be sent completely the first time round |
48 | if (proto) { | 47 | json_object *header, *version; |
49 | json_object *version; | 48 | if (status->buffer[read_bytes - 1] == '\n' |
50 | if (json_object_object_get_ex(proto, "version", &version) | 49 | && (header = json_tokener_parse(status->buffer)) |
51 | && json_object_get_int(version) == 1) { | 50 | && json_object_object_get_ex(header, "version", &version) |
52 | wlr_log(WLR_DEBUG, "Switched to i3bar protocol."); | 51 | && json_object_get_int(version) == 1) { |
53 | status->protocol = PROTOCOL_I3BAR; | 52 | wlr_log(WLR_DEBUG, "Using i3bar protocol."); |
54 | } | 53 | status->protocol = PROTOCOL_I3BAR; |
55 | json_object *click_events; | 54 | |
56 | if (json_object_object_get_ex( | 55 | json_object *click_events; |
57 | proto, "click_events", &click_events) | 56 | if (json_object_object_get_ex(header, "click_events", &click_events) |
58 | && json_object_get_boolean(click_events)) { | 57 | && json_object_get_boolean(click_events)) { |
59 | wlr_log(WLR_DEBUG, "Enabled click events."); | 58 | wlr_log(WLR_DEBUG, "Enabling click events."); |
60 | status->i3bar_state.click_events = true; | 59 | status->click_events = true; |
61 | const char *events_array = "[\n"; | 60 | if (write(status->write_fd, "[\n", 2) != 2) { |
62 | ssize_t len = strlen(events_array); | 61 | status_error(status, "[failed to write to status command]"); |
63 | if (write(status->write_fd, events_array, len) != len) { | 62 | json_object_put(header); |
64 | status_error(status, | 63 | return true; |
65 | "[failed to write to status command]"); | ||
66 | } | ||
67 | } | 64 | } |
68 | json_object_put(proto); | ||
69 | } | 65 | } |
66 | json_object_put(header); | ||
70 | 67 | ||
71 | status->protocol = PROTOCOL_I3BAR; | ||
72 | free(status->text_state.buffer); | ||
73 | wl_list_init(&status->blocks); | 68 | wl_list_init(&status->blocks); |
74 | status->i3bar_state.buffer_size = 4096; | 69 | status->tokener = json_tokener_new(); |
75 | status->i3bar_state.buffer = | 70 | status->buffer_index = getdelim(&status->buffer, |
76 | malloc(status->i3bar_state.buffer_size); | 71 | &status->buffer_size, EOF, status->read); |
77 | } else { | 72 | return i3bar_handle_readable(status); |
78 | status->protocol = PROTOCOL_TEXT; | ||
79 | status->text = line; | ||
80 | } | 73 | } |
81 | return true; | 74 | |
75 | wlr_log(WLR_DEBUG, "Using text protocol."); | ||
76 | status->protocol = PROTOCOL_TEXT; | ||
77 | status->text = status->buffer; | ||
78 | // intentional fall-through | ||
79 | case PROTOCOL_TEXT: | ||
80 | errno = 0; | ||
81 | while (true) { | ||
82 | if (status->buffer[read_bytes - 1] == '\n') { | ||
83 | status->buffer[read_bytes - 1] = '\0'; | ||
84 | } | ||
85 | read_bytes = getline(&status->buffer, | ||
86 | &status->buffer_size, status->read); | ||
87 | if (errno == EAGAIN) { | ||
88 | clearerr(status->read); | ||
89 | return true; | ||
90 | } else if (errno) { | ||
91 | status_error(status, "[error reading from status command]"); | ||
92 | return true; | ||
93 | } | ||
94 | } | ||
95 | case PROTOCOL_I3BAR: | ||
96 | return i3bar_handle_readable(status); | ||
97 | default: | ||
98 | return false; | ||
82 | } | 99 | } |
83 | return false; | ||
84 | } | 100 | } |
85 | 101 | ||
86 | struct status_line *status_line_init(char *cmd) { | 102 | struct status_line *status_line_init(char *cmd) { |
87 | struct status_line *status = calloc(1, sizeof(struct status_line)); | 103 | struct status_line *status = calloc(1, sizeof(struct status_line)); |
88 | status->text_state.buffer_size = 8192; | 104 | status->buffer_size = 8192; |
89 | status->text_state.buffer = malloc(status->text_state.buffer_size); | 105 | status->buffer = malloc(status->buffer_size); |
90 | 106 | ||
91 | int pipe_read_fd[2]; | 107 | int pipe_read_fd[2]; |
92 | int pipe_write_fd[2]; | 108 | int pipe_write_fd[2]; |
@@ -123,20 +139,16 @@ struct status_line *status_line_init(char *cmd) { | |||
123 | } | 139 | } |
124 | 140 | ||
125 | void status_line_free(struct status_line *status) { | 141 | void status_line_free(struct status_line *status) { |
126 | close(status->read_fd); | 142 | status_line_close_fds(status); |
127 | close(status->write_fd); | ||
128 | kill(status->pid, SIGTERM); | 143 | kill(status->pid, SIGTERM); |
129 | switch (status->protocol) { | 144 | if (status->protocol == PROTOCOL_I3BAR) { |
130 | case PROTOCOL_I3BAR:; | ||
131 | struct i3bar_block *block, *tmp; | 145 | struct i3bar_block *block, *tmp; |
132 | wl_list_for_each_safe(block, tmp, &status->blocks, link) { | 146 | wl_list_for_each_safe(block, tmp, &status->blocks, link) { |
147 | wl_list_remove(&block->link); | ||
133 | i3bar_block_unref(block); | 148 | i3bar_block_unref(block); |
134 | } | 149 | } |
135 | free(status->i3bar_state.buffer); | 150 | json_tokener_free(status->tokener); |
136 | break; | ||
137 | default: | ||
138 | free(status->text_state.buffer); | ||
139 | break; | ||
140 | } | 151 | } |
152 | free(status->buffer); | ||
141 | free(status); | 153 | free(status); |
142 | } | 154 | } |