Lock on suspend with inhibit
This commit is contained in:
parent
eb3ba78e57
commit
9d4fe5bb0b
2 changed files with 73 additions and 15 deletions
|
|
@ -24,8 +24,10 @@ use std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
ffi::{CStr, CString},
|
ffi::{CStr, CString},
|
||||||
fs,
|
fs,
|
||||||
|
os::fd::OwnedFd,
|
||||||
path::Path,
|
path::Path,
|
||||||
process,
|
process,
|
||||||
|
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};
|
||||||
|
|
@ -195,6 +197,7 @@ pub enum Message {
|
||||||
SessionLockEvent(SessionLockEvent),
|
SessionLockEvent(SessionLockEvent),
|
||||||
Channel(mpsc::Sender<String>),
|
Channel(mpsc::Sender<String>),
|
||||||
BackgroundState(cosmic_bg_config::state::State),
|
BackgroundState(cosmic_bg_config::state::State),
|
||||||
|
Inhibit(Arc<OwnedFd>),
|
||||||
NetworkIcon(Option<&'static str>),
|
NetworkIcon(Option<&'static str>),
|
||||||
PowerInfo(Option<(String, f64)>),
|
PowerInfo(Option<(String, f64)>),
|
||||||
Prompt(String, bool, Option<String>),
|
Prompt(String, bool, Option<String>),
|
||||||
|
|
@ -223,6 +226,7 @@ pub struct App {
|
||||||
surface_images: HashMap<SurfaceId, widget::image::Handle>,
|
surface_images: HashMap<SurfaceId, widget::image::Handle>,
|
||||||
surface_names: HashMap<SurfaceId, String>,
|
surface_names: HashMap<SurfaceId, String>,
|
||||||
text_input_ids: HashMap<SurfaceId, widget::Id>,
|
text_input_ids: HashMap<SurfaceId, widget::Id>,
|
||||||
|
inhibit_opt: Option<Arc<OwnedFd>>,
|
||||||
network_icon_opt: Option<&'static str>,
|
network_icon_opt: Option<&'static str>,
|
||||||
power_info_opt: Option<(String, f64)>,
|
power_info_opt: Option<(String, f64)>,
|
||||||
value_tx_opt: Option<mpsc::Sender<String>>,
|
value_tx_opt: Option<mpsc::Sender<String>>,
|
||||||
|
|
@ -318,6 +322,7 @@ impl cosmic::Application for App {
|
||||||
surface_images: HashMap::new(),
|
surface_images: HashMap::new(),
|
||||||
surface_names: HashMap::new(),
|
surface_names: HashMap::new(),
|
||||||
text_input_ids: HashMap::new(),
|
text_input_ids: HashMap::new(),
|
||||||
|
inhibit_opt: None,
|
||||||
network_icon_opt: None,
|
network_icon_opt: None,
|
||||||
power_info_opt: None,
|
power_info_opt: None,
|
||||||
value_tx_opt: None,
|
value_tx_opt: None,
|
||||||
|
|
@ -415,6 +420,8 @@ impl cosmic::Application for App {
|
||||||
SessionLockEvent::Locked => {
|
SessionLockEvent::Locked => {
|
||||||
log::info!("session locked");
|
log::info!("session locked");
|
||||||
self.state = State::Locked;
|
self.state = State::Locked;
|
||||||
|
// Allow suspend
|
||||||
|
self.inhibit_opt = None;
|
||||||
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()));
|
||||||
|
|
@ -443,6 +450,9 @@ impl cosmic::Application for App {
|
||||||
self.surface_images.clear();
|
self.surface_images.clear();
|
||||||
self.update_wallpapers();
|
self.update_wallpapers();
|
||||||
}
|
}
|
||||||
|
Message::Inhibit(inhibit) => {
|
||||||
|
self.inhibit_opt = Some(inhibit);
|
||||||
|
}
|
||||||
Message::NetworkIcon(network_icon_opt) => {
|
Message::NetworkIcon(network_icon_opt) => {
|
||||||
self.network_icon_opt = network_icon_opt;
|
self.network_icon_opt = network_icon_opt;
|
||||||
}
|
}
|
||||||
|
|
@ -813,13 +823,7 @@ impl cosmic::Application for App {
|
||||||
|
|
||||||
#[cfg(feature = "logind")]
|
#[cfg(feature = "logind")]
|
||||||
{
|
{
|
||||||
subscriptions.push(crate::logind::subscription().map(|lock| {
|
subscriptions.push(crate::logind::subscription());
|
||||||
if lock {
|
|
||||||
Message::Lock
|
|
||||||
} else {
|
|
||||||
Message::Unlock
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "networkmanager")]
|
#[cfg(feature = "networkmanager")]
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,22 @@ use cosmic::iced::{
|
||||||
futures::{channel::mpsc, SinkExt, StreamExt},
|
futures::{channel::mpsc, SinkExt, StreamExt},
|
||||||
subscription, Subscription,
|
subscription, Subscription,
|
||||||
};
|
};
|
||||||
use logind_zbus::{manager::ManagerProxy, session::SessionProxy};
|
use logind_zbus::{
|
||||||
use std::{any::TypeId, error::Error, process};
|
manager::{InhibitType, ManagerProxy},
|
||||||
|
session::SessionProxy,
|
||||||
|
};
|
||||||
|
use std::{
|
||||||
|
any::TypeId,
|
||||||
|
error::Error,
|
||||||
|
os::fd::{FromRawFd, IntoRawFd, OwnedFd},
|
||||||
|
process,
|
||||||
|
sync::Arc,
|
||||||
|
};
|
||||||
use tokio::time;
|
use tokio::time;
|
||||||
use zbus::Connection;
|
use zbus::Connection;
|
||||||
|
|
||||||
|
use crate::locker::Message;
|
||||||
|
|
||||||
pub async fn power_off() -> zbus::Result<()> {
|
pub async fn power_off() -> zbus::Result<()> {
|
||||||
let connection = Connection::system().await?;
|
let connection = Connection::system().await?;
|
||||||
let manager = ManagerProxy::new(&connection).await?;
|
let manager = ManagerProxy::new(&connection).await?;
|
||||||
|
|
@ -25,7 +36,21 @@ pub async fn suspend() -> zbus::Result<()> {
|
||||||
manager.suspend(false).await
|
manager.suspend(false).await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn subscription() -> Subscription<bool> {
|
async fn inhibit(manager: &ManagerProxy<'_>) -> zbus::Result<OwnedFd> {
|
||||||
|
let what = InhibitType::Sleep;
|
||||||
|
let who = "COSMIC Greeter";
|
||||||
|
let why = "COSMIC Greeter needs to display a lock screen";
|
||||||
|
let mode = "delay";
|
||||||
|
//TODO: update logind-zbus to fix inhibit signature
|
||||||
|
let fd: zbus::zvariant::OwnedFd = manager
|
||||||
|
.inner()
|
||||||
|
.call("Inhibit", &(what, who, why, mode))
|
||||||
|
.await?;
|
||||||
|
// Have to convert to std type to avoid leaking zbus dependency
|
||||||
|
Ok(unsafe { OwnedFd::from_raw_fd(fd.into_raw_fd()) })
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn subscription() -> Subscription<Message> {
|
||||||
struct LogindSubscription;
|
struct LogindSubscription;
|
||||||
|
|
||||||
subscription::channel(
|
subscription::channel(
|
||||||
|
|
@ -49,7 +74,7 @@ pub fn subscription() -> Subscription<bool> {
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: use never type?
|
//TODO: use never type?
|
||||||
pub async fn handler(msg_tx: &mut mpsc::Sender<bool>) -> 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(process::id()).await?;
|
let session_path = manager.get_session_by_PID(process::id()).await?;
|
||||||
|
|
@ -58,16 +83,45 @@ pub async fn handler(msg_tx: &mut mpsc::Sender<bool>) -> Result<(), Box<dyn Erro
|
||||||
.build()
|
.build()
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
let mut inhibit_opt = Some(inhibit(&manager).await?);
|
||||||
|
let mut prepare_for_sleep = manager.receive_prepare_for_sleep().await?;
|
||||||
let mut lock = session.receive_lock().await?;
|
let mut lock = session.receive_lock().await?;
|
||||||
let mut unlock = session.receive_unlock().await?;
|
let mut unlock = session.receive_unlock().await?;
|
||||||
loop {
|
loop {
|
||||||
// Waits until lock or unlock signals have been received
|
// Waits until a signal has been received
|
||||||
tokio::select!(_ = lock.next() => {
|
tokio::select!(
|
||||||
|
signal_opt = prepare_for_sleep.next() => {
|
||||||
|
match signal_opt {
|
||||||
|
Some(signal) => match signal.args() {
|
||||||
|
Ok(args) => {
|
||||||
|
if args.start {
|
||||||
|
log::info!("logind prepare for sleep");
|
||||||
|
if let Some(inhibit) = inhibit_opt.take() {
|
||||||
|
msg_tx.send(Message::Inhibit(Arc::new(inhibit))).await?;
|
||||||
|
}
|
||||||
|
msg_tx.send(Message::Lock).await?;
|
||||||
|
} else {
|
||||||
|
log::info!("logind resume");
|
||||||
|
if inhibit_opt.is_none() {
|
||||||
|
inhibit_opt = Some(inhibit(&manager).await?);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Err(err) => {
|
||||||
|
log::warn!("logind prepare to sleep invalid data: {}", err);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
None => {
|
||||||
|
log::warn!("logind prepare to sleep missing data");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ = lock.next() => {
|
||||||
log::info!("logind lock");
|
log::info!("logind lock");
|
||||||
msg_tx.send(true).await?;
|
msg_tx.send(Message::Lock).await?;
|
||||||
}, _ = unlock.next() => {
|
}, _ = unlock.next() => {
|
||||||
log::info!("logind unlock");
|
log::info!("logind unlock");
|
||||||
msg_tx.send(false).await?;
|
msg_tx.send(Message::Unlock).await?;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue