mirror of
				https://github.com/swaywm/sway.git
				synced 2025-11-03 09:01:43 -05:00 
			
		
		
		
	
							parent
							
								
									d2fceae379
								
							
						
					
					
						commit
						7246bf909c
					
				
					 5 changed files with 102 additions and 89 deletions
				
			
		| 
						 | 
					@ -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…
	
	Add table
		Add a link
		
	
		Reference in a new issue