summaryrefslogtreecommitdiffstats
path: root/swaybar
diff options
context:
space:
mode:
Diffstat (limited to 'swaybar')
-rw-r--r--swaybar/bar.c161
-rw-r--r--swaybar/config.c2
-rw-r--r--swaybar/i3bar.c19
-rw-r--r--swaybar/ipc.c19
-rw-r--r--swaybar/main.c5
-rw-r--r--swaybar/meson.build1
-rw-r--r--swaybar/render.c146
-rw-r--r--swaybar/status_line.c36
8 files changed, 251 insertions, 138 deletions
diff --git a/swaybar/bar.c b/swaybar/bar.c
index 3ae730f7..388c24c4 100644
--- a/swaybar/bar.c
+++ b/swaybar/bar.c
@@ -16,12 +16,13 @@
16#else 16#else
17#include <linux/input-event-codes.h> 17#include <linux/input-event-codes.h>
18#endif 18#endif
19#include "swaybar/render.h" 19#include "swaybar/bar.h"
20#include "swaybar/config.h" 20#include "swaybar/config.h"
21#include "swaybar/event_loop.h" 21#include "swaybar/event_loop.h"
22#include "swaybar/status_line.h" 22#include "swaybar/i3bar.h"
23#include "swaybar/bar.h"
24#include "swaybar/ipc.h" 23#include "swaybar/ipc.h"
24#include "swaybar/status_line.h"
25#include "swaybar/render.h"
25#include "ipc-client.h" 26#include "ipc-client.h"
26#include "list.h" 27#include "list.h"
27#include "log.h" 28#include "log.h"
@@ -48,8 +49,13 @@ static void swaybar_output_free(struct swaybar_output *output) {
48 return; 49 return;
49 } 50 }
50 wlr_log(WLR_DEBUG, "Removing output %s", output->name); 51 wlr_log(WLR_DEBUG, "Removing output %s", output->name);
51 zwlr_layer_surface_v1_destroy(output->layer_surface); 52 if (output->layer_surface != NULL) {
52 wl_surface_destroy(output->surface); 53 zwlr_layer_surface_v1_destroy(output->layer_surface);
54 }
55 if (output->surface != NULL) {
56 wl_surface_destroy(output->surface);
57 }
58 zxdg_output_v1_destroy(output->xdg_output);
53 wl_output_destroy(output->output); 59 wl_output_destroy(output->output);
54 destroy_buffer(&output->buffers[0]); 60 destroy_buffer(&output->buffers[0]);
55 destroy_buffer(&output->buffers[1]); 61 destroy_buffer(&output->buffers[1]);
@@ -66,6 +72,16 @@ static void swaybar_output_free(struct swaybar_output *output) {
66 free(output); 72 free(output);
67} 73}
68 74
75static void set_output_dirty(struct swaybar_output *output) {
76 if (output->frame_scheduled) {
77 output->dirty = true;
78 return;
79 }
80 if (output->surface) {
81 render_frame(output);
82 }
83}
84
69static void layer_surface_configure(void *data, 85static void layer_surface_configure(void *data,
70 struct zwlr_layer_surface_v1 *surface, 86 struct zwlr_layer_surface_v1 *surface,
71 uint32_t serial, uint32_t width, uint32_t height) { 87 uint32_t serial, uint32_t width, uint32_t height) {
@@ -73,7 +89,7 @@ static void layer_surface_configure(void *data,
73 output->width = width; 89 output->width = width;
74 output->height = height; 90 output->height = height;
75 zwlr_layer_surface_v1_ack_configure(surface, serial); 91 zwlr_layer_surface_v1_ack_configure(surface, serial);
76 render_frame(output->bar, output); 92 set_output_dirty(output);
77} 93}
78 94
79static void layer_surface_closed(void *_output, 95static void layer_surface_closed(void *_output,
@@ -283,28 +299,58 @@ const struct wl_seat_listener seat_listener = {
283 .name = seat_handle_name, 299 .name = seat_handle_name,
284}; 300};
285 301
286static void output_geometry(void *data, struct wl_output *output, int32_t x, 302static void add_layer_surface(struct swaybar_output *output) {
303 if (output->surface != NULL) {
304 return;
305 }
306 struct swaybar *bar = output->bar;
307
308 output->surface = wl_compositor_create_surface(bar->compositor);
309 assert(output->surface);
310 output->layer_surface = zwlr_layer_shell_v1_get_layer_surface(
311 bar->layer_shell, output->surface, output->output,
312 ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM, "panel");
313 assert(output->layer_surface);
314 zwlr_layer_surface_v1_add_listener(output->layer_surface,
315 &layer_surface_listener, output);
316 zwlr_layer_surface_v1_set_anchor(output->layer_surface,
317 bar->config->position);
318}
319
320static bool bar_uses_output(struct swaybar *bar, const char *name) {
321 if (bar->config->all_outputs) {
322 return true;
323 }
324 struct config_output *coutput;
325 wl_list_for_each(coutput, &bar->config->outputs, link) {
326 if (strcmp(coutput->name, name) == 0) {
327 return true;
328 }
329 }
330 return false;
331}
332
333static void output_geometry(void *data, struct wl_output *wl_output, int32_t x,
287 int32_t y, int32_t width_mm, int32_t height_mm, int32_t subpixel, 334 int32_t y, int32_t width_mm, int32_t height_mm, int32_t subpixel,
288 const char *make, const char *model, int32_t transform) { 335 const char *make, const char *model, int32_t transform) {
289 // Who cares 336 struct swaybar_output *output = data;
337 output->subpixel = subpixel;
290} 338}
291 339
292static void output_mode(void *data, struct wl_output *output, uint32_t flags, 340static void output_mode(void *data, struct wl_output *wl_output, uint32_t flags,
293 int32_t width, int32_t height, int32_t refresh) { 341 int32_t width, int32_t height, int32_t refresh) {
294 // Who cares 342 // Who cares
295} 343}
296 344
297static void output_done(void *data, struct wl_output *output) { 345static void output_done(void *data, struct wl_output *wl_output) {
298 // Who cares 346 struct swaybar_output *output = data;
347 set_output_dirty(output);
299} 348}
300 349
301static void output_scale(void *data, struct wl_output *wl_output, 350static void output_scale(void *data, struct wl_output *wl_output,
302 int32_t factor) { 351 int32_t factor) {
303 struct swaybar_output *output = data; 352 struct swaybar_output *output = data;
304 output->scale = factor; 353 output->scale = factor;
305 if (output->surface) {
306 render_frame(output->bar, output);
307 }
308} 354}
309 355
310struct wl_output_listener output_listener = { 356struct wl_output_listener output_listener = {
@@ -326,7 +372,22 @@ static void xdg_output_handle_logical_size(void *data,
326 372
327static void xdg_output_handle_done(void *data, 373static void xdg_output_handle_done(void *data,
328 struct zxdg_output_v1 *xdg_output) { 374 struct zxdg_output_v1 *xdg_output) {
329 // Who cares 375 struct swaybar_output *output = data;
376 struct swaybar *bar = output->bar;
377
378 assert(output->name != NULL);
379 if (!bar_uses_output(bar, output->name)) {
380 swaybar_output_free(output);
381 return;
382 }
383
384 if (wl_list_empty(&output->link)) {
385 wl_list_remove(&output->link);
386 wl_list_insert(&bar->outputs, &output->link);
387
388 add_layer_surface(output);
389 set_output_dirty(output);
390 }
330} 391}
331 392
332static void xdg_output_handle_name(void *data, 393static void xdg_output_handle_name(void *data,
@@ -349,17 +410,15 @@ struct zxdg_output_v1_listener xdg_output_listener = {
349 .description = xdg_output_handle_description, 410 .description = xdg_output_handle_description,
350}; 411};
351 412
352static bool bar_uses_output(struct swaybar *bar, const char *name) { 413static void add_xdg_output(struct swaybar_output *output) {
353 if (bar->config->all_outputs) { 414 if (output->xdg_output != NULL) {
354 return true; 415 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 } 416 }
362 return false; 417 assert(output->bar->xdg_output_manager != NULL);
418 output->xdg_output = zxdg_output_manager_v1_get_xdg_output(
419 output->bar->xdg_output_manager, output->output);
420 zxdg_output_v1_add_listener(output->xdg_output, &xdg_output_listener,
421 output);
363} 422}
364 423
365static void handle_global(void *data, struct wl_registry *registry, 424static void handle_global(void *data, struct wl_registry *registry,
@@ -386,7 +445,10 @@ static void handle_global(void *data, struct wl_registry *registry,
386 output->wl_name = name; 445 output->wl_name = name;
387 wl_list_init(&output->workspaces); 446 wl_list_init(&output->workspaces);
388 wl_list_init(&output->hotspots); 447 wl_list_init(&output->hotspots);
389 wl_list_insert(&bar->outputs, &output->link); 448 wl_list_init(&output->link);
449 if (bar->xdg_output_manager != NULL) {
450 add_xdg_output(output);
451 }
390 } else if (strcmp(interface, zwlr_layer_shell_v1_interface.name) == 0) { 452 } else if (strcmp(interface, zwlr_layer_shell_v1_interface.name) == 0) {
391 bar->layer_shell = wl_registry_bind( 453 bar->layer_shell = wl_registry_bind(
392 registry, name, &zwlr_layer_shell_v1_interface, 1); 454 registry, name, &zwlr_layer_shell_v1_interface, 1);
@@ -413,21 +475,23 @@ static const struct wl_registry_listener registry_listener = {
413 .global_remove = handle_global_remove, 475 .global_remove = handle_global_remove,
414}; 476};
415 477
416static void render_all_frames(struct swaybar *bar) { 478static void set_bar_dirty(struct swaybar *bar) {
417 struct swaybar_output *output; 479 struct swaybar_output *output;
418 wl_list_for_each(output, &bar->outputs, link) { 480 wl_list_for_each(output, &bar->outputs, link) {
419 render_frame(bar, output); 481 set_output_dirty(output);
420 } 482 }
421} 483}
422 484
423void bar_setup(struct swaybar *bar, 485bool bar_setup(struct swaybar *bar,
424 const char *socket_path, const char *bar_id) { 486 const char *socket_path, const char *bar_id) {
425 bar_init(bar); 487 bar_init(bar);
426 init_event_loop(); 488 init_event_loop();
427 489
428 bar->ipc_socketfd = ipc_open_socket(socket_path); 490 bar->ipc_socketfd = ipc_open_socket(socket_path);
429 bar->ipc_event_socketfd = ipc_open_socket(socket_path); 491 bar->ipc_event_socketfd = ipc_open_socket(socket_path);
430 ipc_initialize(bar, bar_id); 492 if (!ipc_initialize(bar, bar_id)) {
493 return false;
494 }
431 if (bar->config->status_command) { 495 if (bar->config->status_command) {
432 bar->status = status_line_init(bar->config->status_command); 496 bar->status = status_line_init(bar->config->status_command);
433 } 497 }
@@ -443,23 +507,10 @@ void bar_setup(struct swaybar *bar,
443 507
444 struct swaybar_output *output; 508 struct swaybar_output *output;
445 wl_list_for_each(output, &bar->outputs, link) { 509 wl_list_for_each(output, &bar->outputs, link) {
446 output->xdg_output = zxdg_output_manager_v1_get_xdg_output( 510 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 } 511 }
451 wl_display_roundtrip(bar->display); 512 wl_display_roundtrip(bar->display);
452 513
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; 514 struct swaybar_pointer *pointer = &bar->pointer;
464 515
465 int max_scale = 1; 516 int max_scale = 1;
@@ -479,20 +530,9 @@ void bar_setup(struct swaybar *bar,
479 pointer->cursor_surface = wl_compositor_create_surface(bar->compositor); 530 pointer->cursor_surface = wl_compositor_create_surface(bar->compositor);
480 assert(pointer->cursor_surface); 531 assert(pointer->cursor_surface);
481 532
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); 533 ipc_get_workspaces(bar);
495 render_all_frames(bar); 534 set_bar_dirty(bar);
535 return true;
496} 536}
497 537
498static void display_in(int fd, short mask, void *data) { 538static void display_in(int fd, short mask, void *data) {
@@ -506,7 +546,7 @@ static void display_in(int fd, short mask, void *data) {
506static void ipc_in(int fd, short mask, void *data) { 546static void ipc_in(int fd, short mask, void *data) {
507 struct swaybar *bar = data; 547 struct swaybar *bar = data;
508 if (handle_ipc_readable(bar)) { 548 if (handle_ipc_readable(bar)) {
509 render_all_frames(bar); 549 set_bar_dirty(bar);
510 } 550 }
511} 551}
512 552
@@ -514,10 +554,10 @@ static void status_in(int fd, short mask, void *data) {
514 struct swaybar *bar = data; 554 struct swaybar *bar = data;
515 if (mask & (POLLHUP | POLLERR)) { 555 if (mask & (POLLHUP | POLLERR)) {
516 status_error(bar->status, "[error reading from status command]"); 556 status_error(bar->status, "[error reading from status command]");
517 render_all_frames(bar); 557 set_bar_dirty(bar);
518 remove_event(fd); 558 remove_event(fd);
519 } else if (status_handle_readable(bar->status)) { 559 } else if (status_handle_readable(bar->status)) {
520 render_all_frames(bar); 560 set_bar_dirty(bar);
521 } 561 }
522} 562}
523 563
@@ -529,6 +569,7 @@ void bar_run(struct swaybar *bar) {
529 } 569 }
530 while (1) { 570 while (1) {
531 event_loop_poll(); 571 event_loop_poll();
572 wl_display_flush(bar->display);
532 } 573 }
533} 574}
534 575
diff --git a/swaybar/config.c b/swaybar/config.c
index db7b0db6..4e851cca 100644
--- a/swaybar/config.c
+++ b/swaybar/config.c
@@ -22,7 +22,7 @@ uint32_t parse_position(const char *position) {
22 } 22 }
23} 23}
24 24
25struct swaybar_config *init_config() { 25struct swaybar_config *init_config(void) {
26 struct swaybar_config *config = calloc(1, sizeof(struct swaybar_config)); 26 struct swaybar_config *config = calloc(1, sizeof(struct swaybar_config));
27 config->status_command = NULL; 27 config->status_command = NULL;
28 config->pango_markup = false; 28 config->pango_markup = false;
diff --git a/swaybar/i3bar.c b/swaybar/i3bar.c
index 88404703..8e9b038b 100644
--- a/swaybar/i3bar.c
+++ b/swaybar/i3bar.c
@@ -6,7 +6,9 @@
6#include <string.h> 6#include <string.h>
7#include <unistd.h> 7#include <unistd.h>
8#include <wlr/util/log.h> 8#include <wlr/util/log.h>
9#include "swaybar/bar.h"
9#include "swaybar/config.h" 10#include "swaybar/config.h"
11#include "swaybar/i3bar.h"
10#include "swaybar/status_line.h" 12#include "swaybar/status_line.h"
11 13
12void i3bar_block_unref(struct i3bar_block *block) { 14void i3bar_block_unref(struct i3bar_block *block) {
@@ -117,7 +119,9 @@ bool i3bar_handle_readable(struct status_line *status) {
117 memmove(status->buffer, &status->buffer[c], status->buffer_index); 119 memmove(status->buffer, &status->buffer[c], status->buffer_index);
118 break; 120 break;
119 } else if (!isspace(status->buffer[c])) { 121 } else if (!isspace(status->buffer[c])) {
120 status_error(status, "[invalid json]"); 122 wlr_log(WLR_DEBUG, "Invalid i3bar json: expected '[' but encountered '%c'",
123 status->buffer[c]);
124 status_error(status, "[invalid i3bar json]");
121 return true; 125 return true;
122 } 126 }
123 } 127 }
@@ -155,6 +159,8 @@ bool i3bar_handle_readable(struct status_line *status) {
155 ++buffer_pos; 159 ++buffer_pos;
156 break; 160 break;
157 } else if (!isspace(status->buffer[buffer_pos])) { 161 } else if (!isspace(status->buffer[buffer_pos])) {
162 wlr_log(WLR_DEBUG, "Invalid i3bar json: expected ',' but encountered '%c'",
163 status->buffer[buffer_pos]);
158 status_error(status, "[invalid i3bar json]"); 164 status_error(status, "[invalid i3bar json]");
159 return true; 165 return true;
160 } 166 }
@@ -166,7 +172,8 @@ bool i3bar_handle_readable(struct status_line *status) {
166 } else { 172 } else {
167 test_object = json_tokener_parse_ex(status->tokener, 173 test_object = json_tokener_parse_ex(status->tokener,
168 &status->buffer[buffer_pos], status->buffer_index - buffer_pos); 174 &status->buffer[buffer_pos], status->buffer_index - buffer_pos);
169 if (json_tokener_get_error(status->tokener) == json_tokener_success) { 175 enum json_tokener_error err = json_tokener_get_error(status->tokener);
176 if (err == json_tokener_success) {
170 if (json_object_get_type(test_object) == json_type_array) { 177 if (json_object_get_type(test_object) == json_type_array) {
171 if (last_object) { 178 if (last_object) {
172 json_object_put(last_object); 179 json_object_put(last_object);
@@ -198,12 +205,14 @@ bool i3bar_handle_readable(struct status_line *status) {
198 continue; // look for comma without reading more input 205 continue; // look for comma without reading more input
199 } 206 }
200 buffer_pos = status->buffer_index = 0; 207 buffer_pos = status->buffer_index = 0;
201 } else if (json_tokener_get_error(status->tokener) == json_tokener_continue) { 208 } else if (err == json_tokener_continue) {
209 json_tokener_reset(status->tokener);
202 if (status->buffer_index < status->buffer_size) { 210 if (status->buffer_index < status->buffer_size) {
203 // move the object to the start of the buffer 211 // move the object to the start of the buffer
204 status->buffer_index -= buffer_pos; 212 status->buffer_index -= buffer_pos;
205 memmove(status->buffer, &status->buffer[buffer_pos], 213 memmove(status->buffer, &status->buffer[buffer_pos],
206 status->buffer_index); 214 status->buffer_index);
215 buffer_pos = 0;
207 } else { 216 } else {
208 // expand buffer 217 // expand buffer
209 status->buffer_size *= 2; 218 status->buffer_size *= 2;
@@ -217,6 +226,10 @@ bool i3bar_handle_readable(struct status_line *status) {
217 } 226 }
218 } 227 }
219 } else { 228 } else {
229 char last_char = status->buffer[status->buffer_index - 1];
230 status->buffer[status->buffer_index - 1] = '\0';
231 wlr_log(WLR_DEBUG, "Failed to parse i3bar json - %s: '%s%c'",
232 json_tokener_error_desc(err), &status->buffer[buffer_pos], last_char);
220 status_error(status, "[failed to parse i3bar json]"); 233 status_error(status, "[failed to parse i3bar json]");
221 return true; 234 return true;
222 } 235 }
diff --git a/swaybar/ipc.c b/swaybar/ipc.c
index 0e60c10c..7c53a44f 100644
--- a/swaybar/ipc.c
+++ b/swaybar/ipc.c
@@ -141,9 +141,16 @@ static void ipc_parse_colors(
141 } 141 }
142} 142}
143 143
144static void ipc_parse_config( 144static bool ipc_parse_config(
145 struct swaybar_config *config, const char *payload) { 145 struct swaybar_config *config, const char *payload) {
146 json_object *bar_config = json_tokener_parse(payload); 146 json_object *bar_config = json_tokener_parse(payload);
147 json_object *success;
148 if (json_object_object_get_ex(bar_config, "success", &success)
149 && !json_object_get_boolean(success)) {
150 wlr_log(WLR_ERROR, "No bar with that ID. Use 'swaymsg -t get_bar_config to get the available bar configs.");
151 json_object_put(bar_config);
152 return false;
153 }
147 json_object *markup, *mode, *hidden_bar, *position, *status_command; 154 json_object *markup, *mode, *hidden_bar, *position, *status_command;
148 json_object *font, *bar_height, *wrap_scroll, *workspace_buttons, *strip_workspace_numbers; 155 json_object *font, *bar_height, *wrap_scroll, *workspace_buttons, *strip_workspace_numbers;
149 json_object *binding_mode_indicator, *verbose, *colors, *sep_symbol, *outputs; 156 json_object *binding_mode_indicator, *verbose, *colors, *sep_symbol, *outputs;
@@ -226,10 +233,10 @@ static void ipc_parse_config(
226 } 233 }
227 234
228 json_object_put(bar_config); 235 json_object_put(bar_config);
236 return true;
229} 237}
230 238
231void ipc_get_workspaces(struct swaybar *bar) { 239void ipc_get_workspaces(struct swaybar *bar) {
232 bar->focused_output = NULL;
233 struct swaybar_output *output; 240 struct swaybar_output *output;
234 wl_list_for_each(output, &bar->outputs, link) { 241 wl_list_for_each(output, &bar->outputs, link) {
235 free_workspaces(&output->workspaces); 242 free_workspaces(&output->workspaces);
@@ -312,11 +319,14 @@ static void ipc_get_outputs(struct swaybar *bar) {
312 free(res); 319 free(res);
313} 320}
314 321
315void ipc_initialize(struct swaybar *bar, const char *bar_id) { 322bool ipc_initialize(struct swaybar *bar, const char *bar_id) {
316 uint32_t len = strlen(bar_id); 323 uint32_t len = strlen(bar_id);
317 char *res = ipc_single_command(bar->ipc_socketfd, 324 char *res = ipc_single_command(bar->ipc_socketfd,
318 IPC_GET_BAR_CONFIG, bar_id, &len); 325 IPC_GET_BAR_CONFIG, bar_id, &len);
319 ipc_parse_config(bar->config, res); 326 if (!ipc_parse_config(bar->config, res)) {
327 free(res);
328 return false;
329 }
320 free(res); 330 free(res);
321 ipc_get_outputs(bar); 331 ipc_get_outputs(bar);
322 332
@@ -324,6 +334,7 @@ void ipc_initialize(struct swaybar *bar, const char *bar_id) {
324 len = strlen(subscribe); 334 len = strlen(subscribe);
325 free(ipc_single_command(bar->ipc_event_socketfd, 335 free(ipc_single_command(bar->ipc_event_socketfd,
326 IPC_SUBSCRIBE, subscribe, &len)); 336 IPC_SUBSCRIBE, subscribe, &len));
337 return true;
327} 338}
328 339
329bool handle_ipc_readable(struct swaybar *bar) { 340bool handle_ipc_readable(struct swaybar *bar) {
diff --git a/swaybar/main.c b/swaybar/main.c
index 60e4b37c..d2c579db 100644
--- a/swaybar/main.c
+++ b/swaybar/main.c
@@ -96,7 +96,10 @@ int main(int argc, char **argv) {
96 96
97 signal(SIGTERM, sig_handler); 97 signal(SIGTERM, sig_handler);
98 98
99 bar_setup(&swaybar, socket_path, bar_id); 99 if (!bar_setup(&swaybar, socket_path, bar_id)) {
100 free(socket_path);
101 return 1;
102 }
100 103
101 free(socket_path); 104 free(socket_path);
102 free(bar_id); 105 free(bar_id);
diff --git a/swaybar/meson.build b/swaybar/meson.build
index d65edb11..7a02a33f 100644
--- a/swaybar/meson.build
+++ b/swaybar/meson.build
@@ -24,5 +24,6 @@ executable(
24 wlroots, 24 wlroots,
25 ], 25 ],
26 link_with: [lib_sway_common, lib_sway_client], 26 link_with: [lib_sway_common, lib_sway_client],
27 install_rpath : rpathdir,
27 install: true 28 install: true
28) 29)
diff --git a/swaybar/render.c b/swaybar/render.c
index 97690338..dc31a5ea 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>
@@ -9,6 +10,7 @@
9#include "pool-buffer.h" 10#include "pool-buffer.h"
10#include "swaybar/bar.h" 11#include "swaybar/bar.h"
11#include "swaybar/config.h" 12#include "swaybar/config.h"
13#include "swaybar/i3bar.h"
12#include "swaybar/ipc.h" 14#include "swaybar/ipc.h"
13#include "swaybar/render.h" 15#include "swaybar/render.h"
14#include "swaybar/status_line.h" 16#include "swaybar/status_line.h"
@@ -19,47 +21,47 @@ static const double WS_VERTICAL_PADDING = 1.5;
19static const double BORDER_WIDTH = 1; 21static const double BORDER_WIDTH = 1;
20 22
21static uint32_t render_status_line_error(cairo_t *cairo, 23static uint32_t render_status_line_error(cairo_t *cairo,
22 struct swaybar_output *output, struct swaybar_config *config, 24 struct swaybar_output *output, double *x) {
23 const char *error, double *x, uint32_t surface_height) { 25 const char *error = output->bar->status->text;
24 if (!error) { 26 if (!error) {
25 return 0; 27 return 0;
26 } 28 }
27 29
28 uint32_t height = surface_height * output->scale; 30 uint32_t height = output->height * output->scale;
29 31
30 cairo_set_source_u32(cairo, 0xFF0000FF); 32 cairo_set_source_u32(cairo, 0xFF0000FF);
31 33
32 int margin = 3 * output->scale; 34 int margin = 3 * output->scale;
33 int ws_vertical_padding = WS_VERTICAL_PADDING * output->scale; 35 int ws_vertical_padding = WS_VERTICAL_PADDING * output->scale;
34 36
37 char *font = output->bar->config->font;
35 int text_width, text_height; 38 int text_width, text_height;
36 get_text_size(cairo, config->font, &text_width, &text_height, NULL, 39 get_text_size(cairo, font, &text_width, &text_height, NULL,
37 output->scale, false, "%s", error); 40 output->scale, false, "%s", error);
38 41
39 uint32_t ideal_height = text_height + ws_vertical_padding * 2; 42 uint32_t ideal_height = text_height + ws_vertical_padding * 2;
40 uint32_t ideal_surface_height = ideal_height / output->scale; 43 uint32_t ideal_surface_height = ideal_height / output->scale;
41 if (surface_height < ideal_surface_height) { 44 if (output->height < ideal_surface_height) {
42 return ideal_surface_height; 45 return ideal_surface_height;
43 } 46 }
44 *x -= text_width + margin; 47 *x -= text_width + margin;
45 48
46 double text_y = height / 2.0 - text_height / 2.0; 49 double text_y = height / 2.0 - text_height / 2.0;
47 cairo_move_to(cairo, *x, (int)floor(text_y)); 50 cairo_move_to(cairo, *x, (int)floor(text_y));
48 pango_printf(cairo, config->font, output->scale, false, "%s", error); 51 pango_printf(cairo, font, output->scale, false, "%s", error);
49 *x -= margin; 52 *x -= margin;
50 return surface_height; 53 return output->height;
51} 54}
52 55
53static uint32_t render_status_line_text(cairo_t *cairo, 56static uint32_t render_status_line_text(cairo_t *cairo,
54 struct swaybar_output *output, struct swaybar_config *config, 57 struct swaybar_output *output, double *x) {
55 const char *text, bool focused, double *x, uint32_t surface_height) { 58 const char *text = output->bar->status->text;
56 if (!text) { 59 if (!text) {
57 return 0; 60 return 0;
58 } 61 }
59 62
60 uint32_t height = surface_height * output->scale; 63 struct swaybar_config *config = output->bar->config;
61 64 cairo_set_source_u32(cairo, output->focused ?
62 cairo_set_source_u32(cairo, focused ?
63 config->colors.focused_statusline : config->colors.statusline); 65 config->colors.focused_statusline : config->colors.statusline);
64 66
65 int text_width, text_height; 67 int text_width, text_height;
@@ -71,17 +73,18 @@ static uint32_t render_status_line_text(cairo_t *cairo,
71 73
72 uint32_t ideal_height = text_height + ws_vertical_padding * 2; 74 uint32_t ideal_height = text_height + ws_vertical_padding * 2;
73 uint32_t ideal_surface_height = ideal_height / output->scale; 75 uint32_t ideal_surface_height = ideal_height / output->scale;
74 if (surface_height < ideal_surface_height) { 76 if (output->height < ideal_surface_height) {
75 return ideal_surface_height; 77 return ideal_surface_height;
76 } 78 }
77 79
78 *x -= text_width + margin; 80 *x -= text_width + margin;
81 uint32_t height = output->height * output->scale;
79 double text_y = height / 2.0 - text_height / 2.0; 82 double text_y = height / 2.0 - text_height / 2.0;
80 cairo_move_to(cairo, *x, (int)floor(text_y)); 83 cairo_move_to(cairo, *x, (int)floor(text_y));
81 pango_printf(cairo, config->font, output->scale, 84 pango_printf(cairo, config->font, output->scale,
82 config->pango_markup, "%s", text); 85 config->pango_markup, "%s", text);
83 *x -= margin; 86 *x -= margin;
84 return surface_height; 87 return output->height;
85} 88}
86 89
87static void render_sharp_line(cairo_t *cairo, uint32_t color, 90static void render_sharp_line(cairo_t *cairo, uint32_t color,
@@ -121,12 +124,11 @@ static void i3bar_block_unref_callback(void *data) {
121 124
122static uint32_t render_status_block(cairo_t *cairo, 125static uint32_t render_status_block(cairo_t *cairo,
123 struct swaybar_output *output, struct i3bar_block *block, double *x, 126 struct swaybar_output *output, struct i3bar_block *block, double *x,
124 uint32_t surface_height, bool focused, bool edge) { 127 bool edge) {
125 if (!block->full_text || !*block->full_text) { 128 if (!block->full_text || !*block->full_text) {
126 return 0; 129 return 0;
127 } 130 }
128 131
129 uint32_t height = surface_height * output->scale;
130 struct swaybar_config *config = output->bar->config; 132 struct swaybar_config *config = output->bar->config;
131 133
132 int text_width, text_height; 134 int text_width, text_height;
@@ -144,7 +146,7 @@ static uint32_t render_status_block(cairo_t *cairo,
144 double block_width = width; 146 double block_width = width;
145 uint32_t ideal_height = text_height + ws_vertical_padding * 2; 147 uint32_t ideal_height = text_height + ws_vertical_padding * 2;
146 uint32_t ideal_surface_height = ideal_height / output->scale; 148 uint32_t ideal_surface_height = ideal_height / output->scale;
147 if (surface_height < ideal_surface_height) { 149 if (output->height < ideal_surface_height) {
148 return ideal_surface_height; 150 return ideal_surface_height;
149 } 151 }
150 152
@@ -165,7 +167,7 @@ static uint32_t render_status_block(cairo_t *cairo,
165 output->scale, false, "%s", config->sep_symbol); 167 output->scale, false, "%s", config->sep_symbol);
166 uint32_t _ideal_height = sep_height + ws_vertical_padding * 2; 168 uint32_t _ideal_height = sep_height + ws_vertical_padding * 2;
167 uint32_t _ideal_surface_height = _ideal_height / output->scale; 169 uint32_t _ideal_surface_height = _ideal_height / output->scale;
168 if (surface_height < _ideal_surface_height) { 170 if (output->height < _ideal_surface_height) {
169 return _ideal_surface_height; 171 return _ideal_surface_height;
170 } 172 }
171 if (sep_width > block->separator_block_width) { 173 if (sep_width > block->separator_block_width) {
@@ -177,6 +179,7 @@ static uint32_t render_status_block(cairo_t *cairo,
177 *x -= margin; 179 *x -= margin;
178 } 180 }
179 181
182 uint32_t height = output->height * output->scale;
180 if (output->bar->status->click_events) { 183 if (output->bar->status->click_events) {
181 struct swaybar_hotspot *hotspot = calloc(1, sizeof(struct swaybar_hotspot)); 184 struct swaybar_hotspot *hotspot = calloc(1, sizeof(struct swaybar_hotspot));
182 hotspot->x = *x; 185 hotspot->x = *x;
@@ -240,7 +243,7 @@ static uint32_t render_status_block(cairo_t *cairo,
240 } 243 }
241 244
242 if (!edge && block->separator) { 245 if (!edge && block->separator) {
243 if (focused) { 246 if (output->focused) {
244 cairo_set_source_u32(cairo, config->colors.focused_separator); 247 cairo_set_source_u32(cairo, config->colors.focused_separator);
245 } else { 248 } else {
246 cairo_set_source_u32(cairo, config->colors.separator); 249 cairo_set_source_u32(cairo, config->colors.separator);
@@ -259,19 +262,16 @@ static uint32_t render_status_block(cairo_t *cairo,
259 cairo_stroke(cairo); 262 cairo_stroke(cairo);
260 } 263 }
261 } 264 }
262 return surface_height; 265 return output->height;
263} 266}
264 267
265static uint32_t render_status_line_i3bar(cairo_t *cairo, 268static uint32_t render_status_line_i3bar(cairo_t *cairo,
266 struct swaybar_config *config, struct swaybar_output *output, 269 struct swaybar_output *output, double *x) {
267 struct status_line *status, bool focused,
268 double *x, uint32_t surface_height) {
269 uint32_t max_height = 0; 270 uint32_t max_height = 0;
270 bool edge = true; 271 bool edge = true;
271 struct i3bar_block *block; 272 struct i3bar_block *block;
272 wl_list_for_each(block, &status->blocks, link) { 273 wl_list_for_each(block, &output->bar->status->blocks, link) {
273 uint32_t h = render_status_block(cairo, output, 274 uint32_t h = render_status_block(cairo, output, block, x, edge);
274 block, x, surface_height, focused, edge);
275 max_height = h > max_height ? h : max_height; 275 max_height = h > max_height ? h : max_height;
276 edge = false; 276 edge = false;
277 } 277 }
@@ -279,19 +279,15 @@ static uint32_t render_status_line_i3bar(cairo_t *cairo,
279} 279}
280 280
281static uint32_t render_status_line(cairo_t *cairo, 281static uint32_t render_status_line(cairo_t *cairo,
282 struct swaybar_config *config, struct swaybar_output *output, 282 struct swaybar_output *output, double *x) {
283 struct status_line *status, bool focused, 283 struct status_line *status = output->bar->status;
284 double *x, uint32_t surface_height) {
285 switch (status->protocol) { 284 switch (status->protocol) {
286 case PROTOCOL_ERROR: 285 case PROTOCOL_ERROR:
287 return render_status_line_error(cairo, output, config, 286 return render_status_line_error(cairo, output, x);
288 status->text, x, surface_height);
289 case PROTOCOL_TEXT: 287 case PROTOCOL_TEXT:
290 return render_status_line_text(cairo, output, config, 288 return render_status_line_text(cairo, output, x);
291 status->text, focused, x, surface_height);
292 case PROTOCOL_I3BAR: 289 case PROTOCOL_I3BAR:
293 return render_status_line_i3bar(cairo, config, output, 290 return render_status_line_i3bar(cairo, output, x);
294 status, focused, x, surface_height);
295 case PROTOCOL_UNDEF: 291 case PROTOCOL_UNDEF:
296 return 0; 292 return 0;
297 } 293 }
@@ -299,10 +295,9 @@ static uint32_t render_status_line(cairo_t *cairo,
299} 295}
300 296
301static uint32_t render_binding_mode_indicator(cairo_t *cairo, 297static uint32_t render_binding_mode_indicator(cairo_t *cairo,
302 struct swaybar_output *output, struct swaybar_config *config, 298 struct swaybar_output *output, double x) {
303 const char *mode, double x, uint32_t surface_height) { 299 struct swaybar_config *config = output->bar->config;
304 uint32_t height = surface_height * output->scale; 300 const char *mode = config->mode;
305
306 int text_width, text_height; 301 int text_width, text_height;
307 get_text_size(cairo, config->font, &text_width, &text_height, NULL, 302 get_text_size(cairo, config->font, &text_width, &text_height, NULL,
308 output->scale, config->mode_pango_markup, 303 output->scale, config->mode_pango_markup,
@@ -315,11 +310,12 @@ static uint32_t render_binding_mode_indicator(cairo_t *cairo,
315 uint32_t ideal_height = text_height + ws_vertical_padding * 2 310 uint32_t ideal_height = text_height + ws_vertical_padding * 2
316 + border_width * 2; 311 + border_width * 2;
317 uint32_t ideal_surface_height = ideal_height / output->scale; 312 uint32_t ideal_surface_height = ideal_height / output->scale;
318 if (surface_height < ideal_surface_height) { 313 if (output->height < ideal_surface_height) {
319 return ideal_surface_height; 314 return ideal_surface_height;
320 } 315 }
321 uint32_t width = text_width + ws_horizontal_padding * 2 + border_width * 2; 316 uint32_t width = text_width + ws_horizontal_padding * 2 + border_width * 2;
322 317
318 uint32_t height = output->height * output->scale;
323 cairo_set_source_u32(cairo, config->colors.binding_mode.background); 319 cairo_set_source_u32(cairo, config->colors.binding_mode.background);
324 cairo_rectangle(cairo, x, 0, width, height); 320 cairo_rectangle(cairo, x, 0, width, height);
325 cairo_fill(cairo); 321 cairo_fill(cairo);
@@ -339,7 +335,7 @@ static uint32_t render_binding_mode_indicator(cairo_t *cairo,
339 cairo_move_to(cairo, x + width / 2 - text_width / 2, (int)floor(text_y)); 335 cairo_move_to(cairo, x + width / 2 - text_width / 2, (int)floor(text_y));
340 pango_printf(cairo, config->font, output->scale, config->mode_pango_markup, 336 pango_printf(cairo, config->font, output->scale, config->mode_pango_markup,
341 "%s", mode); 337 "%s", mode);
342 return surface_height; 338 return output->height;
343} 339}
344 340
345static const char *strip_workspace_number(const char *ws_name) { 341static const char *strip_workspace_number(const char *ws_name) {
@@ -365,8 +361,9 @@ static enum hotspot_event_handling workspace_hotspot_callback(struct swaybar_out
365} 361}
366 362
367static uint32_t render_workspace_button(cairo_t *cairo, 363static uint32_t render_workspace_button(cairo_t *cairo,
368 struct swaybar_output *output, struct swaybar_config *config, 364 struct swaybar_output *output,
369 struct swaybar_workspace *ws, double *x, uint32_t surface_height) { 365 struct swaybar_workspace *ws, double *x) {
366 struct swaybar_config *config = output->bar->config;
370 const char *name = ws->name; 367 const char *name = ws->name;
371 if (config->strip_workspace_numbers) { 368 if (config->strip_workspace_numbers) {
372 name = strip_workspace_number(ws->name); 369 name = strip_workspace_number(ws->name);
@@ -383,7 +380,7 @@ static uint32_t render_workspace_button(cairo_t *cairo,
383 box_colors = config->colors.inactive_workspace; 380 box_colors = config->colors.inactive_workspace;
384 } 381 }
385 382
386 uint32_t height = surface_height * output->scale; 383 uint32_t height = output->height * output->scale;
387 384
388 int text_width, text_height; 385 int text_width, text_height;
389 get_text_size(cairo, config->font, &text_width, &text_height, NULL, 386 get_text_size(cairo, config->font, &text_width, &text_height, NULL,
@@ -396,7 +393,7 @@ static uint32_t render_workspace_button(cairo_t *cairo,
396 uint32_t ideal_height = ws_vertical_padding * 2 + text_height 393 uint32_t ideal_height = ws_vertical_padding * 2 + text_height
397 + border_width * 2; 394 + border_width * 2;
398 uint32_t ideal_surface_height = ideal_height / output->scale; 395 uint32_t ideal_surface_height = ideal_height / output->scale;
399 if (surface_height < ideal_surface_height) { 396 if (output->height < ideal_surface_height) {
400 return ideal_surface_height; 397 return ideal_surface_height;
401 } 398 }
402 399
@@ -433,11 +430,11 @@ static uint32_t render_workspace_button(cairo_t *cairo,
433 wl_list_insert(&output->hotspots, &hotspot->link); 430 wl_list_insert(&output->hotspots, &hotspot->link);
434 431
435 *x += width; 432 *x += width;
436 return surface_height; 433 return output->height;
437} 434}
438 435
439static uint32_t render_to_cairo(cairo_t *cairo, 436static uint32_t render_to_cairo(cairo_t *cairo, struct swaybar_output *output) {
440 struct swaybar *bar, struct swaybar_output *output) { 437 struct swaybar *bar = output->bar;
441 struct swaybar_config *config = bar->config; 438 struct swaybar_config *config = bar->config;
442 cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE); 439 cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE);
443 if (output->focused) { 440 if (output->focused) {
@@ -457,29 +454,43 @@ static uint32_t render_to_cairo(cairo_t *cairo,
457 */ 454 */
458 double x = output->width * output->scale; 455 double x = output->width * output->scale;
459 if (bar->status) { 456 if (bar->status) {
460 uint32_t h = render_status_line(cairo, config, output, 457 uint32_t h = render_status_line(cairo, output, &x);
461 bar->status, output->focused, &x, output->height);
462 max_height = h > max_height ? h : max_height; 458 max_height = h > max_height ? h : max_height;
463 } 459 }
464 x = 0; 460 x = 0;
465 if (config->workspace_buttons) { 461 if (config->workspace_buttons) {
466 struct swaybar_workspace *ws; 462 struct swaybar_workspace *ws;
467 wl_list_for_each_reverse(ws, &output->workspaces, link) { 463 wl_list_for_each_reverse(ws, &output->workspaces, link) {
468 uint32_t h = render_workspace_button(cairo, 464 uint32_t h = render_workspace_button(cairo, output, ws, &x);
469 output, config, ws, &x, output->height);
470 max_height = h > max_height ? h : max_height; 465 max_height = h > max_height ? h : max_height;
471 } 466 }
472 } 467 }
473 if (config->binding_mode_indicator && config->mode) { 468 if (config->binding_mode_indicator && config->mode) {
474 uint32_t h = render_binding_mode_indicator(cairo, 469 uint32_t h = render_binding_mode_indicator(cairo, output, x);
475 output, config, config->mode, x, output->height);
476 max_height = h > max_height ? h : max_height; 470 max_height = h > max_height ? h : max_height;
477 } 471 }
478 472
479 return max_height > output->height ? max_height : output->height; 473 return max_height > output->height ? max_height : output->height;
480} 474}
481 475
482void render_frame(struct swaybar *bar, struct swaybar_output *output) { 476static void output_frame_handle_done(void *data, struct wl_callback *callback,
477 uint32_t time) {
478 wl_callback_destroy(callback);
479 struct swaybar_output *output = data;
480 output->frame_scheduled = false;
481 if (output->dirty) {
482 render_frame(output);
483 output->dirty = false;
484 }
485}
486
487static const struct wl_callback_listener output_frame_listener = {
488 .done = output_frame_handle_done
489};
490
491void render_frame(struct swaybar_output *output) {
492 assert(output->surface != NULL);
493
483 struct swaybar_hotspot *hotspot, *tmp; 494 struct swaybar_hotspot *hotspot, *tmp;
484 wl_list_for_each_safe(hotspot, tmp, &output->hotspots, link) { 495 wl_list_for_each_safe(hotspot, tmp, &output->hotspots, link) {
485 if (hotspot->destroy) { 496 if (hotspot->destroy) {
@@ -492,13 +503,21 @@ void render_frame(struct swaybar *bar, struct swaybar_output *output) {
492 cairo_surface_t *recorder = cairo_recording_surface_create( 503 cairo_surface_t *recorder = cairo_recording_surface_create(
493 CAIRO_CONTENT_COLOR_ALPHA, NULL); 504 CAIRO_CONTENT_COLOR_ALPHA, NULL);
494 cairo_t *cairo = cairo_create(recorder); 505 cairo_t *cairo = cairo_create(recorder);
506 cairo_set_antialias(cairo, CAIRO_ANTIALIAS_BEST);
507 cairo_font_options_t *fo = cairo_font_options_create();
508 cairo_font_options_set_hint_style(fo, CAIRO_HINT_STYLE_FULL);
509 cairo_font_options_set_antialias(fo, CAIRO_ANTIALIAS_SUBPIXEL);
510 cairo_font_options_set_subpixel_order(fo, to_cairo_subpixel_order(output->subpixel));
511 cairo_set_font_options(cairo, fo);
512 cairo_font_options_destroy(fo);
495 cairo_save(cairo); 513 cairo_save(cairo);
496 cairo_set_operator(cairo, CAIRO_OPERATOR_CLEAR); 514 cairo_set_operator(cairo, CAIRO_OPERATOR_CLEAR);
497 cairo_paint(cairo); 515 cairo_paint(cairo);
498 cairo_restore(cairo); 516 cairo_restore(cairo);
499 uint32_t height = render_to_cairo(cairo, bar, output); 517 uint32_t height = render_to_cairo(cairo, output);
500 if (bar->config->height >= 0 && height < (uint32_t)bar->config->height) { 518 int config_height = output->bar->config->height;
501 height = bar->config->height; 519 if (config_height >= 0 && height < (uint32_t)config_height) {
520 height = config_height;
502 } 521 }
503 if (height != output->height) { 522 if (height != output->height) {
504 // Reconfigure surface 523 // Reconfigure surface
@@ -507,14 +526,15 @@ void render_frame(struct swaybar *bar, struct swaybar_output *output) {
507 // TODO: this could infinite loop if the compositor assigns us a 526 // TODO: this could infinite loop if the compositor assigns us a
508 // different height than what we asked for 527 // different height than what we asked for
509 wl_surface_commit(output->surface); 528 wl_surface_commit(output->surface);
510 wl_display_roundtrip(bar->display);
511 } else if (height > 0) { 529 } else if (height > 0) {
512 // Replay recording into shm and send it off 530 // Replay recording into shm and send it off
513 output->current_buffer = get_next_buffer(bar->shm, 531 output->current_buffer = get_next_buffer(output->bar->shm,
514 output->buffers, 532 output->buffers,
515 output->width * output->scale, 533 output->width * output->scale,
516 output->height * output->scale); 534 output->height * output->scale);
517 if (!output->current_buffer) { 535 if (!output->current_buffer) {
536 cairo_surface_destroy(recorder);
537 cairo_destroy(cairo);
518 return; 538 return;
519 } 539 }
520 cairo_t *shm = output->current_buffer->cairo; 540 cairo_t *shm = output->current_buffer->cairo;
@@ -532,8 +552,12 @@ void render_frame(struct swaybar *bar, struct swaybar_output *output) {
532 output->current_buffer->buffer, 0, 0); 552 output->current_buffer->buffer, 0, 0);
533 wl_surface_damage(output->surface, 0, 0, 553 wl_surface_damage(output->surface, 0, 0,
534 output->width, output->height); 554 output->width, output->height);
555
556 struct wl_callback *frame_callback = wl_surface_frame(output->surface);
557 wl_callback_add_listener(frame_callback, &output_frame_listener, output);
558 output->frame_scheduled = true;
559
535 wl_surface_commit(output->surface); 560 wl_surface_commit(output->surface);
536 wl_display_roundtrip(bar->display);
537 } 561 }
538 cairo_surface_destroy(recorder); 562 cairo_surface_destroy(recorder);
539 cairo_destroy(cairo); 563 cairo_destroy(cairo);
diff --git a/swaybar/status_line.c b/swaybar/status_line.c
index 401bf6f6..ed6dc7c8 100644
--- a/swaybar/status_line.c
+++ b/swaybar/status_line.c
@@ -1,12 +1,15 @@
1#define _POSIX_C_SOURCE 200809L 1#define _POSIX_C_SOURCE 200809L
2#include <fcntl.h> 2#include <fcntl.h>
3#include <sys/ioctl.h>
3#include <json-c/json.h> 4#include <json-c/json.h>
4#include <stdlib.h> 5#include <stdlib.h>
5#include <string.h> 6#include <string.h>
6#include <stdio.h> 7#include <stdio.h>
7#include <unistd.h> 8#include <unistd.h>
8#include <wlr/util/log.h> 9#include <wlr/util/log.h>
10#include "swaybar/bar.h"
9#include "swaybar/config.h" 11#include "swaybar/config.h"
12#include "swaybar/i3bar.h"
10#include "swaybar/event_loop.h" 13#include "swaybar/event_loop.h"
11#include "swaybar/status_line.h" 14#include "swaybar/status_line.h"
12#include "readline.h" 15#include "readline.h"
@@ -34,18 +37,35 @@ bool status_handle_readable(struct status_line *status) {
34 switch (status->protocol) { 37 switch (status->protocol) {
35 case PROTOCOL_UNDEF: 38 case PROTOCOL_UNDEF:
36 errno = 0; 39 errno = 0;
37 read_bytes = getline(&status->buffer, 40 int available_bytes;
38 &status->buffer_size, status->read); 41 if (ioctl(status->read_fd, FIONREAD, &available_bytes) == -1) {
39 if (errno == EAGAIN) { 42 wlr_log(WLR_ERROR, "Unable to read status command output size");
40 clearerr(status->read);
41 } else if (errno) {
42 status_error(status, "[error reading from status command]"); 43 status_error(status, "[error reading from status command]");
43 return true; 44 return true;
44 } 45 }
45 46
47 if ((size_t)available_bytes + 1 > status->buffer_size) {
48 // need room for leading '\0' too
49 status->buffer_size = available_bytes + 1;
50 status->buffer = realloc(status->buffer, status->buffer_size);
51 }
52 if (status->buffer == NULL) {
53 wlr_log_errno(WLR_ERROR, "Unable to read status line");
54 status_error(status, "[error reading from status command]");
55 return true;
56 }
57
58 read_bytes = read(status->read_fd, status->buffer, available_bytes);
59 if (read_bytes != available_bytes) {
60 status_error(status, "[error reading from status command]");
61 return true;
62 }
63 status->buffer[available_bytes] = 0;
64
46 // the header must be sent completely the first time round 65 // the header must be sent completely the first time round
66 char *newline = strchr(status->buffer, '\n');
47 json_object *header, *version; 67 json_object *header, *version;
48 if (status->buffer[read_bytes - 1] == '\n' 68 if (newline != NULL
49 && (header = json_tokener_parse(status->buffer)) 69 && (header = json_tokener_parse(status->buffer))
50 && json_object_object_get_ex(header, "version", &version) 70 && json_object_object_get_ex(header, "version", &version)
51 && json_object_get_int(version) == 1) { 71 && json_object_get_int(version) == 1) {
@@ -67,8 +87,8 @@ bool status_handle_readable(struct status_line *status) {
67 87
68 wl_list_init(&status->blocks); 88 wl_list_init(&status->blocks);
69 status->tokener = json_tokener_new(); 89 status->tokener = json_tokener_new();
70 status->buffer_index = getdelim(&status->buffer, 90 status->buffer_index = strlen(newline + 1);
71 &status->buffer_size, EOF, status->read); 91 memmove(status->buffer, newline + 1, status->buffer_index + 1);
72 return i3bar_handle_readable(status); 92 return i3bar_handle_readable(status);
73 } 93 }
74 94