aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKirill Primak <vyivel@eclair.cafe>2024-01-19 12:10:39 +0300
committerKirill Primak <vyivel@eclair.cafe>2024-01-27 17:48:07 +0300
commit4688a371e04787f5bb059e80b5de506f0a8f00ff (patch)
tree97e7a3c2e9b1cb5ae627742ef0673700bb307503
parent00b869c1a96f300a8f25da95d624524895e0ddf2 (diff)
compositor: don't get buffer from pending buffer resource too early
Fixes: https://gitlab.freedesktop.org/wlroots/wlroots/-/issues/3795
-rw-r--r--include/wlr/types/wlr_compositor.h3
-rw-r--r--types/wlr_compositor.c48
2 files changed, 39 insertions, 12 deletions
diff --git a/include/wlr/types/wlr_compositor.h b/include/wlr/types/wlr_compositor.h
index 2005a949..39bc3e21 100644
--- a/include/wlr/types/wlr_compositor.h
+++ b/include/wlr/types/wlr_compositor.h
@@ -240,6 +240,9 @@ struct wlr_surface {
struct wl_list synced; // wlr_surface_synced.link
size_t synced_len;
+
+ struct wl_resource *pending_buffer_resource;
+ struct wl_listener pending_buffer_resource_destroy;
};
struct wlr_renderer;
diff --git a/types/wlr_compositor.c b/types/wlr_compositor.c
index c5a604ac..b2978775 100644
--- a/types/wlr_compositor.c
+++ b/types/wlr_compositor.c
@@ -35,6 +35,24 @@ static int max(int fst, int snd) {
}
}
+static void set_pending_buffer_resource(struct wlr_surface *surface,
+ struct wl_resource *resource) {
+ wl_list_remove(&surface->pending_buffer_resource_destroy.link);
+ surface->pending_buffer_resource = resource;
+ if (resource != NULL) {
+ wl_resource_add_destroy_listener(resource, &surface->pending_buffer_resource_destroy);
+ } else {
+ wl_list_init(&surface->pending_buffer_resource_destroy.link);
+ }
+}
+
+static void pending_buffer_resource_handle_destroy(struct wl_listener *listener, void *data) {
+ struct wlr_surface *surface =
+ wl_container_of(listener, surface, pending_buffer_resource_destroy);
+
+ set_pending_buffer_resource(surface, NULL);
+}
+
static void surface_handle_destroy(struct wl_client *client,
struct wl_resource *resource) {
struct wlr_surface *surface = wlr_surface_from_resource(resource);
@@ -60,19 +78,8 @@ static void surface_handle_attach(struct wl_client *client,
return;
}
- struct wlr_buffer *buffer = NULL;
- if (buffer_resource != NULL) {
- buffer = wlr_buffer_try_from_resource(buffer_resource);
- if (buffer == NULL) {
- wl_resource_post_error(buffer_resource, 0, "unknown buffer type");
- return;
- }
- }
-
surface->pending.committed |= WLR_SURFACE_STATE_BUFFER;
-
- wlr_buffer_unlock(surface->pending.buffer);
- surface->pending.buffer = buffer;
+ set_pending_buffer_resource(surface, buffer_resource);
if (wl_resource_get_version(resource) < WL_SURFACE_OFFSET_SINCE_VERSION) {
surface->pending.committed |= WLR_SURFACE_STATE_OFFSET;
@@ -180,6 +187,17 @@ static void surface_finalize_pending(struct wlr_surface *surface) {
struct wlr_surface_state *pending = &surface->pending;
if ((pending->committed & WLR_SURFACE_STATE_BUFFER)) {
+ struct wl_resource *buffer_resource = surface->pending_buffer_resource;
+ if (buffer_resource != NULL) {
+ set_pending_buffer_resource(surface, NULL);
+
+ pending->buffer = wlr_buffer_try_from_resource(buffer_resource);
+ if (pending->buffer == NULL) {
+ wlr_surface_reject_pending(surface,
+ buffer_resource, -1, "unknown buffer type");
+ }
+ }
+
if (pending->buffer != NULL) {
pending->buffer_width = pending->buffer->width;
pending->buffer_height = pending->buffer->height;
@@ -737,6 +755,9 @@ static void surface_handle_resource_destroy(struct wl_resource *resource) {
wl_list_remove(&surface->renderer_destroy.link);
wl_list_remove(&surface->role_resource_destroy.link);
+
+ wl_list_remove(&surface->pending_buffer_resource_destroy.link);
+
surface_state_finish(&surface->pending);
surface_state_finish(&surface->current);
pixman_region32_fini(&surface->buffer_damage);
@@ -805,6 +826,9 @@ static struct wlr_surface *surface_create(struct wl_client *client,
wl_list_init(&surface->role_resource_destroy.link);
+ surface->pending_buffer_resource_destroy.notify = pending_buffer_resource_handle_destroy;
+ wl_list_init(&surface->pending_buffer_resource_destroy.link);
+
return surface;
}