desktop: check if popup is still alive

when searching for a popup of a surface we
have to test if the popup we found is still alive
or otherwise we might return a destroyed popup.
normally this wouldn't be an issue and the popup
should get cleaned up eventually, but it can race
against cleanup when a surface is re-used. re-using
the surface requires that the surface has no buffer
attached on the first commit, so it can happen that
directly after the popup is destroyed a NULL buffer
is committed. In this case we could end in a situation where we try to send the initial configure to the dead popup and afterwards skip sending the configure to the re-used popup.

fixed deadlock in epiphany (Gnome Web) when
selecting an history entry in the title bar.
This commit is contained in:
Christian Meissl 2024-01-29 22:36:52 +01:00
parent b9f6a478cf
commit 593e9f4fce

View file

@ -159,7 +159,7 @@ impl PopupManager {
pub fn find_popup(&self, surface: &WlSurface) -> Option<PopupKind> {
self.unmapped_popups
.iter()
.find(|p| p.wl_surface() == surface)
.find(|p| p.wl_surface() == surface && p.alive())
.cloned()
.or_else(|| {
self.popup_trees
@ -287,6 +287,7 @@ impl PopupTree {
.lock()
.unwrap()
.iter()
.filter(|node| node.surface.alive())
.flat_map(|n| n.iter_popups_relative_to((0, 0)).map(|(p, l)| (p.clone(), l)))
.collect::<Vec<_>>()
.into_iter()
@ -346,6 +347,7 @@ impl PopupNode {
let relative_to = loc.into() + self.surface.location();
self.children
.iter()
.filter(|node| node.surface.alive())
.flat_map(move |x| {
Box::new(x.iter_popups_relative_to(relative_to))
as Box<dyn Iterator<Item = (&PopupKind, Point<i32, Logical>)>>