diff --git a/src/app/cosmic.rs b/src/app/cosmic.rs index 62a70342..0b31606d 100644 --- a/src/app/cosmic.rs +++ b/src/app/cosmic.rs @@ -452,6 +452,33 @@ where crate::surface::Action::DestroyLayerShell(id) => { iced_winit::commands::layer_surface::destroy_layer_surface(id) } + #[cfg(wayland_platform)] + crate::surface::Action::Lock(id, output, live_settings, view) => { + let Some(live_settings) = + std::sync::Arc::try_unwrap(live_settings) + .ok() + .and_then(|s| { + s.downcast:: LiveSettings + Send + Sync>>() + .ok() + }) + else { + tracing::error!("Invalid live settings for popup"); + return Task::none(); + }; + + let live_settings = live_settings(); + let live_settings = Box::new(move |_app: &T| live_settings); + + if let Some(view) = view { + self.get_lock(id, output, live_settings, Some(Box::new(move |_| view()))) + } else { + self.get_lock(id, output, live_settings, None) + } + } + #[cfg(wayland_platform)] + crate::surface::Action::DestroyLock(id) => { + iced_winit::commands::session_lock::destroy_lock_surface(id) + } crate::surface::Action::SyncLiveSettings(id) => { if let Some((_, id, live_settings, _)) = self.surface_views.get(&id) { let live_settings = live_settings(&self.app); @@ -1741,6 +1768,34 @@ impl Cosmic { ); Task::batch([live_settings_task, get_layer_surface(settings)]) } + + #[cfg(wayland_platform)] + pub fn get_lock( + &mut self, + id: window::Id, + output: cctk::wayland_client::protocol::wl_output::WlOutput, + live_settings: Box Fn(&'a App) -> LiveSettings + Send + Sync>, + view: Option< + Box Fn(&'a App) -> Element<'a, crate::Action> + Send + Sync>, + >, + ) -> Task> { + use iced_winit::SurfaceIdWrapper; + use iced_winit::platform_specific::commands::session_lock::get_lock_surface; + *self.opened_surfaces.entry(id).or_insert(0) += 1; + let live_settings_task = + self.apply_live_settings(SurfaceIdWrapper::SessionLock(id), &live_settings(&self.app)); + self.surface_views.insert( + id, + ( + None, // TODO parent for layer shell, platform specific option maybe? + SurfaceIdWrapper::SessionLock(id), + live_settings, + view, + ), + ); + + live_settings_task.chain(get_lock_surface(id, output)) + } } #[cfg(wayland_platform)] diff --git a/src/surface/action.rs b/src/surface/action.rs index a4308306..48f01a82 100644 --- a/src/surface/action.rs +++ b/src/surface/action.rs @@ -5,7 +5,7 @@ use super::{Action, View}; #[cfg(feature = "winit")] use crate::Application; -use iced::{Rectangle, window}; +use iced::window; #[cfg(all(wayland_platform, feature = "winit"))] use iced_runtime::platform_specific::wayland::CornerRadius; #[cfg(wayland_platform)] @@ -275,6 +275,26 @@ pub fn simple_layer_shell( ) } +#[cfg(wayland_platform)] +#[must_use] +pub fn lock( + live_settings: impl Fn() -> LiveSettings + Send + Sync + 'static, + id: window::Id, + output: cctk::wayland_client::protocol::wl_output::WlOutput, + view: Option< + impl Fn() -> crate::Element<'static, crate::Action> + Send + Sync + 'static, + >, +) -> Action { + let boxed_live: Box LiveSettings + Send + Sync + 'static> = Box::new(live_settings); + let boxed_live: Box = Box::new(boxed_live); + Action::Lock( + id, + output, + Arc::new(boxed_live), + view.map(|view| Arc::new(view) as View), + ) +} + #[cfg(wayland_platform)] #[must_use] pub fn app_layer_shell( diff --git a/src/surface/mod.rs b/src/surface/mod.rs index 09243da3..75439b88 100644 --- a/src/surface/mod.rs +++ b/src/surface/mod.rs @@ -64,6 +64,18 @@ pub enum Action { /// Destroy a layer shell surface DestroyLayerShell(iced::window::Id), + #[cfg(wayland_platform)] + /// Create a lock shell surface with a view function + Lock( + iced::window::Id, + cctk::wayland_client::protocol::wl_output::WlOutput, + BoxedSetting, + Option>, + ), + + /// Destroy a lock surface + DestroyLock(iced::window::Id), + /// Responsive menu bar update ResponsiveMenuBar { /// Id of the menu bar @@ -111,6 +123,9 @@ impl Action { Action::AppLayerShell(a, b, c) => Action::AppLayerShell(a, b, c), Action::LayerShell(a, b, view) => Action::LayerShell(a, b, map_view(view)), Action::DestroyLayerShell(id) => Action::DestroyLayerShell(id), + #[cfg(wayland_platform)] + Action::Lock(id, output, a, view) => Action::Lock(id, output, a, map_view(view)), + Action::DestroyLock(id) => Action::DestroyLock(id), Action::ResponsiveMenuBar { menu_bar, limits, @@ -217,6 +232,15 @@ impl std::fmt::Debug for Action { Self::DestroyLayerShell(arg0) => { f.debug_tuple("DestroyLayerShell").field(arg0).finish() } + #[cfg(wayland_platform)] + Self::Lock(id, output, arg0, view) => f + .debug_tuple("Lock") + .field(id) + .field(output) + .field(arg0) + .field(&view.as_ref().map(|_| "view")) + .finish(), + Self::DestroyLock(arg0) => f.debug_tuple("DestroyLock").field(arg0).finish(), Self::SyncLiveSettings(arg0) => f.debug_tuple("SyncLiveSettings").field(arg0).finish(), } }