Demarcate i3bar JSON into individual updates
This commit is contained in:
parent
122b96abed
commit
ee85c91831
|
@ -7,10 +7,52 @@
|
||||||
|
|
||||||
enum status_protocol {
|
enum status_protocol {
|
||||||
PROTOCOL_UNDEF,
|
PROTOCOL_UNDEF,
|
||||||
|
PROTOCOL_ERROR,
|
||||||
PROTOCOL_TEXT,
|
PROTOCOL_TEXT,
|
||||||
PROTOCOL_I3BAR,
|
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 {
|
struct status_line {
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
int read_fd, write_fd;
|
int read_fd, write_fd;
|
||||||
|
@ -18,13 +60,16 @@ struct status_line {
|
||||||
|
|
||||||
enum status_protocol protocol;
|
enum status_protocol protocol;
|
||||||
const char *text;
|
const char *text;
|
||||||
|
struct wl_list blocks; // i3bar_block::link
|
||||||
|
|
||||||
char *buffer;
|
struct text_protocol_state text_state;
|
||||||
size_t buffer_size;
|
struct i3bar_protocol_state i3bar_state;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct status_line *status_line_init(char *cmd);
|
struct status_line *status_line_init(char *cmd);
|
||||||
void status_line_free(struct status_line *status);
|
void status_line_free(struct status_line *status);
|
||||||
bool handle_status_readable(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
|
#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',
|
'bar.c',
|
||||||
'config.c',
|
'config.c',
|
||||||
'event_loop.c',
|
'event_loop.c',
|
||||||
|
'i3bar.c',
|
||||||
'ipc.c',
|
'ipc.c',
|
||||||
'main.c',
|
'main.c',
|
||||||
'render.c',
|
'render.c',
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#define _POSIX_C_SOURCE
|
#define _POSIX_C_SOURCE
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
#include <json-c/json.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
@ -9,35 +10,78 @@
|
||||||
#include "swaybar/status_line.h"
|
#include "swaybar/status_line.h"
|
||||||
#include "readline.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) {
|
bool handle_status_readable(struct status_line *status) {
|
||||||
char *line = read_line_buffer(status->read,
|
char *line;
|
||||||
status->buffer, status->buffer_size);
|
|
||||||
switch (status->protocol) {
|
switch (status->protocol) {
|
||||||
|
case PROTOCOL_ERROR:
|
||||||
|
return false;
|
||||||
case PROTOCOL_I3BAR:
|
case PROTOCOL_I3BAR:
|
||||||
// TODO
|
if (i3bar_readable(status) > 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case PROTOCOL_TEXT:
|
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;
|
status->text = line;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
case PROTOCOL_UNDEF:
|
case PROTOCOL_UNDEF:
|
||||||
|
line = read_line_buffer(status->read,
|
||||||
|
status->text_state.buffer, status->text_state.buffer_size);
|
||||||
if (!line) {
|
if (!line) {
|
||||||
|
status_error(status, "[error reading from status command]");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (line[0] == '{') {
|
if (line[0] == '{') {
|
||||||
// TODO: JSON
|
json_object *proto = json_tokener_parse(line);
|
||||||
} else {
|
if (proto) {
|
||||||
status->text = line;
|
json_object *version;
|
||||||
status->protocol = PROTOCOL_TEXT;
|
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;
|
||||||
}
|
}
|
||||||
return false;
|
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->protocol = PROTOCOL_TEXT;
|
||||||
|
status->text = line;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct status_line *status_line_init(char *cmd) {
|
struct status_line *status_line_init(char *cmd) {
|
||||||
struct status_line *status = calloc(1, sizeof(struct status_line));
|
struct status_line *status = calloc(1, sizeof(struct status_line));
|
||||||
status->buffer_size = 4096;
|
status->text_state.buffer_size = 8192;
|
||||||
status->buffer = malloc(status->buffer_size);
|
status->text_state.buffer = malloc(status->text_state.buffer_size);
|
||||||
|
|
||||||
int pipe_read_fd[2];
|
int pipe_read_fd[2];
|
||||||
int pipe_write_fd[2];
|
int pipe_write_fd[2];
|
||||||
|
|
Loading…
Reference in a new issue