layer_shika_composition/
session_lock.rs1use crate::IntoValue;
2use crate::calloop::channel;
3use crate::slint_interpreter::Value;
4use crate::system::{SessionLockCommand, ShellCommand};
5use crate::{Error, Result};
6use layer_shika_adapters::WaylandSystemOps;
7use layer_shika_domain::dimensions::ScaleFactor;
8use layer_shika_domain::errors::DomainError;
9use layer_shika_domain::value_objects::lock_config::LockConfig;
10use layer_shika_domain::value_objects::lock_state::LockState;
11use layer_shika_domain::value_objects::margins::Margins;
12use layer_shika_domain::value_objects::output_policy::OutputPolicy;
13use std::cell::RefCell;
14use std::rc::Rc;
15use std::rc::Weak;
16
17pub struct SessionLock {
18 system: Weak<RefCell<dyn WaylandSystemOps>>,
19 component_name: String,
20 config: LockConfig,
21 command_sender: channel::Sender<ShellCommand>,
22}
23
24impl SessionLock {
25 pub(crate) fn new(
26 system: Weak<RefCell<dyn WaylandSystemOps>>,
27 component_name: String,
28 config: LockConfig,
29 command_sender: channel::Sender<ShellCommand>,
30 ) -> Self {
31 Self {
32 system,
33 component_name,
34 config,
35 command_sender,
36 }
37 }
38
39 pub fn activate(&self) -> Result<()> {
40 log::info!("Session lock activation called - queuing SessionLockCommand::Activate");
41
42 self.command_sender
43 .send(ShellCommand::SessionLock(SessionLockCommand::Activate {
44 component_name: self.component_name.clone(),
45 config: self.config.clone(),
46 }))
47 .map_err(|e| {
48 Error::Domain(DomainError::InvalidInput {
49 message: format!("Failed to send session lock command: {e:?}"),
50 })
51 })?;
52
53 log::info!("SessionLockCommand::Activate queued successfully");
54 Ok(())
55 }
56
57 pub fn deactivate(&self) -> Result<()> {
58 log::info!("Session lock deactivation called - queuing SessionLockCommand::Deactivate");
59
60 self.command_sender
61 .send(ShellCommand::SessionLock(SessionLockCommand::Deactivate))
62 .map_err(|e| {
63 Error::Domain(DomainError::InvalidInput {
64 message: format!("Failed to send session lock command: {e:?}"),
65 })
66 })?;
67
68 log::info!("SessionLockCommand::Deactivate queued successfully");
69 Ok(())
70 }
71
72 pub fn on_callback<F, R>(&self, callback_name: &str, handler: F) -> Result<()>
77 where
78 F: Fn() -> R + Clone + 'static,
79 R: IntoValue,
80 {
81 self.on_callback_with_args(callback_name, move |_args| handler().into_value())
82 }
83
84 pub fn on_callback_with_args<F, R>(&self, callback_name: &str, handler: F) -> Result<()>
86 where
87 F: Fn(&[Value]) -> R + Clone + 'static,
88 R: IntoValue,
89 {
90 let system = self.system.upgrade().ok_or(Error::SystemDropped)?;
91 let handler = Rc::new(move |args: &[Value]| handler(args).into_value());
92 system
93 .borrow_mut()
94 .register_session_lock_callback(callback_name, handler);
95 Ok(())
96 }
97
98 #[must_use]
99 pub fn state(&self) -> LockState {
100 let Some(system) = self.system.upgrade() else {
101 return LockState::Inactive;
102 };
103
104 let Ok(borrowed) = system.try_borrow() else {
105 return LockState::Inactive;
106 };
107
108 borrowed.session_lock_state().unwrap_or(LockState::Inactive)
109 }
110
111 #[must_use]
112 pub fn is_locked(&self) -> bool {
113 self.state() == LockState::Locked
114 }
115
116 #[must_use]
117 pub fn component_name(&self) -> &str {
118 &self.component_name
119 }
120}
121
122pub struct SessionLockBuilder {
123 component_name: String,
124 config: LockConfig,
125}
126
127impl SessionLockBuilder {
128 #[must_use]
129 pub fn new(component_name: impl Into<String>) -> Self {
130 Self {
131 component_name: component_name.into(),
132 config: LockConfig::default(),
133 }
134 }
135
136 #[must_use]
137 pub fn scale_factor(mut self, factor: impl TryInto<ScaleFactor, Error = DomainError>) -> Self {
138 self.config.scale_factor = factor.try_into().unwrap_or_default();
139 self
140 }
141
142 #[must_use]
143 pub fn margin(mut self, margin: impl Into<Margins>) -> Self {
144 self.config.margin = margin.into();
145 self
146 }
147
148 #[must_use]
149 pub fn namespace(mut self, namespace: impl Into<String>) -> Self {
150 self.config.namespace = namespace.into();
151 self
152 }
153
154 #[must_use]
155 pub fn output_policy(mut self, policy: OutputPolicy) -> Self {
156 self.config.output_policy = policy;
157 self
158 }
159
160 pub(crate) fn build(
161 self,
162 system: Weak<RefCell<dyn WaylandSystemOps>>,
163 command_sender: channel::Sender<ShellCommand>,
164 ) -> SessionLock {
165 SessionLock::new(system, self.component_name, self.config, command_sender)
166 }
167
168 #[must_use]
169 pub fn component_name(&self) -> &str {
170 &self.component_name
171 }
172}