From 0e866013b69e5f63d0676777b88fe37241a369a4 Mon Sep 17 00:00:00 2001 From: Jarkko Oranen Date: Fri, 13 Mar 2020 21:33:05 +0200 Subject: [PATCH] Don't use title content in size calculations Make height configurable instead This prevents distracting screen flashing and seems to work fine for larger glyphs as well (Tested with Japanese). squashed: Free layout and buffer squashed: pass in markup information --- common/pango.c | 34 ++++++++++++++++++++++++ include/pango.h | 2 ++ include/sway/commands.h | 1 + include/sway/config.h | 13 +-------- include/sway/tree/container.h | 2 +- sway/commands.c | 1 + sway/commands/font.c | 1 - sway/commands/reload.c | 1 - sway/commands/title_format.c | 1 - sway/commands/titlebar_max_text_height.c | 29 ++++++++++++++++++++ sway/config.c | 34 ++---------------------- sway/desktop/render.c | 20 +++++++------- sway/meson.build | 1 + sway/tree/container.c | 18 +++++++------ sway/tree/view.c | 1 - 15 files changed, 91 insertions(+), 68 deletions(-) create mode 100644 sway/commands/titlebar_max_text_height.c diff --git a/common/pango.c b/common/pango.c index fc3d06886..b08757de4 100644 --- a/common/pango.c +++ b/common/pango.c @@ -82,6 +82,40 @@ PangoLayout *get_pango_layout(cairo_t *cairo, const char *font, return layout; } +void get_text_physical_size(cairo_t *cairo, const char *font, int* ascent, int* descent, + int* ink_size, bool markup, const char *fmt, ...) { + va_list args; + va_start(args, fmt); + // Add one since vsnprintf excludes null terminator. + int length = vsnprintf(NULL, 0, fmt, args) + 1; + va_end(args); + + char *buf = malloc(length); + if (buf == NULL) { + sway_log(SWAY_ERROR, "Failed to allocate memory"); + return; + } + va_start(args, fmt); + vsnprintf(buf, length, fmt, args); + va_end(args); + + PangoLayout *layout = get_pango_layout(cairo, font, buf, 1, markup); + pango_cairo_update_layout(cairo, layout); + PangoRectangle ir, lr; + pango_layout_get_pixel_extents(layout, &ir, &lr); + if (ascent) { + *ascent = PANGO_ASCENT(ir); + } + if (descent) { + *descent = PANGO_DESCENT(ir); + } + if (ink_size) { + *ink_size = ir.height; + } + g_object_unref(layout); + free(buf); +} + void get_text_size(cairo_t *cairo, const char *font, int *width, int *height, int *baseline, double scale, bool markup, const char *fmt, ...) { va_list args; diff --git a/include/pango.h b/include/pango.h index 6ab83c167..ae245a02c 100644 --- a/include/pango.h +++ b/include/pango.h @@ -15,6 +15,8 @@ size_t escape_markup_text(const char *src, char *dest); PangoLayout *get_pango_layout(cairo_t *cairo, const char *font, const char *text, double scale, bool markup); +void get_text_physical_size(cairo_t *cairo, const char *font, int *ascent, int* descent, + int *ink_size, bool markup, const char *fmt, ...); void get_text_size(cairo_t *cairo, const char *font, int *width, int *height, int *baseline, double scale, bool markup, const char *fmt, ...); void pango_printf(cairo_t *cairo, const char *font, diff --git a/include/sway/commands.h b/include/sway/commands.h index 964b36611..02cb43864 100644 --- a/include/sway/commands.h +++ b/include/sway/commands.h @@ -187,6 +187,7 @@ sway_cmd cmd_tiling_drag_threshold; sway_cmd cmd_title_align; sway_cmd cmd_title_format; sway_cmd cmd_titlebar_border_thickness; +sway_cmd cmd_titlebar_max_text_height; sway_cmd cmd_titlebar_padding; sway_cmd cmd_unbindcode; sway_cmd cmd_unbindswitch; diff --git a/include/sway/config.h b/include/sway/config.h index 59f22ae2b..be8607c0c 100644 --- a/include/sway/config.h +++ b/include/sway/config.h @@ -480,10 +480,9 @@ struct sway_config { enum sway_container_layout default_orientation; enum sway_container_layout default_layout; char *font; - size_t font_height; - size_t font_baseline; bool pango_markup; int titlebar_border_thickness; + int titlebar_max_text_height; int titlebar_h_padding; int titlebar_v_padding; size_t urgent_timeout; @@ -689,16 +688,6 @@ void free_bar_binding(struct bar_binding *binding); void free_workspace_config(struct workspace_config *wsc); -/** - * Updates the value of config->font_height based on the max title height - * reported by each container. If recalculate is true, the containers will - * recalculate their heights before reporting. - * - * If the height has changed, all containers will be rearranged to take on the - * new size. - */ -void config_update_font_height(bool recalculate); - /** * Convert bindsym into bindcode using the first configured layout. * Return false in case the conversion is unsuccessful. diff --git a/include/sway/tree/container.h b/include/sway/tree/container.h index c92901082..3059d369e 100644 --- a/include/sway/tree/container.h +++ b/include/sway/tree/container.h @@ -142,7 +142,7 @@ struct sway_container { struct wlr_texture *title_unfocused; struct wlr_texture *title_urgent; size_t title_height; - size_t title_baseline; + int title_ascent; list_t *marks; // char * struct wlr_texture *marks_focused; diff --git a/sway/commands.c b/sway/commands.c index fe1e98b53..916b40576 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -89,6 +89,7 @@ static struct cmd_handler handlers[] = { { "tiling_drag_threshold", cmd_tiling_drag_threshold }, { "title_align", cmd_title_align }, { "titlebar_border_thickness", cmd_titlebar_border_thickness }, + { "titlebar_max_text_height", cmd_titlebar_max_text_height }, { "titlebar_padding", cmd_titlebar_padding }, { "unbindcode", cmd_unbindcode }, { "unbindswitch", cmd_unbindswitch }, diff --git a/sway/commands/font.c b/sway/commands/font.c index c54365b53..c01980a74 100644 --- a/sway/commands/font.c +++ b/sway/commands/font.c @@ -22,6 +22,5 @@ struct cmd_results *cmd_font(int argc, char **argv) { } free(font); - config_update_font_height(true); return cmd_results_new(CMD_SUCCESS, NULL); } diff --git a/sway/commands/reload.c b/sway/commands/reload.c index 3c994d54f..76f14bba3 100644 --- a/sway/commands/reload.c +++ b/sway/commands/reload.c @@ -48,7 +48,6 @@ static void do_reload(void *data) { } list_free_items_and_destroy(bar_ids); - config_update_font_height(true); root_for_each_container(rebuild_textures_iterator, NULL); arrange_root(); diff --git a/sway/commands/title_format.c b/sway/commands/title_format.c index 9d312470e..a2446b7e4 100644 --- a/sway/commands/title_format.c +++ b/sway/commands/title_format.c @@ -23,6 +23,5 @@ struct cmd_results *cmd_title_format(int argc, char **argv) { } view->title_format = format; view_update_title(view, true); - config_update_font_height(true); return cmd_results_new(CMD_SUCCESS, NULL); } diff --git a/sway/commands/titlebar_max_text_height.c b/sway/commands/titlebar_max_text_height.c new file mode 100644 index 000000000..e7a8d3654 --- /dev/null +++ b/sway/commands/titlebar_max_text_height.c @@ -0,0 +1,29 @@ +#include +#include "sway/commands.h" +#include "sway/config.h" +#include "sway/output.h" +#include "sway/tree/arrange.h" +#include "log.h" + +struct cmd_results *cmd_titlebar_max_text_height(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "titlebar_max_text_height", EXPECTED_EQUAL_TO, 1))) { + return error; + } + + char *inv; + int value = strtol(argv[0], &inv, 10); + if (*inv != '\0' || value < 0) { + return cmd_results_new(CMD_FAILURE, "Invalid size specified"); + } + + config->titlebar_max_text_height = value; + + for (int i = 0; i < root->outputs->length; ++i) { + struct sway_output *output = root->outputs->items[i]; + arrange_workspace(output_get_active_workspace(output)); + output_damage_whole(output); + } + + return cmd_results_new(CMD_SUCCESS, NULL); +} diff --git a/sway/config.c b/sway/config.c index 71382b864..43aef1fae 100644 --- a/sway/config.c +++ b/sway/config.c @@ -236,13 +236,14 @@ static void config_defaults(struct sway_config *config) { config->default_layout = L_NONE; config->default_orientation = L_NONE; if (!(config->font = strdup("monospace 10"))) goto cleanup; - config->font_height = 17; // height of monospace 10 config->urgent_timeout = 500; config->focus_on_window_activation = FOWA_URGENT; config->popup_during_fullscreen = POPUP_SMART; config->xwayland = XWAYLAND_MODE_LAZY; + config->titlebar_max_text_height = 17; // height of monospace 10 config->titlebar_border_thickness = 1; + config->titlebar_h_padding = 5; config->titlebar_v_padding = 4; @@ -960,37 +961,6 @@ int workspace_output_cmp_workspace(const void *a, const void *b) { return lenient_strcmp(wsa->workspace, wsb->workspace); } -static void find_font_height_iterator(struct sway_container *con, void *data) { - size_t amount_below_baseline = con->title_height - con->title_baseline; - size_t extended_height = config->font_baseline + amount_below_baseline; - if (extended_height > config->font_height) { - config->font_height = extended_height; - } -} - -static void find_baseline_iterator(struct sway_container *con, void *data) { - bool *recalculate = data; - if (*recalculate) { - container_calculate_title_height(con); - } - if (con->title_baseline > config->font_baseline) { - config->font_baseline = con->title_baseline; - } -} - -void config_update_font_height(bool recalculate) { - size_t prev_max_height = config->font_height; - config->font_height = 0; - config->font_baseline = 0; - - root_for_each_container(find_baseline_iterator, &recalculate); - root_for_each_container(find_font_height_iterator, NULL); - - if (config->font_height != prev_max_height) { - arrange_root(); - } -} - static void translate_binding_list(list_t *bindings, list_t *bindsyms, list_t *bindcodes) { for (int i = 0; i < bindings->length; ++i) { diff --git a/sway/desktop/render.c b/sway/desktop/render.c index 3a4222935..8bac6730d 100644 --- a/sway/desktop/render.c +++ b/sway/desktop/render.c @@ -468,7 +468,7 @@ static void render_titlebar(struct sway_output *output, int ob_inner_width = scale_length(inner_width, inner_x, output_scale); int ob_bg_height = scale_length( (titlebar_v_padding - titlebar_border_thickness) * 2 + - config->font_height, bg_y, output_scale); + config->titlebar_max_text_height, bg_y, output_scale); // Marks int ob_marks_x = 0; // output-buffer-local @@ -479,11 +479,11 @@ static void render_titlebar(struct sway_output *output, &texture_box.width, &texture_box.height); ob_marks_width = texture_box.width; - // The marks texture might be shorter than the config->font_height, in + // The marks texture might be shorter than config->titlebar_max_text_height, in // which case we need to pad it as evenly as possible above and below. int ob_padding_total = ob_bg_height - texture_box.height; int ob_padding_above = floor(ob_padding_total / 2.0); - int ob_padding_below = ceil(ob_padding_total / 2.0); + int ob_padding_below = ob_padding_total - ob_padding_above; // Render texture. If the title is on the right, the marks will be on // the left. Otherwise, they will be on the right. @@ -532,13 +532,11 @@ static void render_titlebar(struct sway_output *output, &texture_box.width, &texture_box.height); ob_title_width = texture_box.width; - // The title texture might be shorter than the config->font_height, + // The title texture might be shorter than config->titlebar_max_text_height, // in which case we need to pad it above and below. - int ob_padding_above = round((config->font_baseline - - con->title_baseline + titlebar_v_padding - - titlebar_border_thickness) * output_scale); - int ob_padding_below = ob_bg_height - ob_padding_above - - texture_box.height; + int ob_padding_total = fmax(0, (ob_bg_height - con->title_height)); + int ob_padding_above = floor(ob_padding_total / 2.0); + int ob_padding_below = ob_padding_total - ob_padding_above; // Render texture if (texture_box.width > ob_inner_width - ob_marks_width) { @@ -630,7 +628,7 @@ static void render_titlebar(struct sway_output *output, box.y = y + titlebar_border_thickness; box.width = titlebar_h_padding - titlebar_border_thickness; box.height = (titlebar_v_padding - titlebar_border_thickness) * 2 + - config->font_height; + config->titlebar_max_text_height; scale_box(&box, output_scale); int left_x = ob_left_x + round(output_x * output_scale); if (box.x + box.width < left_x) { @@ -643,7 +641,7 @@ static void render_titlebar(struct sway_output *output, box.y = y + titlebar_border_thickness; box.width = titlebar_h_padding - titlebar_border_thickness; box.height = (titlebar_v_padding - titlebar_border_thickness) * 2 + - config->font_height; + config->titlebar_max_text_height; scale_box(&box, output_scale); int right_rx = ob_right_x + ob_right_width + round(output_x * output_scale); if (right_rx < box.x) { diff --git a/sway/meson.build b/sway/meson.build index 6e138101f..c2669711f 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -111,6 +111,7 @@ sway_sources = files( 'commands/title_align.c', 'commands/title_format.c', 'commands/titlebar_border_thickness.c', + 'commands/titlebar_max_text_height.c', 'commands/titlebar_padding.c', 'commands/unmark.c', 'commands/urgent.c', diff --git a/sway/tree/container.c b/sway/tree/container.c index 10d621b4a..9f883e447 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -33,6 +33,7 @@ struct sway_container *container_create(struct sway_view *view) { c->layout = L_NONE; c->view = view; c->alpha = 1.0f; + c->title_ascent = 0; if (!view) { c->children = create_list(); @@ -497,7 +498,7 @@ static void update_title_texture(struct sway_container *con, PangoContext *pango = pango_cairo_create_context(cairo); cairo_set_source_rgba(cairo, class->text[0], class->text[1], class->text[2], class->text[3]); - cairo_move_to(cairo, 0, 0); + cairo_move_to(cairo, 0, con->title_ascent); pango_printf(cairo, config->font, scale, config->pango_markup, "%s", con->formatted_title); @@ -532,13 +533,14 @@ void container_calculate_title_height(struct sway_container *container) { return; } cairo_t *cairo = cairo_create(NULL); - int height; - int baseline; - get_text_size(cairo, config->font, NULL, &height, &baseline, 1, - config->pango_markup, "%s", container->formatted_title); + int ink_size, ascent; + get_text_physical_size(cairo, config->font, &ascent, NULL, + &ink_size, config->pango_markup, "%s", + container->formatted_title); + cairo_destroy(cairo); - container->title_height = height; - container->title_baseline = baseline; + container->title_height = ink_size; + container->title_ascent = ascent; } /** @@ -617,7 +619,7 @@ void container_update_representation(struct sway_container *con) { } size_t container_titlebar_height(void) { - return config->font_height + config->titlebar_v_padding * 2; + return config->titlebar_max_text_height + config->titlebar_v_padding * 2; } void floating_calculate_constraints(int *min_width, int *max_width, diff --git a/sway/tree/view.c b/sway/tree/view.c index 354f2d34b..6354b7604 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c @@ -1214,7 +1214,6 @@ void view_update_title(struct sway_view *view, bool force) { view->container->formatted_title = NULL; } container_calculate_title_height(view->container); - config_update_font_height(false); // Update title after the global font height is updated container_update_title_textures(view->container);