aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/sway/commands.h1
-rw-r--r--include/sway/config.h5
-rw-r--r--include/sway/tree/container.h6
-rw-r--r--include/sway/tree/view.h10
-rw-r--r--sway/commands.c1
-rw-r--r--sway/commands/font.c6
-rw-r--r--sway/commands/title_format.c29
-rw-r--r--sway/config.c9
-rw-r--r--sway/desktop/xdg_shell_v6.c3
-rw-r--r--sway/desktop/xwayland.c2
-rw-r--r--sway/meson.build1
-rw-r--r--sway/tree/container.c46
-rw-r--r--sway/tree/view.c128
-rw-r--r--swaymsg/main.c2
14 files changed, 199 insertions, 50 deletions
diff --git a/include/sway/commands.h b/include/sway/commands.h
index 0732a90a..d39ac56c 100644
--- a/include/sway/commands.h
+++ b/include/sway/commands.h
@@ -144,6 +144,7 @@ sway_cmd cmd_splitt;
sway_cmd cmd_splitv;
sway_cmd cmd_sticky;
sway_cmd cmd_swaybg_command;
+sway_cmd cmd_title_format;
sway_cmd cmd_unmark;
sway_cmd cmd_workspace;
sway_cmd cmd_ws_auto_back_and_forth;
diff --git a/include/sway/config.h b/include/sway/config.h
index db942c3f..fa40ef4e 100644
--- a/include/sway/config.h
+++ b/include/sway/config.h
@@ -465,8 +465,11 @@ void free_bar_config(struct bar_config *bar);
* Updates the value of config->font_height based on the max title height
* reported by each container. If recalculate is true, the containers will
* recalculate their heights before reporting.
+ *
+ * If the height has changed, all containers will be rearranged to take on the
+ * new size.
*/
-void config_find_font_height(bool recalculate);
+void config_update_font_height(bool recalculate);
/* Global config singleton. */
extern struct sway_config *config;
diff --git a/include/sway/tree/container.h b/include/sway/tree/container.h
index b07af72c..61ab7ca1 100644
--- a/include/sway/tree/container.h
+++ b/include/sway/tree/container.h
@@ -63,7 +63,8 @@ struct sway_container {
*/
size_t id;
- char *name;
+ char *name; // The view's title (unformatted)
+ char *formatted_title; // The title displayed in the title bar
enum sway_container_type type;
enum sway_container_layout layout;
@@ -204,7 +205,6 @@ void container_update_title_textures(struct sway_container *container);
*/
void container_calculate_title_height(struct sway_container *container);
-void container_update_title(struct sway_container *container,
- const char *new_title);
+void container_notify_child_title_changed(struct sway_container *container);
#endif
diff --git a/include/sway/tree/view.h b/include/sway/tree/view.h
index 21127ab1..9d4256f7 100644
--- a/include/sway/tree/view.h
+++ b/include/sway/tree/view.h
@@ -48,6 +48,7 @@ struct sway_view {
bool is_fullscreen;
+ char *title_format;
enum sway_container_border border;
int border_thickness;
@@ -164,6 +165,8 @@ const char *view_get_class(struct sway_view *view);
const char *view_get_instance(struct sway_view *view);
+const char *view_get_type(struct sway_view *view);
+
void view_configure(struct sway_view *view, double ox, double oy, int width,
int height);
@@ -207,4 +210,11 @@ void view_child_init(struct sway_view_child *child,
void view_child_destroy(struct sway_view_child *child);
+/**
+ * Re-read the view's title property and update any relevant title bars.
+ * The force argument makes it recreate the title bars even if the title hasn't
+ * changed.
+ */
+void view_update_title(struct sway_view *view, bool force);
+
#endif
diff --git a/sway/commands.c b/sway/commands.c
index efed7ddf..2e1cdc2c 100644
--- a/sway/commands.c
+++ b/sway/commands.c
@@ -182,6 +182,7 @@ static struct cmd_handler command_handlers[] = {
{ "splith", cmd_splith },
{ "splitt", cmd_splitt },
{ "splitv", cmd_splitv },
+ { "title_format", cmd_title_format },
};
static int handler_compare(const void *_a, const void *_b) {
diff --git a/sway/commands/font.c b/sway/commands/font.c
index 38ad8880..8e0b51e3 100644
--- a/sway/commands/font.c
+++ b/sway/commands/font.c
@@ -2,7 +2,6 @@
#include <string.h>
#include "sway/commands.h"
#include "sway/config.h"
-#include "sway/tree/arrange.h"
#include "log.h"
#include "stringop.h"
@@ -14,9 +13,6 @@ struct cmd_results *cmd_font(int argc, char **argv) {
char *font = join_args(argv, argc);
free(config->font);
config->font = strdup(font);
- config_find_font_height(true);
- if (!config->reading) {
- arrange_root();
- }
+ config_update_font_height(true);
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}
diff --git a/sway/commands/title_format.c b/sway/commands/title_format.c
new file mode 100644
index 00000000..3d1c578c
--- /dev/null
+++ b/sway/commands/title_format.c
@@ -0,0 +1,29 @@
+#define _POSIX_C_SOURCE 200809L
+#include <string.h>
+#include "sway/commands.h"
+#include "sway/config.h"
+#include "sway/tree/view.h"
+#include "log.h"
+#include "stringop.h"
+
+struct cmd_results *cmd_title_format(int argc, char **argv) {
+ struct cmd_results *error = NULL;
+ if ((error = checkarg(argc, "title_format", EXPECTED_AT_LEAST, 1))) {
+ return error;
+ }
+ struct sway_container *container =
+ config->handler_context.current_container;
+ if (container->type != C_VIEW) {
+ return cmd_results_new(CMD_INVALID, "title_format",
+ "Only views can have a title_format");
+ }
+ struct sway_view *view = container->sway_view;
+ char *format = join_args(argv, argc);
+ if (view->title_format) {
+ free(view->title_format);
+ }
+ view->title_format = format;
+ view_update_title(view, true);
+ config_update_font_height(true);
+ return cmd_results_new(CMD_SUCCESS, NULL, NULL);
+}
diff --git a/sway/config.c b/sway/config.c
index 2e5eab2b..a14f4ec6 100644
--- a/sway/config.c
+++ b/sway/config.c
@@ -24,6 +24,7 @@
#include "sway/input/seat.h"
#include "sway/commands.h"
#include "sway/config.h"
+#include "sway/tree/arrange.h"
#include "sway/tree/layout.h"
#include "cairo.h"
#include "pango.h"
@@ -741,8 +742,14 @@ static void find_font_height_iterator(struct sway_container *container,
}
}
-void config_find_font_height(bool recalculate) {
+void config_update_font_height(bool recalculate) {
+ size_t prev_max_height = config->font_height;
config->font_height = 0;
+
container_for_each_descendant_dfs(&root_container,
find_font_height_iterator, &recalculate);
+
+ if (config->font_height != prev_max_height) {
+ arrange_root();
+ }
}
diff --git a/sway/desktop/xdg_shell_v6.c b/sway/desktop/xdg_shell_v6.c
index 5880e9a9..fcee8ce9 100644
--- a/sway/desktop/xdg_shell_v6.c
+++ b/sway/desktop/xdg_shell_v6.c
@@ -176,8 +176,7 @@ static void handle_commit(struct wl_listener *listener, void *data) {
// TODO: Let floating views do whatever
view_update_size(view, xdg_shell_v6_view->pending_width,
xdg_shell_v6_view->pending_height);
- container_update_title(view->swayc,
- view->wlr_xdg_surface_v6->toplevel->title);
+ view_update_title(view, false);
view_damage(view, false);
}
diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c
index a1e672ce..b4eda71f 100644
--- a/sway/desktop/xwayland.c
+++ b/sway/desktop/xwayland.c
@@ -223,7 +223,7 @@ static void handle_commit(struct wl_listener *listener, void *data) {
view_update_size(view, xwayland_view->pending_width,
xwayland_view->pending_height);
view_damage(view, false);
- container_update_title(view->swayc, view->wlr_xwayland_surface->title);
+ view_update_title(view, false);
}
static void handle_unmap(struct wl_listener *listener, void *data) {
diff --git a/sway/meson.build b/sway/meson.build
index 7c93b5c4..f70a8e44 100644
--- a/sway/meson.build
+++ b/sway/meson.build
@@ -60,6 +60,7 @@ sway_sources = files(
'commands/set.c',
'commands/split.c',
'commands/swaybg_command.c',
+ 'commands/title_format.c',
'commands/workspace.c',
'commands/ws_auto_back_and_forth.c',
diff --git a/sway/tree/container.c b/sway/tree/container.c
index 9fb47020..e1be32d1 100644
--- a/sway/tree/container.c
+++ b/sway/tree/container.c
@@ -348,7 +348,6 @@ struct sway_container *container_view_create(struct sway_container *sibling,
swayc, title, sibling, sibling ? sibling->type : 0, sibling->name);
// Setup values
swayc->sway_view = sway_view;
- container_update_title(swayc, title);
swayc->width = 0;
swayc->height = 0;
@@ -572,7 +571,7 @@ static void update_title_texture(struct sway_container *con,
if (*texture) {
wlr_texture_destroy(*texture);
}
- if (!con->name) {
+ if (!con->formatted_title) {
return;
}
@@ -581,7 +580,8 @@ static void update_title_texture(struct sway_container *con,
int height = config->font_height * scale;
cairo_t *c = cairo_create(NULL);
- get_text_size(c, config->font, &width, NULL, scale, false, "%s", con->name);
+ get_text_size(c, config->font, &width, NULL, scale, false,
+ "%s", con->formatted_title);
cairo_destroy(c);
cairo_surface_t *surface = cairo_image_surface_create(
@@ -596,7 +596,7 @@ static void update_title_texture(struct sway_container *con,
class->text[2], class->text[3]);
cairo_move_to(cairo, 0, 0);
- pango_printf(cairo, config->font, scale, false, "%s", con->name);
+ pango_printf(cairo, config->font, scale, false, "%s", con->formatted_title);
cairo_surface_flush(surface);
unsigned char *data = cairo_image_surface_get_data(surface);
@@ -622,57 +622,31 @@ void container_update_title_textures(struct sway_container *container) {
}
void container_calculate_title_height(struct sway_container *container) {
- if (!container->name) {
+ if (!container->formatted_title) {
container->title_height = 0;
return;
}
cairo_t *cairo = cairo_create(NULL);
int height;
get_text_size(cairo, config->font, NULL, &height, 1, false,
- "%s", container->name);
+ "%s", container->formatted_title);
cairo_destroy(cairo);
container->title_height = height;
}
-static void container_notify_child_title_changed(
- struct sway_container *container) {
+void container_notify_child_title_changed(struct sway_container *container) {
if (!container || container->type != C_CONTAINER) {
return;
}
if (container->layout != L_TABBED && container->layout != L_STACKED) {
return;
}
- if (container->name) {
- free(container->name);
+ if (container->formatted_title) {
+ free(container->formatted_title);
}
// TODO: iterate children and concatenate their titles
- container->name = strdup("");
+ container->formatted_title = strdup("");
container_calculate_title_height(container);
container_update_title_textures(container);
container_notify_child_title_changed(container->parent);
}
-
-void container_update_title(struct sway_container *container,
- const char *new_title) {
- if (!new_title) {
- new_title = "";
- }
-
- if (container->name && strcmp(container->name, new_title) == 0) {
- return;
- }
-
- if (container->name) {
- free(container->name);
- }
- container->name = strdup(new_title);
- container_calculate_title_height(container);
- container_update_title_textures(container);
- container_notify_child_title_changed(container->parent);
-
- size_t prev_max_height = config->font_height;
- config_find_font_height(false);
- if (config->font_height != prev_max_height) {
- arrange_root();
- }
-}
diff --git a/sway/tree/view.c b/sway/tree/view.c
index 84962306..fe944466 100644
--- a/sway/tree/view.c
+++ b/sway/tree/view.c
@@ -1,3 +1,4 @@
+#define _POSIX_C_SOURCE 200809L
#include <stdlib.h>
#include <wayland-server.h>
#include <wlr/render/wlr_renderer.h>
@@ -67,6 +68,18 @@ const char *view_get_instance(struct sway_view *view) {
return NULL;
}
+const char *view_get_type(struct sway_view *view) {
+ switch(view->type) {
+ case SWAY_VIEW_WL_SHELL:
+ return "wl_shell";
+ case SWAY_VIEW_XDG_SHELL_V6:
+ return "xdg_shell_v6";
+ case SWAY_VIEW_XWAYLAND:
+ return "xwayland";
+ }
+ return "unknown";
+}
+
void view_configure(struct sway_view *view, double ox, double oy, int width,
int height) {
if (view->impl->configure) {
@@ -348,6 +361,11 @@ void view_unmap(struct sway_view *view) {
view->swayc = NULL;
view->surface = NULL;
+ if (view->title_format) {
+ free(view->title_format);
+ view->title_format = NULL;
+ }
+
if (parent->type == C_OUTPUT) {
arrange_output(parent);
} else {
@@ -475,3 +493,113 @@ void view_child_destroy(struct sway_view_child *child) {
free(child);
}
}
+
+/**
+ * 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) {
+ const char *title = view_get_title(view);
+ if (buffer && title) {
+ strcpy(buffer, title);
+ }
+ return title ? strlen(title) : 0;
+ }
+ const char *title = view_get_title(view);
+ const char *class = view_get_class(view);
+ const char *instance = view_get_instance(view);
+ const char *shell = view_get_type(view);
+ size_t title_len = title ? strlen(title) : 0;
+ size_t class_len = class ? strlen(class) : 0;
+ size_t instance_len = instance ? strlen(instance) : 0;
+ size_t shell_len = shell ? strlen(shell) : 0;
+
+ size_t len = 0;
+ char *format = view->title_format;
+ char *next = strchr(format, '%');
+ while (next) {
+ if (buffer) {
+ // Copy everything up to the %
+ strncat(buffer, format, next - format);
+ }
+ len += next - format;
+ format = next;
+
+ if (strncmp(next, "%title", 6) == 0) {
+ if (buffer && title) {
+ strcat(buffer, title);
+ }
+ len += title_len;
+ format += 6;
+ } else if (strncmp(next, "%class", 6) == 0) {
+ if (buffer && class) {
+ strcat(buffer, class);
+ }
+ len += class_len;
+ format += 6;
+ } else if (strncmp(next, "%instance", 9) == 0) {
+ if (buffer && instance) {
+ strcat(buffer, instance);
+ }
+ len += instance_len;
+ format += 9;
+ } else if (strncmp(next, "%shell", 6) == 0) {
+ if (buffer) {
+ strcat(buffer, shell);
+ }
+ len += shell_len;
+ format += 6;
+ } else {
+ if (buffer) {
+ strcat(buffer, "%");
+ }
+ ++format;
+ ++len;
+ }
+ next = strchr(format, '%');
+ }
+ if (buffer) {
+ strcat(buffer, format);
+ }
+ len += strlen(format);
+
+ return len;
+}
+
+void view_update_title(struct sway_view *view, bool force) {
+ if (!view->swayc) {
+ return;
+ }
+ const char *title = view_get_title(view);
+
+ if (!force) {
+ if (title && view->swayc->name && strcmp(title, view->swayc->name) == 0) {
+ return;
+ }
+ if (!title && !view->swayc->name) {
+ return;
+ }
+ }
+
+ free(view->swayc->name);
+ free(view->swayc->formatted_title);
+ if (title) {
+ size_t len = parse_title_format(view, NULL);
+ char *buffer = calloc(len + 1, 1);
+ if (!sway_assert(buffer, "Unable to allocate title string")) {
+ return;
+ }
+ parse_title_format(view, buffer);
+
+ view->swayc->name = strdup(title);
+ view->swayc->formatted_title = buffer;
+ } else {
+ view->swayc->name = NULL;
+ view->swayc->formatted_title = NULL;
+ }
+ container_calculate_title_height(view->swayc);
+ container_update_title_textures(view->swayc);
+ container_notify_child_title_changed(view->swayc->parent);
+ config_update_font_height(false);
+}
diff --git a/swaymsg/main.c b/swaymsg/main.c
index c9be3a86..7e3622d9 100644
--- a/swaymsg/main.c
+++ b/swaymsg/main.c
@@ -32,7 +32,7 @@ static void pretty_print_cmd(json_object *r) {
if (!success(r, true)) {
json_object *error;
if (!json_object_object_get_ex(r, "error", &error)) {
- printf("An unknkown error occured");
+ printf("An unknkown error occurred");
} else {
printf("Error: %s\n", json_object_get_string(error));
}