From c1927f0948791464c6b576755436efd60b2aea39 Mon Sep 17 00:00:00 2001 From: lkn Date: Mon, 22 Jun 2026 00:29:28 +0200 Subject: [PATCH] wayland: defer layer-shell configure to initial commit wlroots 0.19 asserts that the surface is initialized before wlr_layer_surface_v1_configure is called. Defer the configure to the initial commit, matching the pattern used for xdg_toplevel surfaces. Fixes screenshot tool crash. --- src/backend/wayland/wl_layer_shell.c | 58 +++++++++++++++++++--------- src/backend/wayland/wl_types.h | 1 + 2 files changed, 40 insertions(+), 19 deletions(-) diff --git a/src/backend/wayland/wl_layer_shell.c b/src/backend/wayland/wl_layer_shell.c index e0131ac..6e8c7e5 100644 --- a/src/backend/wayland/wl_layer_shell.c +++ b/src/backend/wayland/wl_layer_shell.c @@ -112,6 +112,8 @@ handle_layer_surface_destroy(struct wl_listener *listener, void *data) wl_list_remove(&lv->map_listener.link); wl_list_remove(&lv->unmap_listener.link); wl_list_remove(&lv->destroy_listener.link); + if (lv->commit_listener.link.next) + wl_list_remove(&lv->commit_listener.link); if (lv->scene_node) { wlr_scene_node_destroy(&lv->scene_node->node); lv->scene_node = NULL; @@ -120,6 +122,36 @@ handle_layer_surface_destroy(struct wl_listener *listener, void *data) free(lv); } +static void +handle_layer_surface_initial_commit(struct wl_listener *listener, void *data) +{ + struct wl_layer_view *lv = wl_container_of(listener, lv, commit_listener); + struct wlr_layer_surface_v1 *ls = lv->layer_surface; + (void)data; + + if (!ls->initial_commit) + return; + + /* Only need this once. */ + wl_list_remove(&lv->commit_listener.link); + wl_list_init(&lv->commit_listener.link); + + uint32_t ow = 1920, oh = 1080; + if (ls->output) { + ow = ls->output->width > 0 ? (uint32_t)ls->output->width : 1920; + oh = ls->output->height > 0 ? (uint32_t)ls->output->height : 1080; + } + uint32_t fw, fh; + layer_surface_compute_geometry(ls, ow, oh, &fw, &fh); + wlr_layer_surface_v1_configure(ls, fw, fh); + + if (lv->scene_node) { + int sx, sy; + layer_surface_compute_position(ls, ow, oh, fw, fh, &sx, &sy); + wlr_scene_node_set_position(&lv->scene_node->node, sx, sy); + } +} + /* * handle_layer_shell_new_surface — a client created a layer surface. * Assign the output if unset, compute geometry, send configure, and @@ -162,23 +194,6 @@ handle_layer_shell_new_surface(struct wl_listener *listener, void *data) lv->scene_node = wlr_scene_subsurface_tree_create(_lp, ls->surface); } - /* Compute and send initial configure. */ - uint32_t ow = 1920, oh = 1080; - if (ls->output) { - ow = ls->output->width > 0 ? (uint32_t)ls->output->width : 1920; - oh = ls->output->height > 0 ? (uint32_t)ls->output->height : 1080; - } - uint32_t fw, fh; - layer_surface_compute_geometry(ls, ow, oh, &fw, &fh); - wlr_layer_surface_v1_configure(ls, fw, fh); - - /* Position the scene node. */ - if (lv->scene_node) { - int sx, sy; - layer_surface_compute_position(ls, ow, oh, fw, fh, &sx, &sy); - wlr_scene_node_set_position(&lv->scene_node->node, sx, sy); - } - /* Wire lifecycle listeners. */ lv->map_listener.notify = handle_layer_surface_map; lv->unmap_listener.notify = handle_layer_surface_unmap; @@ -187,10 +202,15 @@ handle_layer_shell_new_surface(struct wl_listener *listener, void *data) wl_signal_add(&ls->surface->events.unmap, &lv->unmap_listener); wl_signal_add(&ls->events.destroy, &lv->destroy_listener); + /* Defer configure until the surface's initial commit (wlroots 0.19 + * requires the surface to be initialized before configure). */ + lv->commit_listener.notify = handle_layer_surface_initial_commit; + wl_signal_add(&ls->surface->events.commit, &lv->commit_listener); + wl_list_insert(&wl_state.layer_list, &lv->link); - wwarning("wl_backend: layer surface new layer=%d %ux%u namespace=%s", - ls->current.layer, fw, fh, + wwarning("wl_backend: layer surface new layer=%d namespace=%s", + ls->pending.layer, ls->namespace ? ls->namespace : ""); } diff --git a/src/backend/wayland/wl_types.h b/src/backend/wayland/wl_types.h index f670dd1..657230d 100644 --- a/src/backend/wayland/wl_types.h +++ b/src/backend/wayland/wl_types.h @@ -122,6 +122,7 @@ struct wl_layer_view { struct wl_listener map_listener; struct wl_listener unmap_listener; struct wl_listener destroy_listener; + struct wl_listener commit_listener; struct wl_list link; /* wl_state.layer_list */ };