From 4cb28de89fa50c2c992702c238d54d16a0269553 Mon Sep 17 00:00:00 2001 From: Ian Fan Date: Sat, 15 Sep 2018 10:14:21 +0100 Subject: [PATCH 01/10] swaybar: remove block links upon exit --- swaybar/status_line.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/swaybar/status_line.c b/swaybar/status_line.c index 3ba990bdd..688e5947d 100644 --- a/swaybar/status_line.c +++ b/swaybar/status_line.c @@ -127,13 +127,15 @@ void status_line_free(struct status_line *status) { close(status->write_fd); kill(status->pid, SIGTERM); switch (status->protocol) { - case PROTOCOL_I3BAR:; + case PROTOCOL_I3BAR: { struct i3bar_block *block, *tmp; wl_list_for_each_safe(block, tmp, &status->blocks, link) { + wl_list_remove(&block->link); i3bar_block_unref(block); } free(status->i3bar_state.buffer); break; + } default: free(status->text_state.buffer); break; From 952453480f6764eb583b2507c7af83e242e0630a Mon Sep 17 00:00:00 2001 From: Ian Fan Date: Sat, 15 Sep 2018 10:15:30 +0100 Subject: [PATCH 02/10] swaybar: invalidate file descriptors upon closing --- swaybar/status_line.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/swaybar/status_line.c b/swaybar/status_line.c index 688e5947d..09ed23753 100644 --- a/swaybar/status_line.c +++ b/swaybar/status_line.c @@ -7,12 +7,24 @@ #include #include #include "swaybar/config.h" +#include "swaybar/event_loop.h" #include "swaybar/status_line.h" #include "readline.h" +static void status_line_close_fds(struct status_line *status) { + if (status->read_fd != -1) { + remove_event(status->read_fd); + close(status->read_fd); + status->read_fd = -1; + } + if (status->write_fd != -1) { + close(status->write_fd); + status->write_fd = -1; + } +} + void status_error(struct status_line *status, const char *text) { - close(status->read_fd); - close(status->write_fd); + status_line_close_fds(status); status->protocol = PROTOCOL_ERROR; status->text = text; } @@ -123,8 +135,7 @@ struct status_line *status_line_init(char *cmd) { } void status_line_free(struct status_line *status) { - close(status->read_fd); - close(status->write_fd); + status_line_close_fds(status); kill(status->pid, SIGTERM); switch (status->protocol) { case PROTOCOL_I3BAR: { From 9932c6a1f1f295531989d9e76494b0ca43509cd4 Mon Sep 17 00:00:00 2001 From: Ian Fan Date: Sun, 16 Sep 2018 11:24:24 +0100 Subject: [PATCH 03/10] swaybar: fix empty function prototypes --- include/swaybar/event_loop.h | 4 ++-- swaybar/event_loop.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/swaybar/event_loop.h b/include/swaybar/event_loop.h index 99f6ed36c..47be5b793 100644 --- a/include/swaybar/event_loop.h +++ b/include/swaybar/event_loop.h @@ -19,8 +19,8 @@ bool remove_event(int fd); bool remove_timer(timer_t timer); // Blocks and returns after sending callbacks -void event_loop_poll(); +void event_loop_poll(void); -void init_event_loop(); +void init_event_loop(void); #endif diff --git a/swaybar/event_loop.c b/swaybar/event_loop.c index bc4053beb..686b99629 100644 --- a/swaybar/event_loop.c +++ b/swaybar/event_loop.c @@ -105,7 +105,7 @@ bool remove_timer(timer_t timer) { return false; } -void event_loop_poll() { +void event_loop_poll(void) { poll(event_loop.fds.items, event_loop.fds.length, -1); for (int i = 0; i < event_loop.fds.length; ++i) { @@ -146,7 +146,7 @@ void event_loop_poll() { } } -void init_event_loop() { +void init_event_loop(void) { event_loop.fds.length = 0; event_loop.fds.capacity = 10; event_loop.fds.items = malloc( From 87c93d6ad986faa384f1279e21c10e35c798686a Mon Sep 17 00:00:00 2001 From: Ian Fan Date: Mon, 17 Sep 2018 13:31:00 +0100 Subject: [PATCH 04/10] swaybar: send trailing comma with click event json --- swaybar/i3bar.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/swaybar/i3bar.c b/swaybar/i3bar.c index 0becae5d4..f4ca5504b 100644 --- a/swaybar/i3bar.c +++ b/swaybar/i3bar.c @@ -214,7 +214,7 @@ enum hotspot_event_handling i3bar_block_send_click(struct status_line *status, json_object_object_add(event_json, "button", json_object_new_int(button)); json_object_object_add(event_json, "x", json_object_new_int(x)); json_object_object_add(event_json, "y", json_object_new_int(y)); - if (dprintf(status->write_fd, "%s\n", + if (dprintf(status->write_fd, "%s,\n", json_object_to_json_string(event_json)) < 0) { status_error(status, "[failed to write click event]"); } From babd9618b93987665c11ff268463b344da698744 Mon Sep 17 00:00:00 2001 From: Ian Fan Date: Mon, 17 Sep 2018 13:31:24 +0100 Subject: [PATCH 05/10] swaybar: only create i3bar block hotspot if click events are enabled --- swaybar/render.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/swaybar/render.c b/swaybar/render.c index 2d848bfa3..b2c1c7102 100644 --- a/swaybar/render.c +++ b/swaybar/render.c @@ -120,14 +120,14 @@ static void i3bar_block_unref_callback(void *data) { } static uint32_t render_status_block(cairo_t *cairo, - struct swaybar_config *config, struct swaybar_output *output, - struct i3bar_block *block, double *x, + struct swaybar_output *output, struct i3bar_block *block, double *x, uint32_t surface_height, bool focused, bool edge) { if (!block->full_text || !*block->full_text) { return 0; } uint32_t height = surface_height * output->scale; + struct swaybar_config *config = output->bar->config; int text_width, text_height; get_text_size(cairo, config->font, &text_width, &text_height, NULL, @@ -177,16 +177,18 @@ static uint32_t render_status_block(cairo_t *cairo, *x -= margin; } - struct swaybar_hotspot *hotspot = calloc(1, sizeof(struct swaybar_hotspot)); - hotspot->x = *x; - hotspot->y = 0; - hotspot->width = width; - hotspot->height = height; - hotspot->callback = block_hotspot_callback; - hotspot->destroy = i3bar_block_unref_callback; - hotspot->data = block; - block->ref_count++; - wl_list_insert(&output->hotspots, &hotspot->link); + if (output->bar->status->i3bar_state.click_events) { + struct swaybar_hotspot *hotspot = calloc(1, sizeof(struct swaybar_hotspot)); + hotspot->x = *x; + hotspot->y = 0; + hotspot->width = width; + hotspot->height = height; + hotspot->callback = block_hotspot_callback; + hotspot->destroy = i3bar_block_unref_callback; + hotspot->data = block; + block->ref_count++; + wl_list_insert(&output->hotspots, &hotspot->link); + } double pos = *x; if (block->background) { @@ -268,7 +270,7 @@ static uint32_t render_status_line_i3bar(cairo_t *cairo, bool edge = true; struct i3bar_block *block; wl_list_for_each(block, &status->blocks, link) { - uint32_t h = render_status_block(cairo, config, output, + uint32_t h = render_status_block(cairo, output, block, x, surface_height, focused, edge); max_height = h > max_height ? h : max_height; edge = false; From 70245c2cd5c34586fa91eb784e58471869ba66bd Mon Sep 17 00:00:00 2001 From: Ian Fan Date: Mon, 17 Sep 2018 13:43:27 +0100 Subject: [PATCH 06/10] swaybar: rewrite text protocol handling This now uses getline to correctly handle multiple or long statuses. It also removes the struct text_protocol_state and moves its members into the status_line struct. --- include/swaybar/status_line.h | 8 ++----- swaybar/status_line.c | 40 +++++++++++++++++++++-------------- 2 files changed, 26 insertions(+), 22 deletions(-) diff --git a/include/swaybar/status_line.h b/include/swaybar/status_line.h index 150267cd2..857948a59 100644 --- a/include/swaybar/status_line.h +++ b/include/swaybar/status_line.h @@ -12,11 +12,6 @@ enum status_protocol { PROTOCOL_I3BAR, }; -struct text_protocol_state { - char *buffer; - size_t buffer_size; -}; - enum json_node_type { JSON_NODE_UNKNOWN, JSON_NODE_ARRAY, @@ -63,7 +58,8 @@ struct status_line { const char *text; struct wl_list blocks; // i3bar_block::link - struct text_protocol_state text_state; + char *buffer; + size_t buffer_size; struct i3bar_protocol_state i3bar_state; }; diff --git a/swaybar/status_line.c b/swaybar/status_line.c index 09ed23753..54a68b401 100644 --- a/swaybar/status_line.c +++ b/swaybar/status_line.c @@ -30,27 +30,17 @@ void status_error(struct status_line *status, const char *text) { } bool status_handle_readable(struct status_line *status) { + ssize_t read_bytes = 1; char *line; switch (status->protocol) { - case PROTOCOL_ERROR: - return false; case PROTOCOL_I3BAR: if (i3bar_handle_readable(status) > 0) { return true; } break; - case PROTOCOL_TEXT: - line = read_line_buffer(status->read, - status->text_state.buffer, status->text_state.buffer_size); - if (!line) { - status_error(status, "[error reading from status command]"); - } else { - status->text = line; - } - return true; case PROTOCOL_UNDEF: line = read_line_buffer(status->read, - status->text_state.buffer, status->text_state.buffer_size); + status->buffer, status->buffer_size); if (!line) { status_error(status, "[error reading from status command]"); return false; @@ -81,7 +71,7 @@ bool status_handle_readable(struct status_line *status) { } status->protocol = PROTOCOL_I3BAR; - free(status->text_state.buffer); + free(status->buffer); wl_list_init(&status->blocks); status->i3bar_state.buffer_size = 4096; status->i3bar_state.buffer = @@ -91,14 +81,32 @@ bool status_handle_readable(struct status_line *status) { status->text = line; } return true; + case PROTOCOL_TEXT: + errno = 0; + while (true) { + if (status->buffer[read_bytes - 1] == '\n') { + status->buffer[read_bytes - 1] = '\0'; + } + read_bytes = getline(&status->buffer, + &status->buffer_size, status->read); + if (errno == EAGAIN) { + clearerr(status->read); + return true; + } else if (errno) { + status_error(status, "[error reading from status command]"); + return true; + } + } + default: + return false; } return false; } struct status_line *status_line_init(char *cmd) { struct status_line *status = calloc(1, sizeof(struct status_line)); - status->text_state.buffer_size = 8192; - status->text_state.buffer = malloc(status->text_state.buffer_size); + status->buffer_size = 8192; + status->buffer = malloc(status->buffer_size); int pipe_read_fd[2]; int pipe_write_fd[2]; @@ -148,7 +156,7 @@ void status_line_free(struct status_line *status) { break; } default: - free(status->text_state.buffer); + free(status->buffer); break; } free(status); From 8cbce77e1deb811754a6175388e5ef89f274ff05 Mon Sep 17 00:00:00 2001 From: Ian Fan Date: Mon, 17 Sep 2018 14:00:44 +0100 Subject: [PATCH 07/10] swaybar: rewrite protocol determination This now uses the getline function to receive the header, replacing read_line_buffer, which has been deleted since it is otherwise unused. Furthermore, once the protocol has been determined, the current status is handled immediately to be shown (though this has not been added for the i3bar protocol since it has not yet been rewritten to handle this). --- common/readline.c | 25 ----------------- swaybar/status_line.c | 64 ++++++++++++++++++++++--------------------- 2 files changed, 33 insertions(+), 56 deletions(-) diff --git a/common/readline.c b/common/readline.c index a2c690185..58652429e 100644 --- a/common/readline.c +++ b/common/readline.c @@ -70,28 +70,3 @@ char *peek_line(FILE *file, int line_offset, long *position) { fseek(file, pos, SEEK_SET); return line; } - -char *read_line_buffer(FILE *file, char *string, size_t string_len) { - size_t length = 0; - if (!string) { - return NULL; - } - while (1) { - int c = getc(file); - if (c == EOF || c == '\n' || c == '\0') { - break; - } - if (c == '\r') { - continue; - } - string[length++] = c; - if (string_len <= length) { - return NULL; - } - } - if (length + 1 == string_len) { - return NULL; - } - string[length] = '\0'; - return string; -} diff --git a/swaybar/status_line.c b/swaybar/status_line.c index 54a68b401..fcc0cb935 100644 --- a/swaybar/status_line.c +++ b/swaybar/status_line.c @@ -31,7 +31,6 @@ void status_error(struct status_line *status, const char *text) { bool status_handle_readable(struct status_line *status) { ssize_t read_bytes = 1; - char *line; switch (status->protocol) { case PROTOCOL_I3BAR: if (i3bar_handle_readable(status) > 0) { @@ -39,36 +38,37 @@ bool status_handle_readable(struct status_line *status) { } break; case PROTOCOL_UNDEF: - line = read_line_buffer(status->read, - status->buffer, status->buffer_size); - if (!line) { + errno = 0; + read_bytes = getline(&status->buffer, + &status->buffer_size, status->read); + if (errno == EAGAIN) { + clearerr(status->read); + } else if (errno) { status_error(status, "[error reading from status command]"); - return false; + return true; } - if (line[0] == '{') { - json_object *proto = json_tokener_parse(line); - if (proto) { - json_object *version; - if (json_object_object_get_ex(proto, "version", &version) - && json_object_get_int(version) == 1) { - wlr_log(WLR_DEBUG, "Switched to i3bar protocol."); - status->protocol = PROTOCOL_I3BAR; + + // the header must be sent completely the first time round + json_object *header, *version; + if (status->buffer[read_bytes - 1] == '\n' + && (header = json_tokener_parse(status->buffer)) + && json_object_object_get_ex(header, "version", &version) + && json_object_get_int(version) == 1) { + wlr_log(WLR_DEBUG, "Using i3bar protocol."); + status->protocol = PROTOCOL_I3BAR; + + json_object *click_events; + if (json_object_object_get_ex(header, "click_events", &click_events) + && json_object_get_boolean(click_events)) { + wlr_log(WLR_DEBUG, "Enabling click events."); + status->i3bar_state.click_events = true; + if (write(status->write_fd, "[\n", 2) != 2) { + status_error(status, "[failed to write to status command]"); + json_object_put(header); + return true; } - json_object *click_events; - if (json_object_object_get_ex( - proto, "click_events", &click_events) - && json_object_get_boolean(click_events)) { - wlr_log(WLR_DEBUG, "Enabled click events."); - status->i3bar_state.click_events = true; - const char *events_array = "[\n"; - ssize_t len = strlen(events_array); - if (write(status->write_fd, events_array, len) != len) { - status_error(status, - "[failed to write to status command]"); - } - } - json_object_put(proto); } + json_object_put(header); status->protocol = PROTOCOL_I3BAR; free(status->buffer); @@ -76,11 +76,13 @@ bool status_handle_readable(struct status_line *status) { status->i3bar_state.buffer_size = 4096; status->i3bar_state.buffer = malloc(status->i3bar_state.buffer_size); - } else { - status->protocol = PROTOCOL_TEXT; - status->text = line; + return false; } - return true; + + wlr_log(WLR_DEBUG, "Using text protocol."); + status->protocol = PROTOCOL_TEXT; + status->text = status->buffer; + // intentional fall-through case PROTOCOL_TEXT: errno = 0; while (true) { From 7882ac66ef4308922045fd100e6a9e12942a240b Mon Sep 17 00:00:00 2001 From: Ian Fan Date: Mon, 17 Sep 2018 14:10:57 +0100 Subject: [PATCH 08/10] swaybar: rewrite i3bar protocol handling This now correctly handles an incoming json infinite array by shifting most of the heavy listing to the json-c parser, as well as sending multiple statuses at once. It also removes the struct i3bar_protocol_state and moves its members into the status_line struct, allowing the same buffer to be used for both protocols. --- include/swaybar/status_line.h | 24 ++--- swaybar/i3bar.c | 189 ++++++++++++++++++++-------------- swaybar/render.c | 2 +- swaybar/status_line.c | 31 ++---- 4 files changed, 128 insertions(+), 118 deletions(-) diff --git a/include/swaybar/status_line.h b/include/swaybar/status_line.h index 857948a59..d3eabdf6a 100644 --- a/include/swaybar/status_line.h +++ b/include/swaybar/status_line.h @@ -1,5 +1,6 @@ #ifndef _SWAYBAR_STATUS_LINE_H #define _SWAYBAR_STATUS_LINE_H +#include #include #include #include @@ -12,23 +13,6 @@ enum status_protocol { PROTOCOL_I3BAR, }; -enum json_node_type { - JSON_NODE_UNKNOWN, - JSON_NODE_ARRAY, - JSON_NODE_STRING, -}; - -struct i3bar_protocol_state { - bool click_events; - char *buffer; - size_t buffer_size; - size_t buffer_index; - const char *current_node; - bool escape; - size_t depth; - enum json_node_type nodes[16]; -}; - struct i3bar_block { struct wl_list link; int ref_count; @@ -58,9 +42,13 @@ struct status_line { const char *text; struct wl_list blocks; // i3bar_block::link + bool click_events; char *buffer; size_t buffer_size; - struct i3bar_protocol_state i3bar_state; + size_t buffer_index; + bool started; + bool expecting_comma; + json_tokener *tokener; }; struct status_line *status_line_init(char *cmd); diff --git a/swaybar/i3bar.c b/swaybar/i3bar.c index f4ca5504b..78cb5bd43 100644 --- a/swaybar/i3bar.c +++ b/swaybar/i3bar.c @@ -1,6 +1,7 @@ #define _POSIX_C_SOURCE 200809L #include #include +#include #include #include #include @@ -24,24 +25,19 @@ void i3bar_block_unref(struct i3bar_block *block) { } } -static bool i3bar_parse_json(struct status_line *status, const char *text) { +static void i3bar_parse_json(struct status_line *status, + struct json_object *json_array) { struct i3bar_block *block, *tmp; wl_list_for_each_safe(block, tmp, &status->blocks, link) { wl_list_remove(&block->link); i3bar_block_unref(block); } - json_object *results = json_tokener_parse(text); - if (!results) { - status_error(status, "[failed to parse i3bar json]"); - return false; - } - wlr_log(WLR_DEBUG, "Got i3bar json: '%s'", text); - for (size_t i = 0; i < json_object_array_length(results); ++i) { + for (size_t i = 0; i < json_object_array_length(json_array); ++i) { json_object *full_text, *short_text, *color, *min_width, *align, *urgent; json_object *name, *instance, *separator, *separator_block_width; json_object *background, *border, *border_top, *border_bottom; json_object *border_left, *border_right, *markup; - json_object *json = json_object_array_get_idx(results, i); + json_object *json = json_object_array_get_idx(json_array, i); if (!json) { continue; } @@ -110,96 +106,133 @@ static bool i3bar_parse_json(struct status_line *status, const char *text) { json_object_get_int(border_right) : 1; wl_list_insert(&status->blocks, &block->link); } - json_object_put(results); - return true; } bool i3bar_handle_readable(struct status_line *status) { - struct i3bar_protocol_state *state = &status->i3bar_state; + while (!status->started) { // look for opening bracket + for (size_t c = 0; c < status->buffer_index; ++c) { + if (status->buffer[c] == '[') { + status->started = true; + status->buffer_index -= ++c; + memmove(status->buffer, &status->buffer[c], status->buffer_index); + break; + } else if (!isspace(status->buffer[c])) { + status_error(status, "[invalid json]"); + return true; + } + } + if (status->started) { + break; + } - char *cur = &state->buffer[state->buffer_index]; - ssize_t n = read(status->read_fd, cur, - state->buffer_size - state->buffer_index); - if (n == -1) { - status_error(status, "[failed to read from status command]"); - return false; - } - - if (n == (ssize_t)(state->buffer_size - state->buffer_index)) { - state->buffer_size = state->buffer_size * 2; - char *new_buffer = realloc(state->buffer, state->buffer_size); - if (!new_buffer) { - free(state->buffer); - status_error(status, "[failed to allocate buffer]"); + errno = 0; + ssize_t read_bytes = read(status->read_fd, status->buffer, status->buffer_size); + if (read_bytes > -1) { + status->buffer_index = read_bytes; + } else if (errno == EAGAIN) { + return false; + } else { + status_error(status, "[error reading from status command]"); return true; } - state->current_node += new_buffer - state->buffer; - cur += new_buffer - state->buffer; - state->buffer = new_buffer; } - cur[n] = '\0'; - bool redraw = false; - while (*cur) { - if (state->nodes[state->depth] == JSON_NODE_STRING) { - if (!state->escape && *cur == '"') { - --state->depth; + struct json_object *last_object = NULL; + struct json_object *test_object; + size_t buffer_pos = 0; + while (true) { + // since the incoming stream is an infinite array + // parsing is split into two parts + // first, attempt to parse the current object, reading more if the + // parser indicates that the current object is incomplete, and failing + // if the parser fails + // second, look for separating comma, ignoring whitespace, failing if + // any other characters are encountered + if (status->expecting_comma) { + for (; buffer_pos < status->buffer_index; ++buffer_pos) { + if (status->buffer[buffer_pos] == ',') { + status->expecting_comma = false; + ++buffer_pos; + break; + } else if (!isspace(status->buffer[buffer_pos])) { + status_error(status, "[invalid i3bar json]"); + return true; + } } - state->escape = !state->escape && *cur == '\\'; + if (buffer_pos < status->buffer_index) { + continue; // look for new object without reading more input + } + buffer_pos = status->buffer_index = 0; } else { - switch (*cur) { - case '[': - ++state->depth; - if (state->depth > - sizeof(state->nodes) / sizeof(state->nodes[0])) { - status_error(status, "[i3bar json too deep]"); - return false; + test_object = json_tokener_parse_ex(status->tokener, + &status->buffer[buffer_pos], status->buffer_index - buffer_pos); + if (json_tokener_get_error(status->tokener) == json_tokener_success) { + if (json_object_get_type(test_object) == json_type_array) { + if (last_object) { + json_object_put(last_object); + } + last_object = test_object; + } else { + json_object_put(test_object); } - state->nodes[state->depth] = JSON_NODE_ARRAY; - if (state->depth == 1) { - state->current_node = cur; + + buffer_pos += status->tokener->char_offset; + status->expecting_comma = true; + + if (buffer_pos < status->buffer_index) { + continue; // look for comma without reading more input } - break; - case ']': - if (state->nodes[state->depth] != JSON_NODE_ARRAY) { - status_error(status, "[failed to parse i3bar json]"); - return false; + buffer_pos = status->buffer_index = 0; + } else if (json_tokener_get_error(status->tokener) == json_tokener_continue) { + if (status->buffer_index < status->buffer_size) { + // move the object to the start of the buffer + status->buffer_index -= buffer_pos; + memmove(status->buffer, &status->buffer[buffer_pos], + status->buffer_index); + } else { + // expand buffer + status->buffer_size *= 2; + char *new_buffer = realloc(status->buffer, status->buffer_size); + if (new_buffer) { + status->buffer = new_buffer; + } else { + free(status->buffer); + status_error(status, "[failed to allocate buffer]"); + return true; + } } - --state->depth; - if (state->depth == 0) { - // cur[1] is valid since cur[0] != '\0' - char p = cur[1]; - cur[1] = '\0'; - redraw = i3bar_parse_json( - status, state->current_node) || redraw; - cur[1] = p; - memmove(state->buffer, cur, - state->buffer_size - (cur - state->buffer)); - cur = state->buffer; - state->current_node = cur + 1; - } - break; - case '"': - ++state->depth; - if (state->depth > - sizeof(state->nodes) / sizeof(state->nodes[0])) { - status_error(status, "[i3bar json too deep]"); - return false; - } - state->nodes[state->depth] = JSON_NODE_STRING; - break; + } else { + status_error(status, "[failed to parse i3bar json]"); + return true; } } - ++cur; + + errno = 0; + ssize_t read_bytes = read(status->read_fd, &status->buffer[status->buffer_index], + status->buffer_size - status->buffer_index); + if (read_bytes > -1) { + status->buffer_index += read_bytes; + } else if (errno == EAGAIN) { + break; + } else { + status_error(status, "[error reading from status command]"); + return true; + } + } + + if (last_object) { + i3bar_parse_json(status, last_object); + json_object_put(last_object); + return true; + } else { + return false; } - state->buffer_index = cur - state->buffer; - return redraw; } enum hotspot_event_handling i3bar_block_send_click(struct status_line *status, struct i3bar_block *block, int x, int y, enum x11_button button) { wlr_log(WLR_DEBUG, "block %s clicked", block->name ? block->name : "(nil)"); - if (!block->name || !status->i3bar_state.click_events) { + if (!block->name || !status->click_events) { return HOTSPOT_PROCESS; } diff --git a/swaybar/render.c b/swaybar/render.c index b2c1c7102..97690338e 100644 --- a/swaybar/render.c +++ b/swaybar/render.c @@ -177,7 +177,7 @@ static uint32_t render_status_block(cairo_t *cairo, *x -= margin; } - if (output->bar->status->i3bar_state.click_events) { + if (output->bar->status->click_events) { struct swaybar_hotspot *hotspot = calloc(1, sizeof(struct swaybar_hotspot)); hotspot->x = *x; hotspot->y = 0; diff --git a/swaybar/status_line.c b/swaybar/status_line.c index fcc0cb935..01ed70d9c 100644 --- a/swaybar/status_line.c +++ b/swaybar/status_line.c @@ -32,11 +32,6 @@ void status_error(struct status_line *status, const char *text) { bool status_handle_readable(struct status_line *status) { ssize_t read_bytes = 1; switch (status->protocol) { - case PROTOCOL_I3BAR: - if (i3bar_handle_readable(status) > 0) { - return true; - } - break; case PROTOCOL_UNDEF: errno = 0; read_bytes = getline(&status->buffer, @@ -61,7 +56,7 @@ bool status_handle_readable(struct status_line *status) { if (json_object_object_get_ex(header, "click_events", &click_events) && json_object_get_boolean(click_events)) { wlr_log(WLR_DEBUG, "Enabling click events."); - status->i3bar_state.click_events = true; + status->click_events = true; if (write(status->write_fd, "[\n", 2) != 2) { status_error(status, "[failed to write to status command]"); json_object_put(header); @@ -70,13 +65,11 @@ bool status_handle_readable(struct status_line *status) { } json_object_put(header); - status->protocol = PROTOCOL_I3BAR; - free(status->buffer); wl_list_init(&status->blocks); - status->i3bar_state.buffer_size = 4096; - status->i3bar_state.buffer = - malloc(status->i3bar_state.buffer_size); - return false; + status->tokener = json_tokener_new(); + status->buffer_index = getdelim(&status->buffer, + &status->buffer_size, EOF, status->read); + return i3bar_handle_readable(status); } wlr_log(WLR_DEBUG, "Using text protocol."); @@ -99,10 +92,11 @@ bool status_handle_readable(struct status_line *status) { return true; } } + case PROTOCOL_I3BAR: + return i3bar_handle_readable(status); default: return false; } - return false; } struct status_line *status_line_init(char *cmd) { @@ -147,19 +141,14 @@ struct status_line *status_line_init(char *cmd) { void status_line_free(struct status_line *status) { status_line_close_fds(status); kill(status->pid, SIGTERM); - switch (status->protocol) { - case PROTOCOL_I3BAR: { + if (status->protocol == PROTOCOL_I3BAR) { struct i3bar_block *block, *tmp; wl_list_for_each_safe(block, tmp, &status->blocks, link) { wl_list_remove(&block->link); i3bar_block_unref(block); } - free(status->i3bar_state.buffer); - break; - } - default: - free(status->buffer); - break; } + json_tokener_free(status->tokener); + free(status->buffer); free(status); } From 5912325d5ca63a552bb1f8e5de0b088e9bfa83e4 Mon Sep 17 00:00:00 2001 From: Ian Fan Date: Mon, 17 Sep 2018 14:21:14 +0100 Subject: [PATCH 09/10] swaybar: add debugging statements for handling i3bar json --- swaybar/i3bar.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/swaybar/i3bar.c b/swaybar/i3bar.c index 78cb5bd43..884047034 100644 --- a/swaybar/i3bar.c +++ b/swaybar/i3bar.c @@ -176,6 +176,21 @@ bool i3bar_handle_readable(struct status_line *status) { json_object_put(test_object); } + // in order to print the json for debugging purposes + // the last character is temporarily replaced with a null character + // (the last character is used in case the buffer is full) + char *last_char_pos = + &status->buffer[buffer_pos + status->tokener->char_offset - 1]; + char last_char = *last_char_pos; + while (isspace(last_char)) { + last_char = *--last_char_pos; + } + *last_char_pos = '\0'; + size_t offset = strspn(&status->buffer[buffer_pos], " \f\n\r\t\v"); + wlr_log(WLR_DEBUG, "Received i3bar json: '%s%c'", + &status->buffer[buffer_pos + offset], last_char); + *last_char_pos = last_char; + buffer_pos += status->tokener->char_offset; status->expecting_comma = true; @@ -221,6 +236,7 @@ bool i3bar_handle_readable(struct status_line *status) { } if (last_object) { + wlr_log(WLR_DEBUG, "Rendering last received json"); i3bar_parse_json(status, last_object); json_object_put(last_object); return true; From 47a66da5de37faccac1207615ce0914b4ab32220 Mon Sep 17 00:00:00 2001 From: Ian Fan Date: Tue, 18 Sep 2018 18:06:19 +0100 Subject: [PATCH 10/10] swaybar: only free tokener when using i3bar protocol --- swaybar/status_line.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/swaybar/status_line.c b/swaybar/status_line.c index 01ed70d9c..401bf6f6f 100644 --- a/swaybar/status_line.c +++ b/swaybar/status_line.c @@ -147,8 +147,8 @@ void status_line_free(struct status_line *status) { wl_list_remove(&block->link); i3bar_block_unref(block); } + json_tokener_free(status->tokener); } - json_tokener_free(status->tokener); free(status->buffer); free(status); }