aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Kenny Levinsen <kl@kl.wtf>2020-05-31 01:37:43 +0200
committerLibravatar Simon Ser <contact@emersion.fr>2020-06-03 16:41:17 +0200
commitfcd0ab8f331a6e74fde113d665d4aed21bccdfc5 (patch)
treec2f53f827372904f8d7b1356231350652bed8a8d
parentxwayland: pass focus to previous unmanaged surface on unmap (diff)
downloadsway-fcd0ab8f331a6e74fde113d665d4aed21bccdfc5.tar.gz
sway-fcd0ab8f331a6e74fde113d665d4aed21bccdfc5.tar.zst
sway-fcd0ab8f331a6e74fde113d665d4aed21bccdfc5.zip
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.
-rw-r--r--include/sway/tree/view.h13
-rw-r--r--sway/desktop/output.c2
-rw-r--r--sway/desktop/render.c61
-rw-r--r--sway/desktop/transaction.c23
-rw-r--r--sway/tree/view.c39
5 files changed, 85 insertions, 53 deletions
diff --git a/include/sway/tree/view.h b/include/sway/tree/view.h
index ab2dc8e4..53c5d34e 100644
--- a/include/sway/tree/view.h
+++ b/include/sway/tree/view.h
@@ -55,6 +55,13 @@ struct sway_view_impl {
55 void (*destroy)(struct sway_view *view); 55 void (*destroy)(struct sway_view *view);
56}; 56};
57 57
58struct sway_saved_buffer {
59 struct wlr_client_buffer *buffer;
60 int x, y;
61 int width, height;
62 struct wl_list link; // sway_view::saved_buffers
63};
64
58struct sway_view { 65struct sway_view {
59 enum sway_view_type type; 66 enum sway_view_type type;
60 const struct sway_view_impl *impl; 67 const struct sway_view_impl *impl;
@@ -65,9 +72,6 @@ struct sway_view {
65 72
66 pid_t pid; 73 pid_t pid;
67 74
68 double saved_x, saved_y;
69 int saved_width, saved_height;
70
71 // The size the view would want to be if it weren't tiled. 75 // The size the view would want to be if it weren't tiled.
72 // Used when changing a view from tiled to floating. 76 // Used when changing a view from tiled to floating.
73 int natural_width, natural_height; 77 int natural_width, natural_height;
@@ -80,8 +84,7 @@ struct sway_view {
80 bool allow_request_urgent; 84 bool allow_request_urgent;
81 struct wl_event_source *urgent_timer; 85 struct wl_event_source *urgent_timer;
82 86
83 struct wlr_client_buffer *saved_buffer; 87 struct wl_list saved_buffers; // sway_saved_buffer::link
84 int saved_buffer_width, saved_buffer_height;
85 88
86 // The geometry for whatever the client is committing, regardless of 89 // The geometry for whatever the client is committing, regardless of
87 // transaction state. Updated on every commit. 90 // transaction state. Updated on every commit.
diff --git a/sway/desktop/output.c b/sway/desktop/output.c
index a86622e1..18250ae6 100644
--- a/sway/desktop/output.c
+++ b/sway/desktop/output.c
@@ -511,7 +511,7 @@ static bool scan_out_fullscreen_view(struct sway_output *output,
511 return false; 511 return false;
512 } 512 }
513 513
514 if (view->saved_buffer) { 514 if (!wl_list_empty(&view->saved_buffers)) {
515 return false; 515 return false;
516 } 516 }
517 517
diff --git a/sway/desktop/render.c b/sway/desktop/render.c
index 14753df2..491a9bc0 100644
--- a/sway/desktop/render.c
+++ b/sway/desktop/render.c
@@ -280,37 +280,44 @@ static void render_saved_view(struct sway_view *view,
280 struct sway_output *output, pixman_region32_t *damage, float alpha) { 280 struct sway_output *output, pixman_region32_t *damage, float alpha) {
281 struct wlr_output *wlr_output = output->wlr_output; 281 struct wlr_output *wlr_output = output->wlr_output;
282 282
283 if (!view->saved_buffer || !view->saved_buffer->texture) { 283 if (wl_list_empty(&view->saved_buffers)) {
284 return; 284 return;
285 } 285 }
286 struct wlr_box box = { 286 struct sway_saved_buffer *saved_buf;
287 .x = view->container->surface_x - output->lx - 287 wl_list_for_each(saved_buf, &view->saved_buffers, link) {
288 view->saved_geometry.x, 288 if (!saved_buf->buffer->texture) {
289 .y = view->container->surface_y - output->ly - 289 continue;
290 view->saved_geometry.y, 290 }
291 .width = view->saved_buffer_width,
292 .height = view->saved_buffer_height,
293 };
294
295 struct wlr_box output_box = {
296 .width = output->width,
297 .height = output->height,
298 };
299 291
300 struct wlr_box intersection; 292 struct wlr_box box = {
301 bool intersects = wlr_box_intersection(&intersection, &output_box, &box); 293 .x = view->container->surface_x - output->lx -
302 if (!intersects) { 294 view->saved_geometry.x + saved_buf->x,
303 return; 295 .y = view->container->surface_y - output->ly -
304 } 296 view->saved_geometry.y + saved_buf->y,
297 .width = saved_buf->width,
298 .height = saved_buf->height,
299 };
300
301 struct wlr_box output_box = {
302 .width = output->width,
303 .height = output->height,
304 };
305
306 struct wlr_box intersection;
307 bool intersects = wlr_box_intersection(&intersection, &output_box, &box);
308 if (!intersects) {
309 continue;
310 }
305 311
306 scale_box(&box, wlr_output->scale); 312 scale_box(&box, wlr_output->scale);
307 313
308 float matrix[9]; 314 float matrix[9];
309 wlr_matrix_project_box(matrix, &box, WL_OUTPUT_TRANSFORM_NORMAL, 0, 315 wlr_matrix_project_box(matrix, &box, WL_OUTPUT_TRANSFORM_NORMAL, 0,
310 wlr_output->transform_matrix); 316 wlr_output->transform_matrix);
311 317
312 render_texture(wlr_output, damage, view->saved_buffer->texture, 318 render_texture(wlr_output, damage, saved_buf->buffer->texture,
313 &box, matrix, alpha); 319 &box, matrix, alpha);
320 }
314 321
315 // FIXME: we should set the surface that this saved buffer originates from 322 // FIXME: we should set the surface that this saved buffer originates from
316 // as sampled here. 323 // as sampled here.
@@ -323,7 +330,7 @@ static void render_saved_view(struct sway_view *view,
323static void render_view(struct sway_output *output, pixman_region32_t *damage, 330static void render_view(struct sway_output *output, pixman_region32_t *damage,
324 struct sway_container *con, struct border_colors *colors) { 331 struct sway_container *con, struct border_colors *colors) {
325 struct sway_view *view = con->view; 332 struct sway_view *view = con->view;
326 if (view->saved_buffer) { 333 if (!wl_list_empty(&view->saved_buffers)) {
327 render_saved_view(view, output, damage, view->container->alpha); 334 render_saved_view(view, output, damage, view->container->alpha);
328 } else if (view->surface) { 335 } else if (view->surface) {
329 render_view_toplevels(view, output, damage, view->container->alpha); 336 render_view_toplevels(view, output, damage, view->container->alpha);
@@ -1020,7 +1027,7 @@ void output_render(struct sway_output *output, struct timespec *when,
1020 } 1027 }
1021 1028
1022 if (fullscreen_con->view) { 1029 if (fullscreen_con->view) {
1023 if (fullscreen_con->view->saved_buffer) { 1030 if (!wl_list_empty(&fullscreen_con->view->saved_buffers)) {
1024 render_saved_view(fullscreen_con->view, output, damage, 1.0f); 1031 render_saved_view(fullscreen_con->view, output, damage, 1.0f);
1025 } else if (fullscreen_con->view->surface) { 1032 } else if (fullscreen_con->view->surface) {
1026 render_view_toplevels(fullscreen_con->view, 1033 render_view_toplevels(fullscreen_con->view,
diff --git a/sway/desktop/transaction.c b/sway/desktop/transaction.c
index ccf60514..ef656102 100644
--- a/sway/desktop/transaction.c
+++ b/sway/desktop/transaction.c
@@ -210,14 +210,17 @@ static void apply_container_state(struct sway_container *container,
210 struct sway_view *view = container->view; 210 struct sway_view *view = container->view;
211 // Damage the old location 211 // Damage the old location
212 desktop_damage_whole_container(container); 212 desktop_damage_whole_container(container);
213 if (view && view->saved_buffer) { 213 if (view && !wl_list_empty(&view->saved_buffers)) {
214 struct wlr_box box = { 214 struct sway_saved_buffer *saved_buf;
215 .x = container->current.content_x - view->saved_geometry.x, 215 wl_list_for_each(saved_buf, &view->saved_buffers, link) {
216 .y = container->current.content_y - view->saved_geometry.y, 216 struct wlr_box box = {
217 .width = view->saved_buffer_width, 217 .x = container->current.content_x - view->saved_geometry.x + saved_buf->x,
218 .height = view->saved_buffer_height, 218 .y = container->current.content_y - view->saved_geometry.y + saved_buf->y,
219 }; 219 .width = saved_buf->width,
220 desktop_damage_box(&box); 220 .height = saved_buf->height,
221 };
222 desktop_damage_box(&box);
223 }
221 } 224 }
222 225
223 // There are separate children lists for each instruction state, the 226 // There are separate children lists for each instruction state, the
@@ -229,7 +232,7 @@ static void apply_container_state(struct sway_container *container,
229 232
230 memcpy(&container->current, state, sizeof(struct sway_container_state)); 233 memcpy(&container->current, state, sizeof(struct sway_container_state));
231 234
232 if (view && view->saved_buffer) { 235 if (view && !wl_list_empty(&view->saved_buffers)) {
233 if (!container->node.destroying || container->node.ntxnrefs == 1) { 236 if (!container->node.destroying || container->node.ntxnrefs == 1) {
234 view_remove_saved_buffer(view); 237 view_remove_saved_buffer(view);
235 } 238 }
@@ -432,7 +435,7 @@ static void transaction_commit(struct sway_transaction *transaction) {
432 wlr_surface_send_frame_done( 435 wlr_surface_send_frame_done(
433 node->sway_container->view->surface, &now); 436 node->sway_container->view->surface, &now);
434 } 437 }
435 if (node_is_view(node) && !node->sway_container->view->saved_buffer) { 438 if (node_is_view(node) && wl_list_empty(&node->sway_container->view->saved_buffers)) {
436 view_save_buffer(node->sway_container->view); 439 view_save_buffer(node->sway_container->view);
437 memcpy(&node->sway_container->view->saved_geometry, 440 memcpy(&node->sway_container->view->saved_geometry,
438 &node->sway_container->view->geometry, 441 &node->sway_container->view->geometry,
diff --git a/sway/tree/view.c b/sway/tree/view.c
index 8e12a229..25951deb 100644
--- a/sway/tree/view.c
+++ b/sway/tree/view.c
@@ -36,6 +36,7 @@ void view_init(struct sway_view *view, enum sway_view_type type,
36 view->type = type; 36 view->type = type;
37 view->impl = impl; 37 view->impl = impl;
38 view->executed_criteria = create_list(); 38 view->executed_criteria = create_list();
39 wl_list_init(&view->saved_buffers);
39 view->allow_request_urgent = true; 40 view->allow_request_urgent = true;
40 view->shortcuts_inhibit = SHORTCUTS_INHIBIT_DEFAULT; 41 view->shortcuts_inhibit = SHORTCUTS_INHIBIT_DEFAULT;
41 wl_signal_init(&view->events.unmap); 42 wl_signal_init(&view->events.unmap);
@@ -54,6 +55,9 @@ void view_destroy(struct sway_view *view) {
54 "(might have a pending transaction?)")) { 55 "(might have a pending transaction?)")) {
55 return; 56 return;
56 } 57 }
58 if (!wl_list_empty(&view->saved_buffers)) {
59 view_remove_saved_buffer(view);
60 }
57 list_free(view->executed_criteria); 61 list_free(view->executed_criteria);
58 62
59 free(view->title_format); 63 free(view->title_format);
@@ -1176,23 +1180,38 @@ bool view_is_urgent(struct sway_view *view) {
1176} 1180}
1177 1181
1178void view_remove_saved_buffer(struct sway_view *view) { 1182void view_remove_saved_buffer(struct sway_view *view) {
1179 if (!sway_assert(view->saved_buffer, "Expected a saved buffer")) { 1183 if (!sway_assert(!wl_list_empty(&view->saved_buffers), "Expected a saved buffer")) {
1180 return; 1184 return;
1181 } 1185 }
1182 wlr_buffer_unlock(&view->saved_buffer->base); 1186 struct sway_saved_buffer *saved_buf, *tmp;
1183 view->saved_buffer = NULL; 1187 wl_list_for_each_safe(saved_buf, tmp, &view->saved_buffers, link) {
1188 wlr_buffer_unlock(&saved_buf->buffer->base);
1189 wl_list_remove(&saved_buf->link);
1190 free(saved_buf);
1191 }
1192}
1193
1194static void view_save_buffer_iterator(struct wlr_surface *surface,
1195 int sx, int sy, void *data) {
1196 struct sway_view *view = data;
1197
1198 if (surface && wlr_surface_has_buffer(surface)) {
1199 wlr_buffer_lock(&surface->buffer->base);
1200 struct sway_saved_buffer *saved_buffer = calloc(1, sizeof(struct sway_saved_buffer));
1201 saved_buffer->buffer = surface->buffer;
1202 saved_buffer->width = surface->current.width;
1203 saved_buffer->height = surface->current.height;
1204 saved_buffer->x = sx;
1205 saved_buffer->y = sy;
1206 wl_list_insert(&view->saved_buffers, &saved_buffer->link);
1207 }
1184} 1208}
1185 1209
1186void view_save_buffer(struct sway_view *view) { 1210void view_save_buffer(struct sway_view *view) {
1187 if (!sway_assert(!view->saved_buffer, "Didn't expect saved buffer")) { 1211 if (!sway_assert(wl_list_empty(&view->saved_buffers), "Didn't expect saved buffer")) {
1188 view_remove_saved_buffer(view); 1212 view_remove_saved_buffer(view);
1189 } 1213 }
1190 if (view->surface && wlr_surface_has_buffer(view->surface)) { 1214 view_for_each_surface(view, view_save_buffer_iterator, view);
1191 wlr_buffer_lock(&view->surface->buffer->base);
1192 view->saved_buffer = view->surface->buffer;
1193 view->saved_buffer_width = view->surface->current.width;
1194 view->saved_buffer_height = view->surface->current.height;
1195 }
1196} 1215}
1197 1216
1198bool view_is_transient_for(struct sway_view *child, 1217bool view_is_transient_for(struct sway_view *child,