aboutsummaryrefslogtreecommitdiffstats
path: root/swaybar/main.c
diff options
context:
space:
mode:
authorLibravatar progandy <code@progandy>2015-12-22 17:34:37 +0100
committerLibravatar progandy <code@progandy>2015-12-22 17:34:37 +0100
commitaa5930c966066dbff28f4bde13c132c456bf01fa (patch)
treeac3ad5d7bd3ddbbe939cf6fd651385f7ebf671b9 /swaybar/main.c
parentswaybar: fix whitespace (diff)
downloadsway-aa5930c966066dbff28f4bde13c132c456bf01fa.tar.gz
sway-aa5930c966066dbff28f4bde13c132c456bf01fa.tar.zst
sway-aa5930c966066dbff28f4bde13c132c456bf01fa.zip
swaybar: Improve i3bar proto implementation
Also reintroduce plaintext fallback for simple status lines.
Diffstat (limited to 'swaybar/main.c')
-rw-r--r--swaybar/main.c147
1 files changed, 134 insertions, 13 deletions
diff --git a/swaybar/main.c b/swaybar/main.c
index e8d26573..1ad5b1cd 100644
--- a/swaybar/main.c
+++ b/swaybar/main.c
@@ -67,6 +67,8 @@ char *output, *status_command;
67struct registry *registry; 67struct registry *registry;
68struct window *window; 68struct window *window;
69bool dirty = true; 69bool dirty = true;
70typedef enum {UNDEF, TEXT, I3BAR} command_protocol;
71command_protocol protocol = UNDEF;
70 72
71struct colors colors = { 73struct colors colors = {
72 .background = 0x000000FF, 74 .background = 0x000000FF,
@@ -100,6 +102,20 @@ struct colors colors = {
100 }, 102 },
101}; 103};
102 104
105#define I3JSON_MAXDEPTH 4
106#define I3JSON_UNKNOWN 0
107#define I3JSON_ARRAY 1
108#define I3JSON_STRING 2
109struct {
110 int bufsize;
111 char *buffer;
112 char *line_start;
113 bool escape;
114 int depth;
115 int state[I3JSON_MAXDEPTH+1];
116} i3json_state = { 0, NULL, NULL, false, 0, { I3JSON_UNKNOWN } };
117
118
103void swaybar_teardown() { 119void swaybar_teardown() {
104 window_teardown(window); 120 window_teardown(window);
105 if (registry) { 121 if (registry) {
@@ -126,7 +142,6 @@ void swaybar_teardown() {
126 } 142 }
127} 143}
128 144
129
130void sway_terminate(void) { 145void sway_terminate(void) {
131 swaybar_teardown(); 146 swaybar_teardown();
132 exit(EXIT_FAILURE); 147 exit(EXIT_FAILURE);
@@ -375,10 +390,14 @@ void render() {
375 cairo_set_source_u32(window->cairo, colors.statusline); 390 cairo_set_source_u32(window->cairo, colors.statusline);
376 int width, height; 391 int width, height;
377 392
378 if (status_line) { 393 if (protocol == TEXT) {
394 get_text_size(window, &width, &height, "%s", line);
395 cairo_move_to(window->cairo, window->width - margin - width, margin);
396 pango_printf(window, "%s", line);
397 } else if (protocol == I3BAR && status_line) {
379 int i; 398 int i;
380 int moved = 0; 399 int moved = 0;
381 for ( i = status_line->length - 1; i >= 0; --i ) { 400 for (i = status_line->length - 1; i >= 0; --i) {
382 struct status_block *block = status_line->items[i]; 401 struct status_block *block = status_line->items[i];
383 if (block->full_text) { 402 if (block->full_text) {
384 get_text_size(window, &width, &height, "%s", block->full_text); 403 get_text_size(window, &width, &height, "%s", block->full_text);
@@ -539,6 +558,81 @@ void parse_json(const char *text) {
539 json_object_put(results); 558 json_object_put(results);
540} 559}
541 560
561int i3json_handle(FILE *file) {
562 char *c;
563 int handled = 0;
564 // handle partially buffered data
565 // make sure 1023+1 bytes at the end are free
566 if (i3json_state.line_start) {
567 int len = strlen(i3json_state.line_start);
568 memmove(i3json_state.buffer, i3json_state.line_start, len+1);
569 if (i3json_state.bufsize < len+1024) {
570 i3json_state.bufsize += 1024;
571 i3json_state.buffer = realloc(i3json_state.buffer, i3json_state.bufsize);
572 }
573 c = i3json_state.buffer+len;
574 i3json_state.line_start = i3json_state.buffer;
575 } else if (!i3json_state.buffer) {
576 i3json_state.buffer = malloc(1024);
577 i3json_state.bufsize = 1024;
578 c = i3json_state.buffer;
579 } else {
580 c = i3json_state.buffer;
581 }
582 if (!i3json_state.buffer) {
583 sway_abort("Could not allocate buffer.");
584 }
585 // get fresh data at the end of the buffer
586 if (!fgets(c, 1023, file)) return -1;
587 c[1023] = '\0';
588
589 while (*c) {
590 if (i3json_state.state[i3json_state.depth] == I3JSON_STRING) {
591 if (!i3json_state.escape && *c == '"') {
592 --i3json_state.depth;
593 }
594 i3json_state.escape = !i3json_state.escape && *c == '\\';
595 } else {
596 switch (*c) {
597 case '[':
598 ++i3json_state.depth;
599 if (i3json_state.depth > I3JSON_MAXDEPTH) {
600 sway_abort("JSON too deep");
601 }
602 i3json_state.state[i3json_state.depth] = I3JSON_ARRAY;
603 if (i3json_state.depth == 2) {
604 i3json_state.line_start = c;
605 }
606 break;
607 case ']':
608 if (i3json_state.state[i3json_state.depth] != I3JSON_ARRAY) {
609 sway_abort("JSON malformed");
610 }
611 --i3json_state.depth;
612 if (i3json_state.depth == 1) {
613 ssize_t len = c-i3json_state.line_start+1;
614 char p = c[len];
615 c[len] = '\0';
616 parse_json(i3json_state.line_start);
617 c[len] = p;
618 ++handled;
619 i3json_state.line_start = c+1;
620 }
621 break;
622 case '"':
623 ++i3json_state.depth;
624 if (i3json_state.depth > I3JSON_MAXDEPTH) {
625 sway_abort("JSON too deep");
626 }
627 i3json_state.state[i3json_state.depth] = I3JSON_STRING;
628 break;
629 }
630 }
631 ++c;
632 }
633 return handled;
634}
635
542void poll_for_update() { 636void poll_for_update() {
543 fd_set readfds; 637 fd_set readfds;
544 int activity; 638 int activity;
@@ -574,17 +668,43 @@ void poll_for_update() {
574 668
575 if (status_command && FD_ISSET(pipefd[0], &readfds)) { 669 if (status_command && FD_ISSET(pipefd[0], &readfds)) {
576 sway_log(L_DEBUG, "Got update from status command."); 670 sway_log(L_DEBUG, "Got update from status command.");
577 fgets(line, sizeof(line), command); 671 int linelen;
578 sway_log(L_DEBUG, "zzz %s", line); 672 switch (protocol) {
579 int l = strlen(line) - 1; 673 case I3BAR:
580 if (line[l] == '\n') { 674 sway_log(L_DEBUG, "Got i3bar protocol.");
581 line[l] = '\0'; 675 if (i3json_handle(command) > 0) {
676 dirty = true;
677 }
678 break;
679 case TEXT:
680 case UNDEF:
681 sway_log(L_DEBUG, "Got text protocol.");
682 fgets(line, sizeof(line), command);
683 linelen = strlen(line) - 1;
684 if (line[linelen] == '\n') {
685 line[linelen] = '\0';
686 }
687 dirty = true;
688 if (protocol == UNDEF) {
689 protocol = TEXT;
690 if (line[0] == '{') {
691 // detect i3bar json protocol
692 json_object *proto = json_tokener_parse(line);
693 json_object *version;
694 if (proto) {
695 if (json_object_object_get_ex(proto, "version", &version)
696 && json_object_get_int(version) == 1
697 ) {
698 sway_log(L_DEBUG, "Switched to i3bar protocol.");
699 protocol = I3BAR;
700 line[0] = '\0';
701 }
702 json_object_put(proto);
703 }
704 }
705 }
706 break;
582 } 707 }
583 if (line[0] == ',') {
584 line[0] = ' ';
585 }
586 dirty = true;
587 parse_json(line);
588 } 708 }
589 } 709 }
590} 710}
@@ -681,6 +801,7 @@ int main(int argc, char **argv) {
681 801
682 close(pipefd[1]); 802 close(pipefd[1]);
683 command = fdopen(pipefd[0], "r"); 803 command = fdopen(pipefd[0], "r");
804 setbuf(command, NULL);
684 line[0] = '\0'; 805 line[0] = '\0';
685 } 806 }
686 807