From 9226aad58cca4dd5a408f46c4ae27f339e415b7d Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Fri, 7 Sep 2018 18:42:43 +1000 Subject: [PATCH 1/2] Fix gaps in title textures and vertically center them There was code that attempted to fill in the gap below the title texture when the texture isn't tall enough, but this only worked when the output was positioned at 0,0. The reason is that render_rect expects a box passed in a hybrid layout-local/output-buffer-local system, and we were passing purely output-buffer-local. I've added a comment documenting this. By the way, we can't use layout-local coordinates for the rectangle box because in some cases we set the box based on a texture size. Texture sizes are buffer-local, and we'd have to divide them to bring it back to layout-local which means losing precision. We could use output-buffer-local coordinates for the box, but this would require translating the coordinates from layout-local to output-buffer-local in many places during rendering. This patch also vertically centers the text inside the title bar. --- sway/desktop/render.c | 90 ++++++++++++++++++++++++++++++++----------- 1 file changed, 68 insertions(+), 22 deletions(-) diff --git a/sway/desktop/render.c b/sway/desktop/render.c index d72d72bf..ecac262e 100644 --- a/sway/desktop/render.c +++ b/sway/desktop/render.c @@ -146,6 +146,8 @@ static void render_drag_icons(struct sway_output *output, render_surface_iterator, &data); } +// _box.x and .y are expected to be layout-local +// _box.width and .height are expected to be output-buffer-local static void render_rect(struct wlr_output *wlr_output, pixman_region32_t *output_damage, const struct wlr_box *_box, float color[static 4]) { @@ -404,9 +406,20 @@ static void render_titlebar(struct sway_output *output, struct wlr_box texture_box; wlr_texture_get_size(marks_texture, &texture_box.width, &texture_box.height); + marks_ob_width = texture_box.width; + + // The marks texture might be shorter than the config->font_height, in + // which case we need to pad it as evenly as possible above and below. + int ob_padding_total = config->font_height * output_scale - + texture_box.height; + int ob_padding_above = floor(ob_padding_total / 2); + int ob_padding_below = ceil(ob_padding_total / 2); + + // Render texture texture_box.x = (x - output_x + width - TITLEBAR_H_PADDING) * output_scale - texture_box.width; - texture_box.y = (y - output_y + TITLEBAR_V_PADDING) * output_scale; + texture_box.y = (y - output_y + TITLEBAR_V_PADDING) * output_scale + + ob_padding_above; float matrix[9]; wlr_matrix_project_box(matrix, &texture_box, @@ -418,17 +431,29 @@ static void render_titlebar(struct sway_output *output, } render_texture(output->wlr_output, output_damage, marks_texture, &texture_box, matrix, con->alpha); - marks_ob_width = texture_box.width; - // Gap between the marks and bottom padding, for when the marks texture - // height is smaller than the config's font height - memcpy(&color, colors->background, sizeof(float) * 4); - premultiply_alpha(color, con->alpha); - box.x = texture_box.x; - box.y = texture_box.y + texture_box.height; - box.width = texture_box.width; - box.height = config->font_height * output_scale - texture_box.height; - if (box.height > 0) { + // Padding above + if (ob_padding_above > 0) { + memcpy(&color, colors->background, sizeof(float) * 4); + premultiply_alpha(color, con->alpha); + box.x = (x + width - TITLEBAR_H_PADDING) * output_scale - + texture_box.width; + box.y = (y + TITLEBAR_V_PADDING) * output_scale; + box.width = texture_box.width; + box.height = ob_padding_above; + render_rect(output->wlr_output, output_damage, &box, color); + } + + // Padding below + if (ob_padding_below > 0) { + memcpy(&color, colors->background, sizeof(float) * 4); + premultiply_alpha(color, con->alpha); + box.x = (x + width - TITLEBAR_H_PADDING) * output_scale - + texture_box.width; + box.y = (y + TITLEBAR_V_PADDING) * output_scale + + ob_padding_above + texture_box.height; + box.width = texture_box.width; + box.height = ob_padding_below; render_rect(output->wlr_output, output_damage, &box, color); } } @@ -439,8 +464,19 @@ static void render_titlebar(struct sway_output *output, struct wlr_box texture_box; wlr_texture_get_size(title_texture, &texture_box.width, &texture_box.height); + title_ob_width = texture_box.width; + + // The title texture might be shorter than the config->font_height, in + // which case we need to pad it as evenly as possible above and below. + int ob_padding_total = config->font_height * output_scale - + texture_box.height; + int ob_padding_above = floor(ob_padding_total / 2); + int ob_padding_below = ceil(ob_padding_total / 2); + + // Render texture texture_box.x = (x - output_x + TITLEBAR_H_PADDING) * output_scale; - texture_box.y = (y - output_y + TITLEBAR_V_PADDING) * output_scale; + texture_box.y = (y - output_y + TITLEBAR_V_PADDING) * output_scale + + ob_padding_above; float matrix[9]; wlr_matrix_project_box(matrix, &texture_box, @@ -452,17 +488,27 @@ static void render_titlebar(struct sway_output *output, } render_texture(output->wlr_output, output_damage, title_texture, &texture_box, matrix, con->alpha); - title_ob_width = texture_box.width; - // Gap between the title and bottom padding, for when the title texture - // height is smaller than the config's font height - memcpy(&color, colors->background, sizeof(float) * 4); - premultiply_alpha(color, con->alpha); - box.x = texture_box.x; - box.y = texture_box.y + texture_box.height; - box.width = texture_box.width; - box.height = config->font_height * output_scale - texture_box.height; - if (box.height > 0) { + // Padding above + if (ob_padding_above > 0) { + memcpy(&color, colors->background, sizeof(float) * 4); + premultiply_alpha(color, con->alpha); + box.x = (x + TITLEBAR_H_PADDING) * output_scale; + box.y = (y + TITLEBAR_V_PADDING) * output_scale; + box.width = texture_box.width; + box.height = ob_padding_above; + render_rect(output->wlr_output, output_damage, &box, color); + } + + // Padding below + if (ob_padding_below > 0) { + memcpy(&color, colors->background, sizeof(float) * 4); + premultiply_alpha(color, con->alpha); + box.x = (x + TITLEBAR_H_PADDING) * output_scale; + box.y = (y + TITLEBAR_V_PADDING) * output_scale + + ob_padding_above + texture_box.height; + box.width = texture_box.width; + box.height = ob_padding_below; render_rect(output->wlr_output, output_damage, &box, color); } } From 9215ca0f01f7d155191d11fd9caa2574387c6f84 Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Sat, 8 Sep 2018 16:19:31 +1000 Subject: [PATCH 2/2] Align titles to baseline This does the following: * Adds a baseline argument to get_text_size (the baseline is the distance from the top of the texture to the baseline). * Stores the baseline in the container when calculating the title height. * Takes the baseline into account when calculating the config's max font height. * When rendering, pads the textures according to the baseline so they line up. --- common/pango.c | 5 ++++- include/pango.h | 2 +- include/sway/config.h | 1 + include/sway/tree/container.h | 1 + sway/config.c | 21 +++++++++++++++------ sway/debug-tree.c | 2 +- sway/desktop/render.c | 12 ++++++------ sway/tree/container.c | 10 ++++++---- sway/tree/view.c | 3 ++- swaybar/render.c | 14 +++++++------- swaynag/render.c | 10 +++++----- 11 files changed, 49 insertions(+), 32 deletions(-) diff --git a/common/pango.c b/common/pango.c index 92703f80..ea71ac4a 100644 --- a/common/pango.c +++ b/common/pango.c @@ -103,7 +103,7 @@ PangoLayout *get_pango_layout(cairo_t *cairo, const char *font, } void get_text_size(cairo_t *cairo, const char *font, int *width, int *height, - double scale, bool markup, const char *fmt, ...) { + int *baseline, double scale, bool markup, const char *fmt, ...) { static char buf[2048]; va_list args; @@ -116,6 +116,9 @@ void get_text_size(cairo_t *cairo, const char *font, int *width, int *height, PangoLayout *layout = get_pango_layout(cairo, font, buf, scale, markup); pango_cairo_update_layout(cairo, layout); pango_layout_get_pixel_size(layout, width, height); + if (baseline) { + *baseline = pango_layout_get_baseline(layout) / PANGO_SCALE; + } g_object_unref(layout); } diff --git a/include/pango.h b/include/pango.h index 4492f01e..09a535a5 100644 --- a/include/pango.h +++ b/include/pango.h @@ -20,7 +20,7 @@ int escape_markup_text(const char *src, char *dest, int dest_length); PangoLayout *get_pango_layout(cairo_t *cairo, const char *font, const char *text, double scale, bool markup); void get_text_size(cairo_t *cairo, const char *font, int *width, int *height, - double scale, bool markup, const char *fmt, ...); + int *baseline, double scale, bool markup, const char *fmt, ...); void pango_printf(cairo_t *cairo, const char *font, double scale, bool markup, const char *fmt, ...); diff --git a/include/sway/config.h b/include/sway/config.h index 2fef0081..b52bb681 100644 --- a/include/sway/config.h +++ b/include/sway/config.h @@ -349,6 +349,7 @@ struct sway_config { enum sway_container_layout default_layout; char *font; size_t font_height; + size_t font_baseline; bool pango_markup; size_t urgent_timeout; enum sway_fowa focus_on_window_activation; diff --git a/include/sway/tree/container.h b/include/sway/tree/container.h index 6efecf7c..2735daa3 100644 --- a/include/sway/tree/container.h +++ b/include/sway/tree/container.h @@ -117,6 +117,7 @@ struct sway_container { struct wlr_texture *title_unfocused; struct wlr_texture *title_urgent; size_t title_height; + size_t title_baseline; struct { struct wl_signal destroy; diff --git a/sway/config.c b/sway/config.c index 89701640..6ff4da03 100644 --- a/sway/config.c +++ b/sway/config.c @@ -807,22 +807,31 @@ 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 *container, - void *data) { +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(container); + container_calculate_title_height(con); } - if (container->title_height > config->font_height) { - config->font_height = container->title_height; + 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_font_height_iterator, &recalculate); + 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(); diff --git a/sway/debug-tree.c b/sway/debug-tree.c index 973c6d88..9644f4e5 100644 --- a/sway/debug-tree.c +++ b/sway/debug-tree.c @@ -84,7 +84,7 @@ static int draw_node(cairo_t *cairo, struct sway_node *node, struct sway_node *focus, int x, int y) { int text_width, text_height; char *buffer = get_string(node); - get_text_size(cairo, "monospace", &text_width, &text_height, + get_text_size(cairo, "monospace", &text_width, &text_height, NULL, 1, false, buffer); cairo_save(cairo); cairo_rectangle(cairo, x + 2, y, text_width - 2, text_height); diff --git a/sway/desktop/render.c b/sway/desktop/render.c index ecac262e..8a6f63aa 100644 --- a/sway/desktop/render.c +++ b/sway/desktop/render.c @@ -466,12 +466,12 @@ static void render_titlebar(struct sway_output *output, &texture_box.width, &texture_box.height); title_ob_width = texture_box.width; - // The title texture might be shorter than the config->font_height, in - // which case we need to pad it as evenly as possible above and below. - int ob_padding_total = config->font_height * output_scale - - texture_box.height; - int ob_padding_above = floor(ob_padding_total / 2); - int ob_padding_below = ceil(ob_padding_total / 2); + // The title texture might be shorter than the config->font_height, + // in which case we need to pad it above and below. + int ob_padding_above = (config->font_baseline - con->title_baseline) + * output_scale; + int ob_padding_below = (config->font_height - con->title_height) + * output_scale - ob_padding_above; // Render texture texture_box.x = (x - output_x + TITLEBAR_H_PADDING) * output_scale; diff --git a/sway/tree/container.c b/sway/tree/container.c index cbbb1f56..ccd79f0e 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -455,8 +455,8 @@ static void update_title_texture(struct sway_container *con, int height = con->title_height * scale; cairo_t *c = cairo_create(NULL); - get_text_size(c, config->font, &width, NULL, scale, config->pango_markup, - "%s", con->formatted_title); + get_text_size(c, config->font, &width, NULL, NULL, scale, + config->pango_markup, "%s", con->formatted_title); cairo_destroy(c); cairo_surface_t *surface = cairo_image_surface_create( @@ -505,10 +505,12 @@ void container_calculate_title_height(struct sway_container *container) { } cairo_t *cairo = cairo_create(NULL); int height; - get_text_size(cairo, config->font, NULL, &height, 1, config->pango_markup, - "%s", container->formatted_title); + int baseline; + get_text_size(cairo, config->font, NULL, &height, &baseline, 1, + config->pango_markup, "%s", container->formatted_title); cairo_destroy(cairo); container->title_height = height; + container->title_baseline = baseline; } /** diff --git a/sway/tree/view.c b/sway/tree/view.c index 312c62d1..53215b40 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c @@ -935,7 +935,8 @@ static void update_marks_texture(struct sway_view *view, int height = view->container->title_height * scale; cairo_t *c = cairo_create(NULL); - get_text_size(c, config->font, &width, NULL, scale, false, "%s", buffer); + get_text_size(c, config->font, &width, NULL, NULL, scale, false, + "%s", buffer); cairo_destroy(c); cairo_surface_t *surface = cairo_image_surface_create( diff --git a/swaybar/render.c b/swaybar/render.c index 702e863c..7303e70f 100644 --- a/swaybar/render.c +++ b/swaybar/render.c @@ -33,8 +33,8 @@ static uint32_t render_status_line_error(cairo_t *cairo, int ws_vertical_padding = WS_VERTICAL_PADDING * output->scale; int text_width, text_height; - get_text_size(cairo, config->font, - &text_width, &text_height, output->scale, false, "%s", error); + get_text_size(cairo, config->font, &text_width, &text_height, NULL, + output->scale, false, "%s", error); uint32_t ideal_height = text_height + ws_vertical_padding * 2; uint32_t ideal_surface_height = ideal_height / output->scale; @@ -63,7 +63,7 @@ static uint32_t render_status_line_text(cairo_t *cairo, config->colors.focused_statusline : config->colors.statusline); int text_width, text_height; - get_text_size(cairo, config->font, &text_width, &text_height, + get_text_size(cairo, config->font, &text_width, &text_height, NULL, output->scale, config->pango_markup, "%s", text); int ws_vertical_padding = WS_VERTICAL_PADDING * output->scale; @@ -126,7 +126,7 @@ static uint32_t render_status_block(cairo_t *cairo, uint32_t height = surface_height * output->scale; int text_width, text_height; - get_text_size(cairo, config->font, &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; @@ -157,7 +157,7 @@ static uint32_t render_status_block(cairo_t *cairo, int sep_width, sep_height; if (!edge) { if (config->sep_symbol) { - get_text_size(cairo, config->font, &sep_width, &sep_height, + 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; @@ -297,7 +297,7 @@ static uint32_t render_binding_mode_indicator(cairo_t *cairo, uint32_t height = surface_height * output->scale; int text_width, text_height; - get_text_size(cairo, config->font, &text_width, &text_height, + get_text_size(cairo, config->font, &text_width, &text_height, NULL, output->scale, config->mode_pango_markup, "%s", mode); @@ -379,7 +379,7 @@ static uint32_t render_workspace_button(cairo_t *cairo, uint32_t height = surface_height * output->scale; int text_width, text_height; - get_text_size(cairo, config->font, &text_width, &text_height, + get_text_size(cairo, config->font, &text_width, &text_height, NULL, output->scale, config->pango_markup, "%s", name); int ws_vertical_padding = WS_VERTICAL_PADDING * output->scale; diff --git a/swaynag/render.c b/swaynag/render.c index 766409e4..7db9fe60 100644 --- a/swaynag/render.c +++ b/swaynag/render.c @@ -12,7 +12,7 @@ static uint32_t render_message(cairo_t *cairo, struct swaynag *swaynag) { height -= swaynag->type->bar_border_thickness * swaynag->scale; int text_width, text_height; - get_text_size(cairo, swaynag->type->font, &text_width, &text_height, + get_text_size(cairo, swaynag->type->font, &text_width, &text_height, NULL, swaynag->scale, true, "%s", swaynag->message); int padding = swaynag->type->message_padding * swaynag->scale; @@ -34,7 +34,7 @@ static uint32_t render_message(cairo_t *cairo, struct swaynag *swaynag) { static void render_details_scroll_button(cairo_t *cairo, struct swaynag *swaynag, struct swaynag_button *button) { int text_width, text_height; - get_text_size(cairo, swaynag->type->font, &text_width, &text_height, + get_text_size(cairo, swaynag->type->font, &text_width, &text_height, NULL, swaynag->scale, true, "%s", button->text); int border = swaynag->type->button_border_thickness * swaynag->scale; @@ -60,10 +60,10 @@ static void render_details_scroll_button(cairo_t *cairo, static int get_detailed_scroll_button_width(cairo_t *cairo, struct swaynag *swaynag) { int up_width, down_width, temp_height; - get_text_size(cairo, swaynag->type->font, &up_width, &temp_height, + get_text_size(cairo, swaynag->type->font, &up_width, &temp_height, NULL, swaynag->scale, true, "%s", swaynag->details.button_up.text); - get_text_size(cairo, swaynag->type->font, &down_width, &temp_height, + get_text_size(cairo, swaynag->type->font, &down_width, &temp_height, NULL, swaynag->scale, true, "%s", swaynag->details.button_down.text); @@ -179,7 +179,7 @@ static uint32_t render_button(cairo_t *cairo, struct swaynag *swaynag, struct swaynag_button *button = swaynag->buttons->items[button_index]; int text_width, text_height; - get_text_size(cairo, swaynag->type->font, &text_width, &text_height, + get_text_size(cairo, swaynag->type->font, &text_width, &text_height, NULL, swaynag->scale, true, "%s", button->text); int border = swaynag->type->button_border_thickness * swaynag->scale;