From 82f1393cbb7383179eab2d10ff679a975d1f5c43 Mon Sep 17 00:00:00 2001 From: emersion Date: Wed, 19 Sep 2018 11:37:24 +0200 Subject: [PATCH 1/2] swaybar: handle hotplugging Don't kill and respawn swaybars on hotplug. --- include/sway/config.h | 4 +- sway/config/bar.c | 26 +++------- sway/main.c | 1 + sway/tree/output.c | 2 - swaybar/bar.c | 111 ++++++++++++++++++++++++++---------------- swaybar/render.c | 3 ++ 6 files changed, 81 insertions(+), 66 deletions(-) diff --git a/include/sway/config.h b/include/sway/config.h index b53c1f1f..36d78ec6 100644 --- a/include/sway/config.h +++ b/include/sway/config.h @@ -512,9 +512,7 @@ void free_sway_binding(struct sway_binding *sb); void seat_execute_command(struct sway_seat *seat, struct sway_binding *binding); -void load_swaybars(); - -void invoke_swaybar(struct bar_config *bar); +void load_swaybars(void); void terminate_swaybg(pid_t pid); diff --git a/sway/config/bar.c b/sway/config/bar.c index f83b37d1..48a632fb 100644 --- a/sway/config/bar.c +++ b/sway/config/bar.c @@ -165,7 +165,7 @@ cleanup: return NULL; } -void invoke_swaybar(struct bar_config *bar) { +static void invoke_swaybar(struct bar_config *bar) { // Pipe to communicate errors int filedes[2]; if (pipe(filedes) == -1) { @@ -219,27 +219,13 @@ void invoke_swaybar(struct bar_config *bar) { close(filedes[1]); } -void load_swaybars() { +void load_swaybars(void) { for (int i = 0; i < config->bars->length; ++i) { struct bar_config *bar = config->bars->items[i]; - bool apply = false; - if (bar->outputs) { - for (int j = 0; j < bar->outputs->length; ++j) { - char *o = bar->outputs->items[j]; - if (!strcmp(o, "*") || output_by_name(o)) { - apply = true; - break; - } - } - } else { - apply = true; - } - if (apply) { - if (bar->pid != 0) { - terminate_swaybar(bar->pid); - } - wlr_log(WLR_DEBUG, "Invoking swaybar for bar id '%s'", bar->id); - invoke_swaybar(bar); + if (bar->pid != 0) { + terminate_swaybar(bar->pid); } + wlr_log(WLR_DEBUG, "Invoking swaybar for bar id '%s'", bar->id); + invoke_swaybar(bar); } } diff --git a/sway/main.c b/sway/main.c index fb4f0d8c..3d7cd158 100644 --- a/sway/main.c +++ b/sway/main.c @@ -424,6 +424,7 @@ int main(int argc, char **argv) { } config->active = true; + load_swaybars(); // Execute commands until there are none left wlr_log(WLR_DEBUG, "Running deferred commands"); while (config->cmd_queue->length) { diff --git a/sway/tree/output.c b/sway/tree/output.c index 1976ad51..06933dc4 100644 --- a/sway/tree/output.c +++ b/sway/tree/output.c @@ -109,8 +109,6 @@ void output_enable(struct sway_output *output, struct output_config *oc) { wl_signal_emit(&root->events.new_node, &output->node); - load_swaybars(); - arrange_layers(output); arrange_root(); } diff --git a/swaybar/bar.c b/swaybar/bar.c index 3ae730f7..49a8ece1 100644 --- a/swaybar/bar.c +++ b/swaybar/bar.c @@ -48,8 +48,13 @@ static void swaybar_output_free(struct swaybar_output *output) { return; } wlr_log(WLR_DEBUG, "Removing output %s", output->name); - zwlr_layer_surface_v1_destroy(output->layer_surface); - wl_surface_destroy(output->surface); + if (output->layer_surface != NULL) { + zwlr_layer_surface_v1_destroy(output->layer_surface); + } + if (output->surface != NULL) { + wl_surface_destroy(output->surface); + } + zxdg_output_v1_destroy(output->xdg_output); wl_output_destroy(output->output); destroy_buffer(&output->buffers[0]); destroy_buffer(&output->buffers[1]); @@ -283,6 +288,37 @@ const struct wl_seat_listener seat_listener = { .name = seat_handle_name, }; +static void add_layer_surface(struct swaybar_output *output) { + if (output->surface != NULL) { + return; + } + struct swaybar *bar = output->bar; + + output->surface = wl_compositor_create_surface(bar->compositor); + assert(output->surface); + output->layer_surface = zwlr_layer_shell_v1_get_layer_surface( + bar->layer_shell, output->surface, output->output, + ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM, "panel"); + assert(output->layer_surface); + zwlr_layer_surface_v1_add_listener(output->layer_surface, + &layer_surface_listener, output); + zwlr_layer_surface_v1_set_anchor(output->layer_surface, + bar->config->position); +} + +static bool bar_uses_output(struct swaybar *bar, const char *name) { + if (bar->config->all_outputs) { + return true; + } + struct config_output *coutput; + wl_list_for_each(coutput, &bar->config->outputs, link) { + if (strcmp(coutput->name, name) == 0) { + return true; + } + } + return false; +} + static void output_geometry(void *data, struct wl_output *output, int32_t x, int32_t y, int32_t width_mm, int32_t height_mm, int32_t subpixel, const char *make, const char *model, int32_t transform) { @@ -326,7 +362,22 @@ static void xdg_output_handle_logical_size(void *data, static void xdg_output_handle_done(void *data, struct zxdg_output_v1 *xdg_output) { - // Who cares + struct swaybar_output *output = data; + struct swaybar *bar = output->bar; + + assert(output->name != NULL); + if (!bar_uses_output(bar, output->name)) { + swaybar_output_free(output); + return; + } + + if (wl_list_empty(&output->link)) { + wl_list_remove(&output->link); + wl_list_insert(&bar->outputs, &output->link); + + add_layer_surface(output); + render_frame(bar, output); + } } static void xdg_output_handle_name(void *data, @@ -349,17 +400,15 @@ struct zxdg_output_v1_listener xdg_output_listener = { .description = xdg_output_handle_description, }; -static bool bar_uses_output(struct swaybar *bar, const char *name) { - if (bar->config->all_outputs) { - return true; - } - struct config_output *coutput; - wl_list_for_each(coutput, &bar->config->outputs, link) { - if (strcmp(coutput->name, name) == 0) { - return true; - } +static void add_xdg_output(struct swaybar_output *output) { + if (output->xdg_output != NULL) { + return; } - return false; + assert(output->bar->xdg_output_manager != NULL); + output->xdg_output = zxdg_output_manager_v1_get_xdg_output( + output->bar->xdg_output_manager, output->output); + zxdg_output_v1_add_listener(output->xdg_output, &xdg_output_listener, + output); } static void handle_global(void *data, struct wl_registry *registry, @@ -386,7 +435,10 @@ static void handle_global(void *data, struct wl_registry *registry, output->wl_name = name; wl_list_init(&output->workspaces); wl_list_init(&output->hotspots); - wl_list_insert(&bar->outputs, &output->link); + wl_list_init(&output->link); + if (bar->xdg_output_manager != NULL) { + add_xdg_output(output); + } } else if (strcmp(interface, zwlr_layer_shell_v1_interface.name) == 0) { bar->layer_shell = wl_registry_bind( registry, name, &zwlr_layer_shell_v1_interface, 1); @@ -416,7 +468,9 @@ static const struct wl_registry_listener registry_listener = { static void render_all_frames(struct swaybar *bar) { struct swaybar_output *output; wl_list_for_each(output, &bar->outputs, link) { - render_frame(bar, output); + if (output->surface != NULL) { + render_frame(bar, output); + } } } @@ -443,23 +497,10 @@ void bar_setup(struct swaybar *bar, struct swaybar_output *output; wl_list_for_each(output, &bar->outputs, link) { - output->xdg_output = zxdg_output_manager_v1_get_xdg_output( - bar->xdg_output_manager, output->output); - zxdg_output_v1_add_listener(output->xdg_output, &xdg_output_listener, - output); + add_xdg_output(output); } wl_display_roundtrip(bar->display); - struct swaybar_output *output_tmp; - wl_list_for_each_safe(output, output_tmp, &bar->outputs, link) { - if (!bar_uses_output(bar, output->name)) { - zxdg_output_v1_destroy(output->xdg_output); - wl_output_destroy(output->output); - wl_list_remove(&output->link); - free(output); - } - } - struct swaybar_pointer *pointer = &bar->pointer; int max_scale = 1; @@ -479,18 +520,6 @@ void bar_setup(struct swaybar *bar, pointer->cursor_surface = wl_compositor_create_surface(bar->compositor); assert(pointer->cursor_surface); - wl_list_for_each(output, &bar->outputs, link) { - output->surface = wl_compositor_create_surface(bar->compositor); - assert(output->surface); - output->layer_surface = zwlr_layer_shell_v1_get_layer_surface( - bar->layer_shell, output->surface, output->output, - ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM, "panel"); - assert(output->layer_surface); - zwlr_layer_surface_v1_add_listener(output->layer_surface, - &layer_surface_listener, output); - zwlr_layer_surface_v1_set_anchor(output->layer_surface, - bar->config->position); - } ipc_get_workspaces(bar); render_all_frames(bar); } diff --git a/swaybar/render.c b/swaybar/render.c index 97690338..1f2dcc30 100644 --- a/swaybar/render.c +++ b/swaybar/render.c @@ -1,4 +1,5 @@ #define _POSIX_C_SOURCE 200809L +#include #include #include #include @@ -480,6 +481,8 @@ static uint32_t render_to_cairo(cairo_t *cairo, } void render_frame(struct swaybar *bar, struct swaybar_output *output) { + assert(output->surface != NULL); + struct swaybar_hotspot *hotspot, *tmp; wl_list_for_each_safe(hotspot, tmp, &output->hotspots, link) { if (hotspot->destroy) { From 8a5ff5a4dbcefabaaeae98c1c53befcb986ba117 Mon Sep 17 00:00:00 2001 From: emersion Date: Thu, 20 Sep 2018 19:31:03 +0200 Subject: [PATCH 2/2] swaybar: don't wl_display_roundtrip on each frame This was the source of numerous bugs, from hotplug events not being received to segfaults because wl_display_roundtrip was making the bar process unplug events while blocking in an iteration over all outputs. --- swaybar/bar.c | 1 + swaybar/render.c | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/swaybar/bar.c b/swaybar/bar.c index 49a8ece1..69069f40 100644 --- a/swaybar/bar.c +++ b/swaybar/bar.c @@ -558,6 +558,7 @@ void bar_run(struct swaybar *bar) { } while (1) { event_loop_poll(); + wl_display_flush(bar->display); } } diff --git a/swaybar/render.c b/swaybar/render.c index 1f2dcc30..26db80cb 100644 --- a/swaybar/render.c +++ b/swaybar/render.c @@ -510,7 +510,6 @@ void render_frame(struct swaybar *bar, struct swaybar_output *output) { // TODO: this could infinite loop if the compositor assigns us a // different height than what we asked for wl_surface_commit(output->surface); - wl_display_roundtrip(bar->display); } else if (height > 0) { // Replay recording into shm and send it off output->current_buffer = get_next_buffer(bar->shm, @@ -536,7 +535,6 @@ void render_frame(struct swaybar *bar, struct swaybar_output *output) { wl_surface_damage(output->surface, 0, 0, output->width, output->height); wl_surface_commit(output->surface); - wl_display_roundtrip(bar->display); } cairo_surface_destroy(recorder); cairo_destroy(cairo);