diff options
author | emersion <contact@emersion.fr> | 2018-04-02 15:30:58 -0400 |
---|---|---|
committer | emersion <contact@emersion.fr> | 2018-04-02 15:30:58 -0400 |
commit | a4a241697ae591289d7c14eff972e1ef787216e2 (patch) | |
tree | d82d3c3eba2946670aa634a62d03feb7102f0bf8 /swaybar | |
parent | Xwayland unmanaged views aren't views anymore (diff) | |
parent | Merge pull request #1699 from acrisci/seat-fixes (diff) | |
download | sway-a4a241697ae591289d7c14eff972e1ef787216e2.tar.gz sway-a4a241697ae591289d7c14eff972e1ef787216e2.tar.zst sway-a4a241697ae591289d7c14eff972e1ef787216e2.zip |
Merge branch 'wlroots' into view-redesign
Diffstat (limited to 'swaybar')
-rw-r--r-- | swaybar/bar.c | 4 | ||||
-rw-r--r-- | swaybar/i3bar.c | 208 | ||||
-rw-r--r-- | swaybar/ipc.c | 2 | ||||
-rw-r--r-- | swaybar/meson.build | 1 | ||||
-rw-r--r-- | swaybar/render.c | 238 | ||||
-rw-r--r-- | swaybar/status_line.c | 65 |
6 files changed, 485 insertions, 33 deletions
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 | ||
309 | static void ipc_in(int fd, short mask, void *_bar) { | 309 | static 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 | ||
316 | static void status_in(int fd, short mask, void *_bar) { | 316 | static 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 | |||
10 | static 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 | |||
23 | static 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 | |||
110 | bool 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 | |||
188 | void 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 | ||
326 | bool handle_ipc_event(struct swaybar *bar) { | 326 | bool 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; | |||
18 | static const double ws_vertical_padding = 1.5; | 18 | static const double ws_vertical_padding = 1.5; |
19 | static const double border_width = 1; | 19 | static const double border_width = 1; |
20 | 20 | ||
21 | static 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 | |||
21 | static uint32_t render_status_line_text(cairo_t *cairo, | 44 | static 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 | |||
68 | static 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 | |||
92 | static 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 | |||
99 | static 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 | ||
44 | static uint32_t render_status_line_i3bar(cairo_t *cairo, | 226 | static 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 | ||
51 | static uint32_t render_status_line(cairo_t *cairo, | 242 | static 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 | ||
66 | static uint32_t render_binding_mode_indicator(cairo_t *cairo, | 262 | static 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, | |||
180 | static uint32_t render_to_cairo(cairo_t *cairo, | 376 | static 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 | ||
12 | bool handle_status_readable(struct status_line *status) { | 13 | void 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 | |||
20 | bool 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 | ||
37 | struct status_line *status_line_init(char *cmd) { | 82 | struct 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]; |