From 9668aeba1f58fa138426a50ec0557e0328cc3be1 Mon Sep 17 00:00:00 2001 From: Ashley Wulber Date: Tue, 10 Jun 2025 10:36:50 -0400 Subject: [PATCH] fix: nested popup destruction --- .../wayland/event_loop/state.rs | 30 +++++++++++-------- .../wayland/handlers/shell/xdg_popup.rs | 11 +++---- 2 files changed, 24 insertions(+), 17 deletions(-) diff --git a/winit/src/platform_specific/wayland/event_loop/state.rs b/winit/src/platform_specific/wayland/event_loop/state.rs index 5eb12c9f..81001fac 100644 --- a/winit/src/platform_specific/wayland/event_loop/state.rs +++ b/winit/src/platform_specific/wayland/event_loop/state.rs @@ -1133,19 +1133,25 @@ impl SctkState { SctkEvent::PopupEvent { variant: crate::sctk_event::PopupEventVariant::Size(size.0, size.1), toplevel_id: existing.data.parent.wl_surface().clone(), parent_id: existing.data.parent.wl_surface().clone(), id: existing.popup.wl_surface().clone() }); return Ok(()); } - let parent_mismatch = self.popups.iter().rev().find(|p| { - self.id_map.get(&p.popup.wl_surface().id()).map_or(true, |p_id|{ - *p_id != settings.parent && p.data.grab && settings.grab}) - }); - if !self.destroyed.is_empty() || parent_mismatch.is_some() { - if parent_mismatch.is_some() { - for i in 0..self.popups.len() { - let id = self.id_map.get(&self.popups[i].popup.wl_surface().id()); - if let Some(id) = id { - if *id != settings.parent { - _ = self.handle_action(Action::Popup(platform_specific::wayland::popup::Action::Destroy{id: *id})); - } + let mut found = false; + let mut parent_mismatch = false; + for p in &self.popups { + found |= p.data.id == settings.parent; + parent_mismatch |= found && p.data.id != settings.parent; + } + parent_mismatch |= !found; + if !self.destroyed.is_empty() || parent_mismatch { + if parent_mismatch { + let mut found = false; + for p in std::mem::take(&mut self.popups).into_iter().rev() { + let id = p.data.id; + self.popups.insert(0, p); + + found |= id == settings.parent; + if !found { + _ = self.handle_action(Action::Popup(platform_specific::wayland::popup::Action::Destroy{id})); } + } } if self.pending_popup.replace((settings, 0)).is_none() { diff --git a/winit/src/platform_specific/wayland/handlers/shell/xdg_popup.rs b/winit/src/platform_specific/wayland/handlers/shell/xdg_popup.rs index 2e7a58c1..3b8a0dd5 100644 --- a/winit/src/platform_specific/wayland/handlers/shell/xdg_popup.rs +++ b/winit/src/platform_specific/wayland/handlers/shell/xdg_popup.rs @@ -65,13 +65,14 @@ impl PopupHandler for SctkState { break; } state::PopupParent::Popup(popup_to_destroy_first) => { - let popup_to_destroy_first = self - .popups - .iter() - .position(|p| { + let Some(popup_to_destroy_first) = + self.popups.iter().position(|p| { p.popup.wl_surface() == &popup_to_destroy_first }) - .unwrap(); + else { + log::warn!("could not find popup to destroy first."); + return; + }; let popup_to_destroy_first = self.popups.remove(popup_to_destroy_first); to_destroy.push(popup_to_destroy_first);