From f0277eabae761c28684ca969c72145c520832bda Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Mon, 16 Oct 2023 12:28:19 -0700 Subject: [PATCH] Add `ext-session-lock` protocol --- src/backend/render/mod.rs | 38 ++++++- src/input/mod.rs | 30 +++++- src/shell/focus/mod.rs | 143 ++++++++++++++------------- src/shell/focus/target.rs | 79 ++++++++++++++- src/state.rs | 55 ++++++++++- src/wayland/handlers/mod.rs | 1 + src/wayland/handlers/session_lock.rs | 52 ++++++++++ 7 files changed, 325 insertions(+), 73 deletions(-) create mode 100644 src/wayland/handlers/session_lock.rs diff --git a/src/backend/render/mod.rs b/src/backend/render/mod.rs index 76c4eb45..993426b5 100644 --- a/src/backend/render/mod.rs +++ b/src/backend/render/mod.rs @@ -16,7 +16,7 @@ use crate::{ focus::target::WindowGroup, grabs::SeatMoveGrabState, layout::tiling::ANIMATION_DURATION, CosmicMapped, CosmicMappedRenderElement, OverviewMode, Trigger, WorkspaceRenderElement, }, - state::{Common, Fps}, + state::{Common, Fps, SessionLock}, utils::prelude::*, wayland::{ handlers::{ @@ -42,7 +42,7 @@ use smithay::{ buffer_dimensions, damage::{Error as RenderError, OutputDamageTracker, RenderOutputResult}, element::{ - surface::render_elements_from_surface_tree, + surface::{render_elements_from_surface_tree, WaylandSurfaceRenderElement}, utils::{Relocate, RelocateRenderElement}, Element, Id, Kind, RenderElement, }, @@ -487,6 +487,16 @@ where } } + // If session locked, only show session lock surfaces + if let Some(session_lock) = &state.session_lock { + elements.extend( + session_lock_elements(renderer, output, session_lock) + .into_iter() + .map(|x| WorkspaceRenderElement::from(x).into()), + ); + return Ok(elements); + } + let overview = state.shell.overview_mode(); let (resize_mode, resize_indicator) = state.shell.resize_mode(); let resize_indicator = resize_indicator.map(|indicator| (resize_mode, indicator)); @@ -783,6 +793,30 @@ where (layer_elements, popup_elements) } +fn session_lock_elements( + renderer: &mut R, + output: &Output, + session_lock: &SessionLock, +) -> Vec> +where + R: Renderer + ImportAll, + ::TextureId: Clone + 'static, +{ + if let Some(surface) = session_lock.surfaces.get(output) { + let scale = Scale::from(output.current_scale().fractional_scale()); + render_elements_from_surface_tree( + renderer, + surface.wl_surface(), + (0, 0), + scale, + 1.0, + Kind::Unspecified, + ) + } else { + Vec::new() + } +} + pub fn render_output( gpu: Option<&DrmNode>, renderer: &mut R, diff --git a/src/input/mod.rs b/src/input/mod.rs index 11b4ea1a..7db3ff0f 100644 --- a/src/input/mod.rs +++ b/src/input/mod.rs @@ -13,7 +13,7 @@ use crate::{ Direction, FocusResult, MoveResult, OverviewMode, ResizeDirection, ResizeMode, Trigger, Workspace, }, - state::Common, + state::{Common, SessionLock}, utils::prelude::*, wayland::{handlers::screencopy::ScreencopySessions, protocols::screencopy::Session}, }; @@ -565,6 +565,7 @@ impl State { &self.common.shell.override_redirect_windows, overview.0.clone(), workspace, + self.common.session_lock.as_ref(), ) .map(|(target, pos)| (target, pos.as_logical())); @@ -646,6 +647,7 @@ impl State { &self.common.shell.override_redirect_windows, overview.0, workspace, + self.common.session_lock.as_ref(), ) .map(|(target, pos)| (target, pos.as_logical())); @@ -776,6 +778,7 @@ impl State { &self.common.shell.override_redirect_windows, overview.0, workspace, + self.common.session_lock.as_ref(), ) .map(|(target, pos)| (target, pos.as_logical())); @@ -852,7 +855,12 @@ impl State { let workspace = self.common.shell.active_space_mut(&output); let mut under = None; - if let Some(window) = workspace.get_fullscreen() { + if let Some(session_lock) = self.common.session_lock.as_ref() { + under = session_lock + .surfaces + .get(&output) + .map(|lock| lock.clone().into()); + } else if let Some(window) = workspace.get_fullscreen() { let layers = layer_map_for_output(&output); if let Some(layer) = layers.layer_under(WlrLayer::Overlay, relative_pos.as_logical()) @@ -1153,6 +1161,14 @@ impl State { pattern: KeyPattern, direction: Option, ) { + // TODO: Detect if started from login manager or tty, and only allow + // `Terminate` if it will return to login manager. + if self.common.session_lock.is_some() + && !matches!(action, Action::Terminate | Action::Debug) + { + return; + } + match action { Action::Terminate => { self.common.should_stop = true; @@ -1718,10 +1734,20 @@ impl State { override_redirect_windows: &[X11Surface], overview: OverviewMode, workspace: &mut Workspace, + session_lock: Option<&SessionLock>, ) -> Option<(PointerFocusTarget, Point)> { let relative_pos = global_pos.to_local(output); let output_geo = output.geometry(); + if let Some(session_lock) = session_lock { + return session_lock.surfaces.get(output).map(|surface| { + ( + PointerFocusTarget::LockSurface(surface.clone()), + output_geo.loc, + ) + }); + } + if let Some(window) = workspace.get_fullscreen() { let layers = layer_map_for_output(output); if let Some(layer) = layers.layer_under(WlrLayer::Overlay, relative_pos.as_logical()) { diff --git a/src/shell/focus/mod.rs b/src/shell/focus/mod.rs index 653225ab..ba389d41 100644 --- a/src/shell/focus/mod.rs +++ b/src/shell/focus/mod.rs @@ -8,6 +8,7 @@ use indexmap::IndexSet; use smithay::{ desktop::{layer_map_for_output, PopupUngrabStrategy}, input::Seat, + output::Output, utils::{IsAlive, Serial, SERIAL_COUNTER}, wayland::seat::WaylandFocus, }; @@ -217,55 +218,11 @@ impl Common { if let Some(target) = last_known_focus { if target.alive() { - match target { - KeyboardFocusTarget::Element(mapped) => { - let workspace = state.common.shell.active_space(&output); - let focus_stack = workspace.focus_stack.get(&seat); - if focus_stack.last().map(|m| m == &mapped).unwrap_or(false) - && workspace.get_fullscreen().is_none() - { - continue; // Focus is valid - } else { - trace!("Wrong Window, focus fixup"); - } - } - KeyboardFocusTarget::LayerSurface(layer) => { - if layer_map_for_output(&output).layers().any(|l| l == &layer) { - continue; // Focus is valid - } - } - KeyboardFocusTarget::Group(WindowGroup { node, .. }) => { - if state - .common - .shell - .workspaces - .active(&output) - .1 - .tiling_layer - .has_node(&node) - { - continue; // Focus is valid, - } - } - KeyboardFocusTarget::Fullscreen(window) => { - let workspace = state.common.shell.active_space(&output); - let focus_stack = workspace.focus_stack.get(&seat); - - if focus_stack - .last() - .map(|m| m.has_active_window(&window)) - .unwrap_or(false) - && workspace.get_fullscreen().is_some() - { - continue; // Focus is valid - } else { - trace!("Wrong Window, focus fixup"); - } - } - KeyboardFocusTarget::Popup(_) => { - continue; // Focus is valid - } - }; + if focus_target_is_valid(state, &seat, &output, target) { + continue; // Focus is valid + } else { + trace!("Wrong Window, focus fixup"); + } } else { if let KeyboardFocusTarget::Popup(_) = target { if let Some(popup_grab) = seat @@ -319,24 +276,7 @@ impl Common { } // update keyboard focus - let target = state - .common - .shell - .active_space(&output) - .get_fullscreen() - .cloned() - .map(KeyboardFocusTarget::Fullscreen) - .or_else(|| { - state - .common - .shell - .active_space(&output) - .focus_stack - .get(&seat) - .last() - .cloned() - .map(KeyboardFocusTarget::from) - }); + let target = update_focus_target(state, &seat, &output); if let Some(keyboard) = seat.get_keyboard() { debug!("Restoring focus to {:?}", target.as_ref()); keyboard.set_focus(state, target.clone(), SERIAL_COUNTER.next_serial()); @@ -349,3 +289,72 @@ impl Common { state.common.shell.update_active(seats.iter()) } } + +fn focus_target_is_valid( + state: &mut State, + seat: &Seat, + output: &Output, + target: KeyboardFocusTarget, +) -> bool { + if state.common.session_lock.is_some() { + return matches!(target, KeyboardFocusTarget::LockSurface(_)); + } + + match target { + KeyboardFocusTarget::Element(mapped) => { + let workspace = state.common.shell.active_space(&output); + let focus_stack = workspace.focus_stack.get(&seat); + focus_stack.last().map(|m| m == &mapped).unwrap_or(false) + && workspace.get_fullscreen().is_none() + } + KeyboardFocusTarget::LayerSurface(layer) => { + layer_map_for_output(&output).layers().any(|l| l == &layer) + } + KeyboardFocusTarget::Group(WindowGroup { node, .. }) => state + .common + .shell + .workspaces + .active(&output) + .1 + .tiling_layer + .has_node(&node), + KeyboardFocusTarget::Fullscreen(window) => { + let workspace = state.common.shell.active_space(&output); + let focus_stack = workspace.focus_stack.get(&seat); + + focus_stack + .last() + .map(|m| m.has_active_window(&window)) + .unwrap_or(false) + && workspace.get_fullscreen().is_some() + } + KeyboardFocusTarget::Popup(_) => true, + KeyboardFocusTarget::LockSurface(_) => false, + } +} + +fn update_focus_target( + state: &mut State, + seat: &Seat, + output: &Output, +) -> Option { + if let Some(session_lock) = &state.common.session_lock { + session_lock + .surfaces + .get(output) + .cloned() + .map(KeyboardFocusTarget::from) + } else if let Some(surface) = state.common.shell.active_space(&output).get_fullscreen() { + Some(KeyboardFocusTarget::Fullscreen(surface.clone())) + } else { + state + .common + .shell + .active_space(&output) + .focus_stack + .get(&seat) + .last() + .cloned() + .map(KeyboardFocusTarget::from) + } +} diff --git a/src/shell/focus/target.rs b/src/shell/focus/target.rs index 15a69a7a..8078ed16 100644 --- a/src/shell/focus/target.rs +++ b/src/shell/focus/target.rs @@ -21,7 +21,7 @@ use smithay::{ }, reexports::wayland_server::{backend::ObjectId, protocol::wl_surface::WlSurface, Resource}, utils::{IsAlive, Serial}, - wayland::seat::WaylandFocus, + wayland::{seat::WaylandFocus, session_lock::LockSurface}, xwayland::X11Surface, }; @@ -33,6 +33,7 @@ pub enum PointerFocusTarget { Popup(PopupKind), OverrideRedirect(X11Surface), ResizeFork(ResizeForkTarget), + LockSurface(LockSurface), } #[derive(Debug, Clone, PartialEq)] @@ -42,6 +43,7 @@ pub enum KeyboardFocusTarget { Group(WindowGroup), LayerSurface(LayerSurface), Popup(PopupKind), + LockSurface(LockSurface), } // TODO: This should be TryFrom, but PopupGrab needs to be able to convert. Fix this in smithay @@ -52,6 +54,7 @@ impl From for PointerFocusTarget { KeyboardFocusTarget::Fullscreen(elem) => PointerFocusTarget::Fullscreen(elem), KeyboardFocusTarget::LayerSurface(layer) => PointerFocusTarget::LayerSurface(layer), KeyboardFocusTarget::Popup(popup) => PointerFocusTarget::Popup(popup), + KeyboardFocusTarget::LockSurface(lock) => PointerFocusTarget::LockSurface(lock), _ => unreachable!("A window grab cannot start a popup grab"), } } @@ -65,6 +68,7 @@ impl TryFrom for KeyboardFocusTarget { PointerFocusTarget::Fullscreen(surf) => Ok(KeyboardFocusTarget::Fullscreen(surf)), PointerFocusTarget::LayerSurface(layer) => Ok(KeyboardFocusTarget::LayerSurface(layer)), PointerFocusTarget::Popup(popup) => Ok(KeyboardFocusTarget::Popup(popup)), + PointerFocusTarget::LockSurface(lock) => Ok(KeyboardFocusTarget::LockSurface(lock)), _ => Err(()), } } @@ -102,6 +106,7 @@ impl IsAlive for PointerFocusTarget { PointerFocusTarget::Popup(p) => p.alive(), PointerFocusTarget::OverrideRedirect(s) => s.alive(), PointerFocusTarget::ResizeFork(f) => f.alive(), + PointerFocusTarget::LockSurface(l) => l.alive(), } } } @@ -114,6 +119,7 @@ impl IsAlive for KeyboardFocusTarget { KeyboardFocusTarget::Group(g) => g.alive.upgrade().is_some(), KeyboardFocusTarget::LayerSurface(l) => l.alive(), KeyboardFocusTarget::Popup(p) => p.alive(), + KeyboardFocusTarget::LockSurface(l) => l.alive(), } } } @@ -127,6 +133,9 @@ impl PointerTarget for PointerFocusTarget { PointerFocusTarget::Popup(p) => PointerTarget::enter(p.wl_surface(), seat, data, event), PointerFocusTarget::OverrideRedirect(s) => PointerTarget::enter(s, seat, data, event), PointerFocusTarget::ResizeFork(f) => PointerTarget::enter(f, seat, data, event), + PointerFocusTarget::LockSurface(l) => { + PointerTarget::enter(l.wl_surface(), seat, data, event) + } } } fn motion(&self, seat: &Seat, data: &mut State, event: &MotionEvent) { @@ -139,6 +148,9 @@ impl PointerTarget for PointerFocusTarget { } PointerFocusTarget::OverrideRedirect(s) => PointerTarget::motion(s, seat, data, event), PointerFocusTarget::ResizeFork(f) => PointerTarget::motion(f, seat, data, event), + PointerFocusTarget::LockSurface(l) => { + PointerTarget::motion(l.wl_surface(), seat, data, event) + } } } fn relative_motion(&self, seat: &Seat, data: &mut State, event: &RelativeMotionEvent) { @@ -159,6 +171,9 @@ impl PointerTarget for PointerFocusTarget { PointerFocusTarget::ResizeFork(f) => { PointerTarget::relative_motion(f, seat, data, event) } + PointerFocusTarget::LockSurface(l) => { + PointerTarget::relative_motion(l.wl_surface(), seat, data, event) + } } } fn button(&self, seat: &Seat, data: &mut State, event: &ButtonEvent) { @@ -171,6 +186,9 @@ impl PointerTarget for PointerFocusTarget { } PointerFocusTarget::OverrideRedirect(s) => PointerTarget::button(s, seat, data, event), PointerFocusTarget::ResizeFork(f) => PointerTarget::button(f, seat, data, event), + PointerFocusTarget::LockSurface(l) => { + PointerTarget::button(l.wl_surface(), seat, data, event) + } } } fn axis(&self, seat: &Seat, data: &mut State, frame: AxisFrame) { @@ -181,6 +199,9 @@ impl PointerTarget for PointerFocusTarget { PointerFocusTarget::Popup(p) => PointerTarget::axis(p.wl_surface(), seat, data, frame), PointerFocusTarget::OverrideRedirect(s) => PointerTarget::axis(s, seat, data, frame), PointerFocusTarget::ResizeFork(f) => PointerTarget::axis(f, seat, data, frame), + PointerFocusTarget::LockSurface(l) => { + PointerTarget::axis(l.wl_surface(), seat, data, frame) + } } } fn frame(&self, seat: &Seat, data: &mut State) { @@ -191,6 +212,7 @@ impl PointerTarget for PointerFocusTarget { PointerFocusTarget::Popup(p) => PointerTarget::frame(p.wl_surface(), seat, data), PointerFocusTarget::OverrideRedirect(s) => PointerTarget::frame(s, seat, data), PointerFocusTarget::ResizeFork(f) => PointerTarget::frame(f, seat, data), + PointerFocusTarget::LockSurface(l) => PointerTarget::frame(l.wl_surface(), seat, data), } } fn leave(&self, seat: &Seat, data: &mut State, serial: Serial, time: u32) { @@ -207,6 +229,9 @@ impl PointerTarget for PointerFocusTarget { PointerTarget::leave(s, seat, data, serial, time) } PointerFocusTarget::ResizeFork(f) => PointerTarget::leave(f, seat, data, serial, time), + PointerFocusTarget::LockSurface(l) => { + PointerTarget::leave(l.wl_surface(), seat, data, serial, time) + } } } fn gesture_swipe_begin( @@ -234,6 +259,9 @@ impl PointerTarget for PointerFocusTarget { PointerFocusTarget::ResizeFork(f) => { PointerTarget::gesture_swipe_begin(f, seat, data, event) } + PointerFocusTarget::LockSurface(l) => { + PointerTarget::gesture_swipe_begin(l.wl_surface(), seat, data, event) + } } } fn gesture_swipe_update( @@ -261,6 +289,9 @@ impl PointerTarget for PointerFocusTarget { PointerFocusTarget::ResizeFork(f) => { PointerTarget::gesture_swipe_update(f, seat, data, event) } + PointerFocusTarget::LockSurface(l) => { + PointerTarget::gesture_swipe_update(l.wl_surface(), seat, data, event) + } } } fn gesture_swipe_end( @@ -288,6 +319,9 @@ impl PointerTarget for PointerFocusTarget { PointerFocusTarget::ResizeFork(f) => { PointerTarget::gesture_swipe_end(f, seat, data, event) } + PointerFocusTarget::LockSurface(l) => { + PointerTarget::gesture_swipe_end(l.wl_surface(), seat, data, event) + } } } fn gesture_pinch_begin( @@ -315,6 +349,9 @@ impl PointerTarget for PointerFocusTarget { PointerFocusTarget::ResizeFork(f) => { PointerTarget::gesture_pinch_begin(f, seat, data, event) } + PointerFocusTarget::LockSurface(l) => { + PointerTarget::gesture_pinch_begin(l.wl_surface(), seat, data, event) + } } } fn gesture_pinch_update( @@ -342,6 +379,9 @@ impl PointerTarget for PointerFocusTarget { PointerFocusTarget::ResizeFork(f) => { PointerTarget::gesture_pinch_update(f, seat, data, event) } + PointerFocusTarget::LockSurface(l) => { + PointerTarget::gesture_pinch_update(l.wl_surface(), seat, data, event) + } } } fn gesture_pinch_end( @@ -369,6 +409,9 @@ impl PointerTarget for PointerFocusTarget { PointerFocusTarget::ResizeFork(f) => { PointerTarget::gesture_pinch_end(f, seat, data, event) } + PointerFocusTarget::LockSurface(l) => { + PointerTarget::gesture_pinch_end(l.wl_surface(), seat, data, event) + } } } fn gesture_hold_begin( @@ -396,6 +439,9 @@ impl PointerTarget for PointerFocusTarget { PointerFocusTarget::ResizeFork(f) => { PointerTarget::gesture_hold_begin(f, seat, data, event) } + PointerFocusTarget::LockSurface(l) => { + PointerTarget::gesture_hold_begin(l.wl_surface(), seat, data, event) + } } } fn gesture_hold_end(&self, seat: &Seat, data: &mut State, event: &GestureHoldEndEvent) { @@ -416,6 +462,9 @@ impl PointerTarget for PointerFocusTarget { PointerFocusTarget::ResizeFork(f) => { PointerTarget::gesture_hold_end(f, seat, data, event) } + PointerFocusTarget::LockSurface(l) => { + PointerTarget::gesture_hold_end(l.wl_surface(), seat, data, event) + } } } } @@ -440,6 +489,9 @@ impl KeyboardTarget for KeyboardFocusTarget { KeyboardFocusTarget::Popup(p) => { KeyboardTarget::enter(p.wl_surface(), seat, data, keys, serial) } + KeyboardFocusTarget::LockSurface(l) => { + KeyboardTarget::enter(l.wl_surface(), seat, data, keys, serial) + } } } fn leave(&self, seat: &Seat, data: &mut State, serial: Serial) { @@ -451,6 +503,9 @@ impl KeyboardTarget for KeyboardFocusTarget { KeyboardFocusTarget::Popup(p) => { KeyboardTarget::leave(p.wl_surface(), seat, data, serial) } + KeyboardFocusTarget::LockSurface(l) => { + KeyboardTarget::leave(l.wl_surface(), seat, data, serial) + } } } fn key( @@ -476,6 +531,9 @@ impl KeyboardTarget for KeyboardFocusTarget { KeyboardFocusTarget::Popup(p) => { KeyboardTarget::key(p.wl_surface(), seat, data, key, state, serial, time) } + KeyboardFocusTarget::LockSurface(l) => { + KeyboardTarget::key(l.wl_surface(), seat, data, key, state, serial, time) + } } } fn modifiers( @@ -499,6 +557,9 @@ impl KeyboardTarget for KeyboardFocusTarget { KeyboardFocusTarget::Popup(p) => { KeyboardTarget::modifiers(p.wl_surface(), seat, data, modifiers, serial) } + KeyboardFocusTarget::LockSurface(l) => { + KeyboardTarget::modifiers(l.wl_surface(), seat, data, modifiers, serial) + } } } } @@ -511,6 +572,7 @@ impl WaylandFocus for KeyboardFocusTarget { KeyboardFocusTarget::Group(_) => None, KeyboardFocusTarget::LayerSurface(l) => Some(l.wl_surface().clone()), KeyboardFocusTarget::Popup(p) => Some(p.wl_surface().clone()), + KeyboardFocusTarget::LockSurface(l) => Some(l.wl_surface().clone()), } } fn same_client_as(&self, object_id: &ObjectId) -> bool { @@ -520,6 +582,7 @@ impl WaylandFocus for KeyboardFocusTarget { KeyboardFocusTarget::Group(_) => false, KeyboardFocusTarget::LayerSurface(l) => l.wl_surface().id().same_client_as(object_id), KeyboardFocusTarget::Popup(p) => p.wl_surface().id().same_client_as(object_id), + KeyboardFocusTarget::LockSurface(l) => l.wl_surface().id().same_client_as(object_id), } } } @@ -537,6 +600,7 @@ impl WaylandFocus for PointerFocusTarget { PointerFocusTarget::ResizeFork(_) => { return None; } + PointerFocusTarget::LockSurface(l) => l.wl_surface().clone(), }) } fn same_client_as(&self, object_id: &ObjectId) -> bool { @@ -547,6 +611,7 @@ impl WaylandFocus for PointerFocusTarget { PointerFocusTarget::Popup(p) => p.wl_surface().id().same_client_as(object_id), PointerFocusTarget::OverrideRedirect(s) => WaylandFocus::same_client_as(s, object_id), PointerFocusTarget::ResizeFork(_) => false, + PointerFocusTarget::LockSurface(l) => l.wl_surface().id().same_client_as(object_id), } } } @@ -587,6 +652,12 @@ impl From for PointerFocusTarget { } } +impl From for PointerFocusTarget { + fn from(l: LockSurface) -> Self { + PointerFocusTarget::LockSurface(l) + } +} + impl From for KeyboardFocusTarget { fn from(w: CosmicMapped) -> Self { KeyboardFocusTarget::Element(w) @@ -616,3 +687,9 @@ impl From for KeyboardFocusTarget { KeyboardFocusTarget::Popup(p) } } + +impl From for KeyboardFocusTarget { + fn from(l: LockSurface) -> Self { + KeyboardFocusTarget::LockSurface(l) + } +} diff --git a/src/state.rs b/src/state.rs index 4ba974ca..e2cd81ff 100644 --- a/src/state.rs +++ b/src/state.rs @@ -70,6 +70,7 @@ use smithay::{ seat::WaylandFocus, security_context::{SecurityContext, SecurityContextState}, selection::{data_device::DataDeviceState, primary_selection::PrimarySelectionState}, + session_lock::{LockSurface, SessionLockManagerState}, shell::{kde::decoration::KdeDecorationState, xdg::decoration::XdgDecorationState}, shm::ShmState, viewporter::ViewporterState, @@ -79,7 +80,10 @@ use smithay::{ use tracing::error; use std::{cell::RefCell, ffi::OsString, time::Duration}; -use std::{collections::VecDeque, time::Instant}; +use std::{ + collections::{HashMap, VecDeque}, + time::Instant, +}; #[derive(RustEmbed)] #[folder = "resources/i18n"] @@ -154,12 +158,15 @@ pub struct Common { pub primary_selection_state: PrimarySelectionState, pub screencopy_state: ScreencopyState, pub seat_state: SeatState, + pub session_lock_manager_state: SessionLockManagerState, pub shm_state: ShmState, pub wl_drm_state: WlDrmState, pub viewporter_state: ViewporterState, pub kde_decoration_state: KdeDecorationState, pub xdg_decoration_state: XdgDecorationState, + pub session_lock: Option, + // xwayland state pub xwayland_state: Option, } @@ -180,6 +187,11 @@ pub struct SurfaceDmabufFeedback { pub scanout_feedback: DmabufFeedback, } +#[derive(Debug)] +pub struct SessionLock { + pub surfaces: HashMap, +} + impl BackendData { pub fn kms(&mut self) -> &mut KmsState { match self { @@ -309,6 +321,8 @@ impl State { let wl_drm_state = WlDrmState; let kde_decoration_state = KdeDecorationState::new::(&dh, Mode::Client); let xdg_decoration_state = XdgDecorationState::new::(&dh); + let session_lock_manager_state = + SessionLockManagerState::new::(&dh, client_has_security_context); XWaylandKeyboardGrabState::new::(&dh); PointerConstraintsState::new::(&dh); PointerGesturesState::new::(&dh); @@ -350,6 +364,7 @@ impl State { screencopy_state, shm_state, seat_state, + session_lock_manager_state, keyboard_shortcuts_inhibit_state, output_state, output_configuration_state, @@ -360,6 +375,8 @@ impl State { kde_decoration_state, xdg_decoration_state, + session_lock: None, + xwayland_state: None, }, backend: BackendData::Unset, @@ -459,6 +476,42 @@ impl Common { let time = self.clock.now(); let throttle = Some(Duration::from_secs(1)); + if let Some(session_lock) = self.session_lock.as_ref() { + if let Some(lock_surface) = session_lock.surfaces.get(output) { + with_surfaces_surface_tree(lock_surface.wl_surface(), |_surface, states| { + with_fractional_scale(states, |fraction_scale| { + fraction_scale + .set_preferred_scale(output.current_scale().fractional_scale()); + }); + }); + send_frames_surface_tree( + lock_surface.wl_surface(), + output, + time, + Some(Duration::ZERO), + surface_primary_scanout_output, + ); + if let Some(feedback) = + source_node_for_surface(lock_surface.wl_surface(), &self.display_handle) + .and_then(|source| dmabuf_feedback(source)) + { + send_dmabuf_feedback_surface_tree( + &lock_surface.wl_surface(), + output, + surface_primary_scanout_output, + |surface, _| { + select_dmabuf_feedback( + surface, + render_element_states, + &feedback.render_feedback, + &feedback.scanout_feedback, + ) + }, + ) + } + } + } + for seat in self.seats.iter() { if &seat.active_output() == output { let cursor_status = seat diff --git a/src/wayland/handlers/mod.rs b/src/wayland/handlers/mod.rs index 2dafa477..14aa5308 100644 --- a/src/wayland/handlers/mod.rs +++ b/src/wayland/handlers/mod.rs @@ -20,6 +20,7 @@ pub mod screencopy; pub mod seat; pub mod security_context; pub mod selection; +pub mod session_lock; pub mod shm; pub mod toplevel_info; pub mod toplevel_management; diff --git a/src/wayland/handlers/session_lock.rs b/src/wayland/handlers/session_lock.rs new file mode 100644 index 00000000..f390b4bb --- /dev/null +++ b/src/wayland/handlers/session_lock.rs @@ -0,0 +1,52 @@ +// SPDX-License-Identifier: GPL-3.0-only + +use crate::{ + state::{SessionLock, State}, + utils::prelude::*, +}; +use smithay::{ + delegate_session_lock, + output::Output, + reexports::wayland_server::protocol::wl_output::WlOutput, + utils::Size, + wayland::session_lock::{ + LockSurface, SessionLockHandler, SessionLockManagerState, SessionLocker, + }, +}; +use std::collections::HashMap; + +impl SessionLockHandler for State { + fn lock_state(&mut self) -> &mut SessionLockManagerState { + &mut self.common.session_lock_manager_state + } + + fn lock(&mut self, locker: SessionLocker) { + if self.common.session_lock.is_none() { + locker.lock(); + self.common.session_lock = Some(SessionLock { + surfaces: HashMap::new(), + }); + } + } + + fn unlock(&mut self) { + self.common.session_lock = None; + } + + fn new_surface(&mut self, lock_surface: LockSurface, wl_output: WlOutput) { + if let Some(session_lock) = &mut self.common.session_lock { + if let Some(output) = Output::from_resource(&wl_output) { + lock_surface.with_pending_state(|states| { + let size = output.geometry().size; + states.size = Some(Size::from((size.w as u32, size.h as u32))); + }); + lock_surface.send_configure(); + session_lock + .surfaces + .insert(output.clone(), lock_surface.clone()); + } + } + } +} + +delegate_session_lock!(State);