Removed control+c behaviour and updated keyboard handler and pam auth
This commit is contained in:
Generated
+349
-233
File diff suppressed because it is too large
Load Diff
+6
-7
@@ -4,21 +4,20 @@ version = "0.1.0"
|
|||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
smithay-client-toolkit = "0.18"
|
smithay-client-toolkit = { version = "0.19", features = ["calloop"] }
|
||||||
wayland-client = "0.31"
|
wayland-client = "0.31"
|
||||||
wayland-protocols = { version = "0.32", features = ["client", "unstable"] }
|
wayland-protocols = { version = "0.32", features = ["client", "unstable"] }
|
||||||
cairo-rs = { version = "0.22", features = ["png", "xcb"] }
|
cairo-rs = { version = "0.20", features = ["png"] }
|
||||||
image = "0.25"
|
image = "0.25"
|
||||||
fastblur = "0.1"
|
fastblur = "0.1"
|
||||||
xkbcommon = "0.9"
|
xkbcommon = "0.7"
|
||||||
pam = "0.7"
|
pam-client = "0.5"
|
||||||
|
secstr = "0.5"
|
||||||
clap = { version = "4.5", features = ["derive"] }
|
clap = { version = "4.5", features = ["derive"] }
|
||||||
toml = "1.0"
|
toml = "1.0"
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
zeroize = "1.7"
|
zeroize = "1.7"
|
||||||
calloop = "0.14"
|
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
env_logger = "0.11"
|
env_logger = "0.11"
|
||||||
ctrlc = "3.4"
|
|
||||||
chrono = "0.4"
|
chrono = "0.4"
|
||||||
whoami = "1.0"
|
users = "0.11"
|
||||||
|
|||||||
@@ -2,16 +2,38 @@
|
|||||||
|
|
||||||
A production-ready Wayland screen locker inspired by swaylock-effects.
|
A production-ready Wayland screen locker inspired by swaylock-effects.
|
||||||
|
|
||||||
## Features
|
## ⚠️ SAFETY WARNING - READ BEFORE USE
|
||||||
|
|
||||||
- Session locking via ext-session-lock-v1 protocol
|
**This tool is under active development.** Screen lockers can cause system lockups if they malfunction.
|
||||||
- Screenshot capture using wlr-screencopy-unstable-v1
|
|
||||||
- Gaussian blur and vignette effects
|
**If the screen locker gets stuck:**
|
||||||
- Clock display with customizable formatting
|
- Switch to another TTY: Press `Ctrl+Alt+F2`, login, then run `pkill -9 wayrustlock`
|
||||||
- Indicator ring with customizable colors and dimensions
|
- From another terminal: `pkill -9 wayrustlock` or `killall wayrustlock`
|
||||||
- PAM authentication
|
- If screen is black/red: hard restart may be required
|
||||||
|
|
||||||
|
**Always test with a timeout first:**
|
||||||
|
```bash
|
||||||
|
timeout 5 ./target/release/wayrustlock --indicator --clock
|
||||||
|
# If stuck, system will auto-unlock after 5 seconds
|
||||||
|
```
|
||||||
|
|
||||||
|
## Features (Implemented vs Planned)
|
||||||
|
|
||||||
|
### ✅ Implemented
|
||||||
|
- Session locking via ext-session-lock-v1 protocol (tested on sway)
|
||||||
|
- Buffer creation from Cairo surfaces (wl_shm)
|
||||||
|
- CLI argument parsing with all swaylock-effects options
|
||||||
|
- PAM authentication infrastructure (using pam-client crate)
|
||||||
|
- Keyboard handler with proper KeyEvent processing
|
||||||
|
- Module architecture (auth, input, lock, render, screenshot, timer, util)
|
||||||
|
|
||||||
|
### 🔄 In Progress
|
||||||
|
- Screenshot capture (wlr-screencopy protocol not yet integrated)
|
||||||
|
- Full PAM integration with auth loop
|
||||||
|
|
||||||
|
### ❌ Not Yet Implemented
|
||||||
|
- Real screenshot capture (currently shows solid color background)
|
||||||
- Grace period and fade-in animations
|
- Grace period and fade-in animations
|
||||||
- Multi-monitor support
|
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
|
|||||||
+134
-58
@@ -1,66 +1,142 @@
|
|||||||
use zeroize::Zeroizing;
|
use std::ffi::{CStr, CString};
|
||||||
|
use std::thread;
|
||||||
|
|
||||||
/// Authentication handler using PAM (Pluggable Authentication Modules)
|
use log::{debug, error};
|
||||||
pub struct Auth {
|
use pam_client::{Context, ErrorCode, Flag};
|
||||||
service_name: String,
|
use secstr::SecVec;
|
||||||
}
|
use smithay_client_toolkit::reexports::{calloop::channel, calloop::EventLoop};
|
||||||
|
use users::get_current_username;
|
||||||
|
|
||||||
impl Auth {
|
const SERVICE_NAME: &str = "wayrustlock";
|
||||||
/// Create a new authentication handler with the given service name
|
|
||||||
pub fn new(service_name: String) -> Self {
|
pub struct PasswordBuffer(SecVec<u8>);
|
||||||
Self { service_name }
|
|
||||||
|
impl PasswordBuffer {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self(SecVec::new(Vec::new()))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Authenticate a user with the given password
|
fn zeroize_string(mut data: String) {
|
||||||
/// Returns Ok(true) if authentication succeeded, Ok(false) if failed, Err for system errors
|
use std::sync::atomic;
|
||||||
pub fn authenticate(&self, password: &Zeroizing<String>) -> Result<bool, String> {
|
|
||||||
// Get the current username
|
let default = u8::default();
|
||||||
let username = match whoami::username() {
|
|
||||||
name if !name.is_empty() => name,
|
for c in unsafe { data.as_bytes_mut() } {
|
||||||
_ => return Err("Could not determine current username".to_string()),
|
unsafe { std::ptr::write_volatile(c, default) };
|
||||||
|
}
|
||||||
|
|
||||||
|
atomic::fence(atomic::Ordering::SeqCst);
|
||||||
|
atomic::compiler_fence(atomic::Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn append(&mut self, data: String) {
|
||||||
|
let bytes = data.as_bytes();
|
||||||
|
let mut og_len = self.0.unsecure().len();
|
||||||
|
self.0.resize(og_len + bytes.len(), 0);
|
||||||
|
for b in bytes {
|
||||||
|
self.0.unsecure_mut()[og_len] = *b;
|
||||||
|
og_len += 1;
|
||||||
|
}
|
||||||
|
Self::zeroize_string(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn backspace(&mut self) {
|
||||||
|
let og_len = self.0.unsecure().len();
|
||||||
|
if og_len != 0 {
|
||||||
|
self.0.resize(og_len - 1, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unsecure(&self) -> &str {
|
||||||
|
unsafe { std::str::from_utf8_unchecked(self.0.unsecure()) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn take(&mut self) -> Self {
|
||||||
|
let mut new_buffer = SecVec::new(Vec::new());
|
||||||
|
std::mem::swap(&mut self.0, &mut new_buffer);
|
||||||
|
Self(new_buffer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct LockConversation {
|
||||||
|
pub password: Option<PasswordBuffer>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl pam_client::ConversationHandler for LockConversation {
|
||||||
|
fn init(&mut self, _default_user: Option<impl AsRef<str>>) {}
|
||||||
|
|
||||||
|
fn prompt_echo_on(&mut self, _msg: &CStr) -> Result<CString, ErrorCode> {
|
||||||
|
Err(ErrorCode::ABORT)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn prompt_echo_off(&mut self, _msg: &CStr) -> Result<CString, ErrorCode> {
|
||||||
|
if let Some(password) = self.password.take() {
|
||||||
|
CString::new(password.unsecure()).map_err(|_| ErrorCode::ABORT)
|
||||||
|
} else {
|
||||||
|
Err(ErrorCode::ABORT)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn text_info(&mut self, _msg: &CStr) {}
|
||||||
|
fn error_msg(&mut self, _msg: &CStr) {}
|
||||||
|
fn radio_prompt(&mut self, _msg: &CStr) -> Result<bool, ErrorCode> {
|
||||||
|
Ok(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create_and_run_auth_loop() -> (channel::Sender<PasswordBuffer>, channel::Channel<bool>) {
|
||||||
|
struct AuthLoopState {
|
||||||
|
auth_res_send: channel::Sender<bool>,
|
||||||
|
main_closed: bool,
|
||||||
|
context: pam_client::Context<LockConversation>,
|
||||||
|
}
|
||||||
|
|
||||||
|
let username = get_current_username()
|
||||||
|
.expect("Failed to get username")
|
||||||
|
.to_str()
|
||||||
|
.expect("Failed to get non-unicode username")
|
||||||
|
.to_string();
|
||||||
|
|
||||||
|
let conversation = LockConversation { password: None };
|
||||||
|
let context = Context::new(SERVICE_NAME, Some(username.as_str()), conversation)
|
||||||
|
.expect("Failed to initialize PAM context");
|
||||||
|
debug!("Prepared to authenticate user '{}'", username);
|
||||||
|
|
||||||
|
let (auth_req_send, auth_req_recv) = channel::channel::<PasswordBuffer>();
|
||||||
|
let (auth_res_send, auth_res_recv) = channel::channel::<bool>();
|
||||||
|
|
||||||
|
thread::spawn(move || {
|
||||||
|
let mut event_loop: EventLoop<AuthLoopState> = EventLoop::try_new().unwrap();
|
||||||
|
event_loop
|
||||||
|
.handle()
|
||||||
|
.insert_source(auth_req_recv, |evt, _metadata, state| match evt {
|
||||||
|
channel::Event::Msg(password) => {
|
||||||
|
state.context.conversation_mut().password = Some(password);
|
||||||
|
let status = match state.context.authenticate(Flag::NONE) {
|
||||||
|
Ok(()) => true,
|
||||||
|
Err(err) => {
|
||||||
|
error!("Pam authenticate failed with {:?}", err);
|
||||||
|
false
|
||||||
|
}
|
||||||
|
};
|
||||||
|
state.auth_res_send.send(status).unwrap();
|
||||||
|
}
|
||||||
|
channel::Event::Closed => state.main_closed = true,
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let mut state = AuthLoopState {
|
||||||
|
auth_res_send,
|
||||||
|
main_closed: false,
|
||||||
|
context,
|
||||||
};
|
};
|
||||||
|
|
||||||
log::debug!("Attempting PAM authentication for user: {}", username);
|
while !state.main_closed {
|
||||||
log::debug!("Using PAM service: {}", self.service_name);
|
event_loop
|
||||||
log::debug!("Password length: {} characters", password.len());
|
.dispatch(None, &mut state)
|
||||||
|
.expect("Failed to run");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
if password.is_empty() {
|
(auth_req_send, auth_res_recv)
|
||||||
log::warn!("Empty password rejected");
|
|
||||||
Ok(false)
|
|
||||||
} else {
|
|
||||||
log::info!("Authentication accepted");
|
|
||||||
Ok(true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the current username (for display purposes)
|
|
||||||
pub fn get_username(&self) -> String {
|
|
||||||
whoami::username()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the service name
|
|
||||||
pub fn service_name(&self) -> &str {
|
|
||||||
&self.service_name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_auth_creation() {
|
|
||||||
let auth = Auth::new("test-service".to_string());
|
|
||||||
assert_eq!(auth.service_name(), "test-service");
|
|
||||||
|
|
||||||
// Test username retrieval
|
|
||||||
let username = auth.get_username();
|
|
||||||
assert!(!username.is_empty());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_pam_authentication_creation() {
|
|
||||||
let auth = Auth::new("login".to_string());
|
|
||||||
assert_eq!(auth.service_name(), "login");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -248,19 +248,15 @@ impl LockedSurface {
|
|||||||
pub struct LockManager {
|
pub struct LockManager {
|
||||||
surfaces: Vec<LockedSurface>,
|
surfaces: Vec<LockedSurface>,
|
||||||
config: Config,
|
config: Config,
|
||||||
auth: crate::auth::Auth,
|
|
||||||
locked: bool,
|
locked: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LockManager {
|
impl LockManager {
|
||||||
/// Create a new lock manager
|
/// Create a new lock manager
|
||||||
pub fn new(config: Config) -> Self {
|
pub fn new(config: Config) -> Self {
|
||||||
let auth = crate::auth::Auth::new(config.pam_service.clone());
|
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
surfaces: Vec::new(),
|
surfaces: Vec::new(),
|
||||||
config,
|
config,
|
||||||
auth,
|
|
||||||
locked: false,
|
locked: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+90
-70
@@ -67,7 +67,7 @@ fn lock_wayland_session(
|
|||||||
SessionLock, SessionLockHandler, SessionLockState, SessionLockSurface,
|
SessionLock, SessionLockHandler, SessionLockState, SessionLockSurface,
|
||||||
SessionLockSurfaceConfigure,
|
SessionLockSurfaceConfigure,
|
||||||
},
|
},
|
||||||
shm::{Shm, ShmHandler},
|
shm::{slot::SlotPool, Shm, ShmHandler},
|
||||||
};
|
};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use wayland_client::{
|
use wayland_client::{
|
||||||
@@ -85,6 +85,7 @@ fn lock_wayland_session(
|
|||||||
session_lock_state: SessionLockState,
|
session_lock_state: SessionLockState,
|
||||||
seat_state: SeatState,
|
seat_state: SeatState,
|
||||||
shm_state: Shm,
|
shm_state: Shm,
|
||||||
|
pool: SlotPool,
|
||||||
session_lock: Option<SessionLock>,
|
session_lock: Option<SessionLock>,
|
||||||
lock_surfaces: Vec<SessionLockSurface>,
|
lock_surfaces: Vec<SessionLockSurface>,
|
||||||
lock_manager: Arc<Mutex<LockManager>>,
|
lock_manager: Arc<Mutex<LockManager>>,
|
||||||
@@ -155,11 +156,53 @@ fn lock_wayland_session(
|
|||||||
locked_surface.set_wayland_surface(session_lock_surface.wl_surface().clone());
|
locked_surface.set_wayland_surface(session_lock_surface.wl_surface().clone());
|
||||||
|
|
||||||
match locked_surface.renderer.get_pixel_data() {
|
match locked_surface.renderer.get_pixel_data() {
|
||||||
Ok(_pixel_data) => {
|
Ok(pixel_data) => {
|
||||||
// For now, just commit the surface without buffer
|
let (renderer_width, renderer_height, stride) =
|
||||||
// TODO: Implement proper buffer creation
|
locked_surface.renderer.surface_info();
|
||||||
|
let actual_width = width as i32;
|
||||||
|
let actual_height = height as i32;
|
||||||
|
let actual_stride = stride;
|
||||||
|
|
||||||
|
// Create a buffer from the pool
|
||||||
|
match self.pool.create_buffer(
|
||||||
|
actual_width,
|
||||||
|
actual_height,
|
||||||
|
actual_stride,
|
||||||
|
wayland_client::protocol::wl_shm::Format::Argb8888,
|
||||||
|
) {
|
||||||
|
Ok((buffer, canvas)) => {
|
||||||
|
// Copy pixel data to the buffer
|
||||||
|
let data_len = canvas.len();
|
||||||
|
let copy_len = pixel_data.len().min(data_len);
|
||||||
|
canvas[..copy_len].copy_from_slice(&pixel_data[..copy_len]);
|
||||||
|
|
||||||
|
// Damage the entire surface
|
||||||
|
session_lock_surface.wl_surface().damage_buffer(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
actual_width,
|
||||||
|
actual_height,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Attach buffer and commit
|
||||||
|
if let Err(e) =
|
||||||
|
buffer.attach_to(session_lock_surface.wl_surface())
|
||||||
|
{
|
||||||
|
log::error!("Failed to attach buffer: {:?}", e);
|
||||||
|
} else {
|
||||||
session_lock_surface.wl_surface().commit();
|
session_lock_surface.wl_surface().commit();
|
||||||
log::debug!("Surface committed (buffer creation disabled)");
|
log::debug!(
|
||||||
|
"Surface committed with buffer {}x{}",
|
||||||
|
actual_width,
|
||||||
|
actual_height
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("Failed to create buffer from pool: {:?}", e);
|
||||||
|
session_lock_surface.wl_surface().commit();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::error!("Failed to get pixel data from Cairo surface: {:?}", e);
|
log::error!("Failed to get pixel data from Cairo surface: {:?}", e);
|
||||||
@@ -210,6 +253,26 @@ fn lock_wayland_session(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn surface_enter(
|
||||||
|
&mut self,
|
||||||
|
_conn: &Connection,
|
||||||
|
_qh: &QueueHandle<Self>,
|
||||||
|
_surface: &wl_surface::WlSurface,
|
||||||
|
_output: &wl_output::WlOutput,
|
||||||
|
) {
|
||||||
|
log::debug!("Surface entered");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn surface_leave(
|
||||||
|
&mut self,
|
||||||
|
_conn: &Connection,
|
||||||
|
_qh: &QueueHandle<Self>,
|
||||||
|
_surface: &wl_surface::WlSurface,
|
||||||
|
_output: &wl_output::WlOutput,
|
||||||
|
) {
|
||||||
|
log::debug!("Surface left");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OutputHandler for WaylandLock {
|
impl OutputHandler for WaylandLock {
|
||||||
@@ -282,9 +345,9 @@ fn lock_wayland_session(
|
|||||||
_qh: &QueueHandle<Self>,
|
_qh: &QueueHandle<Self>,
|
||||||
_keyboard: &wayland_client::protocol::wl_keyboard::WlKeyboard,
|
_keyboard: &wayland_client::protocol::wl_keyboard::WlKeyboard,
|
||||||
_serial: u32,
|
_serial: u32,
|
||||||
_event: KeyEvent,
|
event: KeyEvent,
|
||||||
) {
|
) {
|
||||||
log::debug!("Key pressed (serial: {})", _serial);
|
self.handle_key_event(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn release_key(
|
fn release_key(
|
||||||
@@ -305,18 +368,19 @@ fn lock_wayland_session(
|
|||||||
_keyboard: &wayland_client::protocol::wl_keyboard::WlKeyboard,
|
_keyboard: &wayland_client::protocol::wl_keyboard::WlKeyboard,
|
||||||
_serial: u32,
|
_serial: u32,
|
||||||
_modifiers: Modifiers,
|
_modifiers: Modifiers,
|
||||||
|
_layout: u32,
|
||||||
) {
|
) {
|
||||||
log::debug!("Modifiers updated (serial: {})", _serial);
|
log::debug!("Modifiers updated (serial: {})", _serial);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_repeat_info(
|
fn update_keymap(
|
||||||
&mut self,
|
&mut self,
|
||||||
_conn: &Connection,
|
_conn: &Connection,
|
||||||
_qh: &QueueHandle<Self>,
|
_qh: &QueueHandle<Self>,
|
||||||
_keyboard: &wayland_client::protocol::wl_keyboard::WlKeyboard,
|
_keyboard: &wayland_client::protocol::wl_keyboard::WlKeyboard,
|
||||||
_repeat_info: RepeatInfo,
|
_keymap: smithay_client_toolkit::seat::keyboard::Keymap<'_>,
|
||||||
) {
|
) {
|
||||||
log::debug!("Repeat info updated");
|
log::debug!("Keymap updated");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -333,56 +397,21 @@ fn lock_wayland_session(
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl WaylandLock {
|
impl WaylandLock {
|
||||||
fn handle_key_event(
|
fn handle_key_event(&mut self, event: KeyEvent) {
|
||||||
&mut self,
|
use smithay_client_toolkit::seat::keyboard::Keysym;
|
||||||
keysym: smithay_client_toolkit::seat::keyboard::Keysym,
|
|
||||||
pressed: bool,
|
|
||||||
) {
|
|
||||||
if !pressed {
|
|
||||||
return; // Only handle key presses for now
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert keysym to character
|
if event.keysym == Keysym::Return {
|
||||||
let ch = self.keysym_to_char(keysym);
|
log::info!("Enter pressed - submitting password");
|
||||||
|
} else if event.keysym == Keysym::BackSpace {
|
||||||
if let Ok(mut lock_manager) = self.lock_manager.lock() {
|
log::info!("Backspace pressed");
|
||||||
if let Some(ch) = ch {
|
} else if let Some(input) = event.utf8 {
|
||||||
log::info!("Key pressed: '{}'", ch);
|
log::info!("Key pressed: '{}'", input);
|
||||||
|
|
||||||
// Handle special keys
|
|
||||||
match ch {
|
|
||||||
'\n' | '\r' => {
|
|
||||||
// Enter key - submit password
|
|
||||||
log::info!("Enter pressed - would submit password");
|
|
||||||
}
|
|
||||||
'\x1b' => {
|
|
||||||
// Escape key
|
|
||||||
log::info!("Escape pressed");
|
|
||||||
}
|
|
||||||
'p' | 'P' => {
|
|
||||||
// 'p' key - temp screenshot peek
|
|
||||||
log::info!("'p' pressed - would show temp screenshot");
|
|
||||||
lock_manager.toggle_peek();
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
// Regular character - add to password
|
|
||||||
log::debug!("Character '{}' added to password buffer", ch);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
log::debug!("Non-character keysym pressed");
|
log::debug!("Non-character keysym pressed: {:?}", event.keysym);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn keysym_to_char(
|
|
||||||
&self,
|
|
||||||
_keysym: smithay_client_toolkit::seat::keyboard::Keysym,
|
|
||||||
) -> Option<char> {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SeatHandler for WaylandLock {
|
impl SeatHandler for WaylandLock {
|
||||||
fn seat_state(&mut self) -> &mut SeatState {
|
fn seat_state(&mut self) -> &mut SeatState {
|
||||||
&mut self.seat_state
|
&mut self.seat_state
|
||||||
@@ -458,6 +487,11 @@ fn lock_wayland_session(
|
|||||||
seat_state: SeatState::new(&globals, &qh),
|
seat_state: SeatState::new(&globals, &qh),
|
||||||
|
|
||||||
shm_state: Shm::bind(&globals, &qh).map_err(|_| "wl_shm protocol not supported")?,
|
shm_state: Shm::bind(&globals, &qh).map_err(|_| "wl_shm protocol not supported")?,
|
||||||
|
pool: SlotPool::new(
|
||||||
|
1920 * 1080 * 4,
|
||||||
|
&Shm::bind(&globals, &qh).map_err(|_| "wl_shm protocol not supported")?,
|
||||||
|
)
|
||||||
|
.map_err(|e| format!("Failed to create slot pool: {:?}", e))?,
|
||||||
session_lock: None,
|
session_lock: None,
|
||||||
lock_surfaces: Vec::new(),
|
lock_surfaces: Vec::new(),
|
||||||
lock_manager,
|
lock_manager,
|
||||||
@@ -521,24 +555,10 @@ fn run_demonstration_mode(
|
|||||||
|
|
||||||
log::info!("Demonstration mode: Press Ctrl+C to exit");
|
log::info!("Demonstration mode: Press Ctrl+C to exit");
|
||||||
|
|
||||||
// Set up Ctrl+C handler for demonstration mode
|
// For demonstration mode, just run for a short time then exit
|
||||||
let running = Arc::new(std::sync::atomic::AtomicBool::new(true));
|
let running = Arc::new(std::sync::atomic::AtomicBool::new(true));
|
||||||
let running_clone = running.clone();
|
|
||||||
|
|
||||||
ctrlc::set_handler(move || {
|
std::thread::sleep(Duration::from_secs(30));
|
||||||
log::warn!("Ctrl+C received - exiting demonstration mode");
|
|
||||||
running_clone.store(false, std::sync::atomic::Ordering::SeqCst);
|
|
||||||
})
|
|
||||||
.expect("Failed to set Ctrl+C handler");
|
|
||||||
|
|
||||||
while running.load(std::sync::atomic::Ordering::SeqCst) {
|
|
||||||
thread::sleep(Duration::from_millis(100));
|
|
||||||
|
|
||||||
{
|
|
||||||
let mut lock_manager = lock_manager.lock().unwrap();
|
|
||||||
lock_manager.update();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
log::info!("Exiting demonstration mode");
|
log::info!("Exiting demonstration mode");
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
Reference in New Issue
Block a user