Merge pull request #1915 from RyanDwyer/title-format

Implement title_format
This commit is contained in:
Drew DeVault 2018-05-05 11:08:33 -04:00 committed by GitHub
commit a8d1b05bac
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 198 additions and 49 deletions

View file

@ -144,6 +144,7 @@ sway_cmd cmd_splitt;
sway_cmd cmd_splitv; sway_cmd cmd_splitv;
sway_cmd cmd_sticky; sway_cmd cmd_sticky;
sway_cmd cmd_swaybg_command; sway_cmd cmd_swaybg_command;
sway_cmd cmd_title_format;
sway_cmd cmd_unmark; sway_cmd cmd_unmark;
sway_cmd cmd_workspace; sway_cmd cmd_workspace;
sway_cmd cmd_ws_auto_back_and_forth; sway_cmd cmd_ws_auto_back_and_forth;

View file

@ -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 * Updates the value of config->font_height based on the max title height
* reported by each container. If recalculate is true, the containers will * reported by each container. If recalculate is true, the containers will
* recalculate their heights before reporting. * 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. */ /* Global config singleton. */
extern struct sway_config *config; extern struct sway_config *config;

View file

@ -63,7 +63,8 @@ struct sway_container {
*/ */
size_t id; 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_type type;
enum sway_container_layout layout; 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_calculate_title_height(struct sway_container *container);
void container_update_title(struct sway_container *container, void container_notify_child_title_changed(struct sway_container *container);
const char *new_title);
#endif #endif

View file

@ -48,6 +48,7 @@ struct sway_view {
bool is_fullscreen; bool is_fullscreen;
char *title_format;
enum sway_container_border border; enum sway_container_border border;
int border_thickness; 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_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, void view_configure(struct sway_view *view, double ox, double oy, int width,
int height); int height);
@ -207,4 +210,11 @@ void view_child_init(struct sway_view_child *child,
void view_child_destroy(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 #endif

View file

@ -182,6 +182,7 @@ static struct cmd_handler command_handlers[] = {
{ "splith", cmd_splith }, { "splith", cmd_splith },
{ "splitt", cmd_splitt }, { "splitt", cmd_splitt },
{ "splitv", cmd_splitv }, { "splitv", cmd_splitv },
{ "title_format", cmd_title_format },
}; };
static int handler_compare(const void *_a, const void *_b) { static int handler_compare(const void *_a, const void *_b) {

View file

@ -2,7 +2,6 @@
#include <string.h> #include <string.h>
#include "sway/commands.h" #include "sway/commands.h"
#include "sway/config.h" #include "sway/config.h"
#include "sway/tree/arrange.h"
#include "log.h" #include "log.h"
#include "stringop.h" #include "stringop.h"
@ -14,9 +13,6 @@ struct cmd_results *cmd_font(int argc, char **argv) {
char *font = join_args(argv, argc); char *font = join_args(argv, argc);
free(config->font); free(config->font);
config->font = strdup(font); config->font = strdup(font);
config_find_font_height(true); config_update_font_height(true);
if (!config->reading) {
arrange_root();
}
return cmd_results_new(CMD_SUCCESS, NULL, NULL); return cmd_results_new(CMD_SUCCESS, NULL, NULL);
} }

View file

@ -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);
}

View file

@ -24,6 +24,7 @@
#include "sway/input/seat.h" #include "sway/input/seat.h"
#include "sway/commands.h" #include "sway/commands.h"
#include "sway/config.h" #include "sway/config.h"
#include "sway/tree/arrange.h"
#include "sway/tree/layout.h" #include "sway/tree/layout.h"
#include "cairo.h" #include "cairo.h"
#include "pango.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; config->font_height = 0;
container_for_each_descendant_dfs(&root_container, container_for_each_descendant_dfs(&root_container,
find_font_height_iterator, &recalculate); find_font_height_iterator, &recalculate);
if (config->font_height != prev_max_height) {
arrange_root();
}
} }

View file

@ -176,8 +176,7 @@ static void handle_commit(struct wl_listener *listener, void *data) {
// TODO: Let floating views do whatever // TODO: Let floating views do whatever
view_update_size(view, xdg_shell_v6_view->pending_width, view_update_size(view, xdg_shell_v6_view->pending_width,
xdg_shell_v6_view->pending_height); xdg_shell_v6_view->pending_height);
container_update_title(view->swayc, view_update_title(view, false);
view->wlr_xdg_surface_v6->toplevel->title);
view_damage(view, false); view_damage(view, false);
} }

View file

