mirror of
https://github.com/swaywm/sway.git
synced 2024-11-26 09:51:29 +00:00
parent
d2fceae379
commit
7246bf909c
|
@ -103,6 +103,8 @@ struct sway_container {
|
||||||
char *formatted_title; // The title displayed in the title bar
|
char *formatted_title; // The title displayed in the title bar
|
||||||
int title_width;
|
int title_width;
|
||||||
|
|
||||||
|
char *title_format;
|
||||||
|
|
||||||
enum sway_container_layout prev_split_layout;
|
enum sway_container_layout prev_split_layout;
|
||||||
|
|
||||||
// Whether stickiness has been enabled on this container. Use
|
// Whether stickiness has been enabled on this container. Use
|
||||||
|
@ -183,6 +185,8 @@ void container_update_title_bar(struct sway_container *container);
|
||||||
|
|
||||||
void container_update_marks(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,
|
size_t container_build_representation(enum sway_container_layout layout,
|
||||||
list_t *children, char *buffer);
|
list_t *children, char *buffer);
|
||||||
|
|
||||||
|
|
|
@ -80,8 +80,6 @@ struct sway_view {
|
||||||
// Used when changing a view from tiled to floating.
|
// Used when changing a view from tiled to floating.
|
||||||
int natural_width, natural_height;
|
int natural_width, natural_height;
|
||||||
|
|
||||||
char *title_format;
|
|
||||||
|
|
||||||
bool using_csd;
|
bool using_csd;
|
||||||
|
|
||||||
struct timespec urgent;
|
struct timespec urgent;
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
#define _POSIX_C_SOURCE 200809L
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "sway/commands.h"
|
#include "sway/commands.h"
|
||||||
#include "sway/config.h"
|
#include "sway/config.h"
|
||||||
|
@ -11,16 +12,19 @@ struct cmd_results *cmd_title_format(int argc, char **argv) {
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
struct sway_container *container = config->handler_context.container;
|
struct sway_container *container = config->handler_context.container;
|
||||||
if (!container || !container->view) {
|
if (!container) {
|
||||||
return cmd_results_new(CMD_INVALID,
|
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);
|
char *format = join_args(argv, argc);
|
||||||
if (view->title_format) {
|
if (container->title_format) {
|
||||||
free(view->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);
|
return cmd_results_new(CMD_SUCCESS, NULL);
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include "sway/tree/workspace.h"
|
#include "sway/tree/workspace.h"
|
||||||
#include "sway/xdg_decoration.h"
|
#include "sway/xdg_decoration.h"
|
||||||
#include "list.h"
|
#include "list.h"
|
||||||
|
#include "pango.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "stringop.h"
|
#include "stringop.h"
|
||||||
|
|
||||||
|
@ -499,6 +500,7 @@ void container_destroy(struct sway_container *con) {
|
||||||
}
|
}
|
||||||
free(con->title);
|
free(con->title);
|
||||||
free(con->formatted_title);
|
free(con->formatted_title);
|
||||||
|
free(con->title_format);
|
||||||
list_free(con->pending.children);
|
list_free(con->pending.children);
|
||||||
list_free(con->current.children);
|
list_free(con->current.children);
|
||||||
|
|
||||||
|
@ -645,6 +647,87 @@ bool container_has_ancestor(struct sway_container *descendant,
|
||||||
return false;
|
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.
|
* Calculate and return the length of the tree representation.
|
||||||
* An example tree representation is: V[Terminal, Firefox]
|
* 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) {
|
void container_update_representation(struct sway_container *con) {
|
||||||
if (!con->view) {
|
if (!con->view) {
|
||||||
size_t len = container_build_representation(con->pending.layout,
|
size_t len = parse_title_format(con, NULL);
|
||||||
con->pending.children, NULL);
|
|
||||||
free(con->formatted_title);
|
free(con->formatted_title);
|
||||||
con->formatted_title = calloc(len + 1, sizeof(char));
|
con->formatted_title = calloc(len + 1, sizeof(char));
|
||||||
if (!sway_assert(con->formatted_title,
|
if (!sway_assert(con->formatted_title,
|
||||||
"Unable to allocate title string")) {
|
"Unable to allocate title string")) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
container_build_representation(con->pending.layout, con->pending.children,
|
parse_title_format(con, con->formatted_title);
|
||||||
con->formatted_title);
|
|
||||||
|
|
||||||
if (con->title_bar.title_text) {
|
if (con->title_bar.title_text) {
|
||||||
sway_text_node_set_text(con->title_bar.title_text, con->formatted_title);
|
sway_text_node_set_text(con->title_bar.title_text, con->formatted_title);
|
||||||
|
|
|
@ -34,7 +34,6 @@
|
||||||
#include "sway/tree/workspace.h"
|
#include "sway/tree/workspace.h"
|
||||||
#include "sway/config.h"
|
#include "sway/config.h"
|
||||||
#include "sway/xdg_decoration.h"
|
#include "sway/xdg_decoration.h"
|
||||||
#include "pango.h"
|
|
||||||
#include "stringop.h"
|
#include "stringop.h"
|
||||||
|
|
||||||
bool view_init(struct sway_view *view, enum sway_view_type type,
|
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);
|
view_assign_ctx(view, NULL);
|
||||||
wlr_scene_node_destroy(&view->scene_tree->node);
|
wlr_scene_node_destroy(&view->scene_tree->node);
|
||||||
free(view->title_format);
|
|
||||||
|
|
||||||
if (view->impl->destroy) {
|
if (view->impl->destroy) {
|
||||||
view->impl->destroy(view);
|
view->impl->destroy(view);
|
||||||
} else {
|
} else {
|
||||||
|
@ -991,77 +988,6 @@ struct sway_view *view_from_wlr_surface(struct wlr_surface *wlr_surface) {
|
||||||
return NULL;
|
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) {
|
void view_update_app_id(struct sway_view *view) {
|
||||||
const char *app_id = view_get_app_id(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->title);
|
||||||
free(view->container->formatted_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) {
|
if (len) {
|
||||||
char *buffer = calloc(len + 1, sizeof(char));
|
char *buffer = calloc(len + 1, sizeof(char));
|
||||||
|
@ -1098,7 +1024,7 @@ void view_update_title(struct sway_view *view, bool force) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
parse_title_format(view, buffer);
|
parse_title_format(view->container, buffer);
|
||||||
view->container->formatted_title = buffer;
|
view->container->formatted_title = buffer;
|
||||||
} else {
|
} else {
|
||||||
view->container->formatted_title = NULL;
|
view->container->formatted_title = NULL;
|
||||||
|
|
Loading…
Reference in a new issue