diff --git a/core/src/event/wayland/mod.rs b/core/src/event/wayland/mod.rs index 95b7626f84..bf3ddcb1b0 100644 --- a/core/src/event/wayland/mod.rs +++ b/core/src/event/wayland/mod.rs @@ -3,6 +3,7 @@ mod layer; mod output; mod popup; mod seat; +mod session_lock; mod window; use crate::{time::Instant, window::Id}; @@ -15,6 +16,7 @@ pub use layer::*; pub use output::*; pub use popup::*; pub use seat::*; +pub use session_lock::*; pub use window::*; /// wayland events @@ -36,6 +38,8 @@ pub enum Event { DndOffer(DndOfferEvent), /// Selection Offer events SelectionOffer(SelectionOfferEvent), + /// Session lock events + SessionLock(SessionLockEvent), /// Frame events Frame(Instant, WlSurface, Id), } diff --git a/core/src/event/wayland/session_lock.rs b/core/src/event/wayland/session_lock.rs new file mode 100644 index 0000000000..db99566d95 --- /dev/null +++ b/core/src/event/wayland/session_lock.rs @@ -0,0 +1,19 @@ +use crate::window::Id; +use sctk::reexports::client::protocol::wl_surface::WlSurface; + +/// session lock events +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum SessionLockEvent { + /// Compositor has activated lock + Locked, + /// Lock rejected / canceled by compositor + Finished, + /// Session lock protocol not supported + NotSupported, + /// Session lock surface focused + Focused(WlSurface, Id), + /// Session lock surface unfocused + Unfocused(WlSurface, Id), + /// Session unlock has been processed by server + Unlocked, +} diff --git a/examples/sctk_session_lock/Cargo.toml b/examples/sctk_session_lock/Cargo.toml new file mode 100644 index 0000000000..0ceb5bff98 --- /dev/null +++ b/examples/sctk_session_lock/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "sctk_session_lock" +version = "0.1.0" +edition = "2021" + +[dependencies] +sctk = { package = "smithay-client-toolkit", git = "https://github.com/smithay/client-toolkit", rev = "828b1eb" } +iced = { path = "../..", default-features = false, features = ["async-std", "wayland", "debug", "a11y"] } +iced_runtime = { path = "../../runtime" } +env_logger = "0.10" +async-std = "1.0" diff --git a/examples/sctk_session_lock/src/main.rs b/examples/sctk_session_lock/src/main.rs new file mode 100644 index 0000000000..f46baf7201 --- /dev/null +++ b/examples/sctk_session_lock/src/main.rs @@ -0,0 +1,117 @@ +use iced::wayland::session_lock; +use iced::{ + event::wayland::{Event as WaylandEvent, OutputEvent, SessionLockEvent}, + wayland::InitialSurface, + widget::text, + window, Application, Command, Element, Subscription, Theme, +}; +use iced_runtime::window::Id as SurfaceId; + +fn main() { + let mut settings = iced::Settings::default(); + settings.initial_surface = InitialSurface::None; + Locker::run(settings).unwrap(); +} + +#[derive(Debug, Clone, Default)] +struct Locker { + max_surface_id: u128, + exit: bool, +} + +#[derive(Debug, Clone)] +pub enum Message { + WaylandEvent(WaylandEvent), + TimeUp, + Ignore, +} + +impl Locker { + fn next_surface_id(&mut self) -> SurfaceId { + self.max_surface_id += 1; + SurfaceId(self.max_surface_id) + } +} + +impl Application for Locker { + type Executor = iced::executor::Default; + type Message = Message; + type Flags = (); + type Theme = Theme; + + fn new(_flags: ()) -> (Locker, Command) { + ( + Locker { + ..Locker::default() + }, + session_lock::lock(), + ) + } + + fn title(&self) -> String { + String::from("Locker") + } + + fn update(&mut self, message: Self::Message) -> Command { + match message { + Message::WaylandEvent(evt) => match evt { + WaylandEvent::Output(evt, output) => match evt { + OutputEvent::Created(_) => { + return session_lock::get_lock_surface( + self.next_surface_id(), + output, + ); + } + OutputEvent::Removed => {} + _ => {} + }, + WaylandEvent::SessionLock(evt) => match evt { + SessionLockEvent::Locked => { + return iced::Command::perform( + async_std::task::sleep( + std::time::Duration::from_secs(5), + ), + |_| Message::TimeUp, + ); + } + SessionLockEvent::Unlocked => { + // Server has processed unlock, so it's safe to exit + self.exit = true; + } + _ => {} + }, + _ => {} + }, + Message::TimeUp => { + return session_lock::unlock(); + } + Message::Ignore => {} + } + Command::none() + } + + fn should_exit(&self) -> bool { + self.exit + } + + fn view(&self, id: window::Id) -> Element { + text(format!("Lock Surface {:?}", id)).into() + } + + fn subscription(&self) -> Subscription { + iced::subscription::events_with(|evt, _| { + if let iced::Event::PlatformSpecific( + iced::event::PlatformSpecific::Wayland(evt), + ) = evt + { + Some(Message::WaylandEvent(evt)) + } else { + None + } + }) + } + + fn close_requested(&self, _id: window::Id) -> Self::Message { + Message::Ignore + } +} diff --git a/runtime/src/command/platform_specific/wayland/mod.rs b/runtime/src/command/platform_specific/wayland/mod.rs index c5114aca7a..07d12a0a7f 100644 --- a/runtime/src/command/platform_specific/wayland/mod.rs +++ b/runtime/src/command/platform_specific/wayland/mod.rs @@ -10,6 +10,8 @@ pub mod data_device; pub mod layer_surface; /// popup actions pub mod popup; +/// session locks +pub mod session_lock; /// window actions pub mod window; @@ -25,6 +27,8 @@ pub enum Action { DataDevice(data_device::Action), /// activation Activation(activation::Action), + /// session lock + SessionLock(session_lock::Action), } impl Action { @@ -43,6 +47,7 @@ impl Action { Action::Popup(a) => Action::Popup(a.map(f)), Action::DataDevice(a) => Action::DataDevice(a.map(f)), Action::Activation(a) => Action::Activation(a.map(f)), + Action::SessionLock(a) => Action::SessionLock(a.map(f)), } } } @@ -61,6 +66,9 @@ impl Debug for Action { Self::Activation(arg0) => { f.debug_tuple("Activation").field(arg0).finish() } + Self::SessionLock(arg0) => { + f.debug_tuple("SessionLock").field(arg0).finish() + } } } } diff --git a/runtime/src/command/platform_specific/wayland/session_lock.rs b/runtime/src/command/platform_specific/wayland/session_lock.rs new file mode 100644 index 0000000000..fbd0032278 --- /dev/null +++ b/runtime/src/command/platform_specific/wayland/session_lock.rs @@ -0,0 +1,80 @@ +use std::{fmt, marker::PhantomData}; + +use iced_core::window::Id; +use iced_futures::MaybeSend; + +use sctk::reexports::client::protocol::wl_output::WlOutput; + +/// Session lock action +#[derive(Clone)] +pub enum Action { + /// Request a session lock + Lock, + /// Destroy lock + Unlock, + /// Create lock surface for output + LockSurface { + /// unique id for surface + id: Id, + /// output + output: WlOutput, + /// phantom + _phantom: PhantomData, + }, + /// Destroy lock surface + DestroyLockSurface { + /// unique id for surface + id: Id, + }, +} + +impl Action { + /// Maps the output of a window [`Action`] using the provided closure. + pub fn map( + self, + _: impl Fn(T) -> A + 'static + MaybeSend + Sync, + ) -> Action + where + T: 'static, + { + match self { + Action::Lock => Action::Lock, + Action::Unlock => Action::Unlock, + Action::LockSurface { + id, + output, + _phantom, + } => Action::LockSurface { + id, + output, + _phantom: PhantomData, + }, + Action::DestroyLockSurface { id } => { + Action::DestroyLockSurface { id } + } + } + } +} + +impl fmt::Debug for Action { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Action::Lock => write!(f, "Action::SessionLock::Lock"), + Action::Unlock => write!(f, "Action::SessionLock::Unlock"), + Action::LockSurface { + id, + output, + _phantom, + } => write!( + f, + "Action::SessionLock::LockSurface {{ id: {:?}, output: {:?} }}", + id, output + ), + Action::DestroyLockSurface { id } => write!( + f, + "Action::SessionLock::DestroyLockSurface {{ id: {:?} }}", + id + ), + } + } +} diff --git a/sctk/src/application.rs b/sctk/src/application.rs index dd83176177..361f0750ca 100644 --- a/sctk/src/application.rs +++ b/sctk/src/application.rs @@ -93,6 +93,8 @@ pub enum Event { DataDevice(platform_specific::wayland::data_device::Action), /// xdg-activation request from the client Activation(platform_specific::wayland::activation::Action), + /// data session lock requests from the client + SessionLock(platform_specific::wayland::session_lock::Action), /// request sctk to set the cursor of the active pointer SetCursor(Interaction), /// Application Message @@ -770,6 +772,46 @@ where } }) } + SctkEvent::SessionLockSurfaceCreated { surface, native_id } => { + surface_ids.insert(surface.id(), SurfaceIdWrapper::SessionLock(native_id)); + states.insert(native_id, State::new(&application, SurfaceIdWrapper::SessionLock(native_id))); + } + SctkEvent::SessionLockSurfaceConfigure { surface, configure, first } => { + if let Some(id) = surface_ids.get(&surface.id()) { + compositor_surfaces.entry(id.inner()).or_insert_with(|| { + let mut wrapper = SurfaceDisplayWrapper { + comp_surface: None, + backend: backend.clone(), + wl_surface: surface.clone() + }; + let c_surface = compositor.create_surface(&wrapper, configure.new_size.0, configure.new_size.1); + wrapper.comp_surface.replace(c_surface); + wrapper + }); + + let Some(state) = states.get_mut(&id.inner()) else { + continue; + }; + + if first { + let user_interface = build_user_interface( + &application, + user_interface::Cache::default(), + &mut renderer, + state.logical_size(), + &state.title, + &mut debug, + *id, + &mut auto_size_surfaces, + &mut ev_proxy + ); + interfaces.insert(id.inner(), user_interface); + } + + state.set_logical_size(configure.new_size.0 as f64 , configure.new_size.1 as f64); + } + + } _ => {} } } @@ -901,6 +943,9 @@ where SctkEvent::NewOutput { .. } | SctkEvent::UpdateOutput { .. } | SctkEvent::RemovedOutput(_) + | SctkEvent::SessionLocked + | SctkEvent::SessionLockFinished + | SctkEvent::SessionUnlocked ); if remove { let event = sctk_events.remove(i); @@ -1446,6 +1491,7 @@ pub enum SurfaceIdWrapper { Window(SurfaceId), Popup(SurfaceId), Dnd(SurfaceId), + SessionLock(SurfaceId), } impl SurfaceIdWrapper { @@ -1455,6 +1501,7 @@ impl SurfaceIdWrapper { SurfaceIdWrapper::Window(id) => *id, SurfaceIdWrapper::Popup(id) => *id, SurfaceIdWrapper::Dnd(id) => *id, + SurfaceIdWrapper::SessionLock(id) => *id, } } } @@ -1529,6 +1576,7 @@ where ); } SurfaceIdWrapper::Dnd(_) => {} + SurfaceIdWrapper::SessionLock(_) => {} }; } @@ -2086,6 +2134,9 @@ where ) => { proxy.send_event(Event::Activation(activation_action)); } + command::Action::PlatformSpecific(platform_specific::Action::Wayland(platform_specific::wayland::Action::SessionLock(session_lock_action))) => { + proxy.send_event(Event::SessionLock(session_lock_action)); + } _ => {} }; None @@ -2158,5 +2209,14 @@ fn event_is_for_surface( SctkEvent::ScaleFactorChanged { id, .. } => &id.id() == object_id, SctkEvent::DndOffer { surface, .. } => &surface.id() == object_id, SctkEvent::DataSource(_) => true, + SctkEvent::SessionLocked => false, + SctkEvent::SessionLockFinished => false, + SctkEvent::SessionLockSurfaceCreated { surface, .. } => { + &surface.id() == object_id + } + SctkEvent::SessionLockSurfaceConfigure { surface, .. } => { + &surface.id() == object_id + } + SctkEvent::SessionUnlocked => false, } } diff --git a/sctk/src/commands/mod.rs b/sctk/src/commands/mod.rs index 87f53d9b3e..c7866914db 100644 --- a/sctk/src/commands/mod.rs +++ b/sctk/src/commands/mod.rs @@ -4,4 +4,5 @@ pub mod activation; pub mod data_device; pub mod layer_surface; pub mod popup; +pub mod session_lock; pub mod window; diff --git a/sctk/src/commands/session_lock.rs b/sctk/src/commands/session_lock.rs new file mode 100644 index 0000000000..007379efd6 --- /dev/null +++ b/sctk/src/commands/session_lock.rs @@ -0,0 +1,48 @@ +use iced_runtime::command::Command; +use iced_runtime::command::{ + self, + platform_specific::{self, wayland}, +}; +use iced_runtime::window::Id as SurfaceId; +use sctk::reexports::client::protocol::wl_output::WlOutput; + +use std::marker::PhantomData; + +pub fn lock() -> Command { + Command::single(command::Action::PlatformSpecific( + platform_specific::Action::Wayland(wayland::Action::SessionLock( + wayland::session_lock::Action::Lock, + )), + )) +} + +pub fn unlock() -> Command { + Command::single(command::Action::PlatformSpecific( + platform_specific::Action::Wayland(wayland::Action::SessionLock( + wayland::session_lock::Action::Unlock, + )), + )) +} + +pub fn get_lock_surface( + id: SurfaceId, + output: WlOutput, +) -> Command { + Command::single(command::Action::PlatformSpecific( + platform_specific::Action::Wayland(wayland::Action::SessionLock( + wayland::session_lock::Action::LockSurface { + id, + output, + _phantom: PhantomData, + }, + )), + )) +} + +pub fn destroy_lock_surface(id: SurfaceId) -> Command { + Command::single(command::Action::PlatformSpecific( + platform_specific::Action::Wayland(wayland::Action::SessionLock( + wayland::session_lock::Action::DestroyLockSurface { id }, + )), + )) +} diff --git a/sctk/src/event_loop/mod.rs b/sctk/src/event_loop/mod.rs index 79f94e29fb..5b91e4164c 100644 --- a/sctk/src/event_loop/mod.rs +++ b/sctk/src/event_loop/mod.rs @@ -43,6 +43,7 @@ use sctk::{ }, registry::RegistryState, seat::SeatState, + session_lock::SessionLockState, shell::{wlr_layer::LayerShell, xdg::XdgShell, WaylandSurface}, shm::Shm, }; @@ -125,7 +126,8 @@ where calloop::channel::Event::Closed => {} }) .unwrap(); - let wayland_source = WaylandSource::new(connection, event_queue); + let wayland_source = + WaylandSource::new(connection.clone(), event_queue); let wayland_dispatcher = calloop::Dispatcher::new( wayland_source, @@ -166,6 +168,7 @@ where event_loop, wayland_dispatcher, state: SctkState { + connection, registry_state, seat_state: SeatState::new(&globals, &qh), output_state: OutputState::new(&globals, &qh), @@ -181,6 +184,8 @@ where ) .expect("data device manager is not available"), activation_state: ActivationState::bind(&globals, &qh).ok(), + session_lock_state: SessionLockState::new(&globals, &qh), + session_lock: None, queue_handle: qh, loop_handle, @@ -192,6 +197,7 @@ where windows: Vec::new(), layer_surfaces: Vec::new(), popups: Vec::new(), + lock_surfaces: Vec::new(), dnd_source: None, _kbd_focus: None, sctk_events: Vec::new(), @@ -1262,6 +1268,45 @@ where } }, }, + Event::SessionLock(action) => match action { + platform_specific::wayland::session_lock::Action::Lock => { + if self.state.session_lock.is_none() { + // TODO send message on error? When protocol doesn't exist. + self.state.session_lock = self.state.session_lock_state.lock(&self.state.queue_handle).ok(); + } + } + platform_specific::wayland::session_lock::Action::Unlock => { + self.state.session_lock.take(); + // Make sure server processes unlock before client exits + let _ = self.state.connection.roundtrip(); + sticky_exit_callback( + IcedSctkEvent::SctkEvent(SctkEvent::SessionUnlocked), + &self.state, + &mut control_flow, + &mut callback, + ); + } + platform_specific::wayland::session_lock::Action::LockSurface { id, output, _phantom } => { + // TODO how to handle this when there's no lock? + if let Some(surface) = self.state.get_lock_surface(id, &output) { + sticky_exit_callback( + IcedSctkEvent::SctkEvent(SctkEvent::SessionLockSurfaceCreated {surface, native_id: id}), + &self.state, + &mut control_flow, + &mut callback, + ); + } + } + platform_specific::wayland::session_lock::Action::DestroyLockSurface { id } => { + if let Some(i) = + self.state.lock_surfaces.iter().position(|s| { + s.id == id + }) + { + self.state.lock_surfaces.remove(i); + } + } + } } } diff --git a/sctk/src/event_loop/state.rs b/sctk/src/event_loop/state.rs index 09ee473b4d..e2b0e017c0 100644 --- a/sctk/src/event_loop/state.rs +++ b/sctk/src/event_loop/state.rs @@ -48,7 +48,7 @@ use sctk::{ wl_surface::{self, WlSurface}, wl_touch::WlTouch, }, - QueueHandle, + Connection, QueueHandle, }, }, registry::RegistryState, @@ -57,6 +57,10 @@ use sctk::{ pointer::{CursorIcon, ThemedPointer}, SeatState, }, + session_lock::{ + SessionLock, SessionLockState, SessionLockSurface, + SessionLockSurfaceConfigure, + }, shell::{ wlr_layer::{ Anchor, KeyboardInteractivity, Layer, LayerShell, LayerSurface, @@ -207,6 +211,13 @@ impl SctkPopup { } } +#[derive(Debug)] +pub struct SctkLockSurface { + pub(crate) id: window::Id, + pub(crate) session_lock_surface: SessionLockSurface, + pub(crate) last_configure: Option, +} + pub struct Dnd { pub(crate) origin_id: window::Id, pub(crate) origin: WlSurface, @@ -248,6 +259,8 @@ pub struct SctkPopupData { /// Wrapper to carry sctk state. pub struct SctkState { + pub(crate) connection: Connection, + /// the cursor wl_surface pub(crate) _cursor_surface: Option, /// a memory pool @@ -266,6 +279,7 @@ pub struct SctkState { pub(crate) windows: Vec>, pub(crate) layer_surfaces: Vec>, pub(crate) popups: Vec>, + pub(crate) lock_surfaces: Vec, pub(crate) dnd_source: Option>, pub(crate) _kbd_focus: Option, @@ -302,6 +316,8 @@ pub struct SctkState { pub(crate) layer_shell: Option, pub(crate) data_device_manager_state: DataDeviceManagerState, pub(crate) activation_state: Option, + pub(crate) session_lock_state: SessionLockState, + pub(crate) session_lock: Option, pub(crate) token_ctr: u32, } @@ -802,4 +818,27 @@ where }); Ok((id, wl_surface)) } + pub fn get_lock_surface( + &mut self, + id: window::Id, + output: &WlOutput, + ) -> Option { + if let Some(lock) = self.session_lock.as_ref() { + let wl_surface = + self.compositor_state.create_surface(&self.queue_handle); + let session_lock_surface = lock.create_lock_surface( + wl_surface.clone(), + output, + &self.queue_handle, + ); + self.lock_surfaces.push(SctkLockSurface { + id, + session_lock_surface, + last_configure: None, + }); + Some(wl_surface) + } else { + None + } + } } diff --git a/sctk/src/handlers/mod.rs b/sctk/src/handlers/mod.rs index f2720046bd..332d296682 100644 --- a/sctk/src/handlers/mod.rs +++ b/sctk/src/handlers/mod.rs @@ -4,6 +4,7 @@ pub mod compositor; pub mod data_device; pub mod output; pub mod seat; +pub mod session_lock; pub mod shell; pub mod wp_fractional_scaling; pub mod wp_viewporter; diff --git a/sctk/src/handlers/session_lock.rs b/sctk/src/handlers/session_lock.rs new file mode 100644 index 0000000000..16d6322610 --- /dev/null +++ b/sctk/src/handlers/session_lock.rs @@ -0,0 +1,57 @@ +use crate::{handlers::SctkState, sctk_event::SctkEvent}; +use sctk::{ + delegate_session_lock, + reexports::client::{Connection, QueueHandle}, + session_lock::{ + SessionLock, SessionLockHandler, SessionLockSurface, + SessionLockSurfaceConfigure, + }, +}; +use std::fmt::Debug; + +impl SessionLockHandler for SctkState { + fn locked( + &mut self, + _conn: &Connection, + _qh: &QueueHandle, + _session_lock: SessionLock, + ) { + self.sctk_events.push(SctkEvent::SessionLocked); + } + + fn finished( + &mut self, + _conn: &Connection, + _qh: &QueueHandle, + _session_lock: SessionLock, + ) { + self.sctk_events.push(SctkEvent::SessionLockFinished); + } + + fn configure( + &mut self, + _conn: &Connection, + _qh: &QueueHandle, + session_lock_surface: SessionLockSurface, + configure: SessionLockSurfaceConfigure, + _serial: u32, + ) { + let lock_surface = match self.lock_surfaces.iter_mut().find(|s| { + s.session_lock_surface.wl_surface() + == session_lock_surface.wl_surface() + }) { + Some(l) => l, + None => return, + }; + let first = lock_surface.last_configure.is_none(); + lock_surface.last_configure.replace(configure.clone()); + self.sctk_events + .push(SctkEvent::SessionLockSurfaceConfigure { + surface: session_lock_surface.wl_surface().clone(), + configure, + first, + }); + } +} + +delegate_session_lock!(@ SctkState); diff --git a/sctk/src/sctk_event.rs b/sctk/src/sctk_event.rs index d75ada42ff..1062ba6769 100755 --- a/sctk/src/sctk_event.rs +++ b/sctk/src/sctk_event.rs @@ -8,7 +8,7 @@ use crate::{ }; use iced_futures::core::event::{ - wayland::{LayerEvent, PopupEvent}, + wayland::{LayerEvent, PopupEvent, SessionLockEvent}, PlatformSpecific, }; use iced_runtime::{ @@ -34,6 +34,7 @@ use sctk::{ pointer::{PointerEvent, PointerEventKind}, Capability, }, + session_lock::SessionLockSurfaceConfigure, shell::{ wlr_layer::LayerSurfaceConfigure, xdg::{popup::PopupConfigure, window::WindowConfigure}, @@ -189,6 +190,19 @@ pub enum SctkEvent { event: DndOfferEvent, surface: WlSurface, }, + /// session lock events + SessionLocked, + SessionLockFinished, + SessionLockSurfaceCreated { + surface: WlSurface, + native_id: SurfaceId, + }, + SessionLockSurfaceConfigure { + surface: WlSurface, + configure: SessionLockSurfaceConfigure, + first: bool, + }, + SessionUnlocked, } #[derive(Debug, Clone)] @@ -481,6 +495,18 @@ impl SctkEvent { )) } SurfaceIdWrapper::Dnd(_) => None, + SurfaceIdWrapper::SessionLock(_) => { + Some(iced_runtime::core::Event::PlatformSpecific( + PlatformSpecific::Wayland( + wayland::Event::SessionLock( + SessionLockEvent::Unfocused( + surface, + id.inner(), + ), + ), + ), + )) + } }) .into_iter() .chain([iced_runtime::core::Event::PlatformSpecific( @@ -522,6 +548,18 @@ impl SctkEvent { )) } SurfaceIdWrapper::Dnd(_) => None, + SurfaceIdWrapper::SessionLock(_) => { + Some(iced_runtime::core::Event::PlatformSpecific( + PlatformSpecific::Wayland( + wayland::Event::SessionLock( + SessionLockEvent::Focused( + surface, + id.inner(), + ), + ), + ), + )) + } }) .into_iter() .chain([iced_runtime::core::Event::PlatformSpecific( @@ -910,6 +948,35 @@ impl SctkEvent { .collect() } }, + SctkEvent::SessionLocked => { + Some(iced_runtime::core::Event::PlatformSpecific( + PlatformSpecific::Wayland(wayland::Event::SessionLock( + wayland::SessionLockEvent::Locked, + )), + )) + .into_iter() + .collect() + } + SctkEvent::SessionLockFinished => { + Some(iced_runtime::core::Event::PlatformSpecific( + PlatformSpecific::Wayland(wayland::Event::SessionLock( + wayland::SessionLockEvent::Finished, + )), + )) + .into_iter() + .collect() + } + SctkEvent::SessionLockSurfaceCreated { .. } => vec![], + SctkEvent::SessionLockSurfaceConfigure { .. } => vec![], + SctkEvent::SessionUnlocked => { + Some(iced_runtime::core::Event::PlatformSpecific( + PlatformSpecific::Wayland(wayland::Event::SessionLock( + wayland::SessionLockEvent::Unlocked, + )), + )) + .into_iter() + .collect() + } } } }