@ -223,7 +223,7 @@ static void handle_commit(struct wl_listener *listener, void *data) {
view_update_size(view, xwayland_view->pending_width, view_update_size(view, xwayland_view->pending_width,
xwayland_view->pending_height); xwayland_view->pending_height);
view_damage(view, false); 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) { static void handle_unmap(struct wl_listener *listener, void *data) {

View file

@ -60,6 +60,7 @@ sway_sources = files(
'commands/set.c', 'commands/set.c',
'commands/split.c', 'commands/split.c',
'commands/swaybg_command.c', 'commands/swaybg_command.c',
'commands/title_format.c',
'commands/workspace.c', 'commands/workspace.c',
'commands/ws_auto_back_and_forth.c', 'commands/ws_auto_back_and_forth.c',

View file

@ -348,7 +348,6 @@ struct sway_container *container_view_create(struct sway_container *sibling,
swayc, title, sibling, sibling ? sibling->type : 0, sibling->name); swayc, title, sibling, sibling ? sibling->type : 0, sibling->name);
// Setup values // Setup values
swayc->sway_view = sway_view; swayc->sway_view = sway_view;
container_update_title(swayc, title);
swayc->width = 0; swayc->width = 0;
swayc->height = 0; swayc->height = 0;
@ -572,7 +571,7 @@ static void update_title_texture(struct sway_container *con,
if (*texture) { if (*texture) {
wlr_texture_destroy(*texture); wlr_texture_destroy(*texture);
} }
if (!con->name) { if (!con->formatted_title) {
return; return;
} }
@ -581,7 +580,8 @@ static void update_title_texture(struct sway_container *con,
int height = config->font_height * scale; int height = config->font_height * scale;
cairo_t *c = cairo_create(NULL); 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_destroy(c);
cairo_surface_t *surface = cairo_image_surface_create( 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]); class->text[2], class->text[3]);
cairo_move_to(cairo, 0, 0); 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); cairo_surface_flush(surface);
unsigned char *data = cairo_image_surface_get_data(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) { void container_calculate_title_height(struct sway_container *container) {
if (!container->name) { if (!container->formatted_title) {
container->title_height = 0; container->title_height = 0;
return; return;
} }
cairo_t *cairo = cairo_create(NULL); cairo_t *cairo = cairo_create(NULL);
int height; int height;
get_text_size(cairo, config->font, NULL, &height, 1, false, get_text_size(cairo, config->font, NULL, &height, 1, false,
"%s", container->name); "%s", container->formatted_title);
cairo_destroy(cairo); cairo_destroy(cairo);
container->title_height = height; container->title_height = height;
} }
static void container_notify_child_title_changed( void container_notify_child_title_changed(struct sway_container *container) {
struct sway_container *container) {
if (!container || container->type != C_CONTAINER) { if (!container || container->type != C_CONTAINER) {
return; return;
} }
if (container->layout != L_TABBED && container->layout != L_STACKED) { if (container->layout != L_TABBED && container->layout != L_STACKED) {
return; return;
} }
if (container->name) { if (container->formatted_title) {
free(container->name); free(container->formatted_title);
} }
// TODO: iterate children and concatenate their titles // TODO: iterate children and concatenate their titles
container->name = strdup(""); container->formatted_title = strdup("");
container_calculate_title_height(container); container_calculate_title_height(container);
container_update_title_textures(container); container_update_title_textures(container);
container_notify_child_title_changed(container->parent); 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();
}
}

View file

@ -1,3 +1,4 @@
#define _POSIX_C_SOURCE 200809L
#include <stdlib.h> #include <stdlib.h>
#include <wayland-server.h> #include <wayland-server.h>
#include <wlr/render/wlr_renderer.h> #include <wlr/render/wlr_renderer.h>
@ -67,6 +68,18 @@ const char *view_get_instance(struct sway_view *view) {
return NULL; 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, void view_configure(struct sway_view *view, double ox, double oy, int width,
int height) { int height) {
if (view->impl->configure) { if (view->impl->configure) {
@ -348,6 +361,11 @@ void view_unmap(struct sway_view *view) {
view->swayc = NULL; view->swayc = NULL;
view->surface = NULL; view->surface = NULL;
if (view->title_format) {
free(view->title_format);
view->title_format = NULL;
}
if (parent->type == C_OUTPUT) { if (parent->type == C_OUTPUT) {
arrange_output(parent); arrange_output(parent);
} else { } else {
@ -475,3 +493,113 @@ void view_child_destroy(struct sway_view_child *child) {
free(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);
}