From 4cb28de89fa50c2c992702c238d54d16a0269553 Mon Sep 17 00:00:00 2001 From: Ian Fan Date: Sat, 15 Sep 2018 10:14:21 +0100 Subject: swaybar: remove block links upon exit --- swaybar/status_line.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'swaybar') diff --git a/swaybar/status_line.c b/swaybar/status_line.c index 3ba990bd..688e5947 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; -- cgit v1.2.3-54-g00ecf From 952453480f6764eb583b2507c7af83e242e0630a Mon Sep 17 00:00:00 2001 From: Ian Fan Date: Sat, 15 Sep 2018 10:15:30 +0100 Subject: swaybar: invalidate file descriptors upon closing --- swaybar/status_line.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) (limited to 'swaybar') diff --git a/swaybar/status_line.c b/swaybar/status_line.c index 688e5947..09ed2375 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: { -- cgit v1.2.3-54-g00ecf From 9932c6a1f1f295531989d9e76494b0ca43509cd4 Mon Sep 17 00:00:00 2001 From: Ian Fan Date: Sun, 16 Sep 2018 11:24:24 +0100 Subject: swaybar: fix empty function prototypes --- include/swaybar/event_loop.h | 4 ++-- swaybar/event_loop.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'swaybar') diff --git a/include/swaybar/event_loop.h b/include/swaybar/event_loop.h index 99f6ed36..47be5b79 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 bc4053be..686b9962 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( -- cgit v1.2.3-54-g00ecf From 87c93d6ad986faa384f1279e21c10e35c798686a Mon Sep 17 00:00:00 2001 From: Ian Fan Date: Mon, 17 Sep 2018 13:31:00 +0100 Subject: swaybar: send trailing comma with click event json --- swaybar/i3bar.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'swaybar') diff --git a/swaybar/i3bar.c b/swaybar/i3bar.c index 0becae5d..f4ca5504 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]"); } -- cgit v1.2.3-54-g00ecf From babd9618b93987665c11ff268463b344da698744 Mon Sep 17 00:00:00 2001 From: Ian Fan Date: Mon, 17 Sep 2018 13:31:24 +0100 Subject: swaybar: only create i3bar block hotspot if click events are enabled --- swaybar/render.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) (limited to 'swaybar') diff --git a/swaybar/render.c b/swaybar/render.c index 2d848bfa..b2c1c710 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; -- cgit v1.2.3-54-g00ecf From 70245c2cd5c34586fa91eb784e58471869ba66bd Mon Sep 17 00:00:00 2001 From: Ian Fan Date: Mon, 17 Sep 2018 13:43:27 +0100 Subject: 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(-) (limited to 'swaybar') diff --git a/include/swaybar/status_line.h b/include/swaybar/status_line.h index 150267cd..857948a5 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 09ed2375..54a68b40 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); -- cgit v1.2.3-54-g00ecf From 8cbce77e1deb811754a6175388e5ef89f274ff05 Mon Sep 17 00:00:00 2001 From: Ian Fan Date: Mon, 17 Sep 2018 14:00:44 +0100 Subject: 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(-) (limited to 'swaybar') diff --git a/common/readline.c b/common/readline.c index a2c69018..58652429 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 54a68b40..fcc0cb93 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; - } - 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]"); - } + + // 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_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) { -- cgit v1.2.3-54-g00ecf From 7882ac66ef4308922045fd100e6a9e12942a240b Mon Sep 17 00:00:00 2001 From: Ian Fan Date: Mon, 17 Sep 2018 14:10:57 +0100 Subject: 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(-) (limited to 'swaybar') diff --git a/include/swaybar/status_line.h b/include/swaybar/status_line.h index 857948a5..d3eabdf6 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 f4ca5504..78cb5bd4 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; - - 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; - } + 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; + } - 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; + } + } + if (buffer_pos < status->buffer_index) { + continue; // look for new object without reading more input } - state->escape = !state->escape && *cur == '\\'; + 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; - } - state->nodes[state->depth] = JSON_NODE_ARRAY; - if (state->depth == 1) { - state->current_node = cur; + 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); } - break; - case ']': - if (state->nodes[state->depth] != JSON_NODE_ARRAY) { - status_error(status, "[failed to parse i3bar json]"); - return false; + + buffer_pos += status->tokener->char_offset; + status->expecting_comma = true; + + if (buffer_pos < status->buffer_index) { + continue; // look for comma without reading more input } - --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; + 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; + } } - 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 b2c1c710..97690338 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 fcc0cb93..01ed70d9 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); } -- cgit v1.2.3-54-g00ecf From 5912325d5ca63a552bb1f8e5de0b088e9bfa83e4 Mon Sep 17 00:00:00 2001 From: Ian Fan Date: Mon, 17 Sep 2018 14:21:14 +0100 Subject: swaybar: add debugging statements for handling i3bar json --- swaybar/i3bar.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'swaybar') diff --git a/swaybar/i3bar.c b/swaybar/i3bar.c index 78cb5bd4..88404703 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; -- cgit v1.2.3-54-g00ecf From 47a66da5de37faccac1207615ce0914b4ab32220 Mon Sep 17 00:00:00 2001 From: Ian Fan Date: Tue, 18 Sep 2018 18:06:19 +0100 Subject: swaybar: only free tokener when using i3bar protocol --- swaybar/status_line.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'swaybar') diff --git a/swaybar/status_line.c b/swaybar/status_line.c index 01ed70d9..401bf6f6 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); } -- cgit v1.2.3-54-g00ecf