From 30248e1ba3b651b70f9cf525945e084fd88bfae4 Mon Sep 17 00:00:00 2001 From: Consolatis <35009135+Consolatis@users.noreply.github.com> Date: Wed, 18 Jun 2025 17:40:04 +0200 Subject: [PATCH] Destroy xdg_popups when its parent is destroyed Fixes: #2845 --- include/layers.h | 1 + src/layers.c | 23 +++++++++++++++++++++++ src/xdg-popup.c | 6 ++++++ src/xdg.c | 5 +++++ 4 files changed, 35 insertions(+) diff --git a/include/layers.h b/include/layers.h index 6f98d41d..21705fc3 100644 --- a/include/layers.h +++ b/include/layers.h @@ -9,6 +9,7 @@ struct output; struct seat; struct lab_layer_surface { + struct wlr_layer_surface_v1 *layer_surface; struct wlr_scene_layer_surface_v1 *scene_layer_surface; struct server *server; struct output *output; diff --git a/src/layers.c b/src/layers.c index e52ea3c4..c702b4df 100644 --- a/src/layers.c +++ b/src/layers.c @@ -314,6 +314,22 @@ handle_node_destroy(struct wl_listener *listener, void *data) { struct lab_layer_surface *layer = wl_container_of(listener, layer, node_destroy); + + /* + * Important: + * + * We can no longer access layer->scene_layer_surface anymore + * because it has already been free'd by wlroots. + * Set it to NULL to run into a proper crash rather than accessing + * random free'd memory. + */ + layer->scene_layer_surface = NULL; + + struct wlr_xdg_popup *popup, *tmp; + wl_list_for_each_safe(popup, tmp, &layer->layer_surface->popups, link) { + wlr_xdg_popup_destroy(popup); + } + /* * TODO: Determine if this layer is being used by an exclusive client. * If it is, try and find another layer owned by this client to pass @@ -377,6 +393,12 @@ handle_popup_destroy(struct wl_listener *listener, void *data) { struct lab_layer_popup *popup = wl_container_of(listener, popup, destroy); + + struct wlr_xdg_popup *_popup, *tmp; + wl_list_for_each_safe(_popup, tmp, &popup->wlr_popup->base->popups, link) { + wlr_xdg_popup_destroy(_popup); + } + wl_list_remove(&popup->destroy.link); wl_list_remove(&popup->new_popup.link); wl_list_remove(&popup->reposition.link); @@ -565,6 +587,7 @@ handle_new_layer_surface(struct wl_listener *listener, void *data) } struct lab_layer_surface *surface = znew(*surface); + surface->layer_surface = layer_surface; struct output *output = layer_surface->output->data; surface->output = output; diff --git a/src/xdg-popup.c b/src/xdg-popup.c index f7e174ac..d4daadd6 100644 --- a/src/xdg-popup.c +++ b/src/xdg-popup.c @@ -73,6 +73,12 @@ static void handle_destroy(struct wl_listener *listener, void *data) { struct xdg_popup *popup = wl_container_of(listener, popup, destroy); + + struct wlr_xdg_popup *_popup, *tmp; + wl_list_for_each_safe(_popup, tmp, &popup->wlr_popup->base->popups, link) { + wlr_xdg_popup_destroy(_popup); + } + wl_list_remove(&popup->destroy.link); wl_list_remove(&popup->new_popup.link); wl_list_remove(&popup->reposition.link); diff --git a/src/xdg.c b/src/xdg.c index 5ff5ccb0..db64c92c 100644 --- a/src/xdg.c +++ b/src/xdg.c @@ -345,6 +345,11 @@ handle_destroy(struct wl_listener *listener, void *data) struct xdg_toplevel_view *xdg_toplevel_view = xdg_toplevel_view_from_view(view); + struct wlr_xdg_popup *popup, *tmp; + wl_list_for_each_safe(popup, tmp, &xdg_toplevel_view->xdg_surface->popups, link) { + wlr_xdg_popup_destroy(popup); + } + xdg_toplevel_view->xdg_surface->data = NULL; xdg_toplevel_view->xdg_surface = NULL;