view: Save all buffers associated with view
During the execution of a resize transaction, the buffer associated with a view's surface is saved and reused until the client acknowledges the resulting configure event. However, only one the main buffer of the main surface was stored and rendered, meaning that subsurfaces disappear during resize. Iterate over all, store and render buffers from all surfaces in the view to ensure that correct rendering is preserved.
This commit is contained in:
parent
613abdda6f
commit
fcd0ab8f33
|
@ -55,6 +55,13 @@ struct sway_view_impl {
|
||||||
void (*destroy)(struct sway_view *view);
|
void (*destroy)(struct sway_view *view);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct sway_saved_buffer {
|
||||||
|
struct wlr_client_buffer *buffer;
|
||||||
|
int x, y;
|
||||||
|
int width, height;
|
||||||
|
struct wl_list link; // sway_view::saved_buffers
|
||||||
|
};
|
||||||
|
|
||||||
struct sway_view {
|
struct sway_view {
|
||||||
enum sway_view_type type;
|
enum sway_view_type type;
|
||||||
const struct sway_view_impl *impl;
|
const struct sway_view_impl *impl;
|
||||||
|
@ -65,9 +72,6 @@ struct sway_view {
|
||||||
|
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
|
|
||||||
double saved_x, saved_y;
|
|
||||||
int saved_width, saved_height;
|
|
||||||
|
|
||||||
// The size the view would want to be if it weren't tiled.
|
// The size the view would want to be if it weren't tiled.
|
||||||
// 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;
|
||||||
|
@ -80,8 +84,7 @@ struct sway_view {
|
||||||
bool allow_request_urgent;
|
bool allow_request_urgent;
|
||||||
struct wl_event_source *urgent_timer;
|
struct wl_event_source *urgent_timer;
|
||||||
|
|
||||||
struct wlr_client_buffer *saved_buffer;
|
struct wl_list saved_buffers; // sway_saved_buffer::link
|
||||||
int saved_buffer_width, saved_buffer_height;
|
|
||||||
|
|
||||||
// The geometry for whatever the client is committing, regardless of
|
// The geometry for whatever the client is committing, regardless of
|
||||||
// transaction state. Updated on every commit.
|
// transaction state. Updated on every commit.
|
||||||
|
|
|
@ -511,7 +511,7 @@ static bool scan_out_fullscreen_view(struct sway_output *output,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (view->saved_buffer) {
|
if (!wl_list_empty(&view->saved_buffers)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -280,38 +280,45 @@ static void render_saved_view(struct sway_view *view,
|
||||||
struct sway_output *output, pixman_region32_t *damage, float alpha) {
|
struct sway_output *output, pixman_region32_t *damage, float alpha) {
|
||||||
struct wlr_output *wlr_output = output->wlr_output;
|
struct wlr_output *wlr_output = output->wlr_output;
|
||||||
|
|
||||||
if (!view->saved_buffer || !view->saved_buffer->texture) {
|
if (wl_list_empty(&view->saved_buffers)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
struct wlr_box box = {
|
struct sway_saved_buffer *saved_buf;
|
||||||
.x = view->container->surface_x - output->lx -
|
wl_list_for_each(saved_buf, &view->saved_buffers, link) {
|
||||||
view->saved_geometry.x,
|
if (!saved_buf->buffer->texture) {
|
||||||
.y = view->container->surface_y - output->ly -
|
continue;
|
||||||
view->saved_geometry.y,
|
}
|
||||||
.width = view->saved_buffer_width,
|
|
||||||
.height = view->saved_buffer_height,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct wlr_box output_box = {
|
struct wlr_box box = {
|
||||||
.width = output->width,
|
.x = view->container->surface_x - output->lx -
|
||||||
.height = output->height,
|
view->saved_geometry.x + saved_buf->x,
|
||||||
};
|
.y = view->container->surface_y - output->ly -
|
||||||
|
view->saved_geometry.y + saved_buf->y,
|
||||||
|
.width = saved_buf->width,
|
||||||
|
.height = saved_buf->height,
|
||||||
|
};
|
||||||
|
|
||||||
struct wlr_box intersection;
|
struct wlr_box output_box = {
|
||||||
bool intersects = wlr_box_intersection(&intersection, &output_box, &box);
|
.width = output->width,
|
||||||
if (!intersects) {
|
.height = output->height,
|
||||||
return;
|
};
|
||||||
|
|
||||||
|
struct wlr_box intersection;
|
||||||
|
bool intersects = wlr_box_intersection(&intersection, &output_box, &box);
|
||||||
|
if (!intersects) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
scale_box(&box, wlr_output->scale);
|
||||||
|
|
||||||
|
float matrix[9];
|
||||||
|
wlr_matrix_project_box(matrix, &box, WL_OUTPUT_TRANSFORM_NORMAL, 0,
|
||||||
|
wlr_output->transform_matrix);
|
||||||
|
|
||||||
|
render_texture(wlr_output, damage, saved_buf->buffer->texture,
|
||||||
|
&box, matrix, alpha);
|
||||||
}
|
}
|
||||||
|
|
||||||
scale_box(&box, wlr_output->scale);
|
|
||||||
|
|
||||||
float matrix[9];
|
|
||||||
wlr_matrix_project_box(matrix, &box, WL_OUTPUT_TRANSFORM_NORMAL, 0,
|
|
||||||
wlr_output->transform_matrix);
|
|
||||||
|
|
||||||
render_texture(wlr_output, damage, view->saved_buffer->texture,
|
|
||||||
&box, matrix, alpha);
|
|
||||||
|
|
||||||
// FIXME: we should set the surface that this saved buffer originates from
|
// FIXME: we should set the surface that this saved buffer originates from
|
||||||
// as sampled here.
|
// as sampled here.
|
||||||
// https://github.com/swaywm/sway/pull/4465#discussion_r321082059
|
// https://github.com/swaywm/sway/pull/4465#discussion_r321082059
|
||||||
|
@ -323,7 +330,7 @@ static void render_saved_view(struct sway_view *view,
|
||||||
static void render_view(struct sway_output *output, pixman_region32_t *damage,
|
static void render_view(struct sway_output *output, pixman_region32_t *damage,
|
||||||
struct sway_container *con, struct border_colors *colors) {
|
struct sway_container *con, struct border_colors *colors) {
|
||||||
struct sway_view *view = con->view;
|
struct sway_view *view = con->view;
|
||||||
if (view->saved_buffer) {
|
if (!wl_list_empty(&view->saved_buffers)) {
|
||||||
render_saved_view(view, output, damage, view->container->alpha);
|
render_saved_view(view, output, damage, view->container->alpha);
|
||||||
} else if (view->surface) {
|
} else if (view->surface) {
|
||||||
render_view_toplevels(view, output, damage, view->container->alpha);
|
render_view_toplevels(view, output, damage, view->container->alpha);
|
||||||
|
@ -1020,7 +1027,7 @@ void output_render(struct sway_output *output, struct timespec *when,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fullscreen_con->view) {
|
if (fullscreen_con->view) {
|
||||||
if (fullscreen_con->view->saved_buffer) {
|
if (!wl_list_empty(&fullscreen_con->view->saved_buffers)) {
|
||||||
render_saved_view(fullscreen_con->view, output, damage, 1.0f);
|
render_saved_view(fullscreen_con->view, output, damage, 1.0f);
|
||||||
} else if (fullscreen_con->view->surface) {
|
} else if (fullscreen_con->view->surface) {
|
||||||
render_view_toplevels(fullscreen_con->view,
|
render_view_toplevels(fullscreen_con->view,
|
||||||
|
|
|
@ -210,14 +210,17 @@ static void apply_container_state(struct sway_container *container,
|
||||||
struct sway_view *view = container->view;
|
struct sway_view *view = container->view;
|
||||||
// Damage the old location
|
// Damage the old location
|
||||||
desktop_damage_whole_container(container);
|
desktop_damage_whole_container(container);
|
||||||
if (view && view->saved_buffer) {
|
if (view && !wl_list_empty(&view->saved_buffers)) {
|
||||||
struct wlr_box box = {
|
struct sway_saved_buffer *saved_buf;
|
||||||
.x = container->current.content_x - view->saved_geometry.x,
|
wl_list_for_each(saved_buf, &view->saved_buffers, link) {
|
||||||
.y = container->current.content_y - view->saved_geometry.y,
|
struct wlr_box box = {
|
||||||
.width = view->saved_buffer_width,
|
.x = container->current.content_x - view->saved_geometry.x + saved_buf->x,
|
||||||
.height = view->saved_buffer_height,
|
.y = container->current.content_y - view->saved_geometry.y + saved_buf->y,
|
||||||
};
|
.width = saved_buf->width,
|
||||||
desktop_damage_box(&box);
|
.height = saved_buf->height,
|
||||||
|
};
|
||||||
|
desktop_damage_box(&box);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// There are separate children lists for each instruction state, the
|
// There are separate children lists for each instruction state, the
|
||||||
|
@ -229,7 +232,7 @@ static void apply_container_state(struct sway_container *container,
|
||||||
|
|
||||||
memcpy(&container->current, state, sizeof(struct sway_container_state));
|
memcpy(&container->current, state, sizeof(struct sway_container_state));
|
||||||
|
|
||||||
if (view && view->saved_buffer) {
|
if (view && !wl_list_empty(&view->saved_buffers)) {
|
||||||
if (!container->node.destroying || container->node.ntxnrefs == 1) {
|
if (!container->node.destroying || container->node.ntxnrefs == 1) {
|
||||||
view_remove_saved_buffer(view);
|
view_remove_saved_buffer(view);
|
||||||
}
|
}
|
||||||
|
@ -432,7 +435,7 @@ static void transaction_commit(struct sway_transaction *transaction) {
|
||||||
wlr_surface_send_frame_done(
|
wlr_surface_send_frame_done(
|
||||||
node->sway_container->view->surface, &now);
|
node->sway_container->view->surface, &now);
|
||||||
}
|
}
|
||||||
if (node_is_view(node) && !node->sway_container->view->saved_buffer) {
|
if (node_is_view(node) && wl_list_empty(&node->sway_container->view->saved_buffers)) {
|
||||||
view_save_buffer(node->sway_container->view);
|
view_save_buffer(node->sway_container->view);
|
||||||
memcpy(&node->sway_container->view->saved_geometry,
|
memcpy(&node->sway_container->view->saved_geometry,
|
||||||
&node->sway_container->view->geometry,
|
&node->sway_container->view->geometry,
|
||||||
|
|
|
@ -36,6 +36,7 @@ void view_init(struct sway_view *view, enum sway_view_type type,
|
||||||
view->type = type;
|
view->type = type;
|
||||||
view->impl = impl;
|
view->impl = impl;
|
||||||
view->executed_criteria = create_list();
|
view->executed_criteria = create_list();
|
||||||
|
wl_list_init(&view->saved_buffers);
|
||||||
view->allow_request_urgent = true;
|
view->allow_request_urgent = true;
|
||||||
view->shortcuts_inhibit = SHORTCUTS_INHIBIT_DEFAULT;
|
view->shortcuts_inhibit = SHORTCUTS_INHIBIT_DEFAULT;
|
||||||
wl_signal_init(&view->events.unmap);
|
wl_signal_init(&view->events.unmap);
|
||||||
|
@ -54,6 +55,9 @@ void view_destroy(struct sway_view *view) {
|
||||||
"(might have a pending transaction?)")) {
|
"(might have a pending transaction?)")) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (!wl_list_empty(&view->saved_buffers)) {
|
||||||
|
view_remove_saved_buffer(view);
|
||||||
|
}
|
||||||
list_free(view->executed_criteria);
|
list_free(view->executed_criteria);
|
||||||
|
|
||||||
free(view->title_format);
|
free(view->title_format);
|
||||||
|
@ -1176,23 +1180,38 @@ bool view_is_urgent(struct sway_view *view) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void view_remove_saved_buffer(struct sway_view *view) {
|
void view_remove_saved_buffer(struct sway_view *view) {
|
||||||
if (!sway_assert(view->saved_buffer, "Expected a saved buffer")) {
|
if (!sway_assert(!wl_list_empty(&view->saved_buffers), "Expected a saved buffer")) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
wlr_buffer_unlock(&view->saved_buffer->base);
|
struct sway_saved_buffer *saved_buf, *tmp;
|
||||||
view->saved_buffer = NULL;
|
wl_list_for_each_safe(saved_buf, tmp, &view->saved_buffers, link) {
|
||||||
|
wlr_buffer_unlock(&saved_buf->buffer->base);
|
||||||
|
wl_list_remove(&saved_buf->link);
|
||||||
|
free(saved_buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void view_save_buffer_iterator(struct wlr_surface *surface,
|
||||||
|
int sx, int sy, void *data) {
|
||||||
|
struct sway_view *view = data;
|
||||||
|
|
||||||
|
if (surface && wlr_surface_has_buffer(surface)) {
|
||||||
|
wlr_buffer_lock(&surface->buffer->base);
|
||||||
|
struct sway_saved_buffer *saved_buffer = calloc(1, sizeof(struct sway_saved_buffer));
|
||||||
|
saved_buffer->buffer = surface->buffer;
|
||||||
|
saved_buffer->width = surface->current.width;
|
||||||
|
saved_buffer->height = surface->current.height;
|
||||||
|
saved_buffer->x = sx;
|
||||||
|
saved_buffer->y = sy;
|
||||||
|
wl_list_insert(&view->saved_buffers, &saved_buffer->link);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void view_save_buffer(struct sway_view *view) {
|
void view_save_buffer(struct sway_view *view) {
|
||||||
if (!sway_assert(!view->saved_buffer, "Didn't expect saved buffer")) {
|
if (!sway_assert(wl_list_empty(&view->saved_buffers), "Didn't expect saved buffer")) {
|
||||||
view_remove_saved_buffer(view);
|
view_remove_saved_buffer(view);
|
||||||
}
|
}
|
||||||
if (view->surface && wlr_surface_has_buffer(view->surface)) {
|
view_for_each_surface(view, view_save_buffer_iterator, view);
|
||||||
wlr_buffer_lock(&view->surface->buffer->base);
|
|
||||||
view->saved_buffer = view->surface->buffer;
|
|
||||||
view->saved_buffer_width = view->surface->current.width;
|
|
||||||
view->saved_buffer_height = view->surface->current.height;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool view_is_transient_for(struct sway_view *child,
|
bool view_is_transient_for(struct sway_view *child,
|
||||||
|
|
Loading…
Reference in a new issue