diff --git a/include/sway/tree/container.h b/include/sway/tree/container.h index 8bf1955d7..4608b8ac2 100644 --- a/include/sway/tree/container.h +++ b/include/sway/tree/container.h @@ -102,6 +102,8 @@ struct sway_container { char *title; // The view's title (unformatted) char *formatted_title; // The title displayed in the title bar int title_width; + + char *title_format; enum sway_container_layout prev_split_layout; @@ -183,6 +185,8 @@ void container_update_title_bar(struct sway_container *container); void container_update_marks(struct sway_container *container); +size_t parse_title_format(struct sway_container *container, char *buffer); + size_t container_build_representation(enum sway_container_layout layout, list_t *children, char *buffer); diff --git a/include/sway/tree/view.h b/include/sway/tree/view.h index 14aad1a18..f60322212 100644 --- a/include/sway/tree/view.h +++ b/include/sway/tree/view.h @@ -80,8 +80,6 @@ struct sway_view { // Used when changing a view from tiled to floating. int natural_width, natural_height; - char *title_format; - bool using_csd; struct timespec urgent; diff --git a/sway/commands/title_format.c b/sway/commands/title_format.c index 0b2ea2659..fbade4731 100644 --- a/sway/commands/title_format.c +++ b/sway/commands/title_format.c @@ -1,3 +1,4 @@ +#define _POSIX_C_SOURCE 200809L #include #include "sway/commands.h" #include "sway/config.h" @@ -11,16 +12,19 @@ struct cmd_results *cmd_title_format(int argc, char **argv) { return error; } struct sway_container *container = config->handler_context.container; - if (!container || !container->view) { + if (!container) { return cmd_results_new(CMD_INVALID, - "Only views can have a title_format"); + "Only valid containers can have a title_format"); } - struct sway_view *view = container->view; char *format = join_args(argv, argc); - if (view->title_format) { - free(view->title_format); + if (container->title_format) { + free(container->title_format); + } + container->title_format = format; + if (container->view) { + view_update_title(container->view, true); + } else { + container_update_representation(container); } - view->title_format = format; - view_update_title(view, true); return cmd_results_new(CMD_SUCCESS, NULL); } diff --git a/sway/tree/container.c b/sway/tree/container.c index 46c388b3e..188d3223a 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -22,6 +22,7 @@ #include "sway/tree/workspace.h" #include "sway/xdg_decoration.h" #include "list.h" +#include "pango.h" #include "log.h" #include "stringop.h" @@ -499,6 +500,7 @@ void container_destroy(struct sway_container *con) { } free(con->title); free(con->formatted_title); + free(con->title_format); list_free(con->pending.children); list_free(con->current.children); @@ -645,6 +647,87 @@ bool container_has_ancestor(struct sway_container *descendant, return false; } +static char *escape_pango_markup(const char *buffer) { + size_t length = escape_markup_text(buffer, NULL); + char *escaped_title = calloc(length + 1, sizeof(char)); + escape_markup_text(buffer, escaped_title); + return escaped_title; +} + +static size_t append_prop(char *buffer, const char *value) { + if (!value) { + return 0; + } + // If using pango_markup in font, we need to escape all markup chars + // from values to make sure tags are not inserted by clients + if (config->pango_markup) { + char *escaped_value = escape_pango_markup(value); + lenient_strcat(buffer, escaped_value); + size_t len = strlen(escaped_value); + free(escaped_value); + return len; + } else { + lenient_strcat(buffer, value); + return strlen(value); + } +} + +/** + * Calculate and return the length of the formatted title. + * If buffer is not NULL, also populate the buffer with the formatted title. + */ +size_t parse_title_format(struct sway_container *container, char *buffer) { + if (!container->title_format || strcmp(container->title_format, "%title") == 0) { + if (container->view) { + return append_prop(buffer, view_get_title(container->view)); + } else { + return container_build_representation(container->pending.layout, container->pending.children, buffer); + } + } + + size_t len = 0; + char *format = container->title_format; + char *next = strchr(format, '%'); + while (next) { + // Copy everything up to the % + lenient_strncat(buffer, format, next - format); + len += next - format; + format = next; + + if (strncmp(next, "%title", 6) == 0) { + if (container->view) { + len += append_prop(buffer, view_get_title(container->view)); + } else { + len += container_build_representation(container->pending.layout, container->pending.children, buffer); + } + format += 6; + } else if (container->view) { + if (strncmp(next, "%app_id", 7) == 0) { + len += append_prop(buffer, view_get_app_id(container->view)); + format += 7; + } else if (strncmp(next, "%class", 6) == 0) { + len += append_prop(buffer, view_get_class(container->view)); + format += 6; + } else if (strncmp(next, "%instance", 9) == 0) { + len += append_prop(buffer, view_get_instance(container->view)); + format += 9; + } else if (strncmp(next, "%shell", 6) == 0) { + len += append_prop(buffer, view_get_shell(container->view)); + format += 6; + } + } else { + lenient_strcat(buffer, "%"); + ++format; + ++len; + } + next = strchr(format, '%'); + } + lenient_strcat(buffer, format); + len += strlen(format); + + return len; +} + /** * Calculate and return the length of the tree representation. * An example tree representation is: V[Terminal, Firefox] @@ -700,16 +783,14 @@ size_t container_build_representation(enum sway_container_layout layout, void container_update_representation(struct sway_container *con) { if (!con->view) { - size_t len = container_build_representation(con->pending.layout, - con->pending.children, NULL); + size_t len = parse_title_format(con, NULL); free(con->formatted_title); con->formatted_title = calloc(len + 1, sizeof(char)); if (!sway_assert(con->formatted_title, "Unable to allocate title string")) { return; } - container_build_representation(con->pending.layout, con->pending.children, - con->formatted_title); + parse_title_format(con, con->formatted_title); if (con->title_bar.title_text) { sway_text_node_set_text(con->title_bar.title_text, con->formatted_title); diff --git a/sway/tree/view.c b/sway/tree/view.c index d25a09c2a..492095b93 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c @@ -34,7 +34,6 @@ #include "sway/tree/workspace.h" #include "sway/config.h" #include "sway/xdg_decoration.h" -#include "pango.h" #include "stringop.h" bool view_init(struct sway_view *view, enum sway_view_type type, @@ -81,8 +80,6 @@ void view_destroy(struct sway_view *view) { view_assign_ctx(view, NULL); wlr_scene_node_destroy(&view->scene_tree->node); - free(view->title_format); - if (view->impl->destroy) { view->impl->destroy(view); } else { @@ -991,77 +988,6 @@ struct sway_view *view_from_wlr_surface(struct wlr_surface *wlr_surface) { return NULL; } -static char *escape_pango_markup(const char *buffer) { - size_t length = escape_markup_text(buffer, NULL); - char *escaped_title = calloc(length + 1, sizeof(char)); - escape_markup_text(buffer, escaped_title); - return escaped_title; -} - -static size_t append_prop(char *buffer, const char *value) { - if (!value) { - return 0; - } - // If using pango_markup in font, we need to escape all markup chars - // from values to make sure tags are not inserted by clients - if (config->pango_markup) { - char *escaped_value = escape_pango_markup(value); - lenient_strcat(buffer, escaped_value); - size_t len = strlen(escaped_value); - free(escaped_value); - return len; - } else { - lenient_strcat(buffer, value); - return strlen(value); - } -} - -/** - * Calculate and return the length of the formatted title. - * If buffer is not NULL, also populate the buffer with the formatted title. - */ -static size_t parse_title_format(struct sway_view *view, char *buffer) { - if (!view->title_format || strcmp(view->title_format, "%title") == 0) { - return append_prop(buffer, view_get_title(view)); - } - - size_t len = 0; - char *format = view->title_format; - char *next = strchr(format, '%'); - while (next) { - // Copy everything up to the % - lenient_strncat(buffer, format, next - format); - len += next - format; - format = next; - - if (strncmp(next, "%title", 6) == 0) { - len += append_prop(buffer, view_get_title(view)); - format += 6; - } else if (strncmp(next, "%app_id", 7) == 0) { - len += append_prop(buffer, view_get_app_id(view)); - format += 7; - } else if (strncmp(next, "%class", 6) == 0) { - len += append_prop(buffer, view_get_class(view)); - format += 6; - } else if (strncmp(next, "%instance", 9) == 0) { - len += append_prop(buffer, view_get_instance(view)); - format += 9; - } else if (strncmp(next, "%shell", 6) == 0) { - len += append_prop(buffer, view_get_shell(view)); - format += 6; - } else { - lenient_strcat(buffer, "%"); - ++format; - ++len; - } - next = strchr(format, '%'); - } - lenient_strcat(buffer, format); - len += strlen(format); - - return len; -} - void view_update_app_id(struct sway_view *view) { const char *app_id = view_get_app_id(view); @@ -1090,7 +1016,7 @@ void view_update_title(struct sway_view *view, bool force) { free(view->container->title); free(view->container->formatted_title); - size_t len = parse_title_format(view, NULL); + size_t len = parse_title_format(view->container, NULL); if (len) { char *buffer = calloc(len + 1, sizeof(char)); @@ -1098,7 +1024,7 @@ void view_update_title(struct sway_view *view, bool force) { return; } - parse_title_format(view, buffer); + parse_title_format(view->container, buffer); view->container->formatted_title = buffer; } else { view->container->formatted_title = NULL;