From 0553e75b53137e6d509b6e336c21586f2b75d527 Mon Sep 17 00:00:00 2001 From: Dmitri Kourennyi Date: Fri, 22 Mar 2019 17:18:21 -0400 Subject: [PATCH] Implement handling of short_text field of i3 input protocol. Matches i3bar behavior of setting all blocks to use the short_text if the full text width does not fit. --- swaybar/render.c | 174 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 170 insertions(+), 4 deletions(-) diff --git a/swaybar/render.c b/swaybar/render.c index 116cc595..faf17509 100644 --- a/swaybar/render.c +++ b/swaybar/render.c @@ -144,16 +144,21 @@ static void i3bar_block_unref_callback(void *data) { static uint32_t render_status_block(cairo_t *cairo, struct swaybar_output *output, struct i3bar_block *block, double *x, - bool edge) { + bool edge, bool use_short_text) { if (!block->full_text || !*block->full_text) { return 0; } + char* text = block->full_text; + if (use_short_text && block->short_text && *block->short_text) { + text = block->short_text; + } + struct swaybar_config *config = output->bar->config; int text_width, text_height; get_text_size(cairo, config->font, &text_width, &text_height, NULL, - output->scale, block->markup, "%s", block->full_text); + output->scale, block->markup, "%s", text); int margin = 3 * output->scale; double ws_vertical_padding = config->status_padding * output->scale; @@ -263,7 +268,7 @@ static uint32_t render_status_block(cairo_t *cairo, color = block->urgent ? config->colors.urgent_workspace.text : color; cairo_set_source_u32(cairo, color); pango_printf(cairo, config->font, output->scale, - block->markup, "%s", block->full_text); + block->markup, "%s", text); x_pos += width; if (block->border && block->border_right > 0) { @@ -294,13 +299,174 @@ static uint32_t render_status_block(cairo_t *cairo, return output->height; } +static void predict_status_block_pos(cairo_t *cairo, + struct swaybar_output *output, struct i3bar_block *block, double *x, + bool edge) { + if (!block->full_text || !*block->full_text) { + return; + } + + struct swaybar_config *config = output->bar->config; + + int text_width, text_height; + get_text_size(cairo, config->font, &text_width, &text_height, NULL, + output->scale, block->markup, "%s", block->full_text); + + int margin = 3 * output->scale; + double ws_vertical_padding = config->status_padding * output->scale; + + int width = text_width; + + if (block->min_width_str) { + int w; + get_text_size(cairo, config->font, &w, NULL, NULL, + output->scale, block->markup, "%s", block->min_width_str); + block->min_width = w; + } + if (width < block->min_width) { + width = block->min_width; + } + + double block_width = width; + uint32_t ideal_height = text_height + ws_vertical_padding * 2; + uint32_t ideal_surface_height = ideal_height / output->scale; + if (!output->bar->config->height && + output->height < ideal_surface_height) { + return; + } + + *x -= width; + if ((block->border || block->urgent) && block->border_left > 0) { + *x -= (block->border_left * output->scale + margin); + block_width += block->border_left * output->scale + margin; + } + if ((block->border || block->urgent) && block->border_right > 0) { + *x -= (block->border_right * output->scale + margin); + block_width += block->border_right * output->scale + margin; + } + + int sep_width, sep_height; + int sep_block_width = block->separator_block_width; + if (!edge) { + if (config->sep_symbol) { + get_text_size(cairo, config->font, &sep_width, &sep_height, NULL, + output->scale, false, "%s", config->sep_symbol); + uint32_t _ideal_height = sep_height + ws_vertical_padding * 2; + uint32_t _ideal_surface_height = _ideal_height / output->scale; + if (!output->bar->config->height && + output->height < _ideal_surface_height) { + return; + } + if (sep_width > sep_block_width) { + sep_block_width = sep_width + margin * 2; + } + } + *x -= sep_block_width; + } else if (config->status_edge_padding) { + *x -= config->status_edge_padding * output->scale; + } +} + +static double predict_status_line_pos(cairo_t *cairo, + struct swaybar_output *output, double x) { + bool edge = x == output->width * output->scale; + struct i3bar_block *block; + wl_list_for_each(block, &output->bar->status->blocks, link) { + predict_status_block_pos(cairo, output, block, &x, edge); + edge = false; + } + return x; +} + +static uint32_t predict_workspace_button_length(cairo_t *cairo, + struct swaybar_output *output, + struct swaybar_workspace *ws) { + struct swaybar_config *config = output->bar->config; + + int text_width, text_height; + get_text_size(cairo, config->font, &text_width, &text_height, NULL, + output->scale, config->pango_markup, "%s", ws->label); + + int ws_vertical_padding = WS_VERTICAL_PADDING * output->scale; + int ws_horizontal_padding = WS_HORIZONTAL_PADDING * output->scale; + int border_width = BORDER_WIDTH * output->scale; + + uint32_t ideal_height = ws_vertical_padding * 2 + text_height + + border_width * 2; + uint32_t ideal_surface_height = ideal_height / output->scale; + if (!output->bar->config->height && + output->height < ideal_surface_height) { + return 0; + } + + return ws_horizontal_padding * 2 + text_width + border_width * 2; +} + +static uint32_t predict_workspace_buttons_length(cairo_t *cairo, + struct swaybar_output *output) { + uint32_t width = 0; + if (output->bar->config->workspace_buttons) { + struct swaybar_workspace *ws; + wl_list_for_each(ws, &output->workspaces, link) { + width += predict_workspace_button_length(cairo, output, ws); + } + } + return width; +} + +static uint32_t predict_binding_mode_indicator_length(cairo_t *cairo, + struct swaybar_output *output) { + const char *mode = output->bar->mode; + if (!mode) { + return 0; + } + + struct swaybar_config *config = output->bar->config; + + if (!config->binding_mode_indicator) { + return 0; + } + + int text_width, text_height; + get_text_size(cairo, config->font, &text_width, &text_height, NULL, + output->scale, output->bar->mode_pango_markup, + "%s", mode); + + int ws_vertical_padding = WS_VERTICAL_PADDING * output->scale; + int ws_horizontal_padding = WS_HORIZONTAL_PADDING * output->scale; + int border_width = BORDER_WIDTH * output->scale; + + uint32_t ideal_height = text_height + ws_vertical_padding * 2 + + border_width * 2; + uint32_t ideal_surface_height = ideal_height / output->scale; + if (!output->bar->config->height && + output->height < ideal_surface_height) { + return 0; + } + return text_width + ws_horizontal_padding * 2 + border_width * 2; +} + static uint32_t render_status_line_i3bar(cairo_t *cairo, struct swaybar_output *output, double *x) { uint32_t max_height = 0; bool edge = *x == output->width * output->scale; struct i3bar_block *block; + bool use_short_text = false; + + // TODO: Add margin here? + uint32_t reserved_width = predict_workspace_buttons_length(cairo, output) + + predict_binding_mode_indicator_length(cairo, output); + + uint32_t predicted_full_pos = + predict_status_line_pos(cairo, output, *x); + + if (predicted_full_pos < reserved_width) { + use_short_text = true; + } + wl_list_for_each(block, &output->bar->status->blocks, link) { - uint32_t h = render_status_block(cairo, output, block, x, edge); + uint32_t h = render_status_block(cairo, output, block, x, edge, + use_short_text); max_height = h > max_height ? h : max_height; edge = false; }