refactor(menu): fallback behavior for non wayland windowing system
This commit is contained in:
parent
ba72aed6fb
commit
00ba16fe01
7 changed files with 268 additions and 160 deletions
|
|
@ -120,6 +120,7 @@ libc = { version = "0.2.171", optional = true }
|
||||||
license = { version = "3.6.0", optional = true }
|
license = { version = "3.6.0", optional = true }
|
||||||
mime = { version = "0.3.17", optional = true }
|
mime = { version = "0.3.17", optional = true }
|
||||||
palette = "0.7.6"
|
palette = "0.7.6"
|
||||||
|
raw-window-handle = "0.6"
|
||||||
rfd = { version = "0.15.3", default-features = false, features = [
|
rfd = { version = "0.15.3", default-features = false, features = [
|
||||||
"xdg-portal",
|
"xdg-portal",
|
||||||
], optional = true }
|
], optional = true }
|
||||||
|
|
|
||||||
2
iced
2
iced
|
|
@ -1 +1 @@
|
||||||
Subproject commit fc9d49eb2f830fe394252ff6799d59ad828243bc
|
Subproject commit 2d1511d0cf0296e6f0cfcfcd13f2a1aa334c6915
|
||||||
|
|
@ -36,6 +36,8 @@ pub enum Action {
|
||||||
NavBar(nav_bar::Id),
|
NavBar(nav_bar::Id),
|
||||||
/// Activates a context menu for an item from the nav bar.
|
/// Activates a context menu for an item from the nav bar.
|
||||||
NavBarContext(nav_bar::Id),
|
NavBarContext(nav_bar::Id),
|
||||||
|
/// A new window was opened.
|
||||||
|
Opened(iced::window::Id),
|
||||||
/// Set scaling factor
|
/// Set scaling factor
|
||||||
ScaleFactor(f32),
|
ScaleFactor(f32),
|
||||||
/// Show the window menu
|
/// Show the window menu
|
||||||
|
|
@ -60,6 +62,8 @@ pub enum Action {
|
||||||
ToolkitConfig(CosmicTk),
|
ToolkitConfig(CosmicTk),
|
||||||
/// Window focus lost
|
/// Window focus lost
|
||||||
Unfocus(iced::window::Id),
|
Unfocus(iced::window::Id),
|
||||||
|
/// Windowing system initialized
|
||||||
|
WindowingSystemInitialized,
|
||||||
/// Updates the window maximized state
|
/// Updates the window maximized state
|
||||||
WindowMaximized(iced::window::Id, bool),
|
WindowMaximized(iced::window::Id, bool),
|
||||||
/// Updates the tracked window geometry.
|
/// Updates the tracked window geometry.
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,65 @@ use iced::{Task, window};
|
||||||
use iced_futures::event::listen_with;
|
use iced_futures::event::listen_with;
|
||||||
use palette::color_difference::EuclideanDistance;
|
use palette::color_difference::EuclideanDistance;
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
|
||||||
|
#[non_exhaustive]
|
||||||
|
pub enum WindowingSystem {
|
||||||
|
UiKit,
|
||||||
|
AppKit,
|
||||||
|
Orbital,
|
||||||
|
OhosNdk,
|
||||||
|
Xlib,
|
||||||
|
Xcb,
|
||||||
|
Wayland,
|
||||||
|
Drm,
|
||||||
|
Gbm,
|
||||||
|
Win32,
|
||||||
|
WinRt,
|
||||||
|
Web,
|
||||||
|
WebCanvas,
|
||||||
|
WebOffscreenCanvas,
|
||||||
|
AndroidNdk,
|
||||||
|
Haiku,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) static WINDOWING_SYSTEM: std::sync::OnceLock<WindowingSystem> =
|
||||||
|
std::sync::OnceLock::new();
|
||||||
|
|
||||||
|
pub fn windowing_system() -> Option<WindowingSystem> {
|
||||||
|
WINDOWING_SYSTEM.get().copied()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn init_windowing_system<M>(handle: raw_window_handle::WindowHandle) -> crate::Action<M> {
|
||||||
|
let raw: &raw_window_handle::RawWindowHandle = handle.as_ref();
|
||||||
|
let system = match raw {
|
||||||
|
window::raw_window_handle::RawWindowHandle::UiKit(_) => WindowingSystem::UiKit,
|
||||||
|
window::raw_window_handle::RawWindowHandle::AppKit(_) => WindowingSystem::AppKit,
|
||||||
|
window::raw_window_handle::RawWindowHandle::Orbital(_) => WindowingSystem::Orbital,
|
||||||
|
window::raw_window_handle::RawWindowHandle::OhosNdk(_) => WindowingSystem::OhosNdk,
|
||||||
|
window::raw_window_handle::RawWindowHandle::Xlib(_) => WindowingSystem::Xlib,
|
||||||
|
window::raw_window_handle::RawWindowHandle::Xcb(_) => WindowingSystem::Xcb,
|
||||||
|
window::raw_window_handle::RawWindowHandle::Wayland(_) => WindowingSystem::Wayland,
|
||||||
|
window::raw_window_handle::RawWindowHandle::Web(_) => WindowingSystem::Web,
|
||||||
|
window::raw_window_handle::RawWindowHandle::WebCanvas(_) => WindowingSystem::WebCanvas,
|
||||||
|
window::raw_window_handle::RawWindowHandle::WebOffscreenCanvas(_) => {
|
||||||
|
WindowingSystem::WebOffscreenCanvas
|
||||||
|
}
|
||||||
|
window::raw_window_handle::RawWindowHandle::AndroidNdk(_) => WindowingSystem::AndroidNdk,
|
||||||
|
window::raw_window_handle::RawWindowHandle::Haiku(_) => WindowingSystem::Haiku,
|
||||||
|
window::raw_window_handle::RawWindowHandle::Drm(_) => WindowingSystem::Drm,
|
||||||
|
window::raw_window_handle::RawWindowHandle::Gbm(_) => WindowingSystem::Gbm,
|
||||||
|
window::raw_window_handle::RawWindowHandle::Win32(_) => WindowingSystem::Win32,
|
||||||
|
window::raw_window_handle::RawWindowHandle::WinRt(_) => WindowingSystem::WinRt,
|
||||||
|
_ => {
|
||||||
|
tracing::warn!("Unknown windowing system: {raw:?}");
|
||||||
|
return crate::Action::Cosmic(Action::WindowingSystemInitialized);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
_ = WINDOWING_SYSTEM.set(system);
|
||||||
|
crate::Action::Cosmic(Action::WindowingSystemInitialized)
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct Cosmic<App: Application> {
|
pub struct Cosmic<App: Application> {
|
||||||
pub app: App,
|
pub app: App,
|
||||||
|
|
@ -41,10 +100,17 @@ where
|
||||||
use iced_futures::futures::executor::block_on;
|
use iced_futures::futures::executor::block_on;
|
||||||
core.settings_daemon = block_on(cosmic_config::dbus::settings_daemon_proxy()).ok();
|
core.settings_daemon = block_on(cosmic_config::dbus::settings_daemon_proxy()).ok();
|
||||||
}
|
}
|
||||||
|
let id = core.main_window_id().unwrap_or(window::Id::RESERVED);
|
||||||
|
|
||||||
let (model, command) = T::init(core, flags);
|
let (model, command) = T::init(core, flags);
|
||||||
|
|
||||||
(Self::new(model), command)
|
(
|
||||||
|
Self::new(model),
|
||||||
|
Task::batch(vec![
|
||||||
|
command,
|
||||||
|
iced_runtime::window::run_with_handle(id, init_windowing_system),
|
||||||
|
]),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "multi-window"))]
|
#[cfg(not(feature = "multi-window"))]
|
||||||
|
|
@ -57,6 +123,7 @@ where
|
||||||
self.app.title(id).to_string()
|
self.app.title(id).to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_lines)]
|
||||||
pub fn surface_update(
|
pub fn surface_update(
|
||||||
&mut self,
|
&mut self,
|
||||||
_surface_message: crate::surface::Action,
|
_surface_message: crate::surface::Action,
|
||||||
|
|
@ -255,6 +322,9 @@ where
|
||||||
iced::Event::Window(window::Event::Resized(iced::Size { width, height })) => {
|
iced::Event::Window(window::Event::Resized(iced::Size { width, height })) => {
|
||||||
return Some(Action::WindowResize(id, width, height));
|
return Some(Action::WindowResize(id, width, height));
|
||||||
}
|
}
|
||||||
|
iced::Event::Window(window::Event::Opened { .. }) => {
|
||||||
|
return Some(Action::Opened(id));
|
||||||
|
}
|
||||||
iced::Event::Window(window::Event::Closed) => {
|
iced::Event::Window(window::Event::Closed) => {
|
||||||
return Some(Action::SurfaceClosed(id));
|
return Some(Action::SurfaceClosed(id));
|
||||||
}
|
}
|
||||||
|
|
@ -786,6 +856,9 @@ impl<T: Application> Cosmic<T> {
|
||||||
let core = self.app.core_mut();
|
let core = self.app.core_mut();
|
||||||
core.applet.suggested_bounds = b;
|
core.applet.suggested_bounds = b;
|
||||||
}
|
}
|
||||||
|
Action::Opened(id) => {
|
||||||
|
return iced_runtime::window::run_with_handle(id, init_windowing_system);
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,8 @@
|
||||||
|
|
||||||
//! A context menu is a menu in a graphical user interface that appears upon user interaction, such as a right-click mouse operation.
|
//! A context menu is a menu in a graphical user interface that appears upon user interaction, such as a right-click mouse operation.
|
||||||
|
|
||||||
|
#[cfg(all(feature = "wayland", feature = "winit", feature = "surface-message"))]
|
||||||
|
use crate::app::cosmic::{WINDOWING_SYSTEM, WindowingSystem};
|
||||||
use crate::widget::menu::{
|
use crate::widget::menu::{
|
||||||
self, CloseCondition, Direction, ItemHeight, ItemWidth, MenuBarState, PathHighlight,
|
self, CloseCondition, Direction, ItemHeight, ItemWidth, MenuBarState, PathHighlight,
|
||||||
init_root_menu, menu_roots_diff,
|
init_root_menu, menu_roots_diff,
|
||||||
|
|
@ -361,21 +363,23 @@ impl<Message: 'static + Clone> Widget<Message, crate::Theme, crate::Renderer>
|
||||||
feature = "winit",
|
feature = "winit",
|
||||||
feature = "surface-message"
|
feature = "surface-message"
|
||||||
))]
|
))]
|
||||||
state.menu_bar_state.inner.with_data_mut(|state| {
|
if matches!(WINDOWING_SYSTEM.get(), Some(WindowingSystem::Wayland)) {
|
||||||
if let Some(id) = state.popup_id.remove(&self.window_id) {
|
state.menu_bar_state.inner.with_data_mut(|state| {
|
||||||
state.menu_states.clear();
|
if let Some(id) = state.popup_id.remove(&self.window_id) {
|
||||||
state.active_root.clear();
|
state.menu_states.clear();
|
||||||
state.open = false;
|
state.active_root.clear();
|
||||||
|
state.open = false;
|
||||||
|
|
||||||
{
|
{
|
||||||
let surface_action = self.on_surface_action.as_ref().unwrap();
|
let surface_action = self.on_surface_action.as_ref().unwrap();
|
||||||
shell.publish(surface_action(
|
shell.publish(surface_action(
|
||||||
crate::surface::action::destroy_popup(id),
|
crate::surface::action::destroy_popup(id),
|
||||||
));
|
));
|
||||||
|
}
|
||||||
|
state.view_cursor = cursor;
|
||||||
}
|
}
|
||||||
state.view_cursor = cursor;
|
});
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => (),
|
_ => (),
|
||||||
|
|
@ -392,7 +396,9 @@ impl<Message: 'static + Clone> Widget<Message, crate::Theme, crate::Renderer>
|
||||||
state.view_cursor = cursor;
|
state.view_cursor = cursor;
|
||||||
});
|
});
|
||||||
#[cfg(all(feature = "wayland", feature = "winit", feature = "surface-message"))]
|
#[cfg(all(feature = "wayland", feature = "winit", feature = "surface-message"))]
|
||||||
self.create_popup(layout, cursor, renderer, shell, viewport, state);
|
if matches!(WINDOWING_SYSTEM.get(), Some(WindowingSystem::Wayland)) {
|
||||||
|
self.create_popup(layout, cursor, renderer, shell, viewport, state);
|
||||||
|
}
|
||||||
|
|
||||||
return event::Status::Captured;
|
return event::Status::Captured;
|
||||||
} else if right_button_released(&event)
|
} else if right_button_released(&event)
|
||||||
|
|
@ -400,33 +406,7 @@ impl<Message: 'static + Clone> Widget<Message, crate::Theme, crate::Renderer>
|
||||||
|| left_button_released(&event)
|
|| left_button_released(&event)
|
||||||
{
|
{
|
||||||
#[cfg(all(feature = "wayland", feature = "winit", feature = "surface-message"))]
|
#[cfg(all(feature = "wayland", feature = "winit", feature = "surface-message"))]
|
||||||
state.menu_bar_state.inner.with_data_mut(|state| {
|
if matches!(WINDOWING_SYSTEM.get(), Some(WindowingSystem::Wayland)) {
|
||||||
if let Some(id) = state.popup_id.remove(&self.window_id) {
|
|
||||||
state.menu_states.clear();
|
|
||||||
state.active_root.clear();
|
|
||||||
state.open = false;
|
|
||||||
|
|
||||||
{
|
|
||||||
let surface_action = self.on_surface_action.as_ref().unwrap();
|
|
||||||
|
|
||||||
shell
|
|
||||||
.publish(surface_action(crate::surface::action::destroy_popup(id)));
|
|
||||||
}
|
|
||||||
state.view_cursor = cursor;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else if open {
|
|
||||||
match event {
|
|
||||||
Event::Mouse(mouse::Event::ButtonReleased(
|
|
||||||
mouse::Button::Right | mouse::Button::Left,
|
|
||||||
))
|
|
||||||
| Event::Touch(touch::Event::FingerLifted { .. }) => {
|
|
||||||
#[cfg(all(
|
|
||||||
feature = "wayland",
|
|
||||||
feature = "winit",
|
|
||||||
feature = "surface-message"
|
|
||||||
))]
|
|
||||||
state.menu_bar_state.inner.with_data_mut(|state| {
|
state.menu_bar_state.inner.with_data_mut(|state| {
|
||||||
if let Some(id) = state.popup_id.remove(&self.window_id) {
|
if let Some(id) = state.popup_id.remove(&self.window_id) {
|
||||||
state.menu_states.clear();
|
state.menu_states.clear();
|
||||||
|
|
@ -444,6 +424,37 @@ impl<Message: 'static + Clone> Widget<Message, crate::Theme, crate::Renderer>
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
} else if open {
|
||||||
|
match event {
|
||||||
|
Event::Mouse(mouse::Event::ButtonReleased(
|
||||||
|
mouse::Button::Right | mouse::Button::Left,
|
||||||
|
))
|
||||||
|
| Event::Touch(touch::Event::FingerLifted { .. }) => {
|
||||||
|
#[cfg(all(
|
||||||
|
feature = "wayland",
|
||||||
|
feature = "winit",
|
||||||
|
feature = "surface-message"
|
||||||
|
))]
|
||||||
|
if matches!(WINDOWING_SYSTEM.get(), Some(WindowingSystem::Wayland)) {
|
||||||
|
state.menu_bar_state.inner.with_data_mut(|state| {
|
||||||
|
if let Some(id) = state.popup_id.remove(&self.window_id) {
|
||||||
|
state.menu_states.clear();
|
||||||
|
state.active_root.clear();
|
||||||
|
state.open = false;
|
||||||
|
|
||||||
|
{
|
||||||
|
let surface_action = self.on_surface_action.as_ref().unwrap();
|
||||||
|
|
||||||
|
shell.publish(surface_action(
|
||||||
|
crate::surface::action::destroy_popup(id),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
state.view_cursor = cursor;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -468,7 +479,10 @@ impl<Message: 'static + Clone> Widget<Message, crate::Theme, crate::Renderer>
|
||||||
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"))]
|
||||||
if self.window_id != window::Id::NONE && self.on_surface_action.is_some() {
|
if matches!(WINDOWING_SYSTEM.get(), Some(WindowingSystem::Wayland))
|
||||||
|
&& self.window_id != window::Id::NONE
|
||||||
|
&& self.on_surface_action.is_some()
|
||||||
|
{
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,8 @@ use super::{
|
||||||
},
|
},
|
||||||
menu_tree::MenuTree,
|
menu_tree::MenuTree,
|
||||||
};
|
};
|
||||||
|
#[cfg(all(feature = "wayland", feature = "winit", feature = "surface-message"))]
|
||||||
|
use crate::app::cosmic::{WINDOWING_SYSTEM, WindowingSystem};
|
||||||
use crate::{
|
use crate::{
|
||||||
Renderer,
|
Renderer,
|
||||||
style::menu_bar::StyleSheet,
|
style::menu_bar::StyleSheet,
|
||||||
|
|
@ -629,13 +631,17 @@ where
|
||||||
return event::Status::Ignored;
|
return event::Status::Ignored;
|
||||||
}
|
}
|
||||||
#[cfg(all(feature = "wayland", feature = "winit", feature = "surface-message"))]
|
#[cfg(all(feature = "wayland", feature = "winit", feature = "surface-message"))]
|
||||||
self.create_popup(layout, view_cursor, renderer, shell, viewport, my_state);
|
if matches!(WINDOWING_SYSTEM.get(), Some(WindowingSystem::Wayland)) {
|
||||||
|
self.create_popup(layout, view_cursor, renderer, shell, viewport, my_state);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Mouse(mouse::Event::CursorMoved { .. } | mouse::Event::CursorEntered)
|
Mouse(mouse::Event::CursorMoved { .. } | mouse::Event::CursorEntered)
|
||||||
if open && view_cursor.is_over(layout.bounds()) =>
|
if open && view_cursor.is_over(layout.bounds()) =>
|
||||||
{
|
{
|
||||||
#[cfg(all(feature = "wayland", feature = "winit", feature = "surface-message"))]
|
#[cfg(all(feature = "wayland", feature = "winit", feature = "surface-message"))]
|
||||||
self.create_popup(layout, view_cursor, renderer, shell, viewport, my_state);
|
if matches!(WINDOWING_SYSTEM.get(), Some(WindowingSystem::Wayland)) {
|
||||||
|
self.create_popup(layout, view_cursor, renderer, shell, viewport, my_state);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
@ -710,7 +716,12 @@ where
|
||||||
translation: Vector,
|
translation: Vector,
|
||||||
) -> Option<overlay::Element<'b, Message, crate::Theme, Renderer>> {
|
) -> Option<overlay::Element<'b, Message, crate::Theme, Renderer>> {
|
||||||
#[cfg(all(feature = "wayland", feature = "winit", feature = "surface-message"))]
|
#[cfg(all(feature = "wayland", feature = "winit", feature = "surface-message"))]
|
||||||
return None;
|
if matches!(WINDOWING_SYSTEM.get(), Some(WindowingSystem::Wayland))
|
||||||
|
&& self.on_surface_action.is_some()
|
||||||
|
&& self.window_id != window::Id::NONE
|
||||||
|
{
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
let state = tree.state.downcast_ref::<MenuBarState>();
|
let state = tree.state.downcast_ref::<MenuBarState>();
|
||||||
if state.inner.with_data(|state| !state.open) {
|
if state.inner.with_data(|state| !state.open) {
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,8 @@
|
||||||
use std::{borrow::Cow, sync::Arc};
|
use std::{borrow::Cow, sync::Arc};
|
||||||
|
|
||||||
use super::{menu_bar::MenuBarState, menu_tree::MenuTree};
|
use super::{menu_bar::MenuBarState, menu_tree::MenuTree};
|
||||||
|
#[cfg(all(feature = "wayland", feature = "winit", feature = "surface-message"))]
|
||||||
|
use crate::app::cosmic::{WINDOWING_SYSTEM, WindowingSystem};
|
||||||
use crate::style::menu_bar::StyleSheet;
|
use crate::style::menu_bar::StyleSheet;
|
||||||
|
|
||||||
use iced::window;
|
use iced::window;
|
||||||
|
|
@ -665,21 +667,24 @@ impl<'b, Message: Clone + 'static> Menu<'b, Message> {
|
||||||
feature = "winit",
|
feature = "winit",
|
||||||
feature = "surface-message"
|
feature = "surface-message"
|
||||||
))]
|
))]
|
||||||
if let Some(handler) = self.on_surface_action.as_ref() {
|
if matches!(WINDOWING_SYSTEM.get(), Some(WindowingSystem::Wayland)) {
|
||||||
let mut root = self.window_id;
|
if let Some(handler) = self.on_surface_action.as_ref() {
|
||||||
let mut depth = self.depth;
|
let mut root = self.window_id;
|
||||||
while let Some(parent) =
|
let mut depth = self.depth;
|
||||||
state.popup_id.iter().find(|(_, v)| **v == root)
|
while let Some(parent) =
|
||||||
{
|
state.popup_id.iter().find(|(_, v)| **v == root)
|
||||||
// parent of root popup is the window, so we stop.
|
{
|
||||||
if depth == 0 {
|
// parent of root popup is the window, so we stop.
|
||||||
break;
|
if depth == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
root = *parent.0;
|
||||||
|
depth = depth.saturating_sub(1);
|
||||||
}
|
}
|
||||||
root = *parent.0;
|
shell.publish((handler)(crate::surface::Action::DestroyPopup(
|
||||||
depth = depth.saturating_sub(1);
|
root,
|
||||||
|
)));
|
||||||
}
|
}
|
||||||
shell
|
|
||||||
.publish((handler)(crate::surface::Action::DestroyPopup(root)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
state.reset();
|
state.reset();
|
||||||
|
|
@ -922,72 +927,73 @@ impl<Message: std::clone::Clone + 'static> Widget<Message, crate::Theme, crate::
|
||||||
let (new_root, status) = self.on_event(event, layout, cursor, renderer, clipboard, shell);
|
let (new_root, status) = self.on_event(event, layout, cursor, renderer, clipboard, shell);
|
||||||
|
|
||||||
#[cfg(all(feature = "wayland", feature = "winit", feature = "surface-message"))]
|
#[cfg(all(feature = "wayland", feature = "winit", feature = "surface-message"))]
|
||||||
if let Some((new_root, new_ms)) = new_root {
|
if matches!(WINDOWING_SYSTEM.get(), Some(WindowingSystem::Wayland)) {
|
||||||
use iced_runtime::platform_specific::wayland::popup::{
|
if let Some((new_root, new_ms)) = new_root {
|
||||||
SctkPopupSettings, SctkPositioner,
|
use iced_runtime::platform_specific::wayland::popup::{
|
||||||
};
|
SctkPopupSettings, SctkPositioner,
|
||||||
let overlay_offset = Point::ORIGIN - viewport.position();
|
|
||||||
|
|
||||||
let overlay_cursor = cursor.position().unwrap_or_default() - overlay_offset;
|
|
||||||
|
|
||||||
let Some((mut menu, popup_id)) = self.tree.inner.with_data_mut(|state| {
|
|
||||||
let popup_id = *state
|
|
||||||
.popup_id
|
|
||||||
.entry(self.window_id)
|
|
||||||
.or_insert_with(window::Id::unique);
|
|
||||||
let active_roots = state
|
|
||||||
.active_root
|
|
||||||
.get(self.depth)
|
|
||||||
.cloned()
|
|
||||||
.unwrap_or_default();
|
|
||||||
|
|
||||||
let root_bounds_list = layout
|
|
||||||
.children()
|
|
||||||
.next()
|
|
||||||
.unwrap()
|
|
||||||
.children()
|
|
||||||
.map(|lo| lo.bounds())
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
let mut popup_menu = Menu {
|
|
||||||
tree: self.tree.clone(),
|
|
||||||
menu_roots: Cow::Owned(Cow::into_owned(self.menu_roots.clone())),
|
|
||||||
bounds_expand: self.bounds_expand,
|
|
||||||
menu_overlays_parent: false,
|
|
||||||
close_condition: self.close_condition,
|
|
||||||
item_width: self.item_width,
|
|
||||||
item_height: self.item_height,
|
|
||||||
bar_bounds: layout.bounds(),
|
|
||||||
main_offset: self.main_offset,
|
|
||||||
cross_offset: self.cross_offset,
|
|
||||||
root_bounds_list,
|
|
||||||
path_highlight: self.path_highlight,
|
|
||||||
style: Cow::Owned(Cow::into_owned(self.style.clone())),
|
|
||||||
position: Point::new(0., 0.),
|
|
||||||
is_overlay: false,
|
|
||||||
window_id: popup_id,
|
|
||||||
depth: self.depth + 1,
|
|
||||||
on_surface_action: self.on_surface_action.clone(),
|
|
||||||
};
|
};
|
||||||
|
let overlay_offset = Point::ORIGIN - viewport.position();
|
||||||
|
|
||||||
state.active_root.push(new_root);
|
let overlay_cursor = cursor.position().unwrap_or_default() - overlay_offset;
|
||||||
|
|
||||||
Some((popup_menu, popup_id))
|
let Some((mut menu, popup_id)) = self.tree.inner.with_data_mut(|state| {
|
||||||
}) else {
|
let popup_id = *state
|
||||||
return status;
|
.popup_id
|
||||||
};
|
.entry(self.window_id)
|
||||||
// XXX we push a new active root manually instead
|
.or_insert_with(window::Id::unique);
|
||||||
init_root_popup_menu(
|
let active_roots = state
|
||||||
&mut menu,
|
.active_root
|
||||||
renderer,
|
.get(self.depth)
|
||||||
shell,
|
.cloned()
|
||||||
cursor.position().unwrap(),
|
.unwrap_or_default();
|
||||||
layout.bounds().size(),
|
|
||||||
Vector::new(0., 0.),
|
let root_bounds_list = layout
|
||||||
layout.bounds(),
|
.children()
|
||||||
self.main_offset as f32,
|
.next()
|
||||||
);
|
.unwrap()
|
||||||
let (anchor_rect, gravity) = self.tree.inner.with_data_mut(|state| {
|
.children()
|
||||||
|
.map(|lo| lo.bounds())
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let mut popup_menu = Menu {
|
||||||
|
tree: self.tree.clone(),
|
||||||
|
menu_roots: Cow::Owned(Cow::into_owned(self.menu_roots.clone())),
|
||||||
|
bounds_expand: self.bounds_expand,
|
||||||
|
menu_overlays_parent: false,
|
||||||
|
close_condition: self.close_condition,
|
||||||
|
item_width: self.item_width,
|
||||||
|
item_height: self.item_height,
|
||||||
|
bar_bounds: layout.bounds(),
|
||||||
|
main_offset: self.main_offset,
|
||||||
|
cross_offset: self.cross_offset,
|
||||||
|
root_bounds_list,
|
||||||
|
path_highlight: self.path_highlight,
|
||||||
|
style: Cow::Owned(Cow::into_owned(self.style.clone())),
|
||||||
|
position: Point::new(0., 0.),
|
||||||
|
is_overlay: false,
|
||||||
|
window_id: popup_id,
|
||||||
|
depth: self.depth + 1,
|
||||||
|
on_surface_action: self.on_surface_action.clone(),
|
||||||
|
};
|
||||||
|
|
||||||
|
state.active_root.push(new_root);
|
||||||
|
|
||||||
|
Some((popup_menu, popup_id))
|
||||||
|
}) else {
|
||||||
|
return status;
|
||||||
|
};
|
||||||
|
// XXX we push a new active root manually instead
|
||||||
|
init_root_popup_menu(
|
||||||
|
&mut menu,
|
||||||
|
renderer,
|
||||||
|
shell,
|
||||||
|
cursor.position().unwrap(),
|
||||||
|
layout.bounds().size(),
|
||||||
|
Vector::new(0., 0.),
|
||||||
|
layout.bounds(),
|
||||||
|
self.main_offset as f32,
|
||||||
|
);
|
||||||
|
let (anchor_rect, gravity) = self.tree.inner.with_data_mut(|state| {
|
||||||
(state
|
(state
|
||||||
.menu_states
|
.menu_states
|
||||||
.get(self.depth + 1)
|
.get(self.depth + 1)
|
||||||
|
|
@ -1016,15 +1022,15 @@ impl<Message: std::clone::Clone + 'static> Widget<Message, crate::Theme, crate::
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
let menu_node = Widget::layout(
|
let menu_node = Widget::layout(
|
||||||
&menu,
|
&menu,
|
||||||
&mut Tree::empty(),
|
&mut Tree::empty(),
|
||||||
renderer,
|
renderer,
|
||||||
&Limits::NONE.min_width(1.).min_height(1.),
|
&Limits::NONE.min_width(1.).min_height(1.),
|
||||||
);
|
);
|
||||||
|
|
||||||
let popup_size = menu_node.size();
|
let popup_size = menu_node.size();
|
||||||
let positioner = SctkPositioner {
|
let positioner = SctkPositioner {
|
||||||
size: Some((
|
size: Some((
|
||||||
popup_size.width.ceil() as u32 + 2,
|
popup_size.width.ceil() as u32 + 2,
|
||||||
popup_size.height.ceil() as u32 + 2,
|
popup_size.height.ceil() as u32 + 2,
|
||||||
|
|
@ -1036,28 +1042,29 @@ impl<Message: std::clone::Clone + 'static> Widget<Message, crate::Theme, crate::
|
||||||
reactive: true,
|
reactive: true,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
let parent = self.window_id;
|
let parent = self.window_id;
|
||||||
shell.publish((self.on_surface_action.as_ref().unwrap())(
|
shell.publish((self.on_surface_action.as_ref().unwrap())(
|
||||||
crate::surface::action::simple_popup(
|
crate::surface::action::simple_popup(
|
||||||
move || SctkPopupSettings {
|
move || SctkPopupSettings {
|
||||||
parent,
|
parent,
|
||||||
id: popup_id,
|
id: popup_id,
|
||||||
positioner: positioner.clone(),
|
positioner: positioner.clone(),
|
||||||
parent_size: None,
|
parent_size: None,
|
||||||
grab: true,
|
grab: true,
|
||||||
close_with_children: false,
|
close_with_children: false,
|
||||||
input_zone: None,
|
input_zone: None,
|
||||||
},
|
},
|
||||||
Some(move || {
|
Some(move || {
|
||||||
crate::Element::from(
|
crate::Element::from(
|
||||||
crate::widget::container(menu.clone()).center(Length::Fill),
|
crate::widget::container(menu.clone()).center(Length::Fill),
|
||||||
)
|
)
|
||||||
.map(crate::action::app)
|
.map(crate::action::app)
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
));
|
));
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
status
|
status
|
||||||
}
|
}
|
||||||
|
|
@ -1460,14 +1467,12 @@ where
|
||||||
.is_some_and(|i| *i != new_index && !active_menu[*i].children.is_empty());
|
.is_some_and(|i| *i != new_index && !active_menu[*i].children.is_empty());
|
||||||
|
|
||||||
#[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)) && remove {
|
||||||
if remove {
|
if let Some(id) = state.popup_id.remove(&menu.window_id) {
|
||||||
if let Some(id) = state.popup_id.remove(&menu.window_id) {
|
state.active_root.truncate(menu.depth + 1);
|
||||||
state.active_root.truncate(menu.depth + 1);
|
_shell.publish((menu.on_surface_action.as_ref().unwrap())({
|
||||||
_shell.publish((menu.on_surface_action.as_ref().unwrap())({
|
crate::surface::action::destroy_popup(id)
|
||||||
crate::surface::action::destroy_popup(id)
|
}));
|
||||||
}));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let item = &active_menu[new_index];
|
let item = &active_menu[new_index];
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue