aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Alexander Orzechowski <alex@ozal.ski>2023-04-27 10:25:40 +0200
committerLibravatar Kirill Primak <vyivel@eclair.cafe>2024-01-18 18:36:54 +0300
commit06ad734e70227ad0527fe11b88ad37e93005ce0c (patch)
tree5a5e2606242e3d229f4979d2b7c5352a139730b0
parentxwayland: Cleanup geometry handling on commit (diff)
downloadsway-06ad734e70227ad0527fe11b88ad37e93005ce0c.tar.gz
sway-06ad734e70227ad0527fe11b88ad37e93005ce0c.tar.zst
sway-06ad734e70227ad0527fe11b88ad37e93005ce0c.zip
scene_graph: Port view saved buffers
-rw-r--r--include/sway/tree/view.h18
-rw-r--r--sway/desktop/transaction.c49
-rw-r--r--sway/desktop/xdg_shell.c10
-rw-r--r--sway/desktop/xwayland.c10
-rw-r--r--sway/tree/view.c88
5 files changed, 91 insertions, 84 deletions
diff --git a/include/sway/tree/view.h b/include/sway/tree/view.h
index 8493958e..66d6db1c 100644
--- a/include/sway/tree/view.h
+++ b/include/sway/tree/view.h
@@ -57,21 +57,13 @@ struct sway_view_impl {
57 void (*destroy)(struct sway_view *view); 57 void (*destroy)(struct sway_view *view);
58}; 58};
59 59
60struct sway_saved_buffer {
61 struct wlr_client_buffer *buffer;
62 int x, y;
63 int width, height;
64 enum wl_output_transform transform;
65 struct wlr_fbox source_box;
66 struct wl_list link; // sway_view::saved_buffers
67};
68
69struct sway_view { 60struct sway_view {
70 enum sway_view_type type; 61 enum sway_view_type type;
71 const struct sway_view_impl *impl; 62 const struct sway_view_impl *impl;
72 63
73 struct wlr_scene_tree *scene_tree; 64 struct wlr_scene_tree *scene_tree;
74 struct wlr_scene_tree *content_tree; 65 struct wlr_scene_tree *content_tree;
66 struct wlr_scene_tree *saved_surface_tree;
75 67
76 struct sway_container *container; // NULL if unmapped and transactions finished 68 struct sway_container *container; // NULL if unmapped and transactions finished
77 struct wlr_surface *surface; // NULL for unmapped views 69 struct wlr_surface *surface; // NULL for unmapped views
@@ -92,16 +84,10 @@ struct sway_view {
92 bool allow_request_urgent; 84 bool allow_request_urgent;
93 struct wl_event_source *urgent_timer; 85 struct wl_event_source *urgent_timer;
94 86
95 struct wl_list saved_buffers; // sway_saved_buffer::link
96
97 // The geometry for whatever the client is committing, regardless of 87 // The geometry for whatever the client is committing, regardless of
98 // transaction state. Updated on every commit. 88 // transaction state. Updated on every commit.
99 struct wlr_box geometry; 89 struct wlr_box geometry;
100 90
101 // The "old" geometry during a transaction. Used to damage the old location
102 // when a transaction is applied.
103 struct wlr_box saved_geometry;
104
105 struct wlr_foreign_toplevel_handle_v1 *foreign_toplevel; 91 struct wlr_foreign_toplevel_handle_v1 *foreign_toplevel;
106 struct wl_listener foreign_activate_request; 92 struct wl_listener foreign_activate_request;
107 struct wl_listener foreign_fullscreen_request; 93 struct wl_listener foreign_fullscreen_request;
@@ -347,4 +333,6 @@ bool view_is_transient_for(struct sway_view *child, struct sway_view *ancestor);
347 333
348void view_assign_ctx(struct sway_view *view, struct launcher_ctx *ctx); 334void view_assign_ctx(struct sway_view *view, struct launcher_ctx *ctx);
349 335
336void view_send_frame_done(struct sway_view *view);
337
350#endif 338#endif
diff --git a/sway/desktop/transaction.c b/sway/desktop/transaction.c
index bb725795..1ae6642b 100644
--- a/sway/desktop/transaction.c
+++ b/sway/desktop/transaction.c
@@ -232,21 +232,6 @@ static void apply_workspace_state(struct sway_workspace *ws,
232static void apply_container_state(struct sway_container *container, 232static void apply_container_state(struct sway_container *container,
233 struct sway_container_state *state) { 233 struct sway_container_state *state) {
234 struct sway_view *view = container->view; 234 struct sway_view *view = container->view;
235 // Damage the old location
236 desktop_damage_whole_container(container);
237 if (view && !wl_list_empty(&view->saved_buffers)) {
238 struct sway_saved_buffer *saved_buf;
239 wl_list_for_each(saved_buf, &view->saved_buffers, link) {
240 struct wlr_box box = {
241 .x = saved_buf->x - view->saved_geometry.x,
242 .y = saved_buf->y - view->saved_geometry.y,
243 .width = saved_buf->width,
244 .height = saved_buf->height,
245 };
246 desktop_damage_box(&box);
247 }
248 }
249
250 // There are separate children lists for each instruction state, the 235 // There are separate children lists for each instruction state, the
251 // container's current state and the container's pending state 236 // container's current state and the container's pending state
252 // (ie. con->children). The list itself needs to be freed here. 237 // (ie. con->children). The list itself needs to be freed here.
@@ -256,17 +241,19 @@ static void apply_container_state(struct sway_container *container,
256 241
257 memcpy(&container->current, state, sizeof(struct sway_container_state)); 242 memcpy(&container->current, state, sizeof(struct sway_container_state));
258 243
259 if (view && !wl_list_empty(&view->saved_buffers)) { 244 if (view) {
260 if (!container->node.destroying || container->node.ntxnrefs == 1) { 245 if (view->saved_surface_tree) {
261 view_remove_saved_buffer(view); 246 if (!container->node.destroying || container->node.ntxnrefs == 1) {
247 view_remove_saved_buffer(view);
248 }
262 } 249 }
263 }
264 250
265 // If the view hasn't responded to the configure, center it within 251 // If the view hasn't responded to the configure, center it within
266 // the container. This is important for fullscreen views which 252 // the container. This is important for fullscreen views which
267 // refuse to resize to the size of the output. 253 // refuse to resize to the size of the output.
268 if (view && view->surface) { 254 if (view->surface) {
269 view_center_surface(view); 255 view_center_surface(view);
256 }
270 } 257 }
271 258
272 // Damage the new location 259 // Damage the new location
@@ -415,21 +402,11 @@ static void transaction_commit(struct sway_transaction *transaction) {
415 ++transaction->num_waiting; 402 ++transaction->num_waiting;
416 } 403 }
417 404
418 // From here on we are rendering a saved buffer of the view, which 405 view_send_frame_done(node->sway_container->view);
419 // means we can send a frame done event to make the client redraw it
420 // as soon as possible. Additionally, this is required if a view is
421 // mapping and its default geometry doesn't intersect an output.
422 struct timespec now;
423 clock_gettime(CLOCK_MONOTONIC, &now);
424 wlr_surface_send_frame_done(
425 node->sway_container->view->surface, &now);
426 } 406 }
427 if (!hidden && node_is_view(node) && 407 if (!hidden && node_is_view(node) &&
428 wl_list_empty(&node->sway_container->view->saved_buffers)) { 408 !node->sway_container->view->saved_surface_tree) {
429 view_save_buffer(node->sway_container->view); 409 view_save_buffer(node->sway_container->view);
430 memcpy(&node->sway_container->view->saved_geometry,
431 &node->sway_container->view->geometry,
432 sizeof(struct wlr_box));
433 } 410 }
434 node->instruction = instruction; 411 node->instruction = instruction;
435 } 412 }
diff --git a/sway/desktop/xdg_shell.c b/sway/desktop/xdg_shell.c
index fed820cf..95b5cb9d 100644
--- a/sway/desktop/xdg_shell.c
+++ b/sway/desktop/xdg_shell.c
@@ -332,8 +332,16 @@ static void handle_commit(struct wl_listener *listener, void *data) {
332 } 332 }
333 333
334 if (view->container->node.instruction) { 334 if (view->container->node.instruction) {
335 transaction_notify_view_ready_by_serial(view, 335 bool successful = transaction_notify_view_ready_by_serial(view,
336 xdg_surface->current.configure_serial); 336 xdg_surface->current.configure_serial);
337
338 // If we saved the view and this commit isn't what we're looking for
339 // that means the user will never actually see the buffers submitted to
340 // us here. Just send frame done events to these surfaces so they can
341 // commit another time for us.
342 if (view->saved_surface_tree && !successful) {
343 view_send_frame_done(view);
344 }
337 } 345 }
338} 346}
339 347
diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c
index 0967c7fc..e0c80c07 100644
--- a/sway/desktop/xwayland.c
+++ b/sway/desktop/xwayland.c
@@ -442,8 +442,16 @@ static void handle_commit(struct wl_listener *listener, void *data) {
442 } 442 }
443 443
444 if (view->container->node.instruction) { 444 if (view->container->node.instruction) {
445 transaction_notify_view_ready_by_geometry(view, 445 bool successful = transaction_notify_view_ready_by_geometry(view,
446 xsurface->x, xsurface->y, state->width, state->height); 446 xsurface->x, xsurface->y, state->width, state->height);
447
448 // If we saved the view and this commit isn't what we're looking for
449 // that means the user will never actually see the buffers submitted to
450 // us here. Just send frame done events to these surfaces so they can
451 // commit another time for us.
452 if (view->saved_surface_tree && !successful) {
453 view_send_frame_done(view);
454 }
447 } 455 }
448} 456}
449 457
diff --git a/sway/tree/view.c b/sway/tree/view.c
index ee25faf1..402fa179 100644
--- a/sway/tree/view.c
+++ b/sway/tree/view.c
@@ -56,7 +56,6 @@ bool view_init(struct sway_view *view, enum sway_view_type type,
56 view->type = type; 56 view->type = type;
57 view->impl = impl; 57 view->impl = impl;
58 view->executed_criteria = create_list(); 58 view->executed_criteria = create_list();
59 wl_list_init(&view->saved_buffers);
60 view->allow_request_urgent = true; 59 view->allow_request_urgent = true;
61 view->shortcuts_inhibit = SHORTCUTS_INHIBIT_DEFAULT; 60 view->shortcuts_inhibit = SHORTCUTS_INHIBIT_DEFAULT;
62 wl_signal_init(&view->events.unmap); 61 wl_signal_init(&view->events.unmap);
@@ -77,9 +76,6 @@ void view_destroy(struct sway_view *view) {
77 return; 76 return;
78 } 77 }
79 wl_list_remove(&view->events.unmap.listener_list); 78 wl_list_remove(&view->events.unmap.listener_list);
80 if (!wl_list_empty(&view->saved_buffers)) {
81 view_remove_saved_buffer(view);
82 }
83 list_free(view->executed_criteria); 79 list_free(view->executed_criteria);
84 80
85 view_assign_ctx(view, NULL); 81 view_assign_ctx(view, NULL);
@@ -931,10 +927,10 @@ void view_center_surface(struct sway_view *view) {
931 struct sway_container *con = view->container; 927 struct sway_container *con = view->container;
932 // We always center the current coordinates rather than the next, as the 928 // We always center the current coordinates rather than the next, as the
933 // geometry immediately affects the currently active rendering. 929 // geometry immediately affects the currently active rendering.
934 con->surface_x = fmax(con->current.content_x, con->current.content_x + 930 int x = (int) fmax(0, (con->current.content_width - view->geometry.width) / 2);
935 (con->current.content_width - view->geometry.width) / 2); 931 int y = (int) fmax(0, (con->current.content_height - view->geometry.height) / 2);
936 con->surface_y = fmax(con->current.content_y, con->current.content_y + 932
937 (con->current.content_height - view->geometry.height) / 2); 933 wlr_scene_node_set_position(&view->content_tree->node, x, y);
938} 934}
939 935
940struct sway_view *view_from_wlr_surface(struct wlr_surface *wlr_surface) { 936struct sway_view *view_from_wlr_surface(struct wlr_surface *wlr_surface) {
@@ -1161,40 +1157,54 @@ bool view_is_urgent(struct sway_view *view) {
1161} 1157}
1162 1158
1163void view_remove_saved_buffer(struct sway_view *view) { 1159void view_remove_saved_buffer(struct sway_view *view) {
1164 if (!sway_assert(!wl_list_empty(&view->saved_buffers), "Expected a saved buffer")) { 1160 if (!sway_assert(view->saved_surface_tree, "Expected a saved buffer")) {
1165 return; 1161 return;
1166 } 1162 }
1167 struct sway_saved_buffer *saved_buf, *tmp; 1163
1168 wl_list_for_each_safe(saved_buf, tmp, &view->saved_buffers, link) { 1164 wlr_scene_node_destroy(&view->saved_surface_tree->node);
1169 wlr_buffer_unlock(&saved_buf->buffer->base); 1165 view->saved_surface_tree = NULL;
1170 wl_list_remove(&saved_buf->link); 1166 wlr_scene_node_set_enabled(&view->content_tree->node, true);
1171 free(saved_buf);
1172 }
1173} 1167}
1174 1168
1175static void view_save_buffer_iterator(struct wlr_surface *surface, 1169static void view_save_buffer_iterator(struct wlr_scene_buffer *buffer,
1176 int sx, int sy, void *data) { 1170 int sx, int sy, void *data) {
1177 struct sway_view *view = data; 1171 struct wlr_scene_tree *tree = data;
1178 1172
1179 if (surface && surface->buffer) { 1173 struct wlr_scene_buffer *sbuf = wlr_scene_buffer_create(tree, NULL);
1180 wlr_buffer_lock(&surface->buffer->base); 1174 if (!sbuf) {
1181 struct sway_saved_buffer *saved_buffer = calloc(1, sizeof(struct sway_saved_buffer)); 1175 sway_log(SWAY_ERROR, "Could not allocate a scene buffer when saving a surface");
1182 saved_buffer->buffer = surface->buffer; 1176 return;
1183 saved_buffer->width = surface->current.width;
1184 saved_buffer->height = surface->current.height;
1185 saved_buffer->x = view->container->surface_x + sx;
1186 saved_buffer->y = view->container->surface_y + sy;
1187 saved_buffer->transform = surface->current.transform;
1188 wlr_surface_get_buffer_source_box(surface, &saved_buffer->source_box);
1189 wl_list_insert(view->saved_buffers.prev, &saved_buffer->link);
1190 } 1177 }
1178
1179 wlr_scene_buffer_set_dest_size(sbuf,
1180 buffer->dst_width, buffer->dst_height);
1181 wlr_scene_buffer_set_opaque_region(sbuf, &buffer->opaque_region);
1182 wlr_scene_buffer_set_source_box(sbuf, &buffer->src_box);
1183 wlr_scene_node_set_position(&sbuf->node, sx, sy);
1184 wlr_scene_buffer_set_transform(sbuf, buffer->transform);
1185 wlr_scene_buffer_set_buffer(sbuf, buffer->buffer);
1191} 1186}
1192 1187
1193void view_save_buffer(struct sway_view *view) { 1188void view_save_buffer(struct sway_view *view) {
1194 if (!sway_assert(wl_list_empty(&view->saved_buffers), "Didn't expect saved buffer")) { 1189 if (!sway_assert(!view->saved_surface_tree, "Didn't expect saved buffer")) {
1195 view_remove_saved_buffer(view); 1190 view_remove_saved_buffer(view);
1196 } 1191 }
1197 view_for_each_surface(view, view_save_buffer_iterator, view); 1192
1193 view->saved_surface_tree = wlr_scene_tree_create(view->scene_tree);
1194 if (!view->saved_surface_tree) {
1195 sway_log(SWAY_ERROR, "Could not allocate a scene tree node when saving a surface");
1196 return;
1197 }
1198
1199 // Enable and disable the saved surface tree like so to atomitaclly update
1200 // the tree. This will prevent over damaging or other weirdness.
1201 wlr_scene_node_set_enabled(&view->saved_surface_tree->node, false);
1202
1203 wlr_scene_node_for_each_buffer(&view->content_tree->node,
1204 view_save_buffer_iterator, view->saved_surface_tree);
1205
1206 wlr_scene_node_set_enabled(&view->content_tree->node, false);
1207 wlr_scene_node_set_enabled(&view->saved_surface_tree->node, true);
1198} 1208}
1199 1209
1200bool view_is_transient_for(struct sway_view *child, 1210bool view_is_transient_for(struct sway_view *child,
@@ -1202,3 +1212,19 @@ bool view_is_transient_for(struct sway_view *child,
1202 return child->impl->is_transient_for && 1212 return child->impl->is_transient_for &&
1203 child->impl->is_transient_for(child, ancestor); 1213 child->impl->is_transient_for(child, ancestor);
1204} 1214}
1215
1216static void send_frame_done_iterator(struct wlr_scene_buffer *scene_buffer,
1217 int x, int y, void *data) {
1218 struct timespec *when = data;
1219 wl_signal_emit_mutable(&scene_buffer->events.frame_done, when);
1220}
1221
1222void view_send_frame_done(struct sway_view *view) {
1223 struct timespec when;
1224 clock_gettime(CLOCK_MONOTONIC, &when);
1225
1226 struct wlr_scene_node *node;
1227 wl_list_for_each(node, &view->content_tree->children, link) {
1228 wlr_scene_node_for_each_buffer(node, send_frame_done_iterator, &when);
1229 }
1230}