diff --git a/Cargo.lock b/Cargo.lock index a53353a7..c27ed2cb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -21,7 +21,7 @@ checksum = "366ffbaa4442f4684d91e2cd7c5ea7c4ed8add41959a31447066e279e432b618" [[package]] name = "accesskit" version = "0.22.0" -source = "git+https://github.com/wash2/accesskit?tag=cosmic-0.14#f0599eed5f18111228266fe3f28991cc48b5964f" +source = "git+https://github.com/wash2/accesskit?rev=6c20249#6c20249d3b9fd45e7002efad9f6b6171a9257912" dependencies = [ "uuid", ] @@ -29,7 +29,7 @@ dependencies = [ [[package]] name = "accesskit_consumer" version = "0.32.0" -source = "git+https://github.com/wash2/accesskit?tag=cosmic-0.14#f0599eed5f18111228266fe3f28991cc48b5964f" +source = "git+https://github.com/wash2/accesskit?rev=6c20249#6c20249d3b9fd45e7002efad9f6b6171a9257912" dependencies = [ "accesskit", "hashbrown 0.16.1", @@ -38,7 +38,7 @@ dependencies = [ [[package]] name = "accesskit_macos" version = "0.23.0" -source = "git+https://github.com/wash2/accesskit?tag=cosmic-0.14#f0599eed5f18111228266fe3f28991cc48b5964f" +source = "git+https://github.com/wash2/accesskit?rev=6c20249#6c20249d3b9fd45e7002efad9f6b6171a9257912" dependencies = [ "accesskit", "accesskit_consumer", @@ -51,7 +51,7 @@ dependencies = [ [[package]] name = "accesskit_windows" version = "0.30.0" -source = "git+https://github.com/wash2/accesskit?tag=cosmic-0.14#f0599eed5f18111228266fe3f28991cc48b5964f" +source = "git+https://github.com/wash2/accesskit?rev=6c20249#6c20249d3b9fd45e7002efad9f6b6171a9257912" dependencies = [ "accesskit", "accesskit_consumer", @@ -64,7 +64,7 @@ dependencies = [ [[package]] name = "accesskit_winit" version = "0.30.0" -source = "git+https://github.com/wash2/accesskit?tag=cosmic-0.14#f0599eed5f18111228266fe3f28991cc48b5964f" +source = "git+https://github.com/wash2/accesskit?rev=6c20249#6c20249d3b9fd45e7002efad9f6b6171a9257912" dependencies = [ "accesskit", "accesskit_macos", @@ -1021,7 +1021,7 @@ dependencies = [ [[package]] name = "cosmic-settings-config" -version = "0.1.0" +version = "1.9.0" dependencies = [ "cosmic-config", "ron 0.11.0", @@ -1040,7 +1040,7 @@ dependencies = [ [[package]] name = "cosmic-settings-daemon-config" -version = "0.1.0" +version = "1.9.0" dependencies = [ "cosmic-config", "cosmic-theme", @@ -3072,6 +3072,7 @@ dependencies = [ "log", "palette", "phf 0.13.1", + "roxmltree 0.20.0", "rust-embed", "serde", "slotmap", @@ -3135,9 +3136,9 @@ checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" [[package]] name = "libredox" -version = "0.1.23" +version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d8f1ea3f21fd3405dcaf6c9b5c1630af9afc422d9073ea39c5f6d6c772e08ed" +checksum = "61ff90caf6077a803a240f62fdbe88645a890bbca49ef8174c3cb0404362171d" dependencies = [ "bitflags 2.13.2", "libc", diff --git a/src/config/mod.rs b/src/config/mod.rs index 4d2fad9b..f8a51585 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -172,7 +172,7 @@ pub enum ColorFilter { } impl Config { - pub fn load(loop_handle: &LoopHandle<'_, State>) -> Config { + pub fn load(loop_handle: &LoopHandle<'_, State>, kiosk_mode: bool) -> Config { let config = cosmic_config::Config::new("com.system76.CosmicComp", 1).unwrap(); let source = cosmic_config::calloop::ConfigWatchSource::new(&config).unwrap(); loop_handle @@ -248,40 +248,48 @@ impl Config { // Source key bindings from com.system76.CosmicSettings.Shortcuts let settings_context = shortcuts::context().expect("Failed to load shortcuts config"); - let system_actions = shortcuts::system_actions(&settings_context); - let shortcuts = shortcuts::shortcuts(&settings_context); + let mut system_actions = Default::default(); + let mut shortcuts = Default::default(); + // Kiosk mode disables shortcuts + if !kiosk_mode { + system_actions = shortcuts::system_actions(&settings_context); + shortcuts = shortcuts::shortcuts(&settings_context); - // Listen for updates to the keybindings config. - match cosmic_config::calloop::ConfigWatchSource::new(&settings_context) { - Ok(source) => { - if let Err(err) = loop_handle.insert_source(source, |(config, keys), (), state| { - for key in keys { - match key.as_str() { - // Reload the keyboard shortcuts config. - "custom" | "defaults" => { - state.common.config.shortcuts = shortcuts::shortcuts(&config); + // Listen for updates to the keybindings config. + match cosmic_config::calloop::ConfigWatchSource::new(&settings_context) { + Ok(source) => { + if let Err(err) = + loop_handle.insert_source(source, |(config, keys), (), state| { + for key in keys { + match key.as_str() { + // Reload the keyboard shortcuts config. + "custom" | "defaults" => { + state.common.config.shortcuts = + shortcuts::shortcuts(&config); + } + + "system_actions" => { + state.common.config.system_actions = + shortcuts::system_actions(&config); + } + + _ => (), + } } - - "system_actions" => { - state.common.config.system_actions = - shortcuts::system_actions(&config); - } - - _ => (), - } + }) + { + warn!( + ?err, + "Failed to watch com.system76.CosmicSettings.Shortcuts config" + ); } - }) { - warn!( - ?err, - "Failed to watch com.system76.CosmicSettings.Shortcuts config" - ); } - } - Err(err) => warn!( - ?err, - "failed to create config watch source for com.system76.CosmicSettings.Shortcuts" - ), - }; + Err(err) => warn!( + ?err, + "failed to create config watch source for com.system76.CosmicSettings.Shortcuts" + ), + }; + } let window_rules_context = window_rules::context().expect("Failed to load window rules config"); diff --git a/src/input/mod.rs b/src/input/mod.rs index 45586b03..af160ae2 100644 --- a/src/input/mod.rs +++ b/src/input/mod.rs @@ -19,7 +19,7 @@ use crate::{ Stage, render_input_order, target::{KeyboardFocusTarget, PointerFocusTarget}, }, - grabs::{ReleaseMode, ResizeEdge}, + grabs::{MenuGrab, MoveGrab, ReleaseMode, ResizeEdge, ResizeGrab}, layout::{ floating::ResizeGrabMarker, tiling::{NodeDesc, SwapWindowGrab, TilingLayout}, @@ -49,7 +49,7 @@ use smithay::{ PointerAxisEvent, ProximityState, TabletToolButtonEvent, TabletToolEvent, TabletToolProximityEvent, TabletToolTipEvent, TabletToolTipState, TouchEvent, }, - desktop::{PopupKeyboardGrab, WindowSurfaceType, utils::under_from_surface_tree}, + desktop::{WindowSurfaceType, utils::under_from_surface_tree}, input::{ Seat, keyboard::KeyboardHandle, @@ -2096,6 +2096,21 @@ impl State { backend_id, seat, modifiers, handle, serial, keycode, key_state, time, ); + // A modifier-only binding fires on the modifier's release, but its press was already + // forwarded. Forward the release too. + if key_state == KeyState::Released + && matches!(&result, FilterResult::Intercept(Some((_, binding))) if binding.key.is_none()) + { + seat.get_keyboard().unwrap().input_forward( + self, + keycode, + key_state, + serial, + time, + previous_modifiers != *modifiers, + ); + } + if (matches!(result, FilterResult::Forward) && !seat.get_keyboard().unwrap().is_grabbed() && !shortcuts_inhibited @@ -2291,17 +2306,15 @@ impl State { let keyboard = seat.get_keyboard().unwrap(); let pointer = seat.get_pointer().unwrap(); - // We're only interested in filtering keyboard grabs if we initiated them. - // The easiest way to check that is to check the type of the grab. - let keyboard_grabbed = keyboard.with_grab(|_serial, grab| { - grab.is::() || grab.is::>() + // Escape only cancels grabs the compositor started for its own interactions + // For keyboard: SwapWindowGrab + // For pointer: MoveGrab, ResizeGrab, and MenuGrab + let keyboard_grabbed = + keyboard.with_grab(|_serial, grab| grab.is::()) == Some(true); + let pointer_grabbed = pointer.with_grab(|_serial, grab| { + grab.is::() || grab.is::() || grab.is::() }) == Some(true); - // A virtual-keyboard key can arrive while the seat's pointer is grabbed by that - // same on-screen keyboard's own button press (the implicit grab from clicking an OSK - // key). That pointer grab must not capture the injected key, otherwise e.g. - // pressing esc on a virtual keyboard gets swallowed here - let from_vk = matches!(backend_id, InputBackendId::VirtualKeyboard); - let is_grabbed = keyboard_grabbed || (pointer.is_grabbed() && !from_vk); + let is_grabbed = keyboard_grabbed || pointer_grabbed; let current_focus = keyboard.current_focus(); //this should fall back to active output since there may not be a focused output diff --git a/src/lib.rs b/src/lib.rs index aa31a464..98bfa2a3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -289,7 +289,7 @@ Project home page: https://github.com/pop-os/cosmic-comp Options: -h, --help Show this message --no-xwayland Run without Xwayland - -v, --version Show the version of cosmic-comp"# + -V, --version Show the version of cosmic-comp"# ); } diff --git a/src/shell/focus/mod.rs b/src/shell/focus/mod.rs index f631372e..dcfd55de 100644 --- a/src/shell/focus/mod.rs +++ b/src/shell/focus/mod.rs @@ -2,12 +2,18 @@ use crate::{ shell::{CosmicSurface, MinimizedWindow, Shell, Trigger, element::CosmicMapped}, state::{Common, State}, utils::prelude::*, - wayland::handlers::{xdg_shell::PopupGrabData, xwayland_keyboard_grab::XWaylandGrabSeatData}, + wayland::{ + handlers::{xdg_shell::PopupGrabData, xwayland_keyboard_grab::XWaylandGrabSeatData}, + protocols::session_lock_layer::layer_show_on_lock, + }, }; use indexmap::IndexSet; use smithay::{ backend::input::InputTime, - desktop::{PopupUngrabStrategy, layer_map_for_output}, + desktop::{ + LayerSurface, PopupUngrabStrategy, WindowSurfaceType, find_popup_root_surface, + layer_map_for_output, + }, input::{Seat, pointer::MotionEvent}, output::Output, reexports::wayland_server::{Resource, protocol::wl_surface::WlSurface}, @@ -627,19 +633,42 @@ fn focus_target_is_valid( output: &Output, target: KeyboardFocusTarget, ) -> bool { - // If a session lock is active, only lock surfaces can be focused + // If a session lock is active, only lock surfaces and lock layers can be focused if shell.session_lock.is_some() { + if let KeyboardFocusTarget::LayerSurface(layer) = &target { + return layer_show_on_lock(layer.wl_surface()); + } else if let KeyboardFocusTarget::Popup(popup) = &target + && let Ok(root) = find_popup_root_surface(popup) + { + return layer_show_on_lock(&root); + } return matches!(target, KeyboardFocusTarget::LockSurface(_)); } // If an exclusive layer shell surface exists (on any output), only exclusive // shell surfaces can have focus, on the highest layer with exclusive surfaces. + // Popups are judged by their root surface, so an exclusive surface can + // still open grabbing popups (menus, dropdowns, context menus). if let Some(layer) = exclusive_layer_surface_layer(shell) { - return if let KeyboardFocusTarget::LayerSurface(layer_surface) = target { + let is_exclusive_on_layer = |layer_surface: &LayerSurface| { let data = layer_surface.cached_state(); (data.keyboard_interactivity, data.layer) == (KeyboardInteractivity::Exclusive, layer) - } else { - false + }; + return match target { + KeyboardFocusTarget::LayerSurface(layer_surface) => { + is_exclusive_on_layer(&layer_surface) + } + KeyboardFocusTarget::Popup(popup) => find_popup_root_surface(&popup) + .ok() + .and_then(|root| { + shell.outputs().find_map(|o| { + layer_map_for_output(o) + .layer_for_surface(&root, WindowSurfaceType::ALL) + .map(&is_exclusive_on_layer) + }) + }) + .unwrap_or(false), + _ => false, }; } diff --git a/src/shell/focus/order.rs b/src/shell/focus/order.rs index fb904c01..937fa311 100644 --- a/src/shell/focus/order.rs +++ b/src/shell/focus/order.rs @@ -22,7 +22,7 @@ use crate::{ prelude::OutputExt, quirks::{WORKSPACE_OVERVIEW_NAMESPACE, workspace_overview_is_open}, }, - wayland::protocols::workspace::WorkspaceHandle, + wayland::protocols::{session_lock_layer::layer_show_on_lock, workspace::WorkspaceHandle}, }; pub enum Stage<'a> { @@ -77,6 +77,8 @@ fn render_input_order_internal( element_filter: ElementFilter, mut callback: impl FnMut(Stage) -> ControlFlow, ()>, ) -> ControlFlow, ()> { + // NOTE: Keep in sync with other surface iteration functions + if shell .zoom_state .as_ref() @@ -87,7 +89,92 @@ fn render_input_order_internal( // Session Lock if let Some(session_lock) = &shell.session_lock { - return callback(Stage::SessionLock(session_lock.surfaces.get(output))); + for (layer, popup, location) in layer_popups(output, Layer::Overlay, element_filter) { + if !layer_show_on_lock(layer.wl_surface()) { + continue; + } + callback(Stage::LayerPopup { + layer, + popup: &popup, + location, + workspace_idx: current.1, + })?; + } + for (layer, location) in layer_surfaces(output, Layer::Overlay, element_filter) { + if !layer_show_on_lock(layer.wl_surface()) { + continue; + } + callback(Stage::LayerSurface { + layer, + location, + workspace_idx: current.1, + })?; + } + for (layer, popup, location) in layer_popups(output, Layer::Top, element_filter) { + if !layer_show_on_lock(layer.wl_surface()) { + continue; + } + callback(Stage::LayerPopup { + layer, + popup: &popup, + location, + workspace_idx: current.1, + })?; + } + for (layer, location) in layer_surfaces(output, Layer::Top, element_filter) { + if !layer_show_on_lock(layer.wl_surface()) { + continue; + } + callback(Stage::LayerSurface { + layer, + location, + workspace_idx: current.1, + })?; + } + callback(Stage::SessionLock(session_lock.surfaces.get(output)))?; + for (layer, popup, location) in layer_popups(output, Layer::Bottom, element_filter) { + if !layer_show_on_lock(layer.wl_surface()) { + continue; + } + callback(Stage::LayerPopup { + layer, + popup: &popup, + location, + workspace_idx: current.1, + })?; + } + for (layer, popup, location) in layer_popups(output, Layer::Background, element_filter) { + if !layer_show_on_lock(layer.wl_surface()) { + continue; + } + callback(Stage::LayerPopup { + layer, + popup: &popup, + location, + workspace_idx: current.1, + })?; + } + for (layer, location) in layer_surfaces(output, Layer::Bottom, element_filter) { + if !layer_show_on_lock(layer.wl_surface()) { + continue; + } + callback(Stage::LayerSurface { + layer, + location, + workspace_idx: current.1, + })?; + } + for (layer, location) in layer_surfaces(output, Layer::Background, element_filter) { + if !layer_show_on_lock(layer.wl_surface()) { + continue; + } + callback(Stage::LayerSurface { + layer, + location, + workspace_idx: current.1, + })?; + } + return ControlFlow::Continue(()); } // Overlay-level layer shell diff --git a/src/shell/mod.rs b/src/shell/mod.rs index 47d78851..8439b13f 100644 --- a/src/shell/mod.rs +++ b/src/shell/mod.rs @@ -19,7 +19,10 @@ use crate::{ utils, wayland::{ handlers::data_device::{self, get_dnd_icon}, - protocols::workspace::{State as WState, WorkspaceCapabilities}, + protocols::{ + session_lock_layer::layer_show_on_lock, + workspace::{State as WState, WorkspaceCapabilities}, + }, }, }; use cosmic_comp_config::{ @@ -2046,12 +2049,27 @@ impl Shell { } pub fn visible_output_for_surface(&self, surface: &WlSurface) -> Option<&Output> { + // NOTE: Keep in sync with surface iteration in `render_input_order_internal` + if let Some(session_lock) = &self.session_lock { - return session_lock + if let Some((output, _)) = session_lock .surfaces .iter() .find(|(_, v)| v.wl_surface() == surface) - .map(|(k, _)| k); + { + return Some(output); + } + for o in self.outputs() { + let map = layer_map_for_output(o); + if let Some(layer_surface) = map.layer_for_surface(surface, WindowSurfaceType::ALL) + { + if layer_show_on_lock(layer_surface.wl_surface()) { + return Some(o); + } else { + return None; + } + } + } } self.outputs() diff --git a/src/state.rs b/src/state.rs index 28ed8fd4..86f5e23e 100644 --- a/src/state.rs +++ b/src/state.rs @@ -23,6 +23,7 @@ use crate::{ output_configuration::OutputConfigurationState, output_power::OutputPowerState, overlap_notify::OverlapNotifyState, + session_lock_layer::SessionLockLayerState, toplevel_info::ToplevelInfoState, toplevel_management::{ManagementCapabilities, ToplevelManagementState}, workspace::{WorkspaceState, WorkspaceUpdateGuard}, @@ -320,6 +321,7 @@ pub struct Common { pub xwayland_state: Option, pub xwayland_shell_state: XWaylandShellState, pub pointer_focus_state: Option, + pub session_lock_layer_state: SessionLockLayerState, #[cfg(feature = "logind")] pub inhibit_lid_fd: Option, @@ -665,7 +667,7 @@ impl State { .unwrap(); let clock = Clock::new(); - let config = Config::load(&handle); + let config = Config::load(&handle, kiosk_command.is_some()); let compositor_state = CompositorState::new::(dh); let corner_radius_state = CornerRadiusState::new::(dh); let data_device_state = DataDeviceState::new::(dh); @@ -763,6 +765,9 @@ impl State { let dbus_state = DBusState::init(&handle); + let session_lock_layer_state = + SessionLockLayerState::new::(dh, client_not_sandboxed); + State { common: Common { config, @@ -830,6 +835,7 @@ impl State { pointer_focus_state: None, dbus_state, keyboard_layout_state, + session_lock_layer_state, #[cfg(feature = "logind")] inhibit_lid_fd: None, @@ -968,6 +974,8 @@ impl Common { output: &Output, render_element_states: &RenderElementStates, ) { + // NOTE: Keep in sync with surface iteration in `render_input_order_internal` + let shell = self.shell.read(); let processor = |namespace: Option| { move |surface: &WlSurface, states: &SurfaceData| { @@ -1074,6 +1082,8 @@ impl Common { render_element_states: &RenderElementStates, mut dmabuf_feedback: impl FnMut(DrmNode) -> Option, ) { + // NOTE: Keep in sync with surface iteration in `render_input_order_internal` + let shell = self.shell.read(); if let Some(session_lock) = shell.session_lock.as_ref() @@ -1287,6 +1297,8 @@ impl Common { #[profiling::function] pub fn send_frames(&self, output: &Output, sequence: Option) { + // NOTE: Keep in sync with surface iteration in `render_input_order_internal` + let time = self.clock.now(); let should_send = |surface: &WlSurface, states: &SurfaceData| { // Do the standard primary scanout output check. For pointer surfaces it deduplicates diff --git a/src/wayland/handlers/xdg_activation.rs b/src/wayland/handlers/xdg_activation.rs index ad8ce0d0..38ba6219 100644 --- a/src/wayland/handlers/xdg_activation.rs +++ b/src/wayland/handlers/xdg_activation.rs @@ -243,7 +243,7 @@ impl State { { for mapped in current_workspace .mapped() - .filter(|m| m.maximized_state.lock().unwrap().is_some()) + .filter(|m| m.maximized_state.lock().unwrap().is_some() && *m != &element) .cloned() .collect::>() .into_iter() diff --git a/src/wayland/protocols/mod.rs b/src/wayland/protocols/mod.rs index c6c0234a..48aa8337 100644 --- a/src/wayland/protocols/mod.rs +++ b/src/wayland/protocols/mod.rs @@ -8,6 +8,7 @@ pub mod keyboard_layout; pub mod output_configuration; pub mod output_power; pub mod overlap_notify; +pub mod session_lock_layer; pub mod toplevel_info; pub mod toplevel_management; pub mod workspace; diff --git a/src/wayland/protocols/session_lock_layer.rs b/src/wayland/protocols/session_lock_layer.rs new file mode 100644 index 00000000..85edda50 --- /dev/null +++ b/src/wayland/protocols/session_lock_layer.rs @@ -0,0 +1,136 @@ +use cosmic_protocols::session_lock_layer::v1::server::cosmic_session_lock_layer_manager_v1; +use smithay::{ + reexports::wayland_server::{ + Client, DataInit, Dispatch, DisplayHandle, GlobalDispatch, New, backend::GlobalId, + protocol::wl_surface, + }, + wayland::{ + Dispatch2, GlobalDispatch2, + compositor::{Cacheable, with_states}, + shell::wlr_layer::WlrLayerShellHandler, + }, +}; + +struct SessionLockLayerData; + +#[derive(Debug)] +pub struct SessionLockLayerState { + global: GlobalId, +} + +impl SessionLockLayerState { + pub fn new(dh: &DisplayHandle, client_filter: F) -> Self + where + F: for<'a> Fn(&'a Client) -> bool + Clone + Send + Sync + 'static, + D: GlobalDispatch< + cosmic_session_lock_layer_manager_v1::CosmicSessionLockLayerManagerV1, + SessionLockLayerGlobalData, + > + 'static, + { + let global = dh + .create_global::( + 1, + SessionLockLayerGlobalData { + filter: Box::new(client_filter.clone()), + }, + ); + Self { global } + } + + pub fn global_id(&self) -> GlobalId { + self.global.clone() + } +} + +#[doc(hidden)] +pub struct SessionLockLayerGlobalData { + filter: Box Fn(&'a Client) -> bool + Send + Sync>, +} + +impl GlobalDispatch2 + for SessionLockLayerGlobalData +where + D: Dispatch< + cosmic_session_lock_layer_manager_v1::CosmicSessionLockLayerManagerV1, + SessionLockLayerData, + >, +{ + fn bind( + &self, + _state: &mut D, + _handle: &DisplayHandle, + _client: &Client, + resource: New, + data_init: &mut DataInit<'_, D>, + ) { + data_init.init(resource, SessionLockLayerData); + } + + fn can_view(&self, client: &Client) -> bool { + (self.filter)(client) + } +} + +#[derive(Clone, Copy, Default)] +struct SessionLockLayerSurfaceData { + show_on_lock: bool, +} + +impl Cacheable for SessionLockLayerSurfaceData { + fn commit(&mut self, _dh: &DisplayHandle) -> Self { + *self + } + + fn merge_into(self, into: &mut Self, _dh: &DisplayHandle) { + *into = self; + } +} + +pub fn layer_show_on_lock(wl_surface: &wl_surface::WlSurface) -> bool { + with_states(wl_surface, |states| { + if states.cached_state.has::() { + let mut state = states.cached_state.get::(); + state.current().show_on_lock + } else { + false + } + }) +} + +impl Dispatch2 + for SessionLockLayerData +where + D: WlrLayerShellHandler, +{ + fn request( + &self, + state: &mut D, + _: &Client, + _: &cosmic_session_lock_layer_manager_v1::CosmicSessionLockLayerManagerV1, + request: cosmic_session_lock_layer_manager_v1::Request, + _: &DisplayHandle, + _: &mut DataInit<'_, D>, + ) { + let (layer, value) = match request { + cosmic_session_lock_layer_manager_v1::Request::SetShowOnLock { layer } => (layer, true), + cosmic_session_lock_layer_manager_v1::Request::UnsetShowOnLock { layer } => { + (layer, false) + } + cosmic_session_lock_layer_manager_v1::Request::Destroy => { + return; + } + _ => unreachable!(), + }; + + if let Some(layer) = state + .shell_state() + .layer_surfaces() + .find(|surface| surface.shell_surface() == &layer) + { + with_states(layer.wl_surface(), |states| { + let mut state = states.cached_state.get::(); + state.pending().show_on_lock = value; + }); + } + } +}