diff options
-rw-r--r-- | README.ja.md | 2 | ||||
-rw-r--r-- | README.md | 8 | ||||
-rw-r--r-- | common/pango.c | 53 | ||||
-rw-r--r-- | common/readline.c | 25 | ||||
-rw-r--r-- | include/pango.h | 14 | ||||
-rw-r--r-- | include/sway/commands.h | 1 | ||||
-rw-r--r-- | include/sway/config.h | 4 | ||||
-rw-r--r-- | include/sway/tree/view.h | 2 | ||||
-rw-r--r-- | include/swaybar/event_loop.h | 4 | ||||
-rw-r--r-- | include/swaybar/status_line.h | 32 | ||||
-rw-r--r-- | sway/commands.c | 14 | ||||
-rw-r--r-- | sway/commands/create_output.c | 45 | ||||
-rw-r--r-- | sway/config/bar.c | 26 | ||||
-rw-r--r-- | sway/config/input.c | 7 | ||||
-rw-r--r-- | sway/desktop/render.c | 11 | ||||
-rw-r--r-- | sway/desktop/transaction.c | 11 | ||||
-rw-r--r-- | sway/ipc-json.c | 2 | ||||
-rw-r--r-- | sway/main.c | 1 | ||||
-rw-r--r-- | sway/meson.build | 1 | ||||
-rw-r--r-- | sway/tree/output.c | 2 | ||||
-rw-r--r-- | sway/tree/view.c | 10 | ||||
-rw-r--r-- | swaybar/bar.c | 112 | ||||
-rw-r--r-- | swaybar/event_loop.c | 4 | ||||
-rw-r--r-- | swaybar/i3bar.c | 216 | ||||
-rw-r--r-- | swaybar/render.c | 33 | ||||
-rw-r--r-- | swaybar/status_line.c | 148 |
26 files changed, 444 insertions, 344 deletions
diff --git a/README.ja.md b/README.ja.md index 75d29c73..b0488c53 100644 --- a/README.ja.md +++ b/README.ja.md | |||
@@ -5,7 +5,7 @@ i3互換な[Wayland](http://wayland.freedesktop.org/)コンポジタです。 | |||
5 | [FAQ](https://github.com/swaywm/sway/wiki)も合わせてご覧ください。 | 5 | [FAQ](https://github.com/swaywm/sway/wiki)も合わせてご覧ください。 |
6 | [IRC チャンネル](http://webchat.freenode.net/?channels=sway&uio=d4) (#sway on irc.freenode.net)もあります。 | 6 | [IRC チャンネル](http://webchat.freenode.net/?channels=sway&uio=d4) (#sway on irc.freenode.net)もあります。 |
7 | 7 | ||
8 | **注意**: Swayは現在*凍結中*であり、Swayとwlrootsの統合が完了するまで、新たな機能は追加されません。バグフィックスは行われます。詳しくは[この記事](https://drewdevault.com/2017/10/09/Future-of-sway.html)をご覧ください。wlrootsとの統合状況については、[このチケット](https://github.com/swaywm/sway/issues/1390)をご覧ください。 | 8 | **注意**: Swayは現在*凍結中*であり、wlcからwlrootsへの移植が完了するまで新たな機能は追加されません。2018年9月以降に発見されるバグは0.15では対応されません。詳しくは[この記事](https://drewdevault.com/2017/10/09/Future-of-sway.html)をご覧ください。wlrootsとの統合状況については、[このチケット](https://github.com/swaywm/sway/issues/1390)をご覧ください。 |
9 | 9 | ||
10 | [![](https://sr.ht/ICd5.png)](https://sr.ht/ICd5.png) | 10 | [![](https://sr.ht/ICd5.png)](https://sr.ht/ICd5.png) |
11 | 11 | ||
@@ -9,10 +9,10 @@ Read the [FAQ](https://github.com/swaywm/sway/wiki). Join the | |||
9 | [IRC channel](http://webchat.freenode.net/?channels=sway&uio=d4) (#sway on | 9 | [IRC channel](http://webchat.freenode.net/?channels=sway&uio=d4) (#sway on |
10 | irc.freenode.net). | 10 | irc.freenode.net). |
11 | 11 | ||
12 | **Notice**: You are viewing the **unstable** and **unsupported** master branch | 12 | **Notice**: work is well underway to port sway to |
13 | of sway, where work is ongoing to port it to | 13 | [wlroots](https://github.com/swaywm/wlroots). This is **unstable** and |
14 | [wlroots](https://github.com/swaywm/wlroots). The supported branch is the 0.15 | 14 | **unsupported** - we accept patches, but are not fond of bug reports. We are no |
15 | branch, and end users are encouraged to use the stable releases cut from it. | 15 | longer accepting bugs for 0.15. |
16 | 16 | ||
17 | If you'd like to support sway development, please contribute to [SirCmpwn's | 17 | If you'd like to support sway development, please contribute to [SirCmpwn's |
18 | Patreon page](https://patreon.com/sircmpwn). | 18 | Patreon page](https://patreon.com/sircmpwn). |
diff --git a/common/pango.c b/common/pango.c index ea71ac4a..5afd72d8 100644 --- a/common/pango.c +++ b/common/pango.c | |||
@@ -7,66 +7,45 @@ | |||
7 | #include <stdlib.h> | 7 | #include <stdlib.h> |
8 | #include <string.h> | 8 | #include <string.h> |
9 | #include "log.h" | 9 | #include "log.h" |
10 | #include "stringop.h" | ||
10 | 11 | ||
11 | int escape_markup_text(const char *src, char *dest, int dest_length) { | 12 | size_t escape_markup_text(const char *src, char *dest) { |
12 | int length = 0; | 13 | size_t length = 0; |
14 | if (dest) { | ||
15 | dest[0] = '\0'; | ||
16 | } | ||
13 | 17 | ||
14 | while (src[0]) { | 18 | while (src[0]) { |
15 | switch (src[0]) { | 19 | switch (src[0]) { |
16 | case '&': | 20 | case '&': |
17 | length += 5; | 21 | length += 5; |
18 | if (dest && dest_length - length >= 0) { | 22 | lenient_strcat(dest, "&"); |
19 | dest += sprintf(dest, "%s", "&"); | ||
20 | } else { | ||
21 | dest_length = -1; | ||
22 | } | ||
23 | break; | 23 | break; |
24 | case '<': | 24 | case '<': |
25 | length += 4; | 25 | length += 4; |
26 | if (dest && dest_length - length >= 0) { | 26 | lenient_strcat(dest, "<"); |
27 | dest += sprintf(dest, "%s", "<"); | ||
28 | } else { | ||
29 | dest_length = -1; | ||
30 | } | ||
31 | break; | 27 | break; |
32 | case '>': | 28 | case '>': |
33 | length += 4; | 29 | length += 4; |
34 | if (dest && dest_length - length >= 0) { | 30 | lenient_strcat(dest, ">"); |
35 | dest += sprintf(dest, "%s", ">"); | ||
36 | } else { | ||
37 | dest_length = -1; | ||
38 | } | ||
39 | break; | 31 | break; |
40 | case '\'': | 32 | case '\'': |
41 | length += 6; | 33 | length += 6; |
42 | if (dest && dest_length - length >= 0) { | 34 | lenient_strcat(dest, "'"); |
43 | dest += sprintf(dest, "%s", "'"); | ||
44 | } else { | ||
45 | dest_length = -1; | ||
46 | } | ||
47 | break; | 35 | break; |
48 | case '"': | 36 | case '"': |
49 | length += 6; | 37 | length += 6; |
50 | if (dest && dest_length - length >= 0) { | 38 | lenient_strcat(dest, """); |
51 | dest += sprintf(dest, "%s", """); | ||
52 | } else { | ||
53 | dest_length = -1; | ||
54 | } | ||
55 | break; | 39 | break; |
56 | default: | 40 | default: |
57 | length += 1; | 41 | if (dest) { |
58 | if (dest && dest_length - length >= 0) { | 42 | dest[length] = *src; |
59 | *(dest++) = *src; | 43 | dest[length + 1] = '\0'; |
60 | } else { | ||
61 | dest_length = -1; | ||
62 | } | 44 | } |
45 | length += 1; | ||
63 | } | 46 | } |
64 | src++; | 47 | src++; |
65 | } | 48 | } |
66 | // if we could not fit the escaped string in dest, return -1 | ||
67 | if (dest && dest_length == -1) { | ||
68 | return -1; | ||
69 | } | ||
70 | return length; | 49 | return length; |
71 | } | 50 | } |
72 | 51 | ||
@@ -78,7 +57,7 @@ PangoLayout *get_pango_layout(cairo_t *cairo, const char *font, | |||
78 | char *buf; | 57 | char *buf; |
79 | GError *error = NULL; | 58 | GError *error = NULL; |
80 | if (pango_parse_markup(text, -1, 0, &attrs, &buf, NULL, &error)) { | 59 | if (pango_parse_markup(text, -1, 0, &attrs, &buf, NULL, &error)) { |
81 | pango_layout_set_markup(layout, buf, -1); | 60 | pango_layout_set_text(layout, buf, -1); |
82 | free(buf); | 61 | free(buf); |
83 | } else { | 62 | } else { |
84 | wlr_log(WLR_ERROR, "pango_parse_markup '%s' -> error %s", text, | 63 | wlr_log(WLR_ERROR, "pango_parse_markup '%s' -> error %s", text, |
diff --git a/common/readline.c b/common/readline.c index a2c69018..58652429 100644 --- a/common/readline.c +++ b/common/readline.c | |||
@@ -70,28 +70,3 @@ char *peek_line(FILE *file, int line_offset, long *position) { | |||
70 | fseek(file, pos, SEEK_SET); | 70 | fseek(file, pos, SEEK_SET); |
71 | return line; | 71 | return line; |
72 | } | 72 | } |
73 | |||
74 | char *read_line_buffer(FILE *file, char *string, size_t string_len) { | ||
75 | size_t length = 0; | ||
76 | if (!string) { | ||
77 | return NULL; | ||
78 | } | ||
79 | while (1) { | ||
80 | int c = getc(file); | ||
81 | if (c == EOF || c == '\n' || c == '\0') { | ||
82 | break; | ||
83 | } | ||
84 | if (c == '\r') { | ||
85 | continue; | ||
86 | } | ||
87 | string[length++] = c; | ||
88 | if (string_len <= length) { | ||
89 | return NULL; | ||
90 | } | ||
91 | } | ||
92 | if (length + 1 == string_len) { | ||
93 | return NULL; | ||
94 | } | ||
95 | string[length] = '\0'; | ||
96 | return string; | ||
97 | } | ||
diff --git a/include/pango.h b/include/pango.h index 09a535a5..6ab83c16 100644 --- a/include/pango.h +++ b/include/pango.h | |||
@@ -6,17 +6,13 @@ | |||
6 | #include <cairo/cairo.h> | 6 | #include <cairo/cairo.h> |
7 | #include <pango/pangocairo.h> | 7 | #include <pango/pangocairo.h> |
8 | 8 | ||
9 | /* Utility function which escape characters a & < > ' ". | 9 | /** |
10 | * Utility function which escape characters a & < > ' ". | ||
10 | * | 11 | * |
11 | * If the dest parameter is NULL, then the function returns the length of | 12 | * The function returns the length of the escaped string, optionally writing the |
12 | * of the escaped src string. The dest_length doesn't matter. | 13 | * escaped string to dest if provided. |
13 | * | ||
14 | * If the dest parameter is not NULL then the fuction escapes the src string | ||
15 | * an puts the escaped string in dest and returns the lenght of the escaped string. | ||
16 | * The dest_length parameter is the size of dest array. If the size of dest is not | ||
17 | * enough, then the function returns -1. | ||
18 | */ | 14 | */ |
19 | int escape_markup_text(const char *src, char *dest, int dest_length); | 15 | size_t escape_markup_text(const char *src, char *dest); |
20 | PangoLayout *get_pango_layout(cairo_t *cairo, const char *font, | 16 | PangoLayout *get_pango_layout(cairo_t *cairo, const char *font, |
21 | const char *text, double scale, bool markup); | 17 | const char *text, double scale, bool markup); |
22 | void get_text_size(cairo_t *cairo, const char *font, int *width, int *height, | 18 | void get_text_size(cairo_t *cairo, const char *font, int *width, int *height, |
diff --git a/include/sway/commands.h b/include/sway/commands.h index e51b12fd..226cf932 100644 --- a/include/sway/commands.h +++ b/include/sway/commands.h | |||
@@ -103,6 +103,7 @@ sway_cmd cmd_client_urgent; | |||
103 | sway_cmd cmd_client_placeholder; | 103 | sway_cmd cmd_client_placeholder; |
104 | sway_cmd cmd_client_background; | 104 | sway_cmd cmd_client_background; |
105 | sway_cmd cmd_commands; | 105 | sway_cmd cmd_commands; |
106 | sway_cmd cmd_create_output; | ||
106 | sway_cmd cmd_debuglog; | 107 | sway_cmd cmd_debuglog; |
107 | sway_cmd cmd_default_border; | 108 | sway_cmd cmd_default_border; |
108 | sway_cmd cmd_default_floating_border; | 109 | sway_cmd cmd_default_floating_border; |
diff --git a/include/sway/config.h b/include/sway/config.h index b53c1f1f..36d78ec6 100644 --- a/include/sway/config.h +++ b/include/sway/config.h | |||
@@ -512,9 +512,7 @@ void free_sway_binding(struct sway_binding *sb); | |||
512 | 512 | ||
513 | void seat_execute_command(struct sway_seat *seat, struct sway_binding *binding); | 513 | void seat_execute_command(struct sway_seat *seat, struct sway_binding *binding); |
514 | 514 | ||
515 | void load_swaybars(); | 515 | void load_swaybars(void); |
516 | |||
517 | void invoke_swaybar(struct bar_config *bar); | ||
518 | 516 | ||
519 | void terminate_swaybg(pid_t pid); | 517 | void terminate_swaybg(pid_t pid); |
520 | 518 | ||
diff --git a/include/sway/tree/view.h b/include/sway/tree/view.h index 439dc1bf..d10251dd 100644 --- a/include/sway/tree/view.h +++ b/include/sway/tree/view.h | |||
@@ -61,6 +61,8 @@ struct sway_view { | |||
61 | struct sway_container *container; // NULL if unmapped and transactions finished | 61 | struct sway_container *container; // NULL if unmapped and transactions finished |
62 | struct wlr_surface *surface; // NULL for unmapped views | 62 | struct wlr_surface *surface; // NULL for unmapped views |
63 | 63 | ||
64 | pid_t pid; | ||
65 | |||
64 | // Geometry of the view itself (excludes borders) in layout coordinates | 66 | // Geometry of the view itself (excludes borders) in layout coordinates |
65 | double x, y; | 67 | double x, y; |
66 | int width, height; | 68 | int width, height; |
diff --git a/include/swaybar/event_loop.h b/include/swaybar/event_loop.h index 99f6ed36..47be5b79 100644 --- a/include/swaybar/event_loop.h +++ b/include/swaybar/event_loop.h | |||
@@ -19,8 +19,8 @@ bool remove_event(int fd); | |||
19 | bool remove_timer(timer_t timer); | 19 | bool remove_timer(timer_t timer); |
20 | 20 | ||
21 | // Blocks and returns after sending callbacks | 21 | // Blocks and returns after sending callbacks |
22 | void event_loop_poll(); | 22 | void event_loop_poll(void); |
23 | 23 | ||
24 | void init_event_loop(); | 24 | void init_event_loop(void); |
25 | 25 | ||
26 | #endif | 26 | #endif |
diff --git a/include/swaybar/status_line.h b/include/swaybar/status_line.h index 150267cd..d3eabdf6 100644 --- a/include/swaybar/status_line.h +++ b/include/swaybar/status_line.h | |||
@@ -1,5 +1,6 @@ | |||
1 | #ifndef _SWAYBAR_STATUS_LINE_H | 1 | #ifndef _SWAYBAR_STATUS_LINE_H |
2 | #define _SWAYBAR_STATUS_LINE_H | 2 | #define _SWAYBAR_STATUS_LINE_H |
3 | #include <json-c/json.h> | ||
3 | #include <stdint.h> | 4 | #include <stdint.h> |
4 | #include <stdio.h> | 5 | #include <stdio.h> |
5 | #include <stdbool.h> | 6 | #include <stdbool.h> |
@@ -12,28 +13,6 @@ enum status_protocol { | |||
12 | PROTOCOL_I3BAR, | 13 | PROTOCOL_I3BAR, |
13 | }; | 14 | }; |
14 | 15 | ||
15 | struct text_protocol_state { | ||
16 | char *buffer; | ||
17 | size_t buffer_size; | ||
18 | }; | ||
19 | |||
20 | enum json_node_type { | ||
21 | JSON_NODE_UNKNOWN, | ||
22 | JSON_NODE_ARRAY, | ||
23 | JSON_NODE_STRING, | ||
24 | }; | ||
25 | |||
26 | struct i3bar_protocol_state { | ||
27 | bool click_events; | ||
28 | char *buffer; | ||
29 | size_t buffer_size; | ||
30 | size_t buffer_index; | ||
31 | const char *current_node; | ||
32 | bool escape; | ||
33 | size_t depth; | ||
34 | enum json_node_type nodes[16]; | ||
35 | }; | ||
36 | |||
37 | struct i3bar_block { | 16 | struct i3bar_block { |
38 | struct wl_list link; | 17 | struct wl_list link; |
39 | int ref_count; | 18 | int ref_count; |
@@ -63,8 +42,13 @@ struct status_line { | |||
63 | const char *text; | 42 | const char *text; |
64 | struct wl_list blocks; // i3bar_block::link | 43 | struct wl_list blocks; // i3bar_block::link |
65 | 44 | ||
66 | struct text_protocol_state text_state; | 45 | bool click_events; |
67 | struct i3bar_protocol_state i3bar_state; | 46 | char *buffer; |
47 | size_t buffer_size; | ||
48 | size_t buffer_index; | ||
49 | bool started; | ||
50 | bool expecting_comma; | ||
51 | json_tokener *tokener; | ||
68 | }; | 52 | }; |
69 | 53 | ||
70 | struct status_line *status_line_init(char *cmd); | 54 | struct status_line *status_line_init(char *cmd); |
diff --git a/sway/commands.c b/sway/commands.c index 41e1c653..07169f1e 100644 --- a/sway/commands.c +++ b/sway/commands.c | |||
@@ -143,6 +143,7 @@ static struct cmd_handler config_handlers[] = { | |||
143 | /* Runtime-only commands. Keep alphabetized */ | 143 | /* Runtime-only commands. Keep alphabetized */ |
144 | static struct cmd_handler command_handlers[] = { | 144 | static struct cmd_handler command_handlers[] = { |
145 | { "border", cmd_border }, | 145 | { "border", cmd_border }, |
146 | { "create_output", cmd_create_output }, | ||
146 | { "exit", cmd_exit }, | 147 | { "exit", cmd_exit }, |
147 | { "floating", cmd_floating }, | 148 | { "floating", cmd_floating }, |
148 | { "fullscreen", cmd_fullscreen }, | 149 | { "fullscreen", cmd_fullscreen }, |
@@ -215,18 +216,23 @@ struct cmd_handler *find_handler(char *line, struct cmd_handler *cmd_handlers, | |||
215 | 216 | ||
216 | static void set_config_node(struct sway_node *node) { | 217 | static void set_config_node(struct sway_node *node) { |
217 | config->handler_context.node = node; | 218 | config->handler_context.node = node; |
219 | config->handler_context.container = NULL; | ||
220 | config->handler_context.workspace = NULL; | ||
221 | |||
222 | if (node == NULL) { | ||
223 | return; | ||
224 | } | ||
225 | |||
218 | switch (node->type) { | 226 | switch (node->type) { |
219 | case N_CONTAINER: | 227 | case N_CONTAINER: |
220 | config->handler_context.container = node->sway_container; | 228 | config->handler_context.container = node->sway_container; |
221 | config->handler_context.workspace = node->sway_container->workspace; | 229 | config->handler_context.workspace = node->sway_container->workspace; |
222 | break; | 230 | break; |
223 | case N_WORKSPACE: | 231 | case N_WORKSPACE: |
224 | config->handler_context.container = NULL; | ||
225 | config->handler_context.workspace = node->sway_workspace; | 232 | config->handler_context.workspace = node->sway_workspace; |
226 | break; | 233 | break; |
227 | default: | 234 | case N_ROOT: |
228 | config->handler_context.container = NULL; | 235 | case N_OUTPUT: |
229 | config->handler_context.workspace = NULL; | ||
230 | break; | 236 | break; |
231 | } | 237 | } |
232 | } | 238 | } |
diff --git a/sway/commands/create_output.c b/sway/commands/create_output.c new file mode 100644 index 00000000..1c2464ea --- /dev/null +++ b/sway/commands/create_output.c | |||
@@ -0,0 +1,45 @@ | |||
1 | #include <wlr/config.h> | ||
2 | #include <wlr/backend/multi.h> | ||
3 | #include <wlr/backend/wayland.h> | ||
4 | #ifdef WLR_HAS_X11_BACKEND | ||
5 | #include <wlr/backend/x11.h> | ||
6 | #endif | ||
7 | #include "sway/commands.h" | ||
8 | #include "sway/server.h" | ||
9 | #include "log.h" | ||
10 | |||
11 | static void create_output(struct wlr_backend *backend, void *data) { | ||
12 | bool *done = data; | ||
13 | if (*done) { | ||
14 | return; | ||
15 | } | ||
16 | |||
17 | if (wlr_backend_is_wl(backend)) { | ||
18 | wlr_wl_output_create(backend); | ||
19 | *done = true; | ||
20 | } | ||
21 | #ifdef WLR_HAS_X11_BACKEND | ||
22 | else if (wlr_backend_is_x11(backend)) { | ||
23 | wlr_x11_output_create(backend); | ||
24 | *done = true; | ||
25 | } | ||
26 | #endif | ||
27 | } | ||
28 | |||
29 | /** | ||
30 | * This command is intended for developer use only. | ||
31 | */ | ||
32 | struct cmd_results *cmd_create_output(int argc, char **argv) { | ||
33 | sway_assert(wlr_backend_is_multi(server.backend), | ||
34 | "Expected a multi backend"); | ||
35 | |||
36 | bool done = false; | ||
37 | wlr_multi_for_each_backend(server.backend, create_output, &done); | ||
38 | |||
39 | if (!done) { | ||
40 | return cmd_results_new(CMD_INVALID, "create_output", | ||
41 | "Can only create outputs for Wayland or X11 backends"); | ||
42 | } | ||
43 | |||
44 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | ||
45 | } | ||
diff --git a/sway/config/bar.c b/sway/config/bar.c index f83b37d1..48a632fb 100644 --- a/sway/config/bar.c +++ b/sway/config/bar.c | |||
@@ -165,7 +165,7 @@ cleanup: | |||
165 | return NULL; | 165 | return NULL; |
166 | } | 166 | } |
167 | 167 | ||
168 | void invoke_swaybar(struct bar_config *bar) { | 168 | static void invoke_swaybar(struct bar_config *bar) { |
169 | // Pipe to communicate errors | 169 | // Pipe to communicate errors |
170 | int filedes[2]; | 170 | int filedes[2]; |
171 | if (pipe(filedes) == -1) { | 171 | if (pipe(filedes) == -1) { |
@@ -219,27 +219,13 @@ void invoke_swaybar(struct bar_config *bar) { | |||
219 | close(filedes[1]); | 219 | close(filedes[1]); |
220 | } | 220 | } |
221 | 221 | ||
222 | void load_swaybars() { | 222 | void load_swaybars(void) { |
223 | for (int i = 0; i < config->bars->length; ++i) { | 223 | for (int i = 0; i < config->bars->length; ++i) { |
224 | struct bar_config *bar = config->bars->items[i]; | 224 | struct bar_config *bar = config->bars->items[i]; |
225 | bool apply = false; | 225 | if (bar->pid != 0) { |
226 | if (bar->outputs) { | 226 | terminate_swaybar(bar->pid); |
227 | for (int j = 0; j < bar->outputs->length; ++j) { | ||
228 | char *o = bar->outputs->items[j]; | ||
229 | if (!strcmp(o, "*") || output_by_name(o)) { | ||
230 | apply = true; | ||
231 | break; | ||
232 | } | ||
233 | } | ||
234 | } else { | ||
235 | apply = true; | ||
236 | } | ||
237 | if (apply) { | ||
238 | if (bar->pid != 0) { | ||
239 | terminate_swaybar(bar->pid); | ||
240 | } | ||
241 | wlr_log(WLR_DEBUG, "Invoking swaybar for bar id '%s'", bar->id); | ||
242 | invoke_swaybar(bar); | ||
243 | } | 227 | } |
228 | wlr_log(WLR_DEBUG, "Invoking swaybar for bar id '%s'", bar->id); | ||
229 | invoke_swaybar(bar); | ||
244 | } | 230 | } |
245 | } | 231 | } |
diff --git a/sway/config/input.c b/sway/config/input.c index 9885e85c..ad5b96c8 100644 --- a/sway/config/input.c +++ b/sway/config/input.c | |||
@@ -140,6 +140,13 @@ void free_input_config(struct input_config *ic) { | |||
140 | return; | 140 | return; |
141 | } | 141 | } |
142 | free(ic->identifier); | 142 | free(ic->identifier); |
143 | free(ic->xkb_layout); | ||
144 | free(ic->xkb_model); | ||
145 | free(ic->xkb_options); | ||
146 | free(ic->xkb_rules); | ||
147 | free(ic->xkb_variant); | ||
148 | free(ic->mapped_from_region); | ||
149 | free(ic->mapped_to_output); | ||
143 | free(ic); | 150 | free(ic); |
144 | } | 151 | } |
145 | 152 | ||
diff --git a/sway/desktop/render.c b/sway/desktop/render.c index 1d2f445d..af4e2905 100644 --- a/sway/desktop/render.c +++ b/sway/desktop/render.c | |||
@@ -914,12 +914,17 @@ void output_render(struct sway_output *output, struct timespec *when, | |||
914 | struct wlr_output *wlr_output = output->wlr_output; | 914 | struct wlr_output *wlr_output = output->wlr_output; |
915 | 915 | ||
916 | struct wlr_renderer *renderer = | 916 | struct wlr_renderer *renderer = |
917 | wlr_backend_get_renderer(wlr_output->backend); | 917 | wlr_backend_get_renderer(wlr_output->backend); |
918 | if (!sway_assert(renderer != NULL, | 918 | if (!sway_assert(renderer != NULL, |
919 | "expected the output backend to have a renderer")) { | 919 | "expected the output backend to have a renderer")) { |
920 | return; | 920 | return; |
921 | } | 921 | } |
922 | 922 | ||
923 | struct sway_workspace *workspace = output->current.active_workspace; | ||
924 | if (workspace == NULL) { | ||
925 | return; | ||
926 | } | ||
927 | |||
923 | wlr_renderer_begin(renderer, wlr_output->width, wlr_output->height); | 928 | wlr_renderer_begin(renderer, wlr_output->width, wlr_output->height); |
924 | 929 | ||
925 | if (!pixman_region32_not_empty(damage)) { | 930 | if (!pixman_region32_not_empty(damage)) { |
@@ -935,13 +940,11 @@ void output_render(struct sway_output *output, struct timespec *when, | |||
935 | pixman_region32_union_rect(damage, damage, 0, 0, width, height); | 940 | pixman_region32_union_rect(damage, damage, 0, 0, width, height); |
936 | } | 941 | } |
937 | 942 | ||
938 | struct sway_workspace *workspace = output->current.active_workspace; | ||
939 | struct sway_container *fullscreen_con = workspace->current.fullscreen; | ||
940 | |||
941 | if (output_has_opaque_overlay_layer_surface(output)) { | 943 | if (output_has_opaque_overlay_layer_surface(output)) { |
942 | goto render_overlay; | 944 | goto render_overlay; |
943 | } | 945 | } |
944 | 946 | ||
947 | struct sway_container *fullscreen_con = workspace->current.fullscreen; | ||
945 | if (fullscreen_con) { | 948 | if (fullscreen_con) { |
946 | float clear_color[] = {0.0f, 0.0f, 0.0f, 1.0f}; | 949 | float clear_color[] = {0.0f, 0.0f, 0.0f, 1.0f}; |
947 | 950 | ||
diff --git a/sway/desktop/transaction.c b/sway/desktop/transaction.c index d747e279..797f6b4c 100644 --- a/sway/desktop/transaction.c +++ b/sway/desktop/transaction.c | |||
@@ -6,6 +6,7 @@ | |||
6 | #include <string.h> | 6 | #include <string.h> |
7 | #include <time.h> | 7 | #include <time.h> |
8 | #include <wlr/types/wlr_buffer.h> | 8 | #include <wlr/types/wlr_buffer.h> |
9 | #include "sway/config.h" | ||
9 | #include "sway/debug.h" | 10 | #include "sway/debug.h" |
10 | #include "sway/desktop.h" | 11 | #include "sway/desktop.h" |
11 | #include "sway/desktop/idle_inhibit_v1.h" | 12 | #include "sway/desktop/idle_inhibit_v1.h" |
@@ -390,6 +391,16 @@ static bool should_configure(struct sway_node *node, | |||
390 | } | 391 | } |
391 | struct sway_container_state *cstate = &node->sway_container->current; | 392 | struct sway_container_state *cstate = &node->sway_container->current; |
392 | struct sway_container_state *istate = instruction->container_state; | 393 | struct sway_container_state *istate = instruction->container_state; |
394 | #ifdef HAVE_XWAYLAND | ||
395 | // Xwayland views are position-aware and need to be reconfigured | ||
396 | // when their position changes. | ||
397 | if (node->sway_container->view->type == SWAY_VIEW_XWAYLAND) { | ||
398 | if (cstate->view_x != istate->view_x || | ||
399 | cstate->view_y != istate->view_y) { | ||
400 | return true; | ||
401 | } | ||
402 | } | ||
403 | #endif | ||
393 | if (cstate->view_width == istate->view_width && | 404 | if (cstate->view_width == istate->view_width && |
394 | cstate->view_height == istate->view_height) { | 405 | cstate->view_height == istate->view_height) { |
395 | return false; | 406 | return false; |
diff --git a/sway/ipc-json.c b/sway/ipc-json.c index 52278be2..f054ac9f 100644 --- a/sway/ipc-json.c +++ b/sway/ipc-json.c | |||
@@ -221,6 +221,8 @@ static const char *describe_container_border(enum sway_container_border border) | |||
221 | } | 221 | } |
222 | 222 | ||
223 | static void ipc_json_describe_view(struct sway_container *c, json_object *object) { | 223 | static void ipc_json_describe_view(struct sway_container *c, json_object *object) { |
224 | json_object_object_add(object, "pid", json_object_new_int(c->view->pid)); | ||
225 | |||
224 | const char *app_id = view_get_app_id(c->view); | 226 | const char *app_id = view_get_app_id(c->view); |
225 | json_object_object_add(object, "app_id", | 227 | json_object_object_add(object, "app_id", |
226 | app_id ? json_object_new_string(app_id) : NULL); | 228 | app_id ? json_object_new_string(app_id) : NULL); |
diff --git a/sway/main.c b/sway/main.c index fb4f0d8c..3d7cd158 100644 --- a/sway/main.c +++ b/sway/main.c | |||
@@ -424,6 +424,7 @@ int main(int argc, char **argv) { | |||
424 | } | 424 | } |
425 | 425 | ||
426 | config->active = true; | 426 | config->active = true; |
427 | load_swaybars(); | ||
427 | // Execute commands until there are none left | 428 | // Execute commands until there are none left |
428 | wlr_log(WLR_DEBUG, "Running deferred commands"); | 429 | wlr_log(WLR_DEBUG, "Running deferred commands"); |
429 | while (config->cmd_queue->length) { | 430 | while (config->cmd_queue->length) { |
diff --git a/sway/meson.build b/sway/meson.build index 01c83a33..d67a4c64 100644 --- a/sway/meson.build +++ b/sway/meson.build | |||
@@ -35,6 +35,7 @@ sway_sources = files( | |||
35 | 'commands/bind.c', | 35 | 'commands/bind.c', |
36 | 'commands/border.c', | 36 | 'commands/border.c', |
37 | 'commands/client.c', | 37 | 'commands/client.c', |
38 | 'commands/create_output.c', | ||
38 | 'commands/default_border.c', | 39 | 'commands/default_border.c', |
39 | 'commands/default_floating_border.c', | 40 | 'commands/default_floating_border.c', |
40 | 'commands/default_orientation.c', | 41 | 'commands/default_orientation.c', |
diff --git a/sway/tree/output.c b/sway/tree/output.c index 1976ad51..06933dc4 100644 --- a/sway/tree/output.c +++ b/sway/tree/output.c | |||
@@ -109,8 +109,6 @@ void output_enable(struct sway_output *output, struct output_config *oc) { | |||
109 | 109 | ||
110 | wl_signal_emit(&root->events.new_node, &output->node); | 110 | wl_signal_emit(&root->events.new_node, &output->node); |
111 | 111 | ||
112 | load_swaybars(); | ||
113 | |||
114 | arrange_layers(output); | 112 | arrange_layers(output); |
115 | arrange_root(); | 113 | arrange_root(); |
116 | } | 114 | } |
diff --git a/sway/tree/view.c b/sway/tree/view.c index e4e1c161..f61f5c84 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c | |||
@@ -470,6 +470,7 @@ static struct sway_workspace *select_workspace(struct sway_view *view) { | |||
470 | wl_resource_get_client(view->surface->resource); | 470 | wl_resource_get_client(view->surface->resource); |
471 | wl_client_get_credentials(client, &pid, NULL, NULL); | 471 | wl_client_get_credentials(client, &pid, NULL, NULL); |
472 | #endif | 472 | #endif |
473 | view->pid = pid; | ||
473 | ws = root_workspace_for_pid(pid); | 474 | ws = root_workspace_for_pid(pid); |
474 | if (ws) { | 475 | if (ws) { |
475 | return ws; | 476 | return ws; |
@@ -784,14 +785,9 @@ static size_t parse_title_format(struct sway_view *view, char *buffer) { | |||
784 | } | 785 | } |
785 | 786 | ||
786 | static char *escape_title(char *buffer) { | 787 | static char *escape_title(char *buffer) { |
787 | int length = escape_markup_text(buffer, NULL, 0); | 788 | size_t length = escape_markup_text(buffer, NULL); |
788 | char *escaped_title = calloc(length + 1, sizeof(char)); | 789 | char *escaped_title = calloc(length + 1, sizeof(char)); |
789 | int result = escape_markup_text(buffer, escaped_title, length); | 790 | escape_markup_text(buffer, escaped_title); |
790 | if (result != length) { | ||
791 | wlr_log(WLR_ERROR, "Could not escape title: %s", buffer); | ||
792 | free(escaped_title); | ||
793 | return buffer; | ||
794 | } | ||
795 | free(buffer); | 791 | free(buffer); |
796 | return escaped_title; | 792 | return escaped_title; |
797 | } | 793 | } |
diff --git a/swaybar/bar.c b/swaybar/bar.c index 3ae730f7..69069f40 100644 --- a/swaybar/bar.c +++ b/swaybar/bar.c | |||
@@ -48,8 +48,13 @@ static void swaybar_output_free(struct swaybar_output *output) { | |||
48 | return; | 48 | return; |
49 | } | 49 | } |
50 | wlr_log(WLR_DEBUG, "Removing output %s", output->name); | 50 | wlr_log(WLR_DEBUG, "Removing output %s", output->name); |
51 | zwlr_layer_surface_v1_destroy(output->layer_surface); | 51 | if (output->layer_surface != NULL) { |
52 | wl_surface_destroy(output->surface); | 52 | zwlr_layer_surface_v1_destroy(output->layer_surface); |
53 | } | ||
54 | if (output->surface != NULL) { | ||
55 | wl_surface_destroy(output->surface); | ||
56 | } | ||
57 | zxdg_output_v1_destroy(output->xdg_output); | ||
53 | wl_output_destroy(output->output); | 58 | wl_output_destroy(output->output); |
54 | destroy_buffer(&output->buffers[0]); | 59 | destroy_buffer(&output->buffers[0]); |
55 | destroy_buffer(&output->buffers[1]); | 60 | destroy_buffer(&output->buffers[1]); |
@@ -283,6 +288,37 @@ const struct wl_seat_listener seat_listener = { | |||
283 | .name = seat_handle_name, | 288 | .name = seat_handle_name, |
284 | }; | 289 | }; |
285 | 290 | ||
291 | static void add_layer_surface(struct swaybar_output *output) { | ||
292 | if (output->surface != NULL) { | ||
293 | return; | ||
294 | } | ||
295 | struct swaybar *bar = output->bar; | ||
296 | |||
297 | output->surface = wl_compositor_create_surface(bar->compositor); | ||
298 | assert(output->surface); | ||
299 | output->layer_surface = zwlr_layer_shell_v1_get_layer_surface( | ||
300 | bar->layer_shell, output->surface, output->output, | ||
301 | ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM, "panel"); | ||
302 | assert(output->layer_surface); | ||
303 | zwlr_layer_surface_v1_add_listener(output->layer_surface, | ||
304 | &layer_surface_listener, output); | ||
305 | zwlr_layer_surface_v1_set_anchor(output->layer_surface, | ||
306 | bar->config->position); | ||
307 | } | ||
308 | |||
309 | static bool bar_uses_output(struct swaybar *bar, const char *name) { | ||
310 | if (bar->config->all_outputs) { | ||
311 | return true; | ||
312 | } | ||
313 | struct config_output *coutput; | ||
314 | wl_list_for_each(coutput, &bar->config->outputs, link) { | ||
315 | if (strcmp(coutput->name, name) == 0) { | ||
316 | return true; | ||
317 | } | ||
318 | } | ||
319 | return false; | ||
320 | } | ||
321 | |||
286 | static void output_geometry(void *data, struct wl_output *output, int32_t x, | 322 | static void output_geometry(void *data, struct wl_output *output, int32_t x, |
287 | int32_t y, int32_t width_mm, int32_t height_mm, int32_t subpixel, | 323 | int32_t y, int32_t width_mm, int32_t height_mm, int32_t subpixel, |
288 | const char *make, const char *model, int32_t transform) { | 324 | const char *make, const char *model, int32_t transform) { |
@@ -326,7 +362,22 @@ static void xdg_output_handle_logical_size(void *data, | |||
326 | 362 | ||
327 | static void xdg_output_handle_done(void *data, | 363 | static void xdg_output_handle_done(void *data, |
328 | struct zxdg_output_v1 *xdg_output) { | 364 | struct zxdg_output_v1 *xdg_output) { |
329 | // Who cares | 365 | struct swaybar_output *output = data; |
366 | struct swaybar *bar = output->bar; | ||
367 | |||
368 | assert(output->name != NULL); | ||
369 | if (!bar_uses_output(bar, output->name)) { | ||
370 | swaybar_output_free(output); | ||
371 | return; | ||
372 | } | ||
373 | |||
374 | if (wl_list_empty(&output->link)) { | ||
375 | wl_list_remove(&output->link); | ||
376 | wl_list_insert(&bar->outputs, &output->link); | ||
377 | |||
378 | add_layer_surface(output); | ||
379 | render_frame(bar, output); | ||
380 | } | ||
330 | } | 381 | } |
331 | 382 | ||
332 | static void xdg_output_handle_name(void *data, | 383 | static void xdg_output_handle_name(void *data, |
@@ -349,17 +400,15 @@ struct zxdg_output_v1_listener xdg_output_listener = { | |||
349 | .description = xdg_output_handle_description, | 400 | .description = xdg_output_handle_description, |
350 | }; | 401 | }; |
351 | 402 | ||
352 | static bool bar_uses_output(struct swaybar *bar, const char *name) { | 403 | static void add_xdg_output(struct swaybar_output *output) { |
353 | if (bar->config->all_outputs) { | 404 | if (output->xdg_output != NULL) { |
354 | return true; | 405 | return; |
355 | } | ||
356 | struct config_output *coutput; | ||
357 | wl_list_for_each(coutput, &bar->config->outputs, link) { | ||
358 | if (strcmp(coutput->name, name) == 0) { | ||
359 | return true; | ||
360 | } | ||
361 | } | 406 | } |
362 | return false; | 407 | assert(output->bar->xdg_output_manager != NULL); |
408 | output->xdg_output = zxdg_output_manager_v1_get_xdg_output( | ||
409 | output->bar->xdg_output_manager, output->output); | ||
410 | zxdg_output_v1_add_listener(output->xdg_output, &xdg_output_listener, | ||
411 | output); | ||
363 | } | 412 | } |
364 | 413 | ||
365 | static void handle_global(void *data, struct wl_registry *registry, | 414 | static void handle_global(void *data, struct wl_registry *registry, |
@@ -386,7 +435,10 @@ static void handle_global(void *data, struct wl_registry *registry, | |||
386 | output->wl_name = name; | 435 | output->wl_name = name; |
387 | wl_list_init(&output->workspaces); | 436 | wl_list_init(&output->workspaces); |
388 | wl_list_init(&output->hotspots); | 437 | wl_list_init(&output->hotspots); |
389 | wl_list_insert(&bar->outputs, &output->link); | 438 | wl_list_init(&output->link); |
439 | if (bar->xdg_output_manager != NULL) { | ||
440 | add_xdg_output(output); | ||
441 | } | ||
390 | } else if (strcmp(interface, zwlr_layer_shell_v1_interface.name) == 0) { | 442 | } else if (strcmp(interface, zwlr_layer_shell_v1_interface.name) == 0) { |
391 | bar->layer_shell = wl_registry_bind( | 443 | bar->layer_shell = wl_registry_bind( |
392 | registry, name, &zwlr_layer_shell_v1_interface, 1); | 444 | registry, name, &zwlr_layer_shell_v1_interface, 1); |
@@ -416,7 +468,9 @@ static const struct wl_registry_listener registry_listener = { | |||
416 | static void render_all_frames(struct swaybar *bar) { | 468 | static void render_all_frames(struct swaybar *bar) { |
417 | struct swaybar_output *output; | 469 | struct swaybar_output *output; |
418 | wl_list_for_each(output, &bar->outputs, link) { | 470 | wl_list_for_each(output, &bar->outputs, link) { |
419 | render_frame(bar, output); | 471 | if (output->surface != NULL) { |
472 | render_frame(bar, output); | ||
473 | } | ||
420 | } | 474 | } |
421 | } | 475 | } |
422 | 476 | ||
@@ -443,23 +497,10 @@ void bar_setup(struct swaybar *bar, | |||
443 | 497 | ||
444 | struct swaybar_output *output; | 498 | struct swaybar_output *output; |
445 | wl_list_for_each(output, &bar->outputs, link) { | 499 | wl_list_for_each(output, &bar->outputs, link) { |
446 | output->xdg_output = zxdg_output_manager_v1_get_xdg_output( | 500 | add_xdg_output(output); |
447 | bar->xdg_output_manager, output->output); | ||
448 | zxdg_output_v1_add_listener(output->xdg_output, &xdg_output_listener, | ||
449 | output); | ||
450 | } | 501 | } |
451 | wl_display_roundtrip(bar->display); | 502 | wl_display_roundtrip(bar->display); |
452 | 503 | ||
453 | struct swaybar_output *output_tmp; | ||
454 | wl_list_for_each_safe(output, output_tmp, &bar->outputs, link) { | ||
455 | if (!bar_uses_output(bar, output->name)) { | ||
456 | zxdg_output_v1_destroy(output->xdg_output); | ||
457 | wl_output_destroy(output->output); | ||
458 | wl_list_remove(&output->link); | ||
459 | free(output); | ||
460 | } | ||
461 | } | ||
462 | |||
463 | struct swaybar_pointer *pointer = &bar->pointer; | 504 | struct swaybar_pointer *pointer = &bar->pointer; |
464 | 505 | ||
465 | int max_scale = 1; | 506 | int max_scale = 1; |
@@ -479,18 +520,6 @@ void bar_setup(struct swaybar *bar, | |||
479 | pointer->cursor_surface = wl_compositor_create_surface(bar->compositor); | 520 | pointer->cursor_surface = wl_compositor_create_surface(bar->compositor); |
480 | assert(pointer->cursor_surface); | 521 | assert(pointer->cursor_surface); |
481 | 522 | ||
482 | wl_list_for_each(output, &bar->outputs, link) { | ||
483 | output->surface = wl_compositor_create_surface(bar->compositor); | ||
484 | assert(output->surface); | ||
485 | output->layer_surface = zwlr_layer_shell_v1_get_layer_surface( | ||
486 | bar->layer_shell, output->surface, output->output, | ||
487 | ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM, "panel"); | ||
488 | assert(output->layer_surface); | ||
489 | zwlr_layer_surface_v1_add_listener(output->layer_surface, | ||
490 | &layer_surface_listener, output); | ||
491 | zwlr_layer_surface_v1_set_anchor(output->layer_surface, | ||
492 | bar->config->position); | ||
493 | } | ||
494 | ipc_get_workspaces(bar); | 523 | ipc_get_workspaces(bar); |
495 | render_all_frames(bar); | 524 | render_all_frames(bar); |
496 | } | 525 | } |
@@ -529,6 +558,7 @@ void bar_run(struct swaybar *bar) { | |||
529 | } | 558 | } |
530 | while (1) { | 559 | while (1) { |
531 | event_loop_poll(); | 560 | event_loop_poll(); |
561 | wl_display_flush(bar->display); | ||
532 | } | 562 | } |
533 | } | 563 | } |
534 | 564 | ||
diff --git a/swaybar/event_loop.c b/swaybar/event_loop.c index bc4053be..686b9962 100644 --- a/swaybar/event_loop.c +++ b/swaybar/event_loop.c | |||
@@ -105,7 +105,7 @@ bool remove_timer(timer_t timer) { | |||
105 | return false; | 105 | return false; |
106 | } | 106 | } |
107 | 107 | ||
108 | void event_loop_poll() { | 108 | void event_loop_poll(void) { |
109 | poll(event_loop.fds.items, event_loop.fds.length, -1); | 109 | poll(event_loop.fds.items, event_loop.fds.length, -1); |
110 | 110 | ||
111 | for (int i = 0; i < event_loop.fds.length; ++i) { | 111 | for (int i = 0; i < event_loop.fds.length; ++i) { |
@@ -146,7 +146,7 @@ void event_loop_poll() { | |||
146 | } | 146 | } |
147 | } | 147 | } |
148 | 148 | ||
149 | void init_event_loop() { | 149 | void init_event_loop(void) { |
150 | event_loop.fds.length = 0; | 150 | event_loop.fds.length = 0; |
151 | event_loop.fds.capacity = 10; | 151 | event_loop.fds.capacity = 10; |
152 | event_loop.fds.items = malloc( | 152 | event_loop.fds.items = malloc( |
diff --git a/swaybar/i3bar.c b/swaybar/i3bar.c index 0becae5d..325aa61a 100644 --- a/swaybar/i3bar.c +++ b/swaybar/i3bar.c | |||
@@ -1,6 +1,7 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | 1 | #define _POSIX_C_SOURCE 200809L |
2 | #include <json-c/json.h> | 2 | #include <json-c/json.h> |
3 | #include <linux/input-event-codes.h> | 3 | #include <linux/input-event-codes.h> |
4 | #include <ctype.h> | ||
4 | #include <stdlib.h> | 5 | #include <stdlib.h> |
5 | #include <string.h> | 6 | #include <string.h> |
6 | #include <unistd.h> | 7 | #include <unistd.h> |
@@ -24,24 +25,19 @@ void i3bar_block_unref(struct i3bar_block *block) { | |||
24 | } | 25 | } |
25 | } | 26 | } |
26 | 27 | ||
27 | static bool i3bar_parse_json(struct status_line *status, const char *text) { | 28 | static void i3bar_parse_json(struct status_line *status, |
29 | struct json_object *json_array) { | ||
28 | struct i3bar_block *block, *tmp; | 30 | struct i3bar_block *block, *tmp; |
29 | wl_list_for_each_safe(block, tmp, &status->blocks, link) { | 31 | wl_list_for_each_safe(block, tmp, &status->blocks, link) { |
30 | wl_list_remove(&block->link); | 32 | wl_list_remove(&block->link); |
31 | i3bar_block_unref(block); | 33 | i3bar_block_unref(block); |
32 | } | 34 | } |
33 | json_object *results = json_tokener_parse(text); | 35 | for (size_t i = 0; i < json_object_array_length(json_array); ++i) { |
34 | if (!results) { | ||
35 | status_error(status, "[failed to parse i3bar json]"); | ||
36 | return false; | ||
37 | } | ||
38 | wlr_log(WLR_DEBUG, "Got i3bar json: '%s'", text); | ||
39 | for (size_t i = 0; i < json_object_array_length(results); ++i) { | ||
40 | json_object *full_text, *short_text, *color, *min_width, *align, *urgent; | 36 | json_object *full_text, *short_text, *color, *min_width, *align, *urgent; |
41 | json_object *name, *instance, *separator, *separator_block_width; | 37 | json_object *name, *instance, *separator, *separator_block_width; |
42 | json_object *background, *border, *border_top, *border_bottom; | 38 | json_object *background, *border, *border_top, *border_bottom; |
43 | json_object *border_left, *border_right, *markup; | 39 | json_object *border_left, *border_right, *markup; |
44 | json_object *json = json_object_array_get_idx(results, i); | 40 | json_object *json = json_object_array_get_idx(json_array, i); |
45 | if (!json) { | 41 | if (!json) { |
46 | continue; | 42 | continue; |
47 | } | 43 | } |
@@ -110,96 +106,160 @@ static bool i3bar_parse_json(struct status_line *status, const char *text) { | |||
110 | json_object_get_int(border_right) : 1; | 106 | json_object_get_int(border_right) : 1; |
111 | wl_list_insert(&status->blocks, &block->link); | 107 | wl_list_insert(&status->blocks, &block->link); |
112 | } | 108 | } |
113 | json_object_put(results); | ||
114 | return true; | ||
115 | } | 109 | } |
116 | 110 | ||
117 | bool i3bar_handle_readable(struct status_line *status) { | 111 | bool i3bar_handle_readable(struct status_line *status) { |
118 | struct i3bar_protocol_state *state = &status->i3bar_state; | 112 | while (!status->started) { // look for opening bracket |
119 | 113 | for (size_t c = 0; c < status->buffer_index; ++c) { | |
120 | char *cur = &state->buffer[state->buffer_index]; | 114 | if (status->buffer[c] == '[') { |
121 | ssize_t n = read(status->read_fd, cur, | 115 | status->started = true; |
122 | state->buffer_size - state->buffer_index); | 116 | status->buffer_index -= ++c; |
123 | if (n == -1) { | 117 | memmove(status->buffer, &status->buffer[c], status->buffer_index); |
124 | status_error(status, "[failed to read from status command]"); | 118 | break; |
125 | return false; | 119 | } else if (!isspace(status->buffer[c])) { |
126 | } | 120 | wlr_log(WLR_DEBUG, "Invalid i3bar json: expected '[' but encountered '%c'", |
121 | status->buffer[c]); | ||
122 | status_error(status, "[invalid i3bar json]"); | ||
123 | return true; | ||
124 | } | ||
125 | } | ||
126 | if (status->started) { | ||
127 | break; | ||
128 | } | ||
127 | 129 | ||
128 | if (n == (ssize_t)(state->buffer_size - state->buffer_index)) { | 130 | errno = 0; |
129 | state->buffer_size = state->buffer_size * 2; | 131 | ssize_t read_bytes = read(status->read_fd, status->buffer, status->buffer_size); |
130 | char *new_buffer = realloc(state->buffer, state->buffer_size); | 132 | if (read_bytes > -1) { |
131 | if (!new_buffer) { | 133 | status->buffer_index = read_bytes; |
132 | free(state->buffer); | 134 | } else if (errno == EAGAIN) { |
133 | status_error(status, "[failed to allocate buffer]"); | 135 | return false; |
136 | } else { | ||
137 | status_error(status, "[error reading from status command]"); | ||
134 | return true; | 138 | return true; |
135 | } | 139 | } |
136 | state->current_node += new_buffer - state->buffer; | ||
137 | cur += new_buffer - state->buffer; | ||
138 | state->buffer = new_buffer; | ||
139 | } | 140 | } |
140 | 141 | ||
141 | cur[n] = '\0'; | 142 | struct json_object *last_object = NULL; |
142 | bool redraw = false; | 143 | struct json_object *test_object; |
143 | while (*cur) { | 144 | size_t buffer_pos = 0; |
144 | if (state->nodes[state->depth] == JSON_NODE_STRING) { | 145 | while (true) { |
145 | if (!state->escape && *cur == '"') { | 146 | // since the incoming stream is an infinite array |
146 | --state->depth; | 147 | // parsing is split into two parts |
148 | // first, attempt to parse the current object, reading more if the | ||
149 | // parser indicates that the current object is incomplete, and failing | ||
150 | // if the parser fails | ||
151 | // second, look for separating comma, ignoring whitespace, failing if | ||
152 | // any other characters are encountered | ||
153 | if (status->expecting_comma) { | ||
154 | for (; buffer_pos < status->buffer_index; ++buffer_pos) { | ||
155 | if (status->buffer[buffer_pos] == ',') { | ||
156 | status->expecting_comma = false; | ||
157 | ++buffer_pos; | ||
158 | break; | ||
159 | } else if (!isspace(status->buffer[buffer_pos])) { | ||
160 | wlr_log(WLR_DEBUG, "Invalid i3bar json: expected ',' but encountered '%c'", | ||
161 | status->buffer[buffer_pos]); | ||
162 | status_error(status, "[invalid i3bar json]"); | ||
163 | return true; | ||
164 | } | ||
165 | } | ||
166 | if (buffer_pos < status->buffer_index) { | ||
167 | continue; // look for new object without reading more input | ||
147 | } | 168 | } |
148 | state->escape = !state->escape && *cur == '\\'; | 169 | buffer_pos = status->buffer_index = 0; |
149 | } else { | 170 | } else { |
150 | switch (*cur) { | 171 | test_object = json_tokener_parse_ex(status->tokener, |
151 | case '[': | 172 | &status->buffer[buffer_pos], status->buffer_index - buffer_pos); |
152 | ++state->depth; | 173 | enum json_tokener_error err = json_tokener_get_error(status->tokener); |
153 | if (state->depth > | 174 | if (err == json_tokener_success) { |
154 | sizeof(state->nodes) / sizeof(state->nodes[0])) { | 175 | if (json_object_get_type(test_object) == json_type_array) { |
155 | status_error(status, "[i3bar json too deep]"); | 176 | if (last_object) { |
156 | return false; | 177 | json_object_put(last_object); |
157 | } | 178 | } |
158 | state->nodes[state->depth] = JSON_NODE_ARRAY; | 179 | last_object = test_object; |
159 | if (state->depth == 1) { | 180 | } else { |
160 | state->current_node = cur; | 181 | json_object_put(test_object); |
161 | } | 182 | } |
162 | break; | 183 | |
163 | case ']': | 184 | // in order to print the json for debugging purposes |
164 | if (state->nodes[state->depth] != JSON_NODE_ARRAY) { | 185 | // the last character is temporarily replaced with a null character |
165 | status_error(status, "[failed to parse i3bar json]"); | 186 | // (the last character is used in case the buffer is full) |
166 | return false; | 187 | char *last_char_pos = |
188 | &status->buffer[buffer_pos + status->tokener->char_offset - 1]; | ||
189 | char last_char = *last_char_pos; | ||
190 | while (isspace(last_char)) { | ||
191 | last_char = *--last_char_pos; | ||
167 | } | 192 | } |
168 | --state->depth; | 193 | *last_char_pos = '\0'; |
169 | if (state->depth == 0) { | 194 | size_t offset = strspn(&status->buffer[buffer_pos], " \f\n\r\t\v"); |
170 | // cur[1] is valid since cur[0] != '\0' | 195 | wlr_log(WLR_DEBUG, "Received i3bar json: '%s%c'", |
171 | char p = cur[1]; | 196 | &status->buffer[buffer_pos + offset], last_char); |
172 | cur[1] = '\0'; | 197 | *last_char_pos = last_char; |
173 | redraw = i3bar_parse_json( | 198 | |
174 | status, state->current_node) || redraw; | 199 | buffer_pos += status->tokener->char_offset; |
175 | cur[1] = p; | 200 | status->expecting_comma = true; |
176 | memmove(state->buffer, cur, | 201 | |
177 | state->buffer_size - (cur - state->buffer)); | 202 | if (buffer_pos < status->buffer_index) { |
178 | cur = state->buffer; | 203 | continue; // look for comma without reading more input |
179 | state->current_node = cur + 1; | ||
180 | } | 204 | } |
181 | break; | 205 | buffer_pos = status->buffer_index = 0; |
182 | case '"': | 206 | } else if (err == json_tokener_continue) { |
183 | ++state->depth; | 207 | json_tokener_reset(status->tokener); |
184 | if (state->depth > | 208 | if (status->buffer_index < status->buffer_size) { |
185 | sizeof(state->nodes) / sizeof(state->nodes[0])) { | 209 | // move the object to the start of the buffer |
186 | status_error(status, "[i3bar json too deep]"); | 210 | status->buffer_index -= buffer_pos; |
187 | return false; | 211 | memmove(status->buffer, &status->buffer[buffer_pos], |
212 | status->buffer_index); | ||
213 | buffer_pos = 0; | ||
214 | } else { | ||
215 | // expand buffer | ||
216 | status->buffer_size *= 2; | ||
217 | char *new_buffer = realloc(status->buffer, status->buffer_size); | ||
218 | if (new_buffer) { | ||
219 | status->buffer = new_buffer; | ||
220 | } else { | ||
221 | free(status->buffer); | ||
222 | status_error(status, "[failed to allocate buffer]"); | ||
223 | return true; | ||
224 | } | ||
188 | } | 225 | } |
189 | state->nodes[state->depth] = JSON_NODE_STRING; | 226 | } else { |
190 | break; | 227 | char last_char = status->buffer[status->buffer_index - 1]; |
228 | status->buffer[status->buffer_index - 1] = '\0'; | ||
229 | wlr_log(WLR_DEBUG, "Failed to parse i3bar json - %s: '%s%c'", | ||
230 | json_tokener_error_desc(err), &status->buffer[buffer_pos], last_char); | ||
231 | status_error(status, "[failed to parse i3bar json]"); | ||
232 | return true; | ||
191 | } | 233 | } |
192 | } | 234 | } |
193 | ++cur; | 235 | |
236 | errno = 0; | ||
237 | ssize_t read_bytes = read(status->read_fd, &status->buffer[status->buffer_index], | ||
238 | status->buffer_size - status->buffer_index); | ||
239 | if (read_bytes > -1) { | ||
240 | status->buffer_index += read_bytes; | ||
241 | } else if (errno == EAGAIN) { | ||
242 | break; | ||
243 | } else { | ||
244 | status_error(status, "[error reading from status command]"); | ||
245 | return true; | ||
246 | } | ||
247 | } | ||
248 | |||
249 | if (last_object) { | ||
250 | wlr_log(WLR_DEBUG, "Rendering last received json"); | ||
251 | i3bar_parse_json(status, last_object); | ||
252 | json_object_put(last_object); | ||
253 | return true; | ||
254 | } else { | ||
255 | return false; | ||
194 | } | 256 | } |
195 | state->buffer_index = cur - state->buffer; | ||
196 | return redraw; | ||
197 | } | 257 | } |
198 | 258 | ||
199 | enum hotspot_event_handling i3bar_block_send_click(struct status_line *status, | 259 | enum hotspot_event_handling i3bar_block_send_click(struct status_line *status, |
200 | struct i3bar_block *block, int x, int y, enum x11_button button) { | 260 | struct i3bar_block *block, int x, int y, enum x11_button button) { |
201 | wlr_log(WLR_DEBUG, "block %s clicked", block->name ? block->name : "(nil)"); | 261 | wlr_log(WLR_DEBUG, "block %s clicked", block->name ? block->name : "(nil)"); |
202 | if (!block->name || !status->i3bar_state.click_events) { | 262 | if (!block->name || !status->click_events) { |
203 | return HOTSPOT_PROCESS; | 263 | return HOTSPOT_PROCESS; |
204 | } | 264 | } |
205 | 265 | ||
@@ -214,7 +274,7 @@ enum hotspot_event_handling i3bar_block_send_click(struct status_line *status, | |||
214 | json_object_object_add(event_json, "button", json_object_new_int(button)); | 274 | json_object_object_add(event_json, "button", json_object_new_int(button)); |
215 | json_object_object_add(event_json, "x", json_object_new_int(x)); | 275 | json_object_object_add(event_json, "x", json_object_new_int(x)); |
216 | json_object_object_add(event_json, "y", json_object_new_int(y)); | 276 | json_object_object_add(event_json, "y", json_object_new_int(y)); |
217 | if (dprintf(status->write_fd, "%s\n", | 277 | if (dprintf(status->write_fd, "%s,\n", |
218 | json_object_to_json_string(event_json)) < 0) { | 278 | json_object_to_json_string(event_json)) < 0) { |
219 | status_error(status, "[failed to write click event]"); | 279 | status_error(status, "[failed to write click event]"); |
220 | } | 280 | } |
diff --git a/swaybar/render.c b/swaybar/render.c index 2d848bfa..26db80cb 100644 --- a/swaybar/render.c +++ b/swaybar/render.c | |||
@@ -1,4 +1,5 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | 1 | #define _POSIX_C_SOURCE 200809L |
2 | #include <assert.h> | ||
2 | #include <limits.h> | 3 | #include <limits.h> |
3 | #include <stdlib.h> | 4 | #include <stdlib.h> |
4 | #include <stdint.h> | 5 | #include <stdint.h> |
@@ -120,14 +121,14 @@ static void i3bar_block_unref_callback(void *data) { | |||
120 | } | 121 | } |
121 | 122 | ||
122 | static uint32_t render_status_block(cairo_t *cairo, | 123 | static uint32_t render_status_block(cairo_t *cairo, |
123 | struct swaybar_config *config, struct swaybar_output *output, | 124 | struct swaybar_output *output, struct i3bar_block *block, double *x, |
124 | struct i3bar_block *block, double *x, | ||
125 | uint32_t surface_height, bool focused, bool edge) { | 125 | uint32_t surface_height, bool focused, bool edge) { |
126 | if (!block->full_text || !*block->full_text) { | 126 | if (!block->full_text || !*block->full_text) { |
127 | return 0; | 127 | return 0; |
128 | } | 128 | } |
129 | 129 | ||
130 | uint32_t height = surface_height * output->scale; | 130 | uint32_t height = surface_height * output->scale; |
131 | struct swaybar_config *config = output->bar->config; | ||
131 | 132 | ||
132 | int text_width, text_height; | 133 | int text_width, text_height; |
133 | get_text_size(cairo, config->font, &text_width, &text_height, NULL, | 134 | get_text_size(cairo, config->font, &text_width, &text_height, NULL, |
@@ -177,16 +178,18 @@ static uint32_t render_status_block(cairo_t *cairo, | |||
177 | *x -= margin; | 178 | *x -= margin; |
178 | } | 179 | } |
179 | 180 | ||
180 | struct swaybar_hotspot *hotspot = calloc(1, sizeof(struct swaybar_hotspot)); | 181 | if (output->bar->status->click_events) { |
181 | hotspot->x = *x; | 182 | struct swaybar_hotspot *hotspot = calloc(1, sizeof(struct swaybar_hotspot)); |
182 | hotspot->y = 0; | 183 | hotspot->x = *x; |
183 | hotspot->width = width; | 184 | hotspot->y = 0; |
184 | hotspot->height = height; | 185 | hotspot->width = width; |
185 | hotspot->callback = block_hotspot_callback; | 186 | hotspot->height = height; |
186 | hotspot->destroy = i3bar_block_unref_callback; | 187 | hotspot->callback = block_hotspot_callback; |
187 | hotspot->data = block; | 188 | hotspot->destroy = i3bar_block_unref_callback; |
188 | block->ref_count++; | 189 | hotspot->data = block; |
189 | wl_list_insert(&output->hotspots, &hotspot->link); | 190 | block->ref_count++; |
191 | wl_list_insert(&output->hotspots, &hotspot->link); | ||
192 | } | ||
190 | 193 | ||
191 | double pos = *x; | 194 | double pos = *x; |
192 | if (block->background) { | 195 | if (block->background) { |
@@ -268,7 +271,7 @@ static uint32_t render_status_line_i3bar(cairo_t *cairo, | |||
268 | bool edge = true; | 271 | bool edge = true; |
269 | struct i3bar_block *block; | 272 | struct i3bar_block *block; |
270 | wl_list_for_each(block, &status->blocks, link) { | 273 | wl_list_for_each(block, &status->blocks, link) { |
271 | uint32_t h = render_status_block(cairo, config, output, | 274 | uint32_t h = render_status_block(cairo, output, |
272 | block, x, surface_height, focused, edge); | 275 | block, x, surface_height, focused, edge); |
273 | max_height = h > max_height ? h : max_height; | 276 | max_height = h > max_height ? h : max_height; |
274 | edge = false; | 277 | edge = false; |
@@ -478,6 +481,8 @@ static uint32_t render_to_cairo(cairo_t *cairo, | |||
478 | } | 481 | } |
479 | 482 | ||
480 | void render_frame(struct swaybar *bar, struct swaybar_output *output) { | 483 | void render_frame(struct swaybar *bar, struct swaybar_output *output) { |
484 | assert(output->surface != NULL); | ||
485 | |||
481 | struct swaybar_hotspot *hotspot, *tmp; | 486 | struct swaybar_hotspot *hotspot, *tmp; |
482 | wl_list_for_each_safe(hotspot, tmp, &output->hotspots, link) { | 487 | wl_list_for_each_safe(hotspot, tmp, &output->hotspots, link) { |
483 | if (hotspot->destroy) { | 488 | if (hotspot->destroy) { |
@@ -505,7 +510,6 @@ void render_frame(struct swaybar *bar, struct swaybar_output *output) { | |||
505 | // TODO: this could infinite loop if the compositor assigns us a | 510 | // TODO: this could infinite loop if the compositor assigns us a |
506 | // different height than what we asked for | 511 | // different height than what we asked for |
507 | wl_surface_commit(output->surface); | 512 | wl_surface_commit(output->surface); |
508 | wl_display_roundtrip(bar->display); | ||
509 | } else if (height > 0) { | 513 | } else if (height > 0) { |
510 | // Replay recording into shm and send it off | 514 | // Replay recording into shm and send it off |
511 | output->current_buffer = get_next_buffer(bar->shm, | 515 | output->current_buffer = get_next_buffer(bar->shm, |
@@ -531,7 +535,6 @@ void render_frame(struct swaybar *bar, struct swaybar_output *output) { | |||
531 | wl_surface_damage(output->surface, 0, 0, | 535 | wl_surface_damage(output->surface, 0, 0, |
532 | output->width, output->height); | 536 | output->width, output->height); |
533 | wl_surface_commit(output->surface); | 537 | wl_surface_commit(output->surface); |
534 | wl_display_roundtrip(bar->display); | ||
535 | } | 538 | } |
536 | cairo_surface_destroy(recorder); | 539 | cairo_surface_destroy(recorder); |
537 | cairo_destroy(cairo); | 540 | cairo_destroy(cairo); |
diff --git a/swaybar/status_line.c b/swaybar/status_line.c index 3ba990bd..48b43248 100644 --- a/swaybar/status_line.c +++ b/swaybar/status_line.c | |||
@@ -7,86 +7,106 @@ | |||
7 | #include <unistd.h> | 7 | #include <unistd.h> |
8 | #include <wlr/util/log.h> | 8 | #include <wlr/util/log.h> |
9 | #include "swaybar/config.h" | 9 | #include "swaybar/config.h" |
10 | #include "swaybar/event_loop.h" | ||
10 | #include "swaybar/status_line.h" | 11 | #include "swaybar/status_line.h" |
11 | #include "readline.h" | 12 | #include "readline.h" |
12 | 13 | ||
14 | static void status_line_close_fds(struct status_line *status) { | ||
15 | if (status->read_fd != -1) { | ||
16 | remove_event(status->read_fd); | ||
17 | close(status->read_fd); | ||
18 | status->read_fd = -1; | ||
19 | } | ||
20 | if (status->write_fd != -1) { | ||
21 | close(status->write_fd); | ||
22 | status->write_fd = -1; | ||
23 | } | ||
24 | } | ||
25 | |||
13 | void status_error(struct status_line *status, const char *text) { | 26 | void status_error(struct status_line *status, const char *text) { |
14 | close(status->read_fd); | 27 | status_line_close_fds(status); |
15 | close(status->write_fd); | ||
16 | status->protocol = PROTOCOL_ERROR; | 28 | status->protocol = PROTOCOL_ERROR; |
17 | status->text = text; | 29 | status->text = text; |
18 | } | 30 | } |
19 | 31 | ||
20 | bool status_handle_readable(struct status_line *status) { | 32 | bool status_handle_readable(struct status_line *status) { |
21 | char *line; | 33 | ssize_t read_bytes = 1; |
22 | switch (status->protocol) { | 34 | switch (status->protocol) { |
23 | case PROTOCOL_ERROR: | ||
24 | return false; | ||
25 | case PROTOCOL_I3BAR: | ||
26 | if (i3bar_handle_readable(status) > 0) { | ||
27 | return true; | ||
28 | } | ||
29 | break; | ||
30 | case PROTOCOL_TEXT: | ||
31 | line = read_line_buffer(status->read, | ||
32 | status->text_state.buffer, status->text_state.buffer_size); | ||
33 | if (!line) { | ||
34 | status_error(status, "[error reading from status command]"); | ||
35 | } else { | ||
36 | status->text = line; | ||
37 | } | ||
38 | return true; | ||
39 | case PROTOCOL_UNDEF: | 35 | case PROTOCOL_UNDEF: |
40 | line = read_line_buffer(status->read, | 36 | errno = 0; |
41 | status->text_state.buffer, status->text_state.buffer_size); | 37 | read_bytes = getline(&status->buffer, |
42 | if (!line) { | 38 | &status->buffer_size, status->read); |
39 | if (errno == EAGAIN) { | ||
40 | clearerr(status->read); | ||
41 | } else if (errno) { | ||
43 | status_error(status, "[error reading from status command]"); | 42 | status_error(status, "[error reading from status command]"); |
44 | return false; | 43 | return true; |
45 | } | 44 | } |
46 | if (line[0] == '{') { | 45 | |
47 | json_object *proto = json_tokener_parse(line); | 46 | // the header must be sent completely the first time round |
48 | if (proto) { | 47 | json_object *header, *version; |
49 | json_object *version; | 48 | if (status->buffer[read_bytes - 1] == '\n' |
50 | if (json_object_object_get_ex(proto, "version", &version) | 49 | && (header = json_tokener_parse(status->buffer)) |
51 | && json_object_get_int(version) == 1) { | 50 | && json_object_object_get_ex(header, "version", &version) |
52 | wlr_log(WLR_DEBUG, "Switched to i3bar protocol."); | 51 | && json_object_get_int(version) == 1) { |
53 | status->protocol = PROTOCOL_I3BAR; | 52 | wlr_log(WLR_DEBUG, "Using i3bar protocol."); |
54 | } | 53 | status->protocol = PROTOCOL_I3BAR; |
55 | json_object *click_events; | 54 | |
56 | if (json_object_object_get_ex( | 55 | json_object *click_events; |
57 | proto, "click_events", &click_events) | 56 | if (json_object_object_get_ex(header, "click_events", &click_events) |
58 | && json_object_get_boolean(click_events)) { | 57 | && json_object_get_boolean(click_events)) { |
59 | wlr_log(WLR_DEBUG, "Enabled click events."); | 58 | wlr_log(WLR_DEBUG, "Enabling click events."); |
60 | status->i3bar_state.click_events = true; | 59 | status->click_events = true; |
61 | const char *events_array = "[\n"; | 60 | if (write(status->write_fd, "[\n", 2) != 2) { |
62 | ssize_t len = strlen(events_array); | 61 | status_error(status, "[failed to write to status command]"); |
63 | if (write(status->write_fd, events_array, len) != len) { | 62 | json_object_put(header); |
64 | status_error(status, | 63 | return true; |
65 | "[failed to write to status command]"); | ||
66 | } | ||
67 | } | 64 | } |
68 | json_object_put(proto); | ||
69 | } | 65 | } |
66 | json_object_put(header); | ||
70 | 67 | ||
71 | status->protocol = PROTOCOL_I3BAR; | ||
72 | free(status->text_state.buffer); | ||
73 | wl_list_init(&status->blocks); | 68 | wl_list_init(&status->blocks); |
74 | status->i3bar_state.buffer_size = 4096; | 69 | status->tokener = json_tokener_new(); |
75 | status->i3bar_state.buffer = | 70 | read_bytes = getdelim(&status->buffer, &status->buffer_size, EOF, status->read); |
76 | malloc(status->i3bar_state.buffer_size); | 71 | if (read_bytes > 0) { |
77 | } else { | 72 | status->buffer_index = read_bytes; |
78 | status->protocol = PROTOCOL_TEXT; | 73 | return i3bar_handle_readable(status); |
79 | status->text = line; | 74 | } else { |
75 | return false; | ||
76 | } | ||
77 | } | ||
78 | |||
79 | wlr_log(WLR_DEBUG, "Using text protocol."); | ||
80 | status->protocol = PROTOCOL_TEXT; | ||
81 | status->text = status->buffer; | ||
82 | // intentional fall-through | ||
83 | case PROTOCOL_TEXT: | ||
84 | errno = 0; | ||
85 | while (true) { | ||
86 | if (status->buffer[read_bytes - 1] == '\n') { | ||
87 | status->buffer[read_bytes - 1] = '\0'; | ||
88 | } | ||
89 | read_bytes = getline(&status->buffer, | ||
90 | &status->buffer_size, status->read); | ||
91 | if (errno == EAGAIN) { | ||
92 | clearerr(status->read); | ||
93 | return true; | ||
94 | } else if (errno) { | ||
95 | status_error(status, "[error reading from status command]"); | ||
96 | return true; | ||
97 | } | ||
80 | } | 98 | } |
81 | return true; | 99 | case PROTOCOL_I3BAR: |
100 | return i3bar_handle_readable(status); | ||
101 | default: | ||
102 | return false; | ||
82 | } | 103 | } |
83 | return false; | ||
84 | } | 104 | } |
85 | 105 | ||
86 | struct status_line *status_line_init(char *cmd) { | 106 | struct status_line *status_line_init(char *cmd) { |
87 | struct status_line *status = calloc(1, sizeof(struct status_line)); | 107 | struct status_line *status = calloc(1, sizeof(struct status_line)); |
88 | status->text_state.buffer_size = 8192; | 108 | status->buffer_size = 8192; |
89 | status->text_state.buffer = malloc(status->text_state.buffer_size); | 109 | status->buffer = malloc(status->buffer_size); |
90 | 110 | ||
91 | int pipe_read_fd[2]; | 111 | int pipe_read_fd[2]; |
92 | int pipe_write_fd[2]; | 112 | int pipe_write_fd[2]; |
@@ -123,20 +143,16 @@ struct status_line *status_line_init(char *cmd) { | |||
123 | } | 143 | } |
124 | 144 | ||
125 | void status_line_free(struct status_line *status) { | 145 | void status_line_free(struct status_line *status) { |
126 | close(status->read_fd); | 146 | status_line_close_fds(status); |
127 | close(status->write_fd); | ||
128 | kill(status->pid, SIGTERM); | 147 | kill(status->pid, SIGTERM); |
129 | switch (status->protocol) { | 148 | if (status->protocol == PROTOCOL_I3BAR) { |
130 | case PROTOCOL_I3BAR:; | ||
131 | struct i3bar_block *block, *tmp; | 149 | struct i3bar_block *block, *tmp; |
132 | wl_list_for_each_safe(block, tmp, &status->blocks, link) { | 150 | wl_list_for_each_safe(block, tmp, &status->blocks, link) { |
151 | wl_list_remove(&block->link); | ||
133 | i3bar_block_unref(block); | 152 | i3bar_block_unref(block); |
134 | } | 153 | } |
135 | free(status->i3bar_state.buffer); | 154 | json_tokener_free(status->tokener); |
136 | break; | ||
137 | default: | ||
138 | free(status->text_state.buffer); | ||
139 | break; | ||
140 | } | 155 | } |
156 | free(status->buffer); | ||
141 | free(status); | 157 | free(status); |
142 | } | 158 | } |