1#![feature(backtrace)]
3use std::env;
4use std::time::Duration;
5
6use dbus::blocking::{Connection, Proxy};
7use dbus::Message;
8
9use crate::api::manager::{
10 OrgFreedesktopLogin1Manager, OrgFreedesktopLogin1ManagerPrepareForSleep,
11};
12pub use crate::error::LogindError;
13use crate::inhibitor::{InhibitEventSet, InhibitMode, InhibitorLock};
14pub use crate::session::{Session, SessionId};
15
16mod api;
17mod error;
18pub mod inhibitor;
19mod session;
20
21pub fn session_id() -> Result<SessionId, LogindError> {
22 match env::var("XDG_SESSION_ID") {
23 Ok(id) => Ok(SessionId::new(id)),
24 Err(_) => Err(LogindError::no_session_id()),
25 }
26}
27
28pub struct Logind<'a> {
31 conn: &'a Connection,
32 timeout: Duration,
33}
34
35impl<'a> Logind<'a> {
36 pub fn new(conn: &'a Connection) -> Logind {
37 Logind {
38 conn,
39 timeout: Duration::from_millis(500),
40 }
41 }
42
43 pub fn session(&self, id: &SessionId) -> Result<Session<'a>, LogindError> {
45 let manager = self.manager();
46 let path = manager.get_session(id.as_str())?;
47 let proxy = Proxy::new(
48 "org.freedesktop.login1",
49 path,
50 self.timeout,
51 self.conn,
52 );
53 Ok(Session::new(proxy))
54 }
55
56 pub fn current_session(&self) -> Result<Session<'a>, LogindError> {
58 let id = session_id()?;
59 self.session(&id)
60 }
61
62 pub fn suspend(&self, interactive: bool) -> Result<(), LogindError> {
65 let manager = self.manager();
66 manager.suspend(interactive)?;
67 Ok(())
68 }
69
70 pub fn reboot(&self, interactive: bool) -> Result<(), LogindError> {
73 let manager = self.manager();
74 manager.reboot(interactive)?;
75 Ok(())
76 }
77
78 pub fn power_off(&self, interactive: bool) -> Result<(), LogindError> {
81 let manager = self.manager();
82 manager.power_off(interactive)?;
83 Ok(())
84 }
85
86 pub fn hibernate(&self, interactive: bool) -> Result<(), LogindError> {
89 let manager = self.manager();
90 manager.hibernate(interactive)?;
91 Ok(())
92 }
93
94 pub fn inhibit(
95 &self,
96 who: &str,
97 why: &str,
98 events: &InhibitEventSet,
99 mode: InhibitMode,
100 ) -> Result<InhibitorLock, LogindError> {
101 let manager = self.manager();
102 let fd = manager.inhibit(events.as_str(), who, why, mode.as_str())?;
103 Ok(InhibitorLock::new(fd))
104 }
105
106 pub fn on_sleep<F: Fn(Logind) + Send + 'static, G: Fn(Logind) + Send + 'static>(
107 &self,
108 pre_sleep: F,
109 post_sleep: G,
110 ) -> Result<(), LogindError> {
111 let manager = self.manager();
112 match manager.match_signal(
113 move |signal: OrgFreedesktopLogin1ManagerPrepareForSleep,
114 conn: &Connection,
115 _: &Message| {
116 if signal.arg0 {
117 pre_sleep(Logind::new(conn));
119 } else {
120 post_sleep(Logind::new(conn));
121 }
122 true
123 },
124 ) {
125 Ok(_) => Ok(()),
126 Err(e) => Err(LogindError::match_failed("PrepareForSleep", e)),
127 }
128 }
129
130 fn manager(&self) -> Proxy<'_, &'a Connection> {
131 Proxy::new(
132 "org.freedesktop.login1",
133 "/org/freedesktop/login1",
134 self.timeout,
135 self.conn,
136 )
137 }
138}