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.
This commit is contained in:
lkn 2026-06-22 00:29:28 +02:00
parent 143b8906bb
commit c1927f0948
2 changed files with 40 additions and 19 deletions

View File

@ -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 : "");
}

View File

@ -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 */
};