summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Drew DeVault <sir@cmpwn.com>2018-04-02 14:23:01 -0400
committerLibravatar GitHub <noreply@github.com>2018-04-02 14:23:01 -0400
commit4134407fa967c7f45cd09554b74a15f28974fca5 (patch)
treea1a6122d927b95b29375af7dbf6adccd8cb4e71f
parentMerge pull request #1697 from RedSoxFan/back-and-forth (diff)
parentRender blocks the correct order (diff)
downloadsway-4134407fa967c7f45cd09554b74a15f28974fca5.tar.gz
sway-4134407fa967c7f45cd09554b74a15f28974fca5.tar.zst
sway-4134407fa967c7f45cd09554b74a15f28974fca5.zip
Merge pull request #1690 from swaywm/i3bar-json
I3bar json
-rw-r--r--common/pango.c9
-rw-r--r--include/swaybar/ipc.h2
-rw-r--r--include/swaybar/status_line.h53
-rw-r--r--sway/tree/layout.c4
-rw-r--r--swaybar/bar.c4
-rw-r--r--swaybar/i3bar.c208
-rw-r--r--swaybar/ipc.c2
-rw-r--r--swaybar/meson.build1
-rw-r--r--swaybar/render.c238
-rw-r--r--swaybar/status_line.c65
10 files changed, 546 insertions, 40 deletions
diff --git a/common/pango.c b/common/pango.c
index 2ae7883c..658d2876 100644
--- a/common/pango.c
+++ b/common/pango.c
@@ -6,6 +6,7 @@
6#include <stdio.h> 6#include <stdio.h>
7#include <stdlib.h> 7#include <stdlib.h>
8#include <string.h> 8#include <string.h>
9#include "log.h"
9 10
10PangoLayout *get_pango_layout(cairo_t *cairo, const char *font, 11PangoLayout *get_pango_layout(cairo_t *cairo, const char *font,
11 const char *text, int32_t scale, bool markup) { 12 const char *text, int32_t scale, bool markup) {
@@ -13,7 +14,13 @@ PangoLayout *get_pango_layout(cairo_t *cairo, const char *font,
13 PangoAttrList *attrs; 14 PangoAttrList *attrs;
14 if (markup) { 15 if (markup) {
15 char *buf; 16 char *buf;
16 pango_parse_markup(text, -1, 0, &attrs, &buf, NULL, NULL); 17 GError *error = NULL;
18 if (!sway_assert(pango_parse_markup(
19 text, -1, 0, &attrs, &buf, NULL, &error),
20 "pango_parse_markup '%s' -> error %s", text,
21 error ? error->message : NULL)) {
22 return NULL;
23 }
17 pango_layout_set_markup(layout, buf, -1); 24 pango_layout_set_markup(layout, buf, -1);
18 free(buf); 25 free(buf);
19 } else { 26 } else {
diff --git a/include/swaybar/ipc.h b/include/swaybar/ipc.h
index 6ea7c4d6..a1696bcf 100644
--- a/include/swaybar/ipc.h
+++ b/include/swaybar/ipc.h
@@ -4,7 +4,7 @@
4#include "swaybar/bar.h" 4#include "swaybar/bar.h"
5 5
6void ipc_initialize(struct swaybar *bar, const char *bar_id); 6void ipc_initialize(struct swaybar *bar, const char *bar_id);
7bool handle_ipc_event(struct swaybar *bar); 7bool handle_ipc_readable(struct swaybar *bar);
8void ipc_get_workspaces(struct swaybar *bar); 8void ipc_get_workspaces(struct swaybar *bar);
9void ipc_send_workspace_command(struct swaybar *bar, const char *ws); 9void ipc_send_workspace_command(struct swaybar *bar, const char *ws);
10 10
diff --git a/include/swaybar/status_line.h b/include/swaybar/status_line.h
index 6c595df0..3538f49c 100644
--- a/include/swaybar/status_line.h
+++ b/include/swaybar/status_line.h
@@ -7,10 +7,52 @@
7 7
8enum status_protocol { 8enum status_protocol {
9 PROTOCOL_UNDEF, 9 PROTOCOL_UNDEF,
10 PROTOCOL_ERROR,
10 PROTOCOL_TEXT, 11 PROTOCOL_TEXT,
11 PROTOCOL_I3BAR, 12 PROTOCOL_I3BAR,
12}; 13};
13 14
15struct text_protocol_state {
16 char *buffer;
17 size_t buffer_size;
18};
19
20enum json_node_type {
21 JSON_NODE_UNKNOWN,
22 JSON_NODE_ARRAY,
23 JSON_NODE_STRING,
24};
25
26struct 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
37struct i3bar_block {
38 struct wl_list link;
39 char *full_text, *short_text, *align;
40 bool urgent;
41 uint32_t *color;
42 int min_width;
43 char *name, *instance;
44 bool separator;
45 int separator_block_width;
46 bool markup;
47 // Airblader features
48 uint32_t background;
49 uint32_t border;
50 int border_top;
51 int border_bottom;
52 int border_left;
53 int border_right;
54};
55
14struct status_line { 56struct status_line {
15 pid_t pid; 57 pid_t pid;
16 int read_fd, write_fd; 58 int read_fd, write_fd;
@@ -18,13 +60,18 @@ struct status_line {
18 60
19 enum status_protocol protocol; 61 enum status_protocol protocol;
20 const char *text; 62 const char *text;
63 struct wl_list blocks; // i3bar_block::link
21 64
22 char *buffer; 65 struct text_protocol_state text_state;
23 size_t buffer_size; 66 struct i3bar_protocol_state i3bar_state;
24}; 67};
25 68
26struct status_line *status_line_init(char *cmd); 69struct status_line *status_line_init(char *cmd);
70void status_error(struct status_line *status, const char *text);
71bool status_handle_readable(struct status_line *status);
27void status_line_free(struct status_line *status); 72void status_line_free(struct status_line *status);
28bool handle_status_readable(struct status_line *status); 73bool i3bar_handle_readable(struct status_line *status);
74void i3bar_block_send_click(struct status_line *status,
75 struct i3bar_block *block, int x, int y, uint32_t button);
29 76
30#endif 77#endif
diff --git a/sway/tree/layout.c b/sway/tree/layout.c
index a8941a40..de210752 100644
--- a/sway/tree/layout.c
+++ b/sway/tree/layout.c
@@ -274,8 +274,8 @@ void arrange_windows(struct sway_container *container,
274 struct wlr_box *area = &output->sway_output->usable_area; 274 struct wlr_box *area = &output->sway_output->usable_area;
275 wlr_log(L_DEBUG, "Usable area for ws: %dx%d@%d,%d", 275 wlr_log(L_DEBUG, "Usable area for ws: %dx%d@%d,%d",
276 area->width, area->height, area->x, area->y); 276 area->width, area->height, area->x, area->y);
277 container->width = area->width; 277 container->width = width = area->width;
278 container->height = area->height; 278 container->height = height = area->height;
279 container->x = x = area->x; 279 container->x = x = area->x;
280 container->y = y = area->y; 280 container->y = y = area->y;
281 wlr_log(L_DEBUG, "Arranging workspace '%s' at %f, %f", 281 wlr_log(L_DEBUG, "Arranging workspace '%s' at %f, %f",
diff --git a/swaybar/bar.c b/swaybar/bar.c
index f743236c..fb417095 100644
--- a/swaybar/bar.c
+++ b/swaybar/bar.c
@@ -308,14 +308,14 @@ static void display_in(int fd, short mask, void *_bar) {
308 308
309static void ipc_in(int fd, short mask, void *_bar) { 309static void ipc_in(int fd, short mask, void *_bar) {
310 struct swaybar *bar = (struct swaybar *)_bar; 310 struct swaybar *bar = (struct swaybar *)_bar;
311 if (handle_ipc_event(bar)) { 311 if (handle_ipc_readable(bar)) {
312 render_all_frames(bar); 312 render_all_frames(bar);
313 } 313 }
314} 314}
315 315
316static void status_in(int fd, short mask, void *_bar) { 316static void status_in(int fd, short mask, void *_bar) {
317 struct swaybar *bar = (struct swaybar *)_bar; 317 struct swaybar *bar = (struct swaybar *)_bar;
318 if (handle_status_readable(bar->status)) { 318 if (status_handle_readable(bar->status)) {
319 render_all_frames(bar); 319 render_all_frames(bar);
320 } 320 }
321} 321}
diff --git a/swaybar/i3bar.c b/swaybar/i3bar.c
new file mode 100644
index 00000000..46459e24
--- /dev/null
+++ b/swaybar/i3bar.c
@@ -0,0 +1,208 @@
1#define _POSIX_C_SOURCE 200809L
2#include <json-c/json.h>
3#include <stdlib.h>
4#include <string.h>
5#include <unistd.h>
6#include <wlr/util/log.h>
7#include "swaybar/config.h"
8#include "swaybar/status_line.h"
9
10static void i3bar_block_free(struct i3bar_block *block) {
11 if (!block) {
12 return;
13 }
14 wl_list_remove(&block->link);
15 free(block->full_text);
16 free(block->short_text);
17 free(block->align);
18 free(block->name);
19 free(block->instance);
20 free(block->color);
21}
22
23static bool i3bar_parse_json(struct status_line *status, const char *text) {
24 struct i3bar_block *block, *tmp;
25 wl_list_for_each_safe(block, tmp, &status->blocks, link) {
26 i3bar_block_free(block);
27 }
28 json_object *results = json_tokener_parse(text);
29 if (!results) {
30 status_error(status, "[failed to parse i3bar json]");
31 return false;
32 }
33 wlr_log(L_DEBUG, "Got i3bar json: '%s'", text);
34 for (size_t i = 0; i < json_object_array_length(results); ++i) {
35 json_object *full_text, *short_text, *color, *min_width, *align, *urgent;
36 json_object *name, *instance, *separator, *separator_block_width;
37 json_object *background, *border, *border_top, *border_bottom;
38 json_object *border_left, *border_right, *markup;
39 json_object *json = json_object_array_get_idx(results, i);
40 if (!json) {
41 continue;
42 }
43 json_object_object_get_ex(json, "full_text", &full_text);
44 json_object_object_get_ex(json, "short_text", &short_text);
45 json_object_object_get_ex(json, "color", &color);
46 json_object_object_get_ex(json, "min_width", &min_width);
47 json_object_object_get_ex(json, "align", &align);
48 json_object_object_get_ex(json, "urgent", &urgent);
49 json_object_object_get_ex(json, "name", &name);
50 json_object_object_get_ex(json, "instance", &instance);
51 json_object_object_get_ex(json, "markup", &markup);
52 json_object_object_get_ex(json, "separator", &separator);
53 json_object_object_get_ex(json, "separator_block_width", &separator_block_width);
54 json_object_object_get_ex(json, "background", &background);
55 json_object_object_get_ex(json, "border", &border);
56 json_object_object_get_ex(json, "border_top", &border_top);
57 json_object_object_get_ex(json, "border_bottom", &border_bottom);
58 json_object_object_get_ex(json, "border_left", &border_left);
59 json_object_object_get_ex(json, "border_right", &border_right);
60
61 struct i3bar_block *block = calloc(1, sizeof(struct i3bar_block));
62 block->full_text = full_text ?
63 strdup(json_object_get_string(full_text)) : NULL;
64 block->short_text = short_text ?
65 strdup(json_object_get_string(short_text)) : NULL;
66 if (color) {
67 block->color = malloc(sizeof(uint32_t));
68 *block->color = parse_color(json_object_get_string(color));
69 }
70 if (min_width) {
71 json_type type = json_object_get_type(min_width);
72 if (type == json_type_int) {
73 block->min_width = json_object_get_int(min_width);
74 } else if (type == json_type_string) {
75 /* the width will be calculated when rendering */
76 block->min_width = 0;
77 }
78 }
79 block->align = strdup(align ? json_object_get_string(align) : "left");
80 block->urgent = urgent ? json_object_get_int(urgent) : false;
81 block->name = name ? strdup(json_object_get_string(name)) : NULL;
82 block->instance = instance ?
83 strdup(json_object_get_string(instance)) : NULL;
84 if (markup) {
85 block->markup = false;
86 const char *markup_str = json_object_get_string(markup);
87 if (strcmp(markup_str, "pango") == 0) {
88 block->markup = true;
89 }
90 }
91 block->separator = separator ? json_object_get_int(separator) : true;
92 block->separator_block_width = separator_block_width ?
93 json_object_get_int(separator_block_width) : 9;
94 // Airblader features
95 block->background = background ?
96 parse_color(json_object_get_string(background)) : 0;
97 block->border = border ?
98 parse_color(json_object_get_string(border)) : 0;
99 block->border_top = border_top ? json_object_get_int(border_top) : 1;
100 block->border_bottom = border_bottom ?
101 json_object_get_int(border_bottom) : 1;
102 block->border_left = border_left ? json_object_get_int(border_left) : 1;
103 block->border_right = border_right ?
104 json_object_get_int(border_right) : 1;
105 wl_list_insert(&status->blocks, &block->link);
106 }
107 return true;
108}
109
110bool i3bar_handle_readable(struct status_line *status) {
111 struct i3bar_protocol_state *state = &status->i3bar_state;
112
113 char *cur = &state->buffer[state->buffer_index];
114 ssize_t n = read(status->read_fd, cur,
115 state->buffer_size - state->buffer_index);
116 if (n == 0) {
117 return 0;
118 }
119
120 if (n == (ssize_t)(state->buffer_size - state->buffer_index)) {
121 state->buffer_size = state->buffer_size * 2;
122 char *new_buffer = realloc(state->buffer, state->buffer_size);
123 if (!new_buffer) {
124 free(state->buffer);
125 status_error(status, "[failed to allocate buffer]");
126 return -1;
127 }
128 state->buffer = new_buffer;
129 }
130
131 bool redraw = false;
132 while (*cur) {
133 if (state->nodes[state->depth] == JSON_NODE_STRING) {
134 if (!state->escape && *cur == '"') {
135 --state->depth;
136 }
137 state->escape = !state->escape && *cur == '\\';
138 } else {
139 switch (*cur) {
140 case '[':
141 ++state->depth;
142 if (state->depth >
143 sizeof(state->nodes) / sizeof(state->nodes[0])) {
144 status_error(status, "[i3bar json too deep]");
145 return false;
146 }
147 state->nodes[state->depth] = JSON_NODE_ARRAY;
148 if (state->depth == 1) {
149 state->current_node = cur;
150 }
151 break;
152 case ']':
153 if (state->nodes[state->depth] != JSON_NODE_ARRAY) {
154 status_error(status, "[failed to parse i3bar json]");
155 return false;
156 }
157 --state->depth;
158 if (state->depth == 0) {
159 // cur[1] is valid since cur[0] != '\0'
160 char p = cur[1];
161 cur[1] = '\0';
162 redraw = i3bar_parse_json(
163 status, state->current_node) || redraw;
164 cur[1] = p;
165 memmove(state->buffer, cur,
166 state->buffer_size - (cur - state->buffer));
167 cur = state->buffer;
168 state->current_node = cur + 1;
169 }
170 break;
171 case '"':
172 ++state->depth;
173 if (state->depth >
174 sizeof(state->nodes) / sizeof(state->nodes[0])) {
175 status_error(status, "[i3bar json too deep]");
176 return false;
177 }
178 state->nodes[state->depth] = JSON_NODE_STRING;
179 break;
180 }
181 }
182 ++cur;
183 }
184 state->buffer_index = cur - state->buffer;
185 return redraw;
186}
187
188void i3bar_block_send_click(struct status_line *status,
189 struct i3bar_block *block, int x, int y, uint32_t button) {
190 wlr_log(L_DEBUG, "block %s clicked", block->name ? block->name : "(nil)");
191 if (!block->name || !status->i3bar_state.click_events) {
192 return;
193 }
194
195 struct json_object *event_json = json_object_new_object();
196 json_object_object_add(event_json, "name",
197 json_object_new_string(block->name));
198 if (block->instance) {
199 json_object_object_add(event_json, "instance",
200 json_object_new_string(block->instance));
201 }
202
203 json_object_object_add(event_json, "button", json_object_new_int(button));
204 json_object_object_add(event_json, "x", json_object_new_int(x));
205 json_object_object_add(event_json, "y", json_object_new_int(y));
206 dprintf(status->write_fd, "%s\n", json_object_to_json_string(event_json));
207 json_object_put(event_json);
208}
diff --git a/swaybar/ipc.c b/swaybar/ipc.c
index 64583df0..ed5d9a31 100644
--- a/swaybar/ipc.c
+++ b/swaybar/ipc.c
@@ -323,7 +323,7 @@ void ipc_initialize(struct swaybar *bar, const char *bar_id) {
323 IPC_SUBSCRIBE, subscribe, &len)); 323 IPC_SUBSCRIBE, subscribe, &len));
324} 324}
325 325
326bool handle_ipc_event(struct swaybar *bar) { 326bool handle_ipc_readable(struct swaybar *bar) {
327 struct ipc_response *resp = ipc_recv_response(bar->ipc_event_socketfd); 327 struct ipc_response *resp = ipc_recv_response(bar->ipc_event_socketfd);
328 if (!resp) { 328 if (!resp) {
329 return false; 329 return false;
diff --git a/swaybar/meson.build b/swaybar/meson.build
index bf6f6d7a..d65edb11 100644
--- a/swaybar/meson.build
+++ b/swaybar/meson.build
@@ -3,6 +3,7 @@ executable(
3 'bar.c', 3 'bar.c',
4 'config.c', 4 'config.c',
5 'event_loop.c', 5 'event_loop.c',
6 'i3bar.c',
6 'ipc.c', 7 'ipc.c',
7 'main.c', 8 'main.c',
8 'render.c', 9 'render.c',
diff --git a/swaybar/render.c b/swaybar/render.c
index c2358724..6f3b0788 100644
--- a/swaybar/render.c
+++ b/swaybar/render.c
@@ -18,10 +18,33 @@ static const int ws_horizontal_padding = 5;
18static const double ws_vertical_padding = 1.5; 18static const double ws_vertical_padding = 1.5;
19static const double border_width = 1; 19static const double border_width = 1;
20 20
21static uint32_t render_status_line_error(cairo_t *cairo,
22 struct swaybar_config *config, const char *error,
23 double *x, uint32_t width, uint32_t height) {
24 if (!error) {
25 return 0;
26 }
27 cairo_set_source_u32(cairo, 0xFF0000FF);
28 static const int margin = 3;
29 int text_width, text_height;
30 get_text_size(cairo, config->font,
31 &text_width, &text_height, 1, false, "%s", error);
32 uint32_t ideal_height = text_height + ws_vertical_padding * 2;
33 if (height < ideal_height) {
34 return ideal_height;
35 }
36 *x -= text_width + margin;
37 double text_y = height / 2.0 - text_height / 2.0;
38 cairo_move_to(cairo, *x, (int)floor(text_y));
39 pango_printf(cairo, config->font, 1, false, "%s", error);
40 *x -= margin;
41 return ideal_height;
42}
43
21static uint32_t render_status_line_text(cairo_t *cairo, 44static uint32_t render_status_line_text(cairo_t *cairo,
22 struct swaybar_config *config, struct status_line *status, 45 struct swaybar_config *config, const char *text,
23 bool focused, uint32_t width, uint32_t height) { 46 bool focused, double *x, uint32_t width, uint32_t height) {
24 if (!status->text) { 47 if (!text) {
25 return 0; 48 return 0;
26 } 49 }
27 cairo_set_source_u32(cairo, focused ? 50 cairo_set_source_u32(cairo, focused ?
@@ -29,38 +52,211 @@ static uint32_t render_status_line_text(cairo_t *cairo,
29 static const int margin = 3; 52 static const int margin = 3;
30 int text_width, text_height; 53 int text_width, text_height;
31 get_text_size(cairo, config->font, &text_width, &text_height, 54 get_text_size(cairo, config->font, &text_width, &text_height,
32 1, config->pango_markup, "%s", status->text); 55 1, config->pango_markup, "%s", text);
33 uint32_t ideal_height = text_height + ws_vertical_padding * 2; 56 uint32_t ideal_height = text_height + ws_vertical_padding * 2;
34 if (height < ideal_height) { 57 if (height < ideal_height) {
35 return ideal_height; 58 return ideal_height;
36 } 59 }
60 *x -= text_width + margin;
37 double text_y = height / 2.0 - text_height / 2.0; 61 double text_y = height / 2.0 - text_height / 2.0;
38 cairo_move_to(cairo, width - text_width - margin, (int)floor(text_y)); 62 cairo_move_to(cairo, *x, (int)floor(text_y));
39 pango_printf(cairo, config->font, 1, config->pango_markup, 63 pango_printf(cairo, config->font, 1, config->pango_markup, "%s", text);
40 "%s", status->text); 64 *x -= margin;
65 return ideal_height;
66}
67
68static void render_sharp_line(cairo_t *cairo, uint32_t color,
69 double x, double y, double width, double height) {
70 cairo_set_source_u32(cairo, color);
71 if (width > 1 && height > 1) {
72 cairo_rectangle(cairo, x, y, width, height);
73 cairo_fill(cairo);
74 } else {
75 if (width == 1) {
76 x += 0.5;
77 height += y;
78 width = x;
79 }
80 if (height == 1) {
81 y += 0.5;
82 width += x;
83 height = y;
84 }
85 cairo_move_to(cairo, x, y);
86 cairo_set_line_width(cairo, 1.0);
87 cairo_line_to(cairo, width, height);
88 cairo_stroke(cairo);
89 }
90}
91
92static void block_hotspot_callback(struct swaybar_output *output,
93 int x, int y, uint32_t button, void *data) {
94 struct i3bar_block *block = data;
95 struct status_line *status = output->bar->status;
96 i3bar_block_send_click(status, block, x, y, button);
97}
98
99static uint32_t render_status_block(cairo_t *cairo,
100 struct swaybar_config *config, struct swaybar_output *output,
101 struct i3bar_block *block, double *x,
102 uint32_t height, bool focused, bool edge) {
103 static const int margin = 3;
104 if (!block->full_text || !*block->full_text) {
105 return 0;
106 }
107
108 int text_width, text_height;
109 get_text_size(cairo, config->font, &text_width, &text_height,
110 1, block->markup, "%s", block->full_text);
111 int width = text_width;
112 if (width < block->min_width) {
113 width = block->min_width;
114 }
115 double block_width = width;
116 uint32_t ideal_height = text_height + ws_vertical_padding * 2;
117 if (height < ideal_height) {
118 return ideal_height;
119 }
120
121 *x -= width;
122 if (block->border && block->border_left > 0) {
123 *x -= (block->border_left + margin);
124 block_width += block->border_left + margin;
125 }
126 if (block->border && block->border_right > 0) {
127 *x -= (block->border_right + margin);
128 block_width += block->border_right + margin;
129 }
130
131 int sep_width;
132 if (!edge) {
133 if (config->sep_symbol) {
134 int _height;
135 get_text_size(cairo, config->font, &sep_width, &_height,
136 1, false, "%s", config->sep_symbol);
137 uint32_t _ideal_height = _height + ws_vertical_padding * 2;
138 if (height < _ideal_height) {
139 return _height;
140 }
141 if (sep_width > block->separator_block_width) {
142 block->separator_block_width = sep_width + margin * 2;
143 }
144 }
145 *x -= block->separator_block_width;
146 } else {
147 *x -= margin;
148 }
149
150 struct swaybar_hotspot *hotspot = calloc(1, sizeof(struct swaybar_hotspot));
151 hotspot->x = *x;
152 hotspot->y = 0;
153 hotspot->width = width;
154 hotspot->height = height;
155 hotspot->callback = block_hotspot_callback;
156 hotspot->destroy = NULL;
157 hotspot->data = block;
158 wl_list_insert(&output->hotspots, &hotspot->link);
159
160 double pos = *x;
161 if (block->background) {
162 cairo_set_source_u32(cairo, block->background);
163 cairo_rectangle(cairo, pos - 0.5, 1, block_width, height);
164 cairo_fill(cairo);
165 }
166
167 if (block->border && block->border_top > 0) {
168 render_sharp_line(cairo, block->border,
169 pos - 0.5, 1, block_width, block->border_top);
170 }
171 if (block->border && block->border_bottom > 0) {
172 render_sharp_line(cairo, block->border,
173 pos - 0.5, height - 1 - block->border_bottom,
174 block_width, block->border_bottom);
175 }
176 if (block->border != 0 && block->border_left > 0) {
177 render_sharp_line(cairo, block->border,
178 pos - 0.5, 1, block->border_left, height);
179 pos += block->border_left + margin;
180 }
181
182 double offset = 0;
183 if (strncmp(block->align, "left", 5) == 0) {
184 offset = pos;
185 } else if (strncmp(block->align, "right", 5) == 0) {
186 offset = pos + width - text_width;
187 } else if (strncmp(block->align, "center", 6) == 0) {
188 offset = pos + (width - text_width) / 2;
189 }
190 cairo_move_to(cairo, offset, height / 2.0 - text_height / 2.0);
191 uint32_t color = block->color ? *block->color : config->colors.statusline;
192 cairo_set_source_u32(cairo, color);
193 pango_printf(cairo, config->font, 1, block->markup, "%s", block->full_text);
194 pos += width;
195
196 if (block->border && block->border_right > 0) {
197 pos += margin;
198 render_sharp_line(cairo, block->border,
199 pos - 0.5, 1, block->border_right, height);
200 pos += block->border_right;
201 }
202
203 if (!edge && block->separator) {
204 if (focused) {
205 cairo_set_source_u32(cairo, config->colors.focused_separator);
206 } else {
207 cairo_set_source_u32(cairo, config->colors.separator);
208 }
209 if (config->sep_symbol) {
210 offset = pos + (block->separator_block_width - sep_width) / 2;
211 cairo_move_to(cairo, offset, margin);
212 pango_printf(cairo, config->font, 1, false,
213 "%s", config->sep_symbol);
214 } else {
215 cairo_set_line_width(cairo, 1);
216 cairo_move_to(cairo,
217 pos + block->separator_block_width / 2, margin);
218 cairo_line_to(cairo,
219 pos + block->separator_block_width / 2, height - margin);
220 cairo_stroke(cairo);
221 }
222 }
41 return ideal_height; 223 return ideal_height;
42} 224}
43 225
44static uint32_t render_status_line_i3bar(cairo_t *cairo, 226static uint32_t render_status_line_i3bar(cairo_t *cairo,
45 struct swaybar_config *config, struct status_line *status, 227 struct swaybar_config *config, struct swaybar_output *output,
46 bool focused, uint32_t width, uint32_t height) { 228 struct status_line *status, bool focused,
47 // TODO 229 double *x, uint32_t width, uint32_t height) {
48 return 0; 230 uint32_t max_height = 0;
231 bool edge = true;
232 struct i3bar_block *block;
233 wl_list_for_each(block, &status->blocks, link) {
234 uint32_t h = render_status_block(cairo, config, output,
235 block, x, height, focused, edge);
236 max_height = h > max_height ? h : max_height;
237 edge = false;
238 }
239 return max_height;
49} 240}
50 241
51static uint32_t render_status_line(cairo_t *cairo, 242static uint32_t render_status_line(cairo_t *cairo,
52 struct swaybar_config *config, struct status_line *status, 243 struct swaybar_config *config, struct swaybar_output *output,
53 bool focused, uint32_t width, uint32_t height) { 244 struct status_line *status, bool focused,
245 double *x, uint32_t width, uint32_t height) {
54 switch (status->protocol) { 246 switch (status->protocol) {
247 case PROTOCOL_ERROR:
248 return render_status_line_error(cairo,
249 config, status->text, x, width, height);
55 case PROTOCOL_TEXT: 250 case PROTOCOL_TEXT:
56 return render_status_line_text(cairo, 251 return render_status_line_text(cairo,
57 config, status, focused, width, height); 252 config, status->text, focused, x, width, height);
58 case PROTOCOL_I3BAR: 253 case PROTOCOL_I3BAR:
59 return render_status_line_i3bar(cairo, 254 return render_status_line_i3bar(cairo, config, output, status,
60 config, status, focused, width, height); 255 focused, x, width, height);
61 default: 256 case PROTOCOL_UNDEF:
62 return 0; 257 return 0;
63 } 258 }
259 return 0;
64} 260}
65 261
66static uint32_t render_binding_mode_indicator(cairo_t *cairo, 262static uint32_t render_binding_mode_indicator(cairo_t *cairo,
@@ -166,8 +362,8 @@ static uint32_t render_workspace_button(cairo_t *cairo,
166 struct swaybar_hotspot *hotspot = calloc(1, sizeof(struct swaybar_hotspot)); 362 struct swaybar_hotspot *hotspot = calloc(1, sizeof(struct swaybar_hotspot));
167 hotspot->x = *x; 363 hotspot->x = *x;
168 hotspot->y = 0; 364 hotspot->y = 0;
169 hotspot->height = height;
170 hotspot->width = width; 365 hotspot->width = width;
366 hotspot->height = height;
171 hotspot->callback = workspace_hotspot_callback; 367 hotspot->callback = workspace_hotspot_callback;
172 hotspot->destroy = free; 368 hotspot->destroy = free;
173 hotspot->data = strdup(name); 369 hotspot->data = strdup(name);
@@ -180,6 +376,7 @@ static uint32_t render_workspace_button(cairo_t *cairo,
180static uint32_t render_to_cairo(cairo_t *cairo, 376static uint32_t render_to_cairo(cairo_t *cairo,
181 struct swaybar *bar, struct swaybar_output *output) { 377 struct swaybar *bar, struct swaybar_output *output) {
182 struct swaybar_config *config = bar->config; 378 struct swaybar_config *config = bar->config;
379 wlr_log(L_DEBUG, "output %p", output);
183 380
184 cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE); 381 cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE);
185 if (output->focused) { 382 if (output->focused) {
@@ -211,9 +408,10 @@ static uint32_t render_to_cairo(cairo_t *cairo,
211 cairo, config, config->mode, x, output->height); 408 cairo, config, config->mode, x, output->height);
212 max_height = h > max_height ? h : max_height; 409 max_height = h > max_height ? h : max_height;
213 } 410 }
411 x = output->width;
214 if (bar->status) { 412 if (bar->status) {
215 uint32_t h = render_status_line(cairo, config, bar->status, 413 uint32_t h = render_status_line(cairo, config, output, bar->status,
216 output->focused, output->width, output->height); 414 output->focused, &x, output->width, output->height);
217 max_height = h > max_height ? h : max_height; 415 max_height = h > max_height ? h : max_height;
218 } 416 }
219 417
diff --git a/swaybar/status_line.c b/swaybar/status_line.c
index 3454f207..cc7e217f 100644
--- a/swaybar/status_line.c
+++ b/swaybar/status_line.c
@@ -1,5 +1,6 @@
1#define _POSIX_C_SOURCE 1#define _POSIX_C_SOURCE
2#include <fcntl.h> 2#include <fcntl.h>
3#include <json-c/json.h>
3#include <stdlib.h> 4#include <stdlib.h>
4#include <string.h> 5#include <string.h>
5#include <stdio.h> 6#include <stdio.h>
@@ -9,35 +10,79 @@
9#include "swaybar/status_line.h" 10#include "swaybar/status_line.h"
10#include "readline.h" 11#include "readline.h"
11 12
12bool handle_status_readable(struct status_line *status) { 13void status_error(struct status_line *status, const char *text) {
13 char *line = read_line_buffer(status->read, 14 close(status->read_fd);
14 status->buffer, status->buffer_size); 15 close(status->write_fd);
16 status->protocol = PROTOCOL_ERROR;
17 status->text = text;
18}
19
20bool status_handle_readable(struct status_line *status) {
21 char *line;
15 switch (status->protocol) { 22 switch (status->protocol) {
23 case PROTOCOL_ERROR:
24 return false;
16 case PROTOCOL_I3BAR: 25 case PROTOCOL_I3BAR:
17 // TODO 26 if (i3bar_handle_readable(status) > 0) {
27 return true;
28 }
18 break; 29 break;
19 case PROTOCOL_TEXT: 30 case PROTOCOL_TEXT:
20 status->text = line; 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 }
21 return true; 38 return true;
22 case PROTOCOL_UNDEF: 39 case PROTOCOL_UNDEF:
40 line = read_line_buffer(status->read,
41 status->text_state.buffer, status->text_state.buffer_size);
23 if (!line) { 42 if (!line) {
43 status_error(status, "[error reading from status command]");
24 return false; 44 return false;
25 } 45 }
26 if (line[0] == '{') { 46 if (line[0] == '{') {
27 // TODO: JSON 47 json_object *proto = json_tokener_parse(line);
48 if (proto) {
49 json_object *version;
50 if (json_object_object_get_ex(proto, "version", &version)
51 && json_object_get_int(version) == 1) {
52 wlr_log(L_DEBUG, "Switched to i3bar protocol.");
53 status->protocol = PROTOCOL_I3BAR;
54 }
55 json_object *click_events;
56 if (json_object_object_get_ex(
57 proto, "click_events", &click_events)
58 && json_object_get_boolean(click_events)) {
59 wlr_log(L_DEBUG, "Enabled click events.");
60 status->i3bar_state.click_events = true;
61 const char *events_array = "[\n";
62 write(status->write_fd, events_array, strlen(events_array));
63 }
64 json_object_put(proto);
65 }
66
67 status->protocol = PROTOCOL_I3BAR;
68 free(status->text_state.buffer);
69 wl_list_init(&status->blocks);
70 status->i3bar_state.buffer_size = 4096;
71 status->i3bar_state.buffer =
72 malloc(status->i3bar_state.buffer_size);
28 } else { 73 } else {
29 status->text = line;
30 status->protocol = PROTOCOL_TEXT; 74 status->protocol = PROTOCOL_TEXT;
75 status->text = line;
31 } 76 }
32 return false; 77 return true;
33 } 78 }
34 return false; 79 return false;
35} 80}
36 81
37struct status_line *status_line_init(char *cmd) { 82struct status_line *status_line_init(char *cmd) {
38 struct status_line *status = calloc(1, sizeof(struct status_line)); 83 struct status_line *status = calloc(1, sizeof(struct status_line));
39 status->buffer_size = 4096; 84 status->text_state.buffer_size = 8192;
40 status->buffer = malloc(status->buffer_size); 85 status->text_state.buffer = malloc(status->text_state.buffer_size);
41 86
42 int pipe_read_fd[2]; 87 int pipe_read_fd[2];
43 int pipe_write_fd[2]; 88 int pipe_write_fd[2];