#![feature(backtrace)]
use std::env;
use std::time::Duration;
use dbus::blocking::{Connection, Proxy};
use dbus::Message;
use crate::api::manager::{
OrgFreedesktopLogin1Manager, OrgFreedesktopLogin1ManagerPrepareForSleep,
};
pub use crate::error::LogindError;
use crate::inhibitor::{InhibitEventSet, InhibitMode, InhibitorLock};
pub use crate::session::{Session, SessionId};
mod api;
mod error;
pub mod inhibitor;
mod session;
pub fn session_id() -> Result<SessionId, LogindError> {
match env::var("XDG_SESSION_ID") {
Ok(id) => Ok(SessionId::new(id)),
Err(_) => Err(LogindError::no_session_id()),
}
}
pub struct Logind<'a> {
conn: &'a Connection,
timeout: Duration,
}
impl<'a> Logind<'a> {
pub fn new(conn: &'a Connection) -> Logind {
Logind {
conn,
timeout: Duration::from_millis(500),
}
}
pub fn session(&self, id: &SessionId) -> Result<Session<'a>, LogindError> {
let manager = self.manager();
let path = manager.get_session(id.as_str())?;
let proxy = Proxy::new(
"org.freedesktop.login1",
path,
self.timeout,
self.conn,
);
Ok(Session::new(proxy))
}
pub fn current_session(&self) -> Result<Session<'a>, LogindError> {
let id = session_id()?;
self.session(&id)
}
pub fn suspend(&self, interactive: bool) -> Result<(), LogindError> {
let manager = self.manager();
manager.suspend(interactive)?;
Ok(())
}
pub fn reboot(&self, interactive: bool) -> Result<(), LogindError> {
let manager = self.manager();
manager.reboot(interactive)?;
Ok(())
}
pub fn power_off(&self, interactive: bool) -> Result<(), LogindError> {
let manager = self.manager();
manager.power_off(interactive)?;
Ok(())
}
pub fn hibernate(&self, interactive: bool) -> Result<(), LogindError> {
let manager = self.manager();
manager.hibernate(interactive)?;
Ok(())
}
pub fn inhibit(
&self,
who: &str,
why: &str,
events: &InhibitEventSet,
mode: InhibitMode,
) -> Result<InhibitorLock, LogindError> {
let manager = self.manager();
let fd = manager.inhibit(events.as_str(), who, why, mode.as_str())?;
Ok(InhibitorLock::new(fd))
}
pub fn on_sleep<F: Fn(Logind) + Send + 'static, G: Fn(Logind) + Send + 'static>(
&self,
pre_sleep: F,
post_sleep: G,
) -> Result<(), LogindError> {
let manager = self.manager();
match manager.match_signal(
move |signal: OrgFreedesktopLogin1ManagerPrepareForSleep,
conn: &Connection,
_: &Message| {
if signal.arg0 {
pre_sleep(Logind::new(conn));
} else {
post_sleep(Logind::new(conn));
}
true
},
) {
Ok(_) => Ok(()),
Err(e) => Err(LogindError::match_failed("PrepareForSleep", e)),
}
}
fn manager(&self) -> Proxy<'_, &'a Connection> {
Proxy::new(
"org.freedesktop.login1",
"/org/freedesktop/login1",
self.timeout,
self.conn,
)
}
}