From ee85c918317ec6a685a999db46f692c7d13cdf2a Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Sat, 31 Mar 2018 13:07:22 -0400 Subject: Demarcate i3bar JSON into individual updates --- swaybar/i3bar.c | 88 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 swaybar/i3bar.c (limited to 'swaybar/i3bar.c') diff --git a/swaybar/i3bar.c b/swaybar/i3bar.c new file mode 100644 index 00000000..5be348b2 --- /dev/null +++ b/swaybar/i3bar.c @@ -0,0 +1,88 @@ +#include +#include +#include +#include +#include "swaybar/config.h" +#include "swaybar/status_line.h" + +static void i3bar_parse_json(struct status_line *status, const char *text) { + wlr_log(L_DEBUG, "got json: %s", text); +} + +int i3bar_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 == 0) { + return 0; + } + + 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]"); + return -1; + } + state->buffer = new_buffer; + } + + int handled = 0; + while (*cur) { + if (state->nodes[state->depth] == JSON_NODE_STRING) { + if (!state->escape && *cur == '"') { + --state->depth; + } + state->escape = !state->escape && *cur == '\\'; + } else { + switch (*cur) { + case '[': + ++state->depth; + if (state->depth > + sizeof(state->nodes) / sizeof(state->nodes[0])) { + status_error(status, "[i3bar json too deep]"); + return -1; + } + state->nodes[state->depth] = JSON_NODE_ARRAY; + if (state->depth == 1) { + state->current_node = cur; + } + break; + case ']': + if (state->nodes[state->depth] != JSON_NODE_ARRAY) { + status_error(status, "[failed to parse i3bar json]"); + return -1; + } + --state->depth; + if (state->depth == 0) { + // cur[1] is valid since cur[0] != '\0' + char p = cur[1]; + cur[1] = '\0'; + i3bar_parse_json(status, state->current_node); + cur[1] = p; + memmove(state->buffer, cur, + state->buffer_size - (cur - state->buffer)); + ++handled; + 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 -1; + } + state->nodes[state->depth] = JSON_NODE_STRING; + break; + } + } + ++cur; + } + state->buffer_index = cur - state->buffer; + return handled; +} -- cgit v1.2.3 From 333dbcbe72b6af95573e374b66ad6ab63f274299 Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Sat, 31 Mar 2018 14:39:18 -0400 Subject: Render i3bar blocks --- swaybar/i3bar.c | 120 +++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 110 insertions(+), 10 deletions(-) (limited to 'swaybar/i3bar.c') diff --git a/swaybar/i3bar.c b/swaybar/i3bar.c index 5be348b2..41b71164 100644 --- a/swaybar/i3bar.c +++ b/swaybar/i3bar.c @@ -1,3 +1,5 @@ +#define _POSIX_C_SOURCE 200809L +#include #include #include #include @@ -5,11 +7,109 @@ #include "swaybar/config.h" #include "swaybar/status_line.h" -static void i3bar_parse_json(struct status_line *status, const char *text) { - wlr_log(L_DEBUG, "got json: %s", text); +static void i3bar_block_free(struct i3bar_block *block) { + if (!block) { + return; + } + wl_list_remove(&block->link); + free(block->full_text); + free(block->short_text); + free(block->align); + free(block->name); + free(block->instance); + free(block->color); +} + +static bool i3bar_parse_json(struct status_line *status, const char *text) { + struct i3bar_block *block, *tmp; + wl_list_for_each_safe(block, tmp, &status->blocks, link) { + i3bar_block_free(block); + } + json_object *results = json_tokener_parse(text); + if (!results) { + status_error(status, "[failed to parse i3bar json]"); + return false; + } + if (json_object_array_length(results) < 1) { + return true; + } + for (size_t i = 0; i < json_object_array_length(results); ++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); + if (!json) { + continue; + } + json_object_object_get_ex(json, "full_text", &full_text); + json_object_object_get_ex(json, "short_text", &short_text); + json_object_object_get_ex(json, "color", &color); + json_object_object_get_ex(json, "min_width", &min_width); + json_object_object_get_ex(json, "align", &align); + json_object_object_get_ex(json, "urgent", &urgent); + json_object_object_get_ex(json, "name", &name); + json_object_object_get_ex(json, "instance", &instance); + json_object_object_get_ex(json, "markup", &markup); + json_object_object_get_ex(json, "separator", &separator); + json_object_object_get_ex(json, "separator_block_width", &separator_block_width); + json_object_object_get_ex(json, "background", &background); + json_object_object_get_ex(json, "border", &border); + json_object_object_get_ex(json, "border_top", &border_top); + json_object_object_get_ex(json, "border_bottom", &border_bottom); + json_object_object_get_ex(json, "border_left", &border_left); + json_object_object_get_ex(json, "border_right", &border_right); + + struct i3bar_block *block = calloc(1, sizeof(struct i3bar_block)); + block->full_text = full_text ? + strdup(json_object_get_string(full_text)) : NULL; + block->short_text = short_text ? + strdup(json_object_get_string(short_text)) : NULL; + if (color) { + block->color = malloc(sizeof(uint32_t)); + *block->color = parse_color(json_object_get_string(color)); + } + if (min_width) { + json_type type = json_object_get_type(min_width); + if (type == json_type_int) { + block->min_width = json_object_get_int(min_width); + } else if (type == json_type_string) { + /* the width will be calculated when rendering */ + block->min_width = 0; + } + } + block->align = strdup(align ? json_object_get_string(align) : "left"); + block->urgent = urgent ? json_object_get_int(urgent) : false; + block->name = name ? strdup(json_object_get_string(name)) : NULL; + block->instance = instance ? + strdup(json_object_get_string(instance)) : NULL; + if (markup) { + block->markup = false; + const char *markup_str = json_object_get_string(markup); + if (strcmp(markup_str, "pango") == 0) { + block->markup = true; + } + } + block->separator = separator ? json_object_get_int(separator) : true; + block->separator_block_width = separator_block_width ? + json_object_get_int(separator_block_width) : 9; + // Airblader features + block->background = background ? + parse_color(json_object_get_string(background)) : 0; + block->border = border ? + parse_color(json_object_get_string(border)) : 0; + block->border_top = border_top ? json_object_get_int(border_top) : 1; + block->border_bottom = border_bottom ? + json_object_get_int(border_bottom) : 1; + block->border_left = border_left ? json_object_get_int(border_left) : 1; + block->border_right = border_right ? + json_object_get_int(border_right) : 1; + wl_list_insert(&status->blocks, &block->link); + } + return true; } -int i3bar_readable(struct status_line *status) { +bool i3bar_handle_readable(struct status_line *status) { struct i3bar_protocol_state *state = &status->i3bar_state; char *cur = &state->buffer[state->buffer_index]; @@ -30,7 +130,7 @@ int i3bar_readable(struct status_line *status) { state->buffer = new_buffer; } - int handled = 0; + bool redraw = false; while (*cur) { if (state->nodes[state->depth] == JSON_NODE_STRING) { if (!state->escape && *cur == '"') { @@ -44,7 +144,7 @@ int i3bar_readable(struct status_line *status) { if (state->depth > sizeof(state->nodes) / sizeof(state->nodes[0])) { status_error(status, "[i3bar json too deep]"); - return -1; + return false; } state->nodes[state->depth] = JSON_NODE_ARRAY; if (state->depth == 1) { @@ -54,18 +154,18 @@ int i3bar_readable(struct status_line *status) { case ']': if (state->nodes[state->depth] != JSON_NODE_ARRAY) { status_error(status, "[failed to parse i3bar json]"); - return -1; + return false; } --state->depth; if (state->depth == 0) { // cur[1] is valid since cur[0] != '\0' char p = cur[1]; cur[1] = '\0'; - i3bar_parse_json(status, state->current_node); + redraw = i3bar_parse_json( + status, state->current_node) || redraw; cur[1] = p; memmove(state->buffer, cur, state->buffer_size - (cur - state->buffer)); - ++handled; cur = state->buffer; state->current_node = cur + 1; } @@ -75,7 +175,7 @@ int i3bar_readable(struct status_line *status) { if (state->depth > sizeof(state->nodes) / sizeof(state->nodes[0])) { status_error(status, "[i3bar json too deep]"); - return -1; + return false; } state->nodes[state->depth] = JSON_NODE_STRING; break; @@ -84,5 +184,5 @@ int i3bar_readable(struct status_line *status) { ++cur; } state->buffer_index = cur - state->buffer; - return handled; + return redraw; } -- cgit v1.2.3 From 0cbd2a4f492b758f495af9f3ec4899dffe8d57d4 Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Sat, 31 Mar 2018 14:58:30 -0400 Subject: Send click events for i3bar blocks --- swaybar/i3bar.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'swaybar/i3bar.c') diff --git a/swaybar/i3bar.c b/swaybar/i3bar.c index 41b71164..5e98c4aa 100644 --- a/swaybar/i3bar.c +++ b/swaybar/i3bar.c @@ -186,3 +186,25 @@ bool i3bar_handle_readable(struct status_line *status) { state->buffer_index = cur - state->buffer; return redraw; } + +void i3bar_block_send_click(struct status_line *status, + struct i3bar_block *block, int x, int y, uint32_t button) { + wlr_log(L_DEBUG, "block %s clicked", block->name ? block->name : "(nil)"); + if (!block->name || !status->i3bar_state.click_events) { + return; + } + + struct json_object *event_json = json_object_new_object(); + json_object_object_add(event_json, "name", + json_object_new_string(block->name)); + if (block->instance) { + json_object_object_add(event_json, "instance", + json_object_new_string(block->instance)); + } + + 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)); + dprintf(status->write_fd, "%s\n", json_object_to_json_string(event_json)); + json_object_put(event_json); +} -- cgit v1.2.3 From c507727ad240b978c6e09e3aa9238080ca9a1c81 Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Mon, 2 Apr 2018 11:53:56 -0400 Subject: Fix use-after-free with block hotspots --- swaybar/i3bar.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'swaybar/i3bar.c') diff --git a/swaybar/i3bar.c b/swaybar/i3bar.c index 5e98c4aa..46459e24 100644 --- a/swaybar/i3bar.c +++ b/swaybar/i3bar.c @@ -30,9 +30,7 @@ static bool i3bar_parse_json(struct status_line *status, const char *text) { status_error(status, "[failed to parse i3bar json]"); return false; } - if (json_object_array_length(results) < 1) { - return true; - } + wlr_log(L_DEBUG, "Got i3bar json: '%s'", text); for (size_t i = 0; i < json_object_array_length(results); ++i) { json_object *full_text, *short_text, *color, *min_width, *align, *urgent; json_object *name, *instance, *separator, *separator_block_width; -- cgit v1.2.3