fix: context-menu

when a popup is created and a focus event is received, we shouldn't close the popups, because it may be a focus event for a popup
This commit is contained in:
Ashley Wulber 2026-02-22 23:32:38 -05:00
parent fb1a7d3640
commit 442ce6ad0c

View file

@ -13,7 +13,7 @@ use derive_setters::Setters;
use iced::touch::Finger; use iced::touch::Finger;
use iced::{Event, Vector, keyboard, window}; use iced::{Event, Vector, keyboard, window};
use iced_core::widget::{Tree, Widget, tree}; use iced_core::widget::{Tree, Widget, tree};
use iced_core::{Length, Point, Size, event, mouse, touch}; use iced_core::{Length, Point, Size, mouse, touch};
use std::collections::HashSet; use std::collections::HashSet;
use std::sync::Arc; use std::sync::Arc;
@ -85,6 +85,7 @@ impl<Message: Clone + 'static> ContextMenu<'_, Message> {
// close existing popups // close existing popups
state.menu_states.clear(); state.menu_states.clear();
state.active_root.clear(); state.active_root.clear();
dbg!("closing existing popups");
shell.publish(self.on_surface_action.as_ref().unwrap()(destroy_popup(id))); shell.publish(self.on_surface_action.as_ref().unwrap()(destroy_popup(id)));
state.view_cursor = view_cursor; state.view_cursor = view_cursor;
( (
@ -336,13 +337,12 @@ impl<Message: 'static + Clone> Widget<Message, crate::Theme, crate::Renderer>
.with_data(|d| !d.open && !d.active_root.is_empty()); .with_data(|d| !d.open && !d.active_root.is_empty());
let open = state.menu_bar_state.inner.with_data_mut(|state| { let open = state.menu_bar_state.inner.with_data_mut(|state| {
if reset { if reset
if let Some(popup_id) = state.popup_id.get(&self.window_id).copied() { && let Some(popup_id) = state.popup_id.get(&self.window_id).copied()
if let Some(handler) = self.on_surface_action.as_ref() { && let Some(handler) = self.on_surface_action.as_ref()
shell.publish((handler)(crate::surface::Action::DestroyPopup(popup_id))); {
state.reset(); shell.publish((handler)(crate::surface::Action::DestroyPopup(popup_id)));
} state.reset();
}
} }
state.open state.open
}); });
@ -356,7 +356,6 @@ impl<Message: 'static + Clone> Widget<Message, crate::Theme, crate::Renderer>
mouse::Button::Right | mouse::Button::Left, mouse::Button::Right | mouse::Button::Left,
)) ))
| Event::Touch(touch::Event::FingerPressed { .. }) | Event::Touch(touch::Event::FingerPressed { .. })
| Event::Window(window::Event::Focused)
if open ) if open )
{ {
state.menu_bar_state.inner.with_data_mut(|state| { state.menu_bar_state.inner.with_data_mut(|state| {
@ -366,15 +365,14 @@ impl<Message: 'static + Clone> Widget<Message, crate::Theme, crate::Renderer>
state.open = false; state.open = false;
#[cfg(all(feature = "wayland", feature = "winit", feature = "surface-message"))] #[cfg(all(feature = "wayland", feature = "winit", feature = "surface-message"))]
if matches!(WINDOWING_SYSTEM.get(), Some(WindowingSystem::Wayland)) { if matches!(WINDOWING_SYSTEM.get(), Some(WindowingSystem::Wayland))
if let Some(id) = state.popup_id.remove(&self.window_id) { && let Some(id) = state.popup_id.remove(&self.window_id)
{ {
let surface_action = self.on_surface_action.as_ref().unwrap(); {
shell let surface_action = self.on_surface_action.as_ref().unwrap();
.publish(surface_action(crate::surface::action::destroy_popup(id))); shell.publish(surface_action(crate::surface::action::destroy_popup(id)));
}
state.view_cursor = cursor;
} }
state.view_cursor = cursor;
} }
}); });
} }
@ -388,7 +386,7 @@ impl<Message: 'static + Clone> Widget<Message, crate::Theme, crate::Renderer>
} }
Event::Touch(touch::Event::FingerLifted { id, .. }) => { Event::Touch(touch::Event::FingerLifted { id, .. }) => {
state.fingers_pressed.remove(&id); state.fingers_pressed.remove(id);
} }
_ => (), _ => (),
@ -397,7 +395,7 @@ impl<Message: 'static + Clone> Widget<Message, crate::Theme, crate::Renderer>
// Present a context menu on a right click event. // Present a context menu on a right click event.
if !was_open if !was_open
&& self.context_menu.is_some() && self.context_menu.is_some()
&& (right_button_released(&event) || (touch_lifted(&event) && fingers_pressed == 2)) && (right_button_released(event) || (touch_lifted(event) && fingers_pressed == 2))
{ {
state.context_cursor = cursor.position().unwrap_or_default(); state.context_cursor = cursor.position().unwrap_or_default();
let state = tree.state.downcast_mut::<LocalState>(); let state = tree.state.downcast_mut::<LocalState>();
@ -412,9 +410,9 @@ impl<Message: 'static + Clone> Widget<Message, crate::Theme, crate::Renderer>
shell.capture_event(); shell.capture_event();
return; return;
} else if !was_open && right_button_released(&event) } else if !was_open && right_button_released(event)
|| (touch_lifted(&event)) || (touch_lifted(event))
|| left_button_released(&event) || left_button_released(event)
{ {
state.menu_bar_state.inner.with_data_mut(|state| { state.menu_bar_state.inner.with_data_mut(|state| {
was_open = true; was_open = true;
@ -427,16 +425,15 @@ impl<Message: 'static + Clone> Widget<Message, crate::Theme, crate::Renderer>
feature = "winit", feature = "winit",
feature = "surface-message" feature = "surface-message"
))] ))]
if matches!(WINDOWING_SYSTEM.get(), Some(WindowingSystem::Wayland)) { if matches!(WINDOWING_SYSTEM.get(), Some(WindowingSystem::Wayland))
if let Some(id) = state.popup_id.remove(&self.window_id) { && let Some(id) = state.popup_id.remove(&self.window_id)
{ {
let surface_action = self.on_surface_action.as_ref().unwrap(); {
shell.publish(surface_action( let surface_action = self.on_surface_action.as_ref().unwrap();
crate::surface::action::destroy_popup(id), shell
)); .publish(surface_action(crate::surface::action::destroy_popup(id)));
}
state.view_cursor = cursor;
} }
state.view_cursor = cursor;
} }
}); });
} }
@ -450,7 +447,7 @@ impl<Message: 'static + Clone> Widget<Message, crate::Theme, crate::Renderer>
clipboard, clipboard,
shell, shell,
viewport, viewport,
) );
} }
fn overlay<'b>( fn overlay<'b>(
@ -458,7 +455,7 @@ impl<Message: 'static + Clone> Widget<Message, crate::Theme, crate::Renderer>
tree: &'b mut Tree, tree: &'b mut Tree,
layout: iced_core::Layout<'_>, layout: iced_core::Layout<'_>,
_renderer: &crate::Renderer, _renderer: &crate::Renderer,
viewport: &iced::Rectangle, _viewport: &iced::Rectangle,
translation: Vector, translation: Vector,
) -> Option<iced_core::overlay::Element<'b, Message, crate::Theme, crate::Renderer>> { ) -> Option<iced_core::overlay::Element<'b, Message, crate::Theme, crate::Renderer>> {
#[cfg(all(feature = "wayland", feature = "winit", feature = "surface-message"))] #[cfg(all(feature = "wayland", feature = "winit", feature = "surface-message"))]