diff --git a/common/pango.c b/common/pango.c index 658d2876..9437c60d 100644 --- a/common/pango.c +++ b/common/pango.c @@ -8,6 +8,68 @@ #include #include "log.h" +int escape_markup_text(const char *src, char *dest, int dest_length) { + int length = 0; + + while (src[0]) { + switch (src[0]) { + case '&': + length += 5; + if (dest && dest_length - length >= 0) { + dest += sprintf(dest, "%s", "&"); + } else { + dest_length = -1; + } + break; + case '<': + length += 4; + if (dest && dest_length - length >= 0) { + dest += sprintf(dest, "%s", "<"); + } else { + dest_length = -1; + } + break; + case '>': + length += 4; + if (dest && dest_length - length >= 0) { + dest += sprintf(dest, "%s", ">"); + } else { + dest_length = -1; + } + break; + case '\'': + length += 6; + if (dest && dest_length - length >= 0) { + dest += sprintf(dest, "%s", "'"); + } else { + dest_length = -1; + } + break; + case '"': + length += 6; + if (dest && dest_length - length >= 0) { + dest += sprintf(dest, "%s", """); + } else { + dest_length = -1; + } + break; + default: + length += 1; + if (dest && dest_length - length >= 0) { + *(dest++) = *src; + } else { + dest_length = -1; + } + } + src++; + } + // if we could not fit the escaped string in dest, return -1 + if (dest && dest_length == -1) { + return -1; + } + return length; +} + PangoLayout *get_pango_layout(cairo_t *cairo, const char *font, const char *text, int32_t scale, bool markup) { PangoLayout *layout = pango_cairo_create_layout(cairo); @@ -15,13 +77,14 @@ PangoLayout *get_pango_layout(cairo_t *cairo, const char *font, if (markup) { char *buf; GError *error = NULL; - if (!sway_assert(pango_parse_markup( - text, -1, 0, &attrs, &buf, NULL, &error), - "pango_parse_markup '%s' -> error %s", text, - error ? error->message : NULL)) { + bool result = pango_parse_markup(text, -1, 0, &attrs, &buf, + NULL, &error); + if (result) { + wlr_log(L_ERROR, "pango_parse_markup '%s' -> error %s", text, + error->message); return NULL; } - pango_layout_set_markup(layout, buf, -1); + pango_layout_set_markup(layout, text, -1); free(buf); } else { attrs = pango_attr_list_new(); diff --git a/include/pango.h b/include/pango.h index f6325f28..d8263f9e 100644 --- a/include/pango.h +++ b/include/pango.h @@ -6,6 +6,17 @@ #include #include +/* Utility function which escape characters a & < > ' ". + * + * If the dest parameter is NULL, then the function returns the length of + * of the escaped src string. The dest_length doesn't matter. + * + * If the dest parameter is not NULL then the fuction escapes the src string + * an puts the escaped string in dest and returns the lenght of the escaped string. + * The dest_length parameter is the size of dest array. If the size of dest is not + * enough, then the function returns -1. + */ +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, int32_t scale, bool markup); void get_text_size(cairo_t *cairo, const char *font, int *width, int *height, diff --git a/sway/tree/view.c b/sway/tree/view.c index e2cb8a7a..9bdc5198 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c @@ -14,6 +14,8 @@ #include "sway/tree/layout.h" #include "sway/tree/view.h" #include "sway/tree/workspace.h" +#include "sway/config.h" +#include "pango.h" void view_init(struct sway_view *view, enum sway_view_type type, const struct sway_view_impl *impl) { @@ -612,6 +614,19 @@ static size_t parse_title_format(struct sway_view *view, char *buffer) { return len; } +static char *escape_title(char *buffer) { + int length = escape_markup_text(buffer, NULL, 0); + char *escaped_title = calloc(length + 1, sizeof(char)); + int result = escape_markup_text(buffer, escaped_title, length); + if (result != length) { + wlr_log(L_ERROR, "Could not escape title: %s", buffer); + free(escaped_title); + return buffer; + } + free(buffer); + return escaped_title; +} + void view_update_title(struct sway_view *view, bool force) { if (!view->swayc) { return; @@ -631,11 +646,15 @@ void view_update_title(struct sway_view *view, bool force) { free(view->swayc->formatted_title); if (title) { size_t len = parse_title_format(view, NULL); - char *buffer = calloc(len + 1, 1); + char *buffer = calloc(len + 1, sizeof(char)); if (!sway_assert(buffer, "Unable to allocate title string")) { return; } parse_title_format(view, buffer); + // now we have the title, but needs to be escaped when using pango markup + if (config->pango_markup) { + buffer = escape_title(buffer); + } view->swayc->name = strdup(title); view->swayc->formatted_title = buffer;