scene_graph: Port container server side decorations

This commit is contained in:
Alexander Orzechowski 2023-11-21 19:51:57 -05:00 committed by Kirill Primak
parent 188811f808
commit 6d7b1321db
9 changed files with 378 additions and 253 deletions

View file

@ -76,6 +76,9 @@ struct sway_container {
struct wlr_scene_tree *border;
struct wlr_scene_tree *background;
struct sway_text_node *title_text;
struct sway_text_node *marks_text;
} title_bar;
struct {
@ -94,6 +97,7 @@ struct sway_container {
char *title; // The view's title (unformatted)
char *formatted_title; // The title displayed in the title bar
int title_width;
enum sway_container_layout prev_split_layout;
@ -141,18 +145,7 @@ struct sway_container {
float alpha;
struct wlr_texture *title_focused;
struct wlr_texture *title_focused_inactive;
struct wlr_texture *title_focused_tab_title;
struct wlr_texture *title_unfocused;
struct wlr_texture *title_urgent;
list_t *marks; // char *
struct wlr_texture *marks_focused;
struct wlr_texture *marks_focused_inactive;
struct wlr_texture *marks_focused_tab_title;
struct wlr_texture *marks_unfocused;
struct wlr_texture *marks_urgent;
struct {
struct wl_signal destroy;
@ -194,7 +187,9 @@ void container_reap_empty(struct sway_container *con);
struct sway_container *container_flatten(struct sway_container *container);
void container_update_title_textures(struct sway_container *container);
void container_update_title_bar(struct sway_container *container);
void container_update_marks(struct sway_container *container);
size_t container_build_representation(enum sway_container_layout layout,
list_t *children, char *buffer);
@ -230,11 +225,6 @@ void container_set_geometry_from_content(struct sway_container *con);
*/
bool container_is_floating(struct sway_container *container);
/**
* Same as above, but for current container state.
*/
bool container_is_current_floating(struct sway_container *container);
/**
* Get a container's box in layout coordinates.
*/
@ -308,15 +298,10 @@ void container_discover_outputs(struct sway_container *con);
enum sway_container_layout container_parent_layout(struct sway_container *con);
enum sway_container_layout container_current_parent_layout(
struct sway_container *con);
list_t *container_get_siblings(struct sway_container *container);
int container_sibling_index(struct sway_container *child);
list_t *container_get_current_siblings(struct sway_container *container);
void container_handle_fullscreen_reparent(struct sway_container *con);
void container_add_child(struct sway_container *parent,
@ -364,8 +349,6 @@ bool container_has_mark(struct sway_container *container, char *mark);
void container_add_mark(struct sway_container *container, char *mark);
void container_update_marks_textures(struct sway_container *container);
void container_raise_floating(struct sway_container *con);
bool container_is_scratchpad_hidden(struct sway_container *con);
@ -389,4 +372,10 @@ bool container_is_sticky_or_child(struct sway_container *con);
*/
int container_squash(struct sway_container *con);
void container_arrange_title_bar(struct sway_container *con);
void container_update(struct sway_container *con);
void container_update_itself_and_parents(struct sway_container *con);
#endif

View file

@ -5,9 +5,8 @@
#include "sway/tree/container.h"
#include "util.h"
static void rebuild_textures_iterator(struct sway_container *con, void *data) {
container_update_marks_textures(con);
container_update_title_textures(con);
static void container_update_iterator(struct sway_container *con, void *data) {
container_update(con);
}
static struct cmd_results *handle_command(int argc, char **argv, char *cmd_name,
@ -51,7 +50,7 @@ static struct cmd_results *handle_command(int argc, char **argv, char *cmd_name,
memcpy(class, &colors, sizeof(struct border_colors));
if (config->active) {
root_for_each_container(rebuild_textures_iterator, NULL);
root_for_each_container(container_update_iterator, NULL);
for (int i = 0; i < root->outputs->length; ++i) {
struct sway_output *output = root->outputs->items[i];

View file

@ -59,7 +59,7 @@ struct cmd_results *cmd_mark(int argc, char **argv) {
}
free(mark);
container_update_marks_textures(container);
container_update_marks(container);
if (container->view) {
view_execute_criteria(container->view);
}

View file

@ -9,9 +9,8 @@
#include "list.h"
#include "log.h"
static void rebuild_textures_iterator(struct sway_container *con, void *data) {
container_update_marks_textures(con);
container_update_title_textures(con);
static void title_bar_update_iterator(struct sway_container *con, void *data) {
container_update_title_bar(con);
}
static void do_reload(void *data) {
@ -48,7 +47,7 @@ static void do_reload(void *data) {
}
list_free_items_and_destroy(bar_ids);
root_for_each_container(rebuild_textures_iterator, NULL);
root_for_each_container(title_bar_update_iterator, NULL);
arrange_root();
}

View file

@ -10,8 +10,8 @@
#include "stringop.h"
#include "util.h"
static void rebuild_marks_iterator(struct sway_container *con, void *data) {
container_update_marks_textures(con);
static void title_bar_update_iterator(struct sway_container *con, void *data) {
container_update_marks(con);
}
struct cmd_results *cmd_show_marks(int argc, char **argv) {
@ -23,7 +23,7 @@ struct cmd_results *cmd_show_marks(int argc, char **argv) {
config->show_marks = parse_boolean(argv[0], config->show_marks);
if (config->show_marks) {
root_for_each_container(rebuild_marks_iterator, NULL);
root_for_each_container(title_bar_update_iterator, NULL);
}
for (int i = 0; i < root->outputs->length; ++i) {

View file

@ -4,6 +4,10 @@
#include "sway/tree/container.h"
#include "sway/tree/root.h"
static void arrange_title_bar_iterator(struct sway_container *con, void *data) {
container_arrange_title_bar(con);
}
struct cmd_results *cmd_title_align(int argc, char **argv) {
struct cmd_results *error = NULL;
if ((error = checkarg(argc, "title_align", EXPECTED_AT_LEAST, 1))) {
@ -21,6 +25,8 @@ struct cmd_results *cmd_title_align(int argc, char **argv) {
"Expected 'title_align left|center|right'");
}
root_for_each_container(arrange_title_bar_iterator, NULL);
for (int i = 0; i < root->outputs->length; ++i) {
struct sway_output *output = root->outputs->items[i];
output_damage_whole(output);

View file

@ -8,9 +8,13 @@
#include "log.h"
#include "stringop.h"
static void remove_all_marks_iterator(struct sway_container *con, void *data) {
static void remove_mark(struct sway_container *con) {
container_clear_marks(con);
container_update_marks_textures(con);
container_update_marks(con);
}
static void remove_all_marks_iterator(struct sway_container *con, void *data) {
remove_mark(con);
}
// unmark Remove all marks from all views
@ -38,8 +42,7 @@ struct cmd_results *cmd_unmark(int argc, char **argv) {
}
} else if (con && !mark) {
// Clear all marks from the given container
container_clear_marks(con);
container_update_marks_textures(con);
remove_mark(con);
} else if (!con && mark) {
// Remove mark from whichever container has it
container_find_and_unmark(mark);

View file

@ -8,15 +8,13 @@
#include <wlr/types/wlr_output_layout.h>
#include <wlr/types/wlr_subcompositor.h>
#include "linux-dmabuf-unstable-v1-protocol.h"
#include "cairo_util.h"
#include "pango.h"
#include "sway/config.h"
#include "sway/desktop.h"
#include "sway/desktop/transaction.h"
#include "sway/input/input-manager.h"
#include "sway/input/seat.h"
#include "sway/ipc-server.h"
#include "sway/scene_descriptor.h"
#include "sway/sway_text_node.h"
#include "sway/output.h"
#include "sway/server.h"
#include "sway/surface.h"
@ -120,9 +118,328 @@ struct sway_container *container_create(struct sway_view *view) {
wl_signal_init(&c->events.destroy);
wl_signal_emit_mutable(&root->events.new_node, &c->node);
container_update(c);
return c;
}
static bool container_is_focused(struct sway_container *con, void *data) {
return con->current.focused;
}
static bool container_has_focused_child(struct sway_container *con) {
return container_find_child(con, container_is_focused, NULL);
}
static bool container_is_current_parent_focused(struct sway_container *con) {
if (con->current.parent) {
struct sway_container *parent = con->current.parent;
return parent->current.focused || container_is_current_parent_focused(parent);
} else if (con->current.workspace) {
struct sway_workspace *ws = con->current.workspace;
return ws->current.focused;
}
return false;
}
static struct border_colors *container_get_current_colors(
struct sway_container *con) {
struct border_colors *colors;
bool urgent = con->view ?
view_is_urgent(con->view) : container_has_urgent_child(con);
struct sway_container *active_child;
if (con->current.parent) {
active_child = con->current.parent->current.focused_inactive_child;
} else if (con->current.workspace) {
active_child = con->current.workspace->current.focused_inactive_child;
} else {
active_child = NULL;
}
if (urgent) {
colors = &config->border_colors.urgent;
} else if (con->current.focused || container_is_current_parent_focused(con)) {
colors = &config->border_colors.focused;
} else if (config->has_focused_tab_title && container_has_focused_child(con)) {
colors = &config->border_colors.focused_tab_title;
} else if (con == active_child) {
colors = &config->border_colors.focused_inactive;
} else {
colors = &config->border_colors.unfocused;
}
return colors;
}
static bool container_is_current_floating(struct sway_container *container) {
if (!container->current.parent && container->current.workspace &&
list_find(container->current.workspace->floating, container) != -1) {
return true;
}
if (container->scratchpad) {
return true;
}
return false;
}
// scene rect wants premultiplied colors
static void scene_rect_set_color(struct wlr_scene_rect *rect,
const float color[4], float opacity) {
const float premultiplied[] = {
color[0] * color[3] * opacity,
color[1] * color[3] * opacity,
color[2] * color[3] * opacity,
color[3] * opacity,
};
wlr_scene_rect_set_color(rect, premultiplied);
}
void container_update(struct sway_container *con) {
struct border_colors *colors = container_get_current_colors(con);
list_t *siblings = NULL;
enum sway_container_layout layout = L_NONE;
float alpha = con->alpha;
if (con->current.parent) {
siblings = con->current.parent->current.children;
layout = con->current.parent->current.layout;
} else if (con->current.workspace) {
siblings = con->current.workspace->current.tiling;
layout = con->current.workspace->current.layout;
}
float bottom[4], right[4];
memcpy(bottom, colors->child_border, sizeof(bottom));
memcpy(right, colors->child_border, sizeof(right));
if (!container_is_current_floating(con) && siblings && siblings->length == 1) {
if (layout == L_HORIZ) {
memcpy(right, colors->indicator, sizeof(right));
} else if (layout == L_VERT) {
memcpy(bottom, colors->indicator, sizeof(bottom));
}
}
struct wlr_scene_node *node;
wl_list_for_each(node, &con->title_bar.border->children, link) {
struct wlr_scene_rect *rect = wlr_scene_rect_from_node(node);
scene_rect_set_color(rect, colors->border, alpha);
}
wl_list_for_each(node, &con->title_bar.background->children, link) {
struct wlr_scene_rect *rect = wlr_scene_rect_from_node(node);
scene_rect_set_color(rect, colors->background, alpha);
}
if (con->view) {
scene_rect_set_color(con->border.top, colors->child_border, alpha);
scene_rect_set_color(con->border.bottom, bottom, alpha);
scene_rect_set_color(con->border.left, colors->child_border, alpha);
scene_rect_set_color(con->border.right, right, alpha);
}
if (con->title_bar.title_text) {
sway_text_node_set_color(con->title_bar.title_text, colors->text);
sway_text_node_set_background(con->title_bar.title_text, colors->background);
}
if (con->title_bar.marks_text) {
sway_text_node_set_color(con->title_bar.marks_text, colors->text);
sway_text_node_set_background(con->title_bar.marks_text, colors->background);
}
}
void container_update_itself_and_parents(struct sway_container *con) {
container_update(con);
if (con->current.parent) {
container_update_itself_and_parents(con->current.parent);
}
}
static void update_rect_list(struct wlr_scene_tree *tree, pixman_region32_t *region) {
int len;
const pixman_box32_t *rects = pixman_region32_rectangles(region, &len);
wlr_scene_node_set_enabled(&tree->node, len > 0);
if (len == 0) {
return;
}
int i = 0;
struct wlr_scene_node *node;
wl_list_for_each(node, &tree->children, link) {
struct wlr_scene_rect *rect = wlr_scene_rect_from_node(node);
wlr_scene_node_set_enabled(&rect->node, i < len);
if (i < len) {
const pixman_box32_t *box = &rects[i++];
wlr_scene_node_set_position(&rect->node, box->x1, box->y1);
wlr_scene_rect_set_size(rect, box->x2 - box->x1, box->y2 - box->y1);
}
}
}
void container_arrange_title_bar(struct sway_container *con) {
enum alignment title_align = config->title_align;
int marks_buffer_width = 0;
int width = con->title_width;
int height = container_titlebar_height();
pixman_region32_t text_area;
pixman_region32_init(&text_area);
if (con->title_bar.marks_text) {
struct sway_text_node *node = con->title_bar.marks_text;
marks_buffer_width = node->width;
int h_padding;
if (title_align == ALIGN_RIGHT) {
h_padding = config->titlebar_h_padding;
} else {
h_padding = width - config->titlebar_h_padding - marks_buffer_width;
}
h_padding = MAX(h_padding, 0);
int alloc_width = MIN((int)node->width,
width - h_padding - config->titlebar_h_padding);
sway_text_node_set_max_width(node, alloc_width);
wlr_scene_node_set_position(node->node,
h_padding, (height - node->height) >> 1);
pixman_region32_union_rect(&text_area, &text_area,
node->node->x, node->node->y, alloc_width, node->height);
}
if (con->title_bar.title_text) {
struct sway_text_node *node = con->title_bar.title_text;
int h_padding;
if (title_align == ALIGN_RIGHT) {
h_padding = width - config->titlebar_h_padding - node->width;
} else if (title_align == ALIGN_CENTER) {
h_padding = ((int)width - marks_buffer_width - node->width) >> 1;
} else {
h_padding = config->titlebar_h_padding;
}
h_padding = MAX(h_padding, 0);
int alloc_width = MIN((int) node->width,
width - h_padding - config->titlebar_h_padding);
sway_text_node_set_max_width(node, alloc_width);
wlr_scene_node_set_position(node->node,
h_padding, (height - node->height) >> 1);
pixman_region32_union_rect(&text_area, &text_area,
node->node->x, node->node->y, alloc_width, node->height);
}
// silence pixman errors
if (width <= 0 || height <= 0) {
pixman_region32_fini(&text_area);
return;
}
pixman_region32_t background, border;
int thickness = config->titlebar_border_thickness;
pixman_region32_init_rect(&background,
thickness, thickness,
width - thickness * 2, height - thickness * 2);
pixman_region32_init_rect(&border, 0, 0, width, height);
pixman_region32_subtract(&border, &border, &background);
pixman_region32_subtract(&background, &background, &text_area);
pixman_region32_fini(&text_area);
update_rect_list(con->title_bar.background, &background);
pixman_region32_fini(&background);
update_rect_list(con->title_bar.border, &border);
pixman_region32_fini(&border);
container_update(con);
}
void container_update_marks(struct sway_container *con) {
char *buffer = NULL;
if (config->show_marks && con->marks->length) {
size_t len = 0;
for (int i = 0; i < con->marks->length; ++i) {
char *mark = con->marks->items[i];
if (mark[0] != '_') {
len += strlen(mark) + 2;
}
}
buffer = calloc(len + 1, 1);
char *part = malloc(len + 1);
if (!sway_assert(buffer && part, "Unable to allocate memory")) {
free(buffer);
return;
}
for (int i = 0; i < con->marks->length; ++i) {
char *mark = con->marks->items[i];
if (mark[0] != '_') {
snprintf(part, len + 1, "[%s]", mark);
strcat(buffer, part);
}
}
free(part);
}
if (!buffer) {
if (con->title_bar.marks_text) {
wlr_scene_node_destroy(con->title_bar.marks_text->node);
con->title_bar.marks_text = NULL;
}
} else if (!con->title_bar.marks_text) {
struct border_colors *colors = container_get_current_colors(con);
con->title_bar.marks_text = sway_text_node_create(con->title_bar.tree,
buffer, colors->text, false);
} else {
sway_text_node_set_text(con->title_bar.marks_text, buffer);
}
container_arrange_title_bar(con);
free(buffer);
}
void container_update_title_bar(struct sway_container *con) {
if (!con->formatted_title) {
return;
}
struct border_colors *colors = container_get_current_colors(con);
if (con->title_bar.title_text) {
wlr_scene_node_destroy(con->title_bar.title_text->node);
con->title_bar.title_text = NULL;
}
con->title_bar.title_text = sway_text_node_create(con->title_bar.tree,
con->formatted_title, colors->text, config->pango_markup);
// we always have to remake these text buffers completely for text font
// changes etc...
if (con->title_bar.marks_text) {
wlr_scene_node_destroy(con->title_bar.marks_text->node);
con->title_bar.marks_text = NULL;
}
container_update_marks(con);
container_arrange_title_bar(con);
}
void container_destroy(struct sway_container *con) {
if (!sway_assert(con->node.destroying,
"Tried to free container which wasn't marked as destroying")) {
@ -134,21 +451,11 @@ void container_destroy(struct sway_container *con) {
}
free(con->title);
free(con->formatted_title);
wlr_texture_destroy(con->title_focused);
wlr_texture_destroy(con->title_focused_inactive);
wlr_texture_destroy(con->title_unfocused);
wlr_texture_destroy(con->title_urgent);
wlr_texture_destroy(con->title_focused_tab_title);
list_free(con->pending.children);
list_free(con->current.children);
list_free(con->outputs);
list_free_items_and_destroy(con->marks);
wlr_texture_destroy(con->marks_focused);
wlr_texture_destroy(con->marks_focused_inactive);
wlr_texture_destroy(con->marks_unfocused);
wlr_texture_destroy(con->marks_urgent);
wlr_texture_destroy(con->marks_focused_tab_title);
if (con->view && con->view->container == con) {
con->view->container = NULL;
@ -308,108 +615,6 @@ struct sway_output *container_get_effective_output(struct sway_container *con) {
return con->outputs->items[con->outputs->length - 1];
}
static void render_titlebar_text_texture(struct sway_output *output,
struct sway_container *con, struct wlr_texture **texture,
struct border_colors *class, bool pango_markup, char *text) {
double scale = output->wlr_output->scale;
int width = 0;
int height = config->font_height * scale;
int baseline;
// We must use a non-nil cairo_t for cairo_set_font_options to work.
// Therefore, we cannot use cairo_create(NULL).
cairo_surface_t *dummy_surface = cairo_image_surface_create(
CAIRO_FORMAT_ARGB32, 0, 0);
cairo_t *c = cairo_create(dummy_surface);
cairo_set_antialias(c, CAIRO_ANTIALIAS_BEST);
cairo_font_options_t *fo = cairo_font_options_create();
if (output->wlr_output->subpixel == WL_OUTPUT_SUBPIXEL_NONE) {
cairo_font_options_set_antialias(fo, CAIRO_ANTIALIAS_GRAY);
} else {
cairo_font_options_set_antialias(fo, CAIRO_ANTIALIAS_SUBPIXEL);
cairo_font_options_set_subpixel_order(fo,
to_cairo_subpixel_order(output->wlr_output->subpixel));
}
cairo_set_font_options(c, fo);
get_text_size(c, config->font_description, &width, NULL, &baseline, scale,
config->pango_markup, "%s", text);
cairo_surface_destroy(dummy_surface);
cairo_destroy(c);
if (width == 0 || height == 0) {
return;
}
if (height > config->font_height * scale) {
height = config->font_height * scale;
}
cairo_surface_t *surface = cairo_image_surface_create(
CAIRO_FORMAT_ARGB32, width, height);
cairo_status_t status = cairo_surface_status(surface);
if (status != CAIRO_STATUS_SUCCESS) {
sway_log(SWAY_ERROR, "cairo_image_surface_create failed: %s",
cairo_status_to_string(status));
return;
}
cairo_t *cairo = cairo_create(surface);
cairo_set_antialias(cairo, CAIRO_ANTIALIAS_BEST);
cairo_set_font_options(cairo, fo);
cairo_font_options_destroy(fo);
cairo_set_source_rgba(cairo, class->background[0], class->background[1],
class->background[2], class->background[3]);
cairo_paint(cairo);
PangoContext *pango = pango_cairo_create_context(cairo);
cairo_set_source_rgba(cairo, class->text[0], class->text[1],
class->text[2], class->text[3]);
cairo_move_to(cairo, 0, config->font_baseline * scale - baseline);
render_text(cairo, config->font_description, scale, pango_markup, "%s", text);
cairo_surface_flush(surface);
unsigned char *data = cairo_image_surface_get_data(surface);
int stride = cairo_image_surface_get_stride(surface);
struct wlr_renderer *renderer = output->wlr_output->renderer;
*texture = wlr_texture_from_pixels(
renderer, DRM_FORMAT_ARGB8888, stride, width, height, data);
cairo_surface_destroy(surface);
g_object_unref(pango);
cairo_destroy(cairo);
}
static void update_title_texture(struct sway_container *con,
struct wlr_texture **texture, struct border_colors *class) {
struct sway_output *output = container_get_effective_output(con);
if (!output) {
return;
}
if (*texture) {
wlr_texture_destroy(*texture);
*texture = NULL;
}
if (!con->formatted_title) {
return;
}
render_titlebar_text_texture(output, con, texture, class,
config->pango_markup, con->formatted_title);
}
void container_update_title_textures(struct sway_container *container) {
update_title_texture(container, &container->title_focused,
&config->border_colors.focused);
update_title_texture(container, &container->title_focused_inactive,
&config->border_colors.focused_inactive);
update_title_texture(container, &container->title_unfocused,
&config->border_colors.unfocused);
update_title_texture(container, &container->title_urgent,
&config->border_colors.urgent);
update_title_texture(container, &container->title_focused_tab_title,
&config->border_colors.focused_tab_title);
container_damage_whole(container);
}
/**
* Calculate and return the length of the tree representation.
* An example tree representation is: V[Terminal, Firefox]
@ -475,7 +680,13 @@ void container_update_representation(struct sway_container *con) {
}
container_build_representation(con->pending.layout, con->pending.children,
con->formatted_title);
container_update_title_textures(con);
if (con->title_bar.title_text) {
sway_text_node_set_text(con->title_bar.title_text, con->formatted_title);
container_arrange_title_bar(con);
} else {
container_update_title_bar(con);
}
}
if (con->pending.parent) {
container_update_representation(con->pending.parent);
@ -761,17 +972,6 @@ bool container_is_floating(struct sway_container *container) {
return false;
}
bool container_is_current_floating(struct sway_container *container) {
if (!container->current.parent && container->current.workspace &&
list_find(container->current.workspace->floating, container) != -1) {
return true;
}
if (container->scratchpad) {
return true;
}
return false;
}
void container_get_box(struct sway_container *container, struct wlr_box *box) {
box->x = container->pending.x;
box->y = container->pending.y;
@ -1092,7 +1292,6 @@ void container_discover_outputs(struct sway_container *con) {
.width = con->current.width,
.height = con->current.height,
};
struct sway_output *old_output = container_get_effective_output(con);
for (int i = 0; i < root->outputs->length; ++i) {
struct sway_output *output = root->outputs->items[i];
@ -1129,14 +1328,6 @@ void container_discover_outputs(struct sway_container *con) {
list_del(con->outputs, index);
}
}
struct sway_output *new_output = container_get_effective_output(con);
double old_scale = old_output && old_output->enabled ?
old_output->wlr_output->scale : -1;
double new_scale = new_output ? new_output->wlr_output->scale : -1;
if (old_scale != new_scale) {
container_update_title_textures(con);
container_update_marks_textures(con);
}
}
enum sway_container_layout container_parent_layout(struct sway_container *con) {
@ -1149,14 +1340,6 @@ enum sway_container_layout container_parent_layout(struct sway_container *con) {
return L_NONE;
}
enum sway_container_layout container_current_parent_layout(
struct sway_container *con) {
if (con->current.parent) {
return con->current.parent->current.layout;
}
return con->current.workspace->current.layout;
}
list_t *container_get_siblings(struct sway_container *container) {
if (container->pending.parent) {
return container->pending.parent->pending.children;
@ -1174,13 +1357,6 @@ int container_sibling_index(struct sway_container *child) {
return list_find(container_get_siblings(child), child);
}
list_t *container_get_current_siblings(struct sway_container *container) {
if (container->current.parent) {
return container->current.parent->current.children;
}
return container->current.workspace->current.tiling;
}
void container_handle_fullscreen_reparent(struct sway_container *con) {
if (con->pending.fullscreen_mode != FULLSCREEN_WORKSPACE || !con->pending.workspace ||
con->pending.workspace->fullscreen == con) {
@ -1395,7 +1571,7 @@ bool container_find_and_unmark(char *mark) {
if (strcmp(con_mark, mark) == 0) {
free(con_mark);
list_del(con->marks, i);
container_update_marks_textures(con);
container_update_marks(con);
ipc_event_window(con, "mark");
return true;
}
@ -1426,70 +1602,15 @@ void container_add_mark(struct sway_container *con, char *mark) {
ipc_event_window(con, "mark");
}
static void update_marks_texture(struct sway_container *con,
struct wlr_texture **texture, struct border_colors *class) {
struct sway_output *output = container_get_effective_output(con);
if (!output) {
return;
}
if (*texture) {
wlr_texture_destroy(*texture);
*texture = NULL;
}
if (!con->marks->length) {
return;
}
size_t len = 0;
for (int i = 0; i < con->marks->length; ++i) {
char *mark = con->marks->items[i];
if (mark[0] != '_') {
len += strlen(mark) + 2;
}
}
char *buffer = calloc(len + 1, 1);
char *part = malloc(len + 1);
if (!sway_assert(buffer && part, "Unable to allocate memory")) {
free(buffer);
return;
}
for (int i = 0; i < con->marks->length; ++i) {
char *mark = con->marks->items[i];
if (mark[0] != '_') {
snprintf(part, len + 1, "[%s]", mark);
strcat(buffer, part);
}
}
free(part);
render_titlebar_text_texture(output, con, texture, class, false, buffer);
free(buffer);
}
void container_update_marks_textures(struct sway_container *con) {
if (!config->show_marks) {
return;
}
update_marks_texture(con, &con->marks_focused,
&config->border_colors.focused);
update_marks_texture(con, &con->marks_focused_inactive,
&config->border_colors.focused_inactive);
update_marks_texture(con, &con->marks_unfocused,
&config->border_colors.unfocused);
update_marks_texture(con, &con->marks_urgent,
&config->border_colors.urgent);
update_marks_texture(con, &con->marks_focused_tab_title,
&config->border_colors.focused_tab_title);
container_damage_whole(con);
}
void container_raise_floating(struct sway_container *con) {
// Bring container to front by putting it at the end of the floating list.
struct sway_container *floater = container_toplevel_ancestor(con);
if (container_is_floating(floater) && floater->pending.workspace) {
// it's okay to just raise the scene directly instead of waiting
// for the transaction to go through. We won't be reconfiguring
// surfaces
wlr_scene_node_raise_to_top(&floater->scene_tree->node);
list_move_to_end(floater->pending.workspace->floating, floater);
node_set_dirty(&floater->pending.workspace->node);
}

View file

@ -27,6 +27,7 @@
#include "sway/scene_descriptor.h"
#include "sway/server.h"
#include "sway/surface.h"
#include "sway/sway_text_node.h"
#include "sway/tree/arrange.h"
#include "sway/tree/container.h"
#include "sway/tree/view.h"
@ -1337,7 +1338,13 @@ void view_update_title(struct sway_view *view, bool force) {
view->container->title = title ? strdup(title) : NULL;
// Update title after the global font height is updated
container_update_title_textures(view->container);
if (view->container->title_bar.title_text && len) {
sway_text_node_set_text(view->container->title_bar.title_text,
view->container->formatted_title);
container_arrange_title_bar(view->container);
} else {
container_update_title_bar(view->container);
}
ipc_event_window(view->container, "title");
@ -1404,6 +1411,7 @@ void view_set_urgent(struct sway_view *view, bool enable) {
return;
}
clock_gettime(CLOCK_MONOTONIC, &view->urgent);
container_update_itself_and_parents(view->container);
} else {
view->urgent = (struct timespec){ 0 };
if (view->urgent_timer) {