fix segfault when exitting cage with a child still present

This commit is contained in:
Sebastien DUMETZ 2026-03-18 12:01:02 +01:00
parent dcd64ae48b
commit e32200c9c0
2 changed files with 22 additions and 1 deletions

22
view.c
View file

@ -112,17 +112,31 @@ view_position_all(struct cg_server *server)
} }
} }
static void
handle_surface_destroy(struct wl_listener *listener, void *data)
{
struct cg_view *view = wl_container_of(listener, view, surface_destroy);
/* wlroots is about to free scene_tree via the subsurface tree listener
* (registered before us). Null it out so view_unmap() skips the destroy. */
view->scene_tree = NULL;
}
void void
view_unmap(struct cg_view *view) view_unmap(struct cg_view *view)
{ {
wl_list_remove(&view->link); wl_list_remove(&view->link);
/* Always registered in view_map() before any unmap can fire. */
wl_list_remove(&view->surface_destroy.link);
wl_list_remove(&view->request_activate.link); wl_list_remove(&view->request_activate.link);
wl_list_remove(&view->request_close.link); wl_list_remove(&view->request_close.link);
wlr_foreign_toplevel_handle_v1_destroy(view->foreign_toplevel_handle); wlr_foreign_toplevel_handle_v1_destroy(view->foreign_toplevel_handle);
view->foreign_toplevel_handle = NULL; view->foreign_toplevel_handle = NULL;
wlr_scene_node_destroy(&view->scene_tree->node); if (view->scene_tree) {
wlr_scene_node_destroy(&view->scene_tree->node);
view->scene_tree = NULL;
}
view->wlr_surface->data = NULL; view->wlr_surface->data = NULL;
view->wlr_surface = NULL; view->wlr_surface = NULL;
@ -152,6 +166,12 @@ view_map(struct cg_view *view, struct wlr_surface *surface)
goto fail; goto fail;
view->scene_tree->node.data = view; view->scene_tree->node.data = view;
/* Register after wlr_scene_subsurface_tree_create() so our listener fires
* after wlroots' internal one, which frees scene_tree on surface destroy.
* This lets us null scene_tree before view_unmap() tries to use it. */
view->surface_destroy.notify = handle_surface_destroy;
wl_signal_add(&surface->events.destroy, &view->surface_destroy);
view->wlr_surface = surface; view->wlr_surface = surface;
surface->data = view; surface->data = view;

1
view.h
View file

@ -26,6 +26,7 @@ struct cg_view {
struct wl_list link; // server::views struct wl_list link; // server::views
struct wlr_surface *wlr_surface; struct wlr_surface *wlr_surface;
struct wlr_scene_tree *scene_tree; struct wlr_scene_tree *scene_tree;
struct wl_listener surface_destroy; /* nullifies scene_tree when wlroots frees it */
/* The view has a position in layout coordinates. */ /* The view has a position in layout coordinates. */
int lx, ly; int lx, ly;