Demarcate i3bar JSON into individual updates
This commit is contained in:
parent
122b96abed
commit
ee85c91831
|
@ -7,10 +7,52 @@
|
|||
|
||||
enum status_protocol {
|
||||
PROTOCOL_UNDEF,
|
||||
PROTOCOL_ERROR,
|
||||
PROTOCOL_TEXT,
|
||||
PROTOCOL_I3BAR,
|
||||
};
|
||||
|
||||
struct text_protocol_state {
|
||||
char *buffer;
|
||||
size_t buffer_size;
|
||||
};
|
||||
|
||||
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;
|
||||
char *full_text, *short_text, *align;
|
||||
bool urgent;
|
||||
uint32_t color;
|
||||
int min_width;
|
||||
char *name, *instance;
|
||||
bool separator;
|
||||
int separator_block_width;
|
||||
bool markup;
|
||||
// Airblader features
|
||||
uint32_t background;
|
||||
uint32_t border;
|
||||
int border_top;
|
||||
int border_bottom;
|
||||
int border_left;
|
||||
int border_right;
|
||||
};
|
||||
|
||||
struct status_line {
|
||||
pid_t pid;
|
||||
int read_fd, write_fd;
|
||||
|
@ -18,13 +60,16 @@ struct status_line {
|
|||
|
||||
enum status_protocol protocol;
|
||||
const char *text;
|
||||
struct wl_list blocks; // i3bar_block::link
|
||||
|
||||
char *buffer;
|
||||
size_t buffer_size;
|
||||
struct text_protocol_state text_state;
|
||||
struct i3bar_protocol_state i3bar_state;
|
||||
};
|
||||
|
||||
struct status_line *status_line_init(char *cmd);
|
||||
void status_line_free(struct status_line *status);
|
||||
bool handle_status_readable(struct status_line *status);
|
||||
int i3bar_readable(struct status_line *status);
|
||||
void status_error(struct status_line *status, const char *text);
|
||||
|
||||
#endif
|
||||
|
|
88
swaybar/i3bar.c
Normal file
88
swaybar/i3bar.c
Normal file
|
@ -0,0 +1,88 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <wlr/util/log.h>
|
||||
#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;
|
||||
}
|
|
@ -3,6 +3,7 @@ executable(
|
|||
'bar.c',
|
||||
'config.c',
|
||||
'event_loop.c',
|
||||
'i3bar.c',
|
||||
'ipc.c',
|
||||
'main.c',
|
||||
'render.c',
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#define _POSIX_C_SOURCE
|
||||
#include <fcntl.h>
|
||||
#include <json-c/json.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
@ -9,35 +10,78 @@
|
|||
#include "swaybar/status_line.h"
|
||||
#include "readline.h"
|
||||
|
||||
void status_error(struct status_line *status, const char *text) {
|
||||
close(status->read_fd);
|
||||
close(status->write_fd);
|
||||
status->protocol = PROTOCOL_ERROR;
|
||||
status->text = text;
|
||||
}
|
||||
|
||||
bool handle_status_readable(struct status_line *status) {
|
||||
char *line = read_line_buffer(status->read,
|
||||
status->buffer, status->buffer_size);
|
||||
char *line;
|
||||
switch (status->protocol) {
|
||||
case PROTOCOL_ERROR:
|
||||
return false;
|
||||
case PROTOCOL_I3BAR:
|
||||
// TODO
|
||||
if (i3bar_readable(status) > 0) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case PROTOCOL_TEXT:
|
||||
status->text = line;
|
||||
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);
|
||||
if (!line) {
|
||||
status_error(status, "[error reading from status command]");
|
||||
return false;
|
||||
}
|
||||
if (line[0] == '{') {
|
||||
// TODO: JSON
|
||||
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(L_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(L_DEBUG, "Enabled click events.");
|
||||
status->i3bar_state.click_events = true;
|
||||
const char *events_array = "[\n";
|
||||
write(status->write_fd, events_array, strlen(events_array));
|
||||
}
|
||||
json_object_put(proto);
|
||||
}
|
||||
|
||||
status->protocol = PROTOCOL_I3BAR;
|
||||
free(status->text_state.buffer);
|
||||
status->i3bar_state.buffer_size = 4096;
|
||||
status->i3bar_state.buffer =
|
||||
malloc(status->i3bar_state.buffer_size);
|
||||
} else {
|
||||
status->text = line;
|
||||
status->protocol = PROTOCOL_TEXT;
|
||||
status->text = line;
|
||||
}
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
struct status_line *status_line_init(char *cmd) {
|
||||
struct status_line *status = calloc(1, sizeof(struct status_line));
|
||||
status->buffer_size = 4096;
|
||||
status->buffer = malloc(status->buffer_size);
|
||||
status->text_state.buffer_size = 8192;
|
||||
status->text_state.buffer = malloc(status->text_state.buffer_size);
|
||||
|
||||
int pipe_read_fd[2];
|
||||
int pipe_write_fd[2];
|
||||
|
|
Loading…
Reference in a new issue