diff options
Diffstat (limited to 'swaybar')
-rw-r--r-- | swaybar/bar.c | 102 | ||||
-rw-r--r-- | swaybar/config.c | 4 | ||||
-rw-r--r-- | swaybar/ipc.c | 128 | ||||
-rw-r--r-- | swaybar/main.c | 8 | ||||
-rw-r--r-- | swaybar/render.c | 32 | ||||
-rw-r--r-- | swaybar/status_line.c | 14 |
6 files changed, 214 insertions, 74 deletions
diff --git a/swaybar/bar.c b/swaybar/bar.c index 5b7fea71..9f72c94c 100644 --- a/swaybar/bar.c +++ b/swaybar/bar.c @@ -32,9 +32,21 @@ static void bar_init(struct swaybar *bar) { bar->config = init_config(); + bar->visible = true; wl_list_init(&bar->outputs); } +void free_hotspots(struct wl_list *list) { + struct swaybar_hotspot *hotspot, *tmp; + wl_list_for_each_safe(hotspot, tmp, list, link) { + wl_list_remove(&hotspot->link); + if (hotspot->destroy) { + hotspot->destroy(hotspot->data); + } + free(hotspot); + } +} + void free_workspaces(struct wl_list *list) { struct swaybar_workspace *ws, *tmp; wl_list_for_each_safe(ws, tmp, list, link) { @@ -59,14 +71,8 @@ static void swaybar_output_free(struct swaybar_output *output) { wl_output_destroy(output->output); destroy_buffer(&output->buffers[0]); destroy_buffer(&output->buffers[1]); + free_hotspots(&output->hotspots); free_workspaces(&output->workspaces); - struct swaybar_hotspot *hotspot, *hotspot_tmp; - wl_list_for_each_safe(hotspot, hotspot_tmp, &output->hotspots, link) { - if (hotspot->destroy) { - hotspot->destroy(hotspot->data); - } - free(hotspot); - } wl_list_remove(&output->link); free(output->name); free(output); @@ -75,9 +81,7 @@ static void swaybar_output_free(struct swaybar_output *output) { static void set_output_dirty(struct swaybar_output *output) { if (output->frame_scheduled) { output->dirty = true; - return; - } - if (output->surface) { + } else if (output->surface) { render_frame(output); } } @@ -335,21 +339,68 @@ const struct wl_seat_listener seat_listener = { }; static void add_layer_surface(struct swaybar_output *output) { - if (output->surface != NULL) { + if (output->layer_surface) { return; } struct swaybar *bar = output->bar; - output->surface = wl_compositor_create_surface(bar->compositor); - assert(output->surface); + struct swaybar_config *config = bar->config; + bool hidden = strcmp(config->mode, "hide") == 0; output->layer_surface = zwlr_layer_shell_v1_get_layer_surface( bar->layer_shell, output->surface, output->output, + hidden ? ZWLR_LAYER_SHELL_V1_LAYER_TOP : 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); + + zwlr_layer_surface_v1_set_anchor(output->layer_surface, config->position); + if (hidden) { + zwlr_layer_surface_v1_set_exclusive_zone(output->layer_surface, -1); + } +} + +static void destroy_layer_surface(struct swaybar_output *output) { + if (!output->layer_surface) { + return; + } + zwlr_layer_surface_v1_destroy(output->layer_surface); + wl_surface_attach(output->surface, NULL, 0, 0); // detach buffer + output->layer_surface = NULL; + output->width = 0; + output->frame_scheduled = false; +} + +bool determine_bar_visibility(struct swaybar *bar, bool moving_layer) { + struct swaybar_config *config = bar->config; + bool visible = !(strcmp(config->mode, "invisible") == 0 || + (strcmp(config->mode, config->hidden_state) == 0 // both "hide" + && !bar->visible_by_modifier && !bar->visible_by_urgency)); + + struct swaybar_output *output; + if (visible == bar->visible) { + if (visible && moving_layer) { + // need to destroy layer surface to move to a different layer + wl_list_for_each(output, &bar->outputs, link) { + destroy_layer_surface(output); + add_layer_surface(output); + } + } + } else { + bar->visible = visible; + wl_list_for_each(output, &bar->outputs, link) { + if (visible) { + add_layer_surface(output); + } else { + destroy_layer_surface(output); + } + } + wlr_log(WLR_DEBUG, "Sending %s signal to status command", + visible ? "cont" : "stop"); + kill(bar->status->pid, + visible ? bar->status->cont_signal : bar->status->stop_signal); + } + return visible; } static bool bar_uses_output(struct swaybar *bar, const char *name) { @@ -420,8 +471,11 @@ static void xdg_output_handle_done(void *data, wl_list_remove(&output->link); wl_list_insert(&bar->outputs, &output->link); - add_layer_surface(output); - set_output_dirty(output); + output->surface = wl_compositor_create_surface(bar->compositor); + assert(output->surface); + if (bar->visible) { + add_layer_surface(output); + } } } @@ -517,14 +571,13 @@ static void set_bar_dirty(struct swaybar *bar) { } } -bool bar_setup(struct swaybar *bar, - const char *socket_path, const char *bar_id) { +bool bar_setup(struct swaybar *bar, const char *socket_path) { bar_init(bar); init_event_loop(); bar->ipc_socketfd = ipc_open_socket(socket_path); bar->ipc_event_socketfd = ipc_open_socket(socket_path); - if (!ipc_initialize(bar, bar_id)) { + if (!ipc_initialize(bar)) { return false; } if (bar->config->status_command) { @@ -565,8 +618,11 @@ bool bar_setup(struct swaybar *bar, pointer->cursor_surface = wl_compositor_create_surface(bar->compositor); assert(pointer->cursor_surface); - ipc_get_workspaces(bar); - set_bar_dirty(bar); + if (bar->config->workspace_buttons) { + if (ipc_get_workspaces(bar)) { + set_bar_dirty(bar); + } + } return true; } @@ -625,4 +681,6 @@ void bar_teardown(struct swaybar *bar) { if (bar->status) { status_line_free(bar->status); } + free(bar->id); + free(bar->mode); } diff --git a/swaybar/config.c b/swaybar/config.c index 09d40c24..eafb0b69 100644 --- a/swaybar/config.c +++ b/swaybar/config.c @@ -30,7 +30,8 @@ struct swaybar_config *init_config(void) { config->pango_markup = false; config->position = parse_position("bottom"); config->font = strdup("monospace 10"); - config->mode = NULL; + config->mode = strdup("dock"); + config->hidden_state = strdup("hide"); config->sep_symbol = NULL; config->strip_workspace_numbers = false; config->binding_mode_indicator = true; @@ -84,6 +85,7 @@ void free_config(struct swaybar_config *config) { free(config->status_command); free(config->font); free(config->mode); + free(config->hidden_state); free(config->sep_symbol); for (int i = 0; i < config->bindings->length; i++) { struct swaybar_binding *binding = config->bindings->items[i]; diff --git a/swaybar/ipc.c b/swaybar/ipc.c index a67814c1..e1b30b52 100644 --- a/swaybar/ipc.c +++ b/swaybar/ipc.c @@ -152,12 +152,12 @@ static bool ipc_parse_config( json_object_put(bar_config); return false; } - json_object *markup, *mode, *hidden_bar, *position, *status_command; + json_object *markup, *mode, *hidden_state, *position, *status_command; json_object *font, *bar_height, *wrap_scroll, *workspace_buttons, *strip_workspace_numbers; json_object *binding_mode_indicator, *verbose, *colors, *sep_symbol, *outputs; json_object *bindings; json_object_object_get_ex(bar_config, "mode", &mode); - json_object_object_get_ex(bar_config, "hidden_bar", &hidden_bar); + json_object_object_get_ex(bar_config, "hidden_state", &hidden_state); json_object_object_get_ex(bar_config, "position", &position); json_object_object_get_ex(bar_config, "status_command", &status_command); json_object_object_get_ex(bar_config, "font", &font); @@ -220,6 +220,14 @@ static bool ipc_parse_config( list_add(config->bindings, binding); } } + if (hidden_state) { + free(config->hidden_state); + config->hidden_state = strdup(json_object_get_string(hidden_state)); + } + if (mode) { + free(config->mode); + config->mode = strdup(json_object_get_string(mode)); + } struct config_output *output, *tmp; wl_list_for_each_safe(output, tmp, &config->outputs, link) { @@ -254,7 +262,7 @@ static bool ipc_parse_config( return true; } -void ipc_get_workspaces(struct swaybar *bar) { +bool ipc_get_workspaces(struct swaybar *bar) { struct swaybar_output *output; wl_list_for_each(output, &bar->outputs, link) { free_workspaces(&output->workspaces); @@ -266,8 +274,10 @@ void ipc_get_workspaces(struct swaybar *bar) { json_object *results = json_tokener_parse(res); if (!results) { free(res); - return; + return false; } + + bar->visible_by_urgency = false; size_t length = json_object_array_length(results); json_object *ws_json; json_object *num, *name, *visible, *focused, *out, *urgent; @@ -294,12 +304,16 @@ void ipc_get_workspaces(struct swaybar *bar) { output->focused = true; } ws->urgent = json_object_get_boolean(urgent); + if (ws->urgent) { + bar->visible_by_urgency = true; + } wl_list_insert(&output->workspaces, &ws->link); } } } json_object_put(results); free(res); + return determine_bar_visibility(bar, false); } static void ipc_get_outputs(struct swaybar *bar) { @@ -345,10 +359,10 @@ void ipc_execute_binding(struct swaybar *bar, struct swaybar_binding *bind) { IPC_COMMAND, bind->command, &len)); } -bool ipc_initialize(struct swaybar *bar, const char *bar_id) { - uint32_t len = strlen(bar_id); +bool ipc_initialize(struct swaybar *bar) { + uint32_t len = strlen(bar->id); char *res = ipc_single_command(bar->ipc_socketfd, - IPC_GET_BAR_CONFIG, bar_id, &len); + IPC_GET_BAR_CONFIG, bar->id, &len); if (!ipc_parse_config(bar->config, res)) { free(res); return false; @@ -356,56 +370,108 @@ bool ipc_initialize(struct swaybar *bar, const char *bar_id) { free(res); ipc_get_outputs(bar); - const char *subscribe = "[ \"workspace\", \"mode\" ]"; - len = strlen(subscribe); + struct swaybar_config *config = bar->config; + char subscribe[128]; // suitably large buffer + len = snprintf(subscribe, 128, + "[ \"barconfig_update\" , \"bar_state_update\" %s %s ]", + config->binding_mode_indicator ? ", \"mode\"" : "", + config->workspace_buttons ? ", \"workspace\"" : ""); free(ipc_single_command(bar->ipc_event_socketfd, IPC_SUBSCRIBE, subscribe, &len)); return true; } +static bool handle_bar_state_update(struct swaybar *bar, json_object *event) { + json_object *json_id; + json_object_object_get_ex(event, "id", &json_id); + const char *id = json_object_get_string(json_id); + if (strcmp(id, bar->id) != 0) { + return false; + } + + json_object *visible_by_modifier; + json_object_object_get_ex(event, "visible_by_modifier", &visible_by_modifier); + bar->visible_by_modifier = json_object_get_boolean(visible_by_modifier); + return determine_bar_visibility(bar, false); +} + +static bool handle_barconfig_update(struct swaybar *bar, + json_object *json_config) { + json_object *json_id; + json_object_object_get_ex(json_config, "id", &json_id); + const char *id = json_object_get_string(json_id); + if (strcmp(id, bar->id) != 0) { + return false; + } + + struct swaybar_config *config = bar->config; + + json_object *json_state; + json_object_object_get_ex(json_config, "hidden_state", &json_state); + const char *new_state = json_object_get_string(json_state); + char *old_state = config->hidden_state; + if (strcmp(new_state, old_state) != 0) { + wlr_log(WLR_DEBUG, "Changing bar hidden state to %s", new_state); + free(old_state); + config->hidden_state = strdup(new_state); + return determine_bar_visibility(bar, false); + } + + free(config->mode); + json_object *json_mode; + json_object_object_get_ex(json_config, "mode", &json_mode); + config->mode = strdup(json_object_get_string(json_mode)); + wlr_log(WLR_DEBUG, "Changing bar mode to %s", config->mode); + + return determine_bar_visibility(bar, true); +} + bool handle_ipc_readable(struct swaybar *bar) { struct ipc_response *resp = ipc_recv_response(bar->ipc_event_socketfd); if (!resp) { return false; } + + json_object *result = json_tokener_parse(resp->payload); + if (!result) { + wlr_log(WLR_ERROR, "failed to parse payload as json"); + free_ipc_response(resp); + return false; + } + + bool bar_is_dirty = true; switch (resp->type) { case IPC_EVENT_WORKSPACE: - ipc_get_workspaces(bar); + bar_is_dirty = ipc_get_workspaces(bar); break; case IPC_EVENT_MODE: { - json_object *result = json_tokener_parse(resp->payload); - if (!result) { - free_ipc_response(resp); - wlr_log(WLR_ERROR, "failed to parse payload as json"); - return false; - } json_object *json_change, *json_pango_markup; if (json_object_object_get_ex(result, "change", &json_change)) { const char *change = json_object_get_string(json_change); - free(bar->config->mode); - if (strcmp(change, "default") == 0) { - bar->config->mode = NULL; - } else { - bar->config->mode = strdup(change); - } + free(bar->mode); + bar->mode = strcmp(change, "default") != 0 ? strdup(change) : NULL; } else { wlr_log(WLR_ERROR, "failed to parse response"); - json_object_put(result); - free_ipc_response(resp); - return false; + bar_is_dirty = false; + break; } if (json_object_object_get_ex(result, "pango_markup", &json_pango_markup)) { - bar->config->mode_pango_markup = json_object_get_boolean( - json_pango_markup); + bar->mode_pango_markup = json_object_get_boolean(json_pango_markup); } - json_object_put(result); break; } + case IPC_EVENT_BARCONFIG_UPDATE: + bar_is_dirty = handle_barconfig_update(bar, result); + break; + case IPC_EVENT_BAR_STATE_UPDATE: + bar_is_dirty = handle_bar_state_update(bar, result); + break; default: - free_ipc_response(resp); - return false; + bar_is_dirty = false; + break; } + json_object_put(result); free_ipc_response(resp); - return true; + return bar_is_dirty; } diff --git a/swaybar/main.c b/swaybar/main.c index db204f4a..2672abef 100644 --- a/swaybar/main.c +++ b/swaybar/main.c @@ -22,7 +22,6 @@ void sway_terminate(int code) { int main(int argc, char **argv) { char *socket_path = NULL; - char *bar_id = NULL; bool debug = false; static struct option long_options[] = { @@ -59,7 +58,7 @@ int main(int argc, char **argv) { socket_path = strdup(optarg); break; case 'b': // Type - bar_id = strdup(optarg); + swaybar.id = strdup(optarg); break; case 'v': fprintf(stdout, "swaybar version " SWAY_VERSION "\n"); @@ -80,7 +79,7 @@ int main(int argc, char **argv) { wlr_log_init(WLR_ERROR, NULL); } - if (!bar_id) { + if (!swaybar.id) { wlr_log(WLR_ERROR, "No bar_id passed. " "Provide --bar_id or let sway start swaybar"); return 1; @@ -96,13 +95,12 @@ int main(int argc, char **argv) { signal(SIGTERM, sig_handler); - if (!bar_setup(&swaybar, socket_path, bar_id)) { + if (!bar_setup(&swaybar, socket_path)) { free(socket_path); return 1; } free(socket_path); - free(bar_id); bar_run(&swaybar); bar_teardown(&swaybar); diff --git a/swaybar/render.c b/swaybar/render.c index dc31a5ea..097eb462 100644 --- a/swaybar/render.c +++ b/swaybar/render.c @@ -296,11 +296,15 @@ static uint32_t render_status_line(cairo_t *cairo, static uint32_t render_binding_mode_indicator(cairo_t *cairo, struct swaybar_output *output, double x) { + const char *mode = output->bar->mode; + if (!mode) { + return 0; + } + struct swaybar_config *config = output->bar->config; - const char *mode = config->mode; int text_width, text_height; get_text_size(cairo, config->font, &text_width, &text_height, NULL, - output->scale, config->mode_pango_markup, + output->scale, output->bar->mode_pango_markup, "%s", mode); int ws_vertical_padding = WS_VERTICAL_PADDING * output->scale; @@ -333,8 +337,8 @@ static uint32_t render_binding_mode_indicator(cairo_t *cairo, double text_y = height / 2.0 - text_height / 2.0; cairo_set_source_u32(cairo, config->colors.binding_mode.text); cairo_move_to(cairo, x + width / 2 - text_width / 2, (int)floor(text_y)); - pango_printf(cairo, config->font, output->scale, config->mode_pango_markup, - "%s", mode); + pango_printf(cairo, config->font, output->scale, + output->bar->mode_pango_markup, "%s", mode); return output->height; } @@ -465,7 +469,7 @@ static uint32_t render_to_cairo(cairo_t *cairo, struct swaybar_output *output) { max_height = h > max_height ? h : max_height; } } - if (config->binding_mode_indicator && config->mode) { + if (config->binding_mode_indicator) { uint32_t h = render_binding_mode_indicator(cairo, output, x); max_height = h > max_height ? h : max_height; } @@ -490,16 +494,12 @@ static const struct wl_callback_listener output_frame_listener = { void render_frame(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) { - hotspot->destroy(hotspot->data); - } - wl_list_remove(&hotspot->link); - free(hotspot); + if (!output->layer_surface) { + return; } + free_hotspots(&output->hotspots); + cairo_surface_t *recorder = cairo_recording_surface_create( CAIRO_CONTENT_COLOR_ALPHA, NULL); cairo_t *cairo = cairo_create(recorder); @@ -519,10 +519,12 @@ void render_frame(struct swaybar_output *output) { if (config_height >= 0 && height < (uint32_t)config_height) { height = config_height; } - if (height != output->height) { + if (height != output->height || output->width == 0) { // Reconfigure surface zwlr_layer_surface_v1_set_size(output->layer_surface, 0, height); - zwlr_layer_surface_v1_set_exclusive_zone(output->layer_surface, height); + if (strcmp(output->bar->config->mode, "dock") == 0) { + zwlr_layer_surface_v1_set_exclusive_zone(output->layer_surface, height); + } // TODO: this could infinite loop if the compositor assigns us a // different height than what we asked for wl_surface_commit(output->surface); diff --git a/swaybar/status_line.c b/swaybar/status_line.c index ed6dc7c8..000609ce 100644 --- a/swaybar/status_line.c +++ b/swaybar/status_line.c @@ -83,6 +83,17 @@ bool status_handle_readable(struct status_line *status) { return true; } } + + json_object *signal; + if (json_object_object_get_ex(header, "stop_signal", &signal)) { + status->stop_signal = json_object_get_int(signal); + wlr_log(WLR_DEBUG, "Setting stop signal to %d", status->stop_signal); + } + if (json_object_object_get_ex(header, "cont_signal", &signal)) { + status->cont_signal = json_object_get_int(signal); + wlr_log(WLR_DEBUG, "Setting cont signal to %d", status->cont_signal); + } + json_object_put(header); wl_list_init(&status->blocks); @@ -121,6 +132,9 @@ bool status_handle_readable(struct status_line *status) { struct status_line *status_line_init(char *cmd) { struct status_line *status = calloc(1, sizeof(struct status_line)); + status->stop_signal = SIGSTOP; + status->cont_signal = SIGCONT; + status->buffer_size = 8192; status->buffer = malloc(status->buffer_size); |