Recover previous locked state

This commit is contained in:
Jeremy Soller 2024-11-07 09:37:16 -07:00
parent 7366808e8c
commit 08202f1572
No known key found for this signature in database
GPG key ID: D02FD439211AF56F
4 changed files with 83 additions and 27 deletions

1
Cargo.lock generated
View file

@ -996,6 +996,7 @@ dependencies = [
"cosmic-dbus-networkmanager", "cosmic-dbus-networkmanager",
"cosmic-greeter-config", "cosmic-greeter-config",
"cosmic-greeter-daemon", "cosmic-greeter-daemon",
"dirs",
"env_logger", "env_logger",
"freedesktop_entry_parser", "freedesktop_entry_parser",
"futures-util", "futures-util",

View file

@ -10,6 +10,7 @@ cosmic-comp-config.workspace = true
cosmic-config = { workspace = true, features = ["calloop", "macro"] } cosmic-config = { workspace = true, features = ["calloop", "macro"] }
cosmic-greeter-config.workspace = true cosmic-greeter-config.workspace = true
cosmic-greeter-daemon = { path = "daemon" } cosmic-greeter-daemon = { path = "daemon" }
dirs = "5"
env_logger.workspace = true env_logger.workspace = true
freedesktop_entry_parser = "1.3.0" freedesktop_entry_parser = "1.3.0"
libcosmic = { workspace = true, features = ["tokio", "wayland"] } libcosmic = { workspace = true, features = ["tokio", "wayland"] }

View file

@ -22,16 +22,30 @@ use cosmic_config::CosmicConfigEntry;
use std::{ use std::{
any::TypeId, any::TypeId,
collections::HashMap, collections::HashMap,
env,
ffi::{CStr, CString}, ffi::{CStr, CString},
fs, fs,
os::fd::OwnedFd, os::fd::OwnedFd,
path::Path, path::{Path, PathBuf},
process, process,
sync::Arc, sync::Arc,
}; };
use tokio::{sync::mpsc, task, time}; use tokio::{sync::mpsc, task, time};
use wayland_client::{protocol::wl_output::WlOutput, Proxy}; use wayland_client::{protocol::wl_output::WlOutput, Proxy};
fn lockfile_opt() -> Option<PathBuf> {
let runtime_dir = dirs::runtime_dir()?;
let session_id_str = env::var("XDG_SESSION_ID").ok()?;
let session_id = match session_id_str.parse::<u64>() {
Ok(ok) => ok,
Err(err) => {
log::warn!("failed to parse session ID {:?}: {}", session_id_str, err);
return None;
}
};
Some(runtime_dir.join(format!("cosmic-greeter-{}.lock", session_id)))
}
pub fn main(current_user: pwd::Passwd) -> Result<(), Box<dyn std::error::Error>> { pub fn main(current_user: pwd::Passwd) -> Result<(), Box<dyn std::error::Error>> {
env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("warn")).init(); env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("warn")).init();
@ -69,6 +83,7 @@ pub fn main(current_user: pwd::Passwd) -> Result<(), Box<dyn std::error::Error>>
let flags = Flags { let flags = Flags {
current_user, current_user,
icon_opt, icon_opt,
lockfile_opt: lockfile_opt(),
wallpapers, wallpapers,
}; };
@ -189,6 +204,7 @@ impl pam_client::ConversationHandler for Conversation {
pub struct Flags { pub struct Flags {
current_user: pwd::Passwd, current_user: pwd::Passwd,
icon_opt: Option<widget::image::Handle>, icon_opt: Option<widget::image::Handle>,
lockfile_opt: Option<PathBuf>,
wallpapers: Vec<(String, cosmic_bg_config::Source)>, wallpapers: Vec<(String, cosmic_bg_config::Source)>,
} }
@ -315,31 +331,46 @@ impl cosmic::Application for App {
core.window.show_minimize = false; core.window.show_minimize = false;
core.window.use_template = false; core.window.use_template = false;
( let already_locked = match flags.lockfile_opt {
App { Some(ref lockfile) => lockfile.exists(),
core, None => false,
flags, };
state: State::Unlocked,
surface_ids: HashMap::new(), let mut app = App {
active_surface_id_opt: None, core,
surface_images: HashMap::new(), flags,
surface_names: HashMap::new(), state: State::Unlocked,
text_input_ids: HashMap::new(), surface_ids: HashMap::new(),
inhibit_opt: None, active_surface_id_opt: None,
network_icon_opt: None, surface_images: HashMap::new(),
power_info_opt: None, surface_names: HashMap::new(),
value_tx_opt: None, text_input_ids: HashMap::new(),
prompt_opt: None, inhibit_opt: None,
error_opt: None, network_icon_opt: None,
}, power_info_opt: None,
if cfg!(feature = "logind") { value_tx_opt: None,
prompt_opt: None,
error_opt: None,
};
let command = if cfg!(feature = "logind") {
if already_locked {
// Recover previously locked state
log::info!("recovering previous locked state");
app.state = State::Locking;
lock()
} else {
// When logind feature is used, wait for lock signal // When logind feature is used, wait for lock signal
Command::none() Command::none()
} else { }
// When logind feature not used, lock immediately } else {
lock() // When logind feature not used, lock immediately
}, log::info!("locking immediately");
) app.state = State::Locking;
lock()
};
(app, command)
} }
/// Handle application events here. /// Handle application events here.
@ -425,6 +456,7 @@ impl cosmic::Application for App {
self.state = State::Locked; self.state = State::Locked;
// Allow suspend // Allow suspend
self.inhibit_opt = None; self.inhibit_opt = None;
// Create lock surfaces
let mut commands = Vec::with_capacity(self.surface_ids.len()); let mut commands = Vec::with_capacity(self.surface_ids.len());
for (output, surface_id) in self.surface_ids.iter() { for (output, surface_id) in self.surface_ids.iter() {
commands.push(get_lock_surface(*surface_id, output.clone())); commands.push(get_lock_surface(*surface_id, output.clone()));
@ -513,6 +545,13 @@ impl cosmic::Application for App {
self.error_opt = None; self.error_opt = None;
// Clear value_tx // Clear value_tx
self.value_tx_opt = None; self.value_tx_opt = None;
// Try to create lockfile when locking
if let Some(ref lockfile) = self.flags.lockfile_opt {
if let Err(err) = fs::File::create(lockfile) {
log::warn!("failed to create lockfile {:?}: {}", lockfile, err);
}
}
// Tell compositor to lock
return lock(); return lock();
} }
State::Unlocking => { State::Unlocking => {
@ -531,10 +570,18 @@ impl cosmic::Application for App {
self.error_opt = None; self.error_opt = None;
// Clear value_tx // Clear value_tx
self.value_tx_opt = None; self.value_tx_opt = None;
// Try to delete lockfile when unlocking
if let Some(ref lockfile) = self.flags.lockfile_opt {
if let Err(err) = fs::remove_file(lockfile) {
log::warn!("failed to remove lockfile {:?}: {}", lockfile, err);
}
}
// Destroy lock surfaces
let mut commands = Vec::with_capacity(self.surface_ids.len() + 1); let mut commands = Vec::with_capacity(self.surface_ids.len() + 1);
for (_output, surface_id) in self.surface_ids.iter() { for (_output, surface_id) in self.surface_ids.iter() {
commands.push(destroy_lock_surface(*surface_id)); commands.push(destroy_lock_surface(*surface_id));
} }
// Tell compositor to unlock
commands.push(unlock()); commands.push(unlock());
// Wait to exit until `Unlocked` event, when server has processed unlock // Wait to exit until `Unlocked` event, when server has processed unlock
return Command::batch(commands); return Command::batch(commands);
@ -642,7 +689,13 @@ impl cosmic::Application for App {
} }
None => {} None => {}
} }
match self.flags.current_user.gecos.as_ref().filter(|s| !s.is_empty()) { match self
.flags
.current_user
.gecos
.as_ref()
.filter(|s| !s.is_empty())
{
Some(gecos) => { Some(gecos) => {
let full_name = gecos.split(",").next().unwrap_or_default(); let full_name = gecos.split(",").next().unwrap_or_default();
column = column.push( column = column.push(

View file

@ -7,7 +7,6 @@ use logind_zbus::{
session::SessionProxy, session::SessionProxy,
}; };
use std::{any::TypeId, error::Error, os::fd::OwnedFd, sync::Arc}; use std::{any::TypeId, error::Error, os::fd::OwnedFd, sync::Arc};
use tokio::time;
use zbus::Connection; use zbus::Connection;
use crate::locker::Message; use crate::locker::Message;
@ -68,7 +67,9 @@ pub fn subscription() -> Subscription<Message> {
pub async fn handler(msg_tx: &mut mpsc::Sender<Message>) -> Result<(), Box<dyn Error>> { pub async fn handler(msg_tx: &mut mpsc::Sender<Message>) -> Result<(), Box<dyn Error>> {
let connection = Connection::system().await?; let connection = Connection::system().await?;
let manager = ManagerProxy::new(&connection).await?; let manager = ManagerProxy::new(&connection).await?;
let session_path = manager.get_session_by_PID(std::os::unix::process::parent_id()).await?; let session_path = manager
.get_session_by_PID(std::os::unix::process::parent_id())
.await?;
let session = SessionProxy::builder(&connection) let session = SessionProxy::builder(&connection)
.path(&session_path)? .path(&session_path)?
.build() .build()