diff options
author | progandy <code@progandy> | 2015-12-22 17:34:37 +0100 |
---|---|---|
committer | progandy <code@progandy> | 2015-12-22 17:34:37 +0100 |
commit | aa5930c966066dbff28f4bde13c132c456bf01fa (patch) | |
tree | ac3ad5d7bd3ddbbe939cf6fd651385f7ebf671b9 /swaybar/main.c | |
parent | swaybar: fix whitespace (diff) | |
download | sway-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.c | 147 |
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; | |||
67 | struct registry *registry; | 67 | struct registry *registry; |
68 | struct window *window; | 68 | struct window *window; |
69 | bool dirty = true; | 69 | bool dirty = true; |
70 | typedef enum {UNDEF, TEXT, I3BAR} command_protocol; | ||
71 | command_protocol protocol = UNDEF; | ||
70 | 72 | ||
71 | struct colors colors = { | 73 | struct 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 | ||
109 | struct { | ||
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 | |||
103 | void swaybar_teardown() { | 119 | void 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 | |||
130 | void sway_terminate(void) { | 145 | void 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 | ||
561 | int 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 | |||
542 | void poll_for_update() { | 636 | void 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 | ||