Skip to main content

keep_active/sys/
linux.rs

1//! Using [`org.freedesktop.ScreenSaver`], and [systemd Inhibitor Locks].
2//!
3//! For VT, should we add support for using `setterm -blank`? is there something better?
4//!
5//! Debug with `systemd-inhibit --list`, `gnome-session-inhibit --list`.
6//!
7//! [`org.freedesktop.ScreenSaver`]: https://people.freedesktop.org/~hadess/idle-inhibition-spec/re01.html
8//! [systemd Inhibitor Locks]: https://www.freedesktop.org/wiki/Software/systemd/inhibit/
9
10use zbus::{blocking::Connection, proxy};
11
12use crate::Options;
13
14pub type Error = zbus::Error;
15
16#[proxy(
17    interface = "org.freedesktop.login1.Manager",
18    default_service = "org.freedesktop.login1",
19    default_path = "/org/freedesktop/login1"
20)]
21trait Manager {
22    /// Inhibit method
23    fn inhibit(
24        &self,
25        what: &str,
26        who: &str,
27        why: &str,
28        mode: &str,
29    ) -> zbus::Result<zbus::zvariant::OwnedFd>;
30}
31
32#[proxy(assume_defaults = true)]
33trait ScreenSaver {
34    /// Inhibit method
35    fn inhibit(&self, application_name: &str, reason_for_inhibit: &str) -> zbus::Result<u32>;
36
37    /// UnInhibit method
38    fn un_inhibit(&self, cookie: u32) -> zbus::Result<()>;
39}
40
41pub struct KeepActive {
42    options: Options,
43
44    session_conn: Option<Connection>,
45    screensaver_proxy: Option<ScreenSaverProxyBlocking<'static>>,
46    cookie: Option<u32>,
47
48    system_conn: Option<Connection>,
49    manager_proxy: Option<ManagerProxyBlocking<'static>>,
50    idle_fd: Option<zbus::zvariant::OwnedFd>,
51    sleep_fd: Option<zbus::zvariant::OwnedFd>,
52}
53
54impl KeepActive {
55    pub fn new(options: Options) -> Result<Self, zbus::Error> {
56        let mut awake = Self {
57            options,
58
59            session_conn: None,
60            screensaver_proxy: None,
61            cookie: None,
62
63            system_conn: None,
64            manager_proxy: None,
65            idle_fd: None,
66            sleep_fd: None,
67        };
68        awake.set()?;
69        Ok(awake)
70    }
71
72    fn set(&mut self) -> Result<(), zbus::Error> {
73        self.cookie = if self.options.display {
74            self.session_conn = Some(Connection::session()?);
75            self.screensaver_proxy = Some(ScreenSaverProxyBlocking::new(
76                self.session_conn.as_ref().unwrap(),
77            )?);
78            Some(
79                self.screensaver_proxy
80                    .as_ref()
81                    .unwrap()
82                    .inhibit(&self.options.app_reverse_domain, &self.options.reason)?,
83            )
84        } else {
85            None
86        };
87
88        if self.options.idle || self.options.sleep {
89            self.system_conn = Some(Connection::system()?);
90            self.manager_proxy = Some(ManagerProxyBlocking::new(
91                self.system_conn.as_ref().unwrap(),
92            )?);
93        }
94
95        self.idle_fd = if self.options.idle {
96            Some(self.manager_proxy.as_ref().unwrap().inhibit(
97                "idle",
98                &self.options.app_name,
99                &self.options.reason,
100                "block",
101            )?)
102        } else {
103            None
104        };
105
106        self.sleep_fd = if self.options.sleep {
107            Some(self.manager_proxy.as_ref().unwrap().inhibit(
108                "sleep",
109                &self.options.app_name,
110                &self.options.reason,
111                "block",
112            )?)
113        } else {
114            None
115        };
116
117        Ok(())
118    }
119}
120
121impl Drop for KeepActive {
122    fn drop(&mut self) {
123        if self.options.display {
124            if let (Some(p), Some(cookie)) = (self.screensaver_proxy.as_ref(), self.cookie) {
125                p.un_inhibit(cookie).unwrap()
126            }
127        }
128    }
129}