Initial import. Most things seem working.
This includes an abortive attempt to do a gtk4 dialog (which I don't think is possible, as gtk4 doesn't allow embedding toplevels anymore), and an iced dialog, which I just never started writing.
This commit is contained in:
18
systemd/Cargo.toml
Normal file
18
systemd/Cargo.toml
Normal file
@ -0,0 +1,18 @@
|
||||
[package]
|
||||
name = "bscreensaver-systemd"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1"
|
||||
async-std = { version = "1.11", features = ["attributes"] }
|
||||
async-xcb = { path = "../async-xcb" }
|
||||
bscreensaver-command = { path = "../command" }
|
||||
bscreensaver-util = { path = "../util" }
|
||||
futures = "0.3"
|
||||
log = "0.4"
|
||||
nix = "0.23"
|
||||
# git source needed until extension event error resolution fix is released
|
||||
xcb = { git = "https://github.com/rust-x-bindings/rust-xcb", rev = "d09b5f91bc07d56673f1bc0d6c7ecd72b5ff7b3e" }
|
||||
zbus = "2.2"
|
||||
logind-zbus = "3"
|
99
systemd/src/main.rs
Normal file
99
systemd/src/main.rs
Normal file
@ -0,0 +1,99 @@
|
||||
use async_std::task;
|
||||
use futures::{future::FutureExt, pin_mut, select, AsyncReadExt, StreamExt};
|
||||
use log::{debug, error, info, warn};
|
||||
use logind_zbus::manager::{InhibitType, ManagerProxy};
|
||||
use std::{os::unix::io::AsRawFd, process::exit};
|
||||
use zbus::Connection;
|
||||
|
||||
use bscreensaver_command::{bscreensaver_command, BCommand};
|
||||
use bscreensaver_util::init_logging;
|
||||
|
||||
#[async_std::main]
|
||||
async fn main() {
|
||||
init_logging("BSCREENSAVER_SYSTEMD_LOG");
|
||||
|
||||
let xcb_handle = task::spawn(xcb_task()).fuse();
|
||||
let dbus_handle = task::spawn(dbus_task()).fuse();
|
||||
|
||||
pin_mut!(xcb_handle, dbus_handle);
|
||||
|
||||
let res = loop {
|
||||
select! {
|
||||
_ = xcb_handle => {
|
||||
info!("Lost connection to X server; quitting");
|
||||
break Ok(());
|
||||
},
|
||||
res = dbus_handle => {
|
||||
match res {
|
||||
Err(err) => error!("Lost connection to the session bus: {}", err),
|
||||
Ok(_) => error!("DBus task exited normally; this should not happen!"),
|
||||
}
|
||||
break Err(());
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
if let Err(_) = res {
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
async fn xcb_task() -> anyhow::Result<()> {
|
||||
let (xcb_conn, _) = task::block_on(async { xcb::Connection::connect(None) })?;
|
||||
let mut xcb_conn = async_xcb::AsyncConnection::new(xcb_conn)?;
|
||||
|
||||
// We need to drain the XCB connection periodically. Even though we have not
|
||||
// asked for any events, we'll still get stuff like MappingNotify if the keyboard
|
||||
// settings change.
|
||||
loop {
|
||||
let mut buf = [0u8; 512];
|
||||
xcb_conn.read(&mut buf).await?;
|
||||
}
|
||||
}
|
||||
|
||||
async fn dbus_task() -> anyhow::Result<()> {
|
||||
|
||||
let system_bus = Connection::system().await?;
|
||||
let manager_proxy = ManagerProxy::new(&system_bus).await?;
|
||||
let mut prepare_for_sleep_stream = manager_proxy.receive_prepare_for_sleep().await?;
|
||||
let mut inhibit_fd = Some(register_sleep_lock(&manager_proxy).await?);
|
||||
|
||||
loop {
|
||||
if let Some(prepare_for_sleep) = prepare_for_sleep_stream.next().await {
|
||||
if *prepare_for_sleep.args()?.start() {
|
||||
debug!("Preparing for sleep");
|
||||
if let Err(err) = do_bscreensaver_command(BCommand::Lock).await {
|
||||
warn!("Failed to lock screen: {}", err);
|
||||
}
|
||||
if let Some(fd) = inhibit_fd.take() {
|
||||
if let Err(err) = nix::unistd::close(fd.as_raw_fd()) {
|
||||
warn!("Failed to close sleep inhibit lock: {}", err);
|
||||
}
|
||||
} else {
|
||||
warn!("No sleep lock present");
|
||||
}
|
||||
} else {
|
||||
debug!("Resuming from sleep");
|
||||
if let Err(err) = do_bscreensaver_command(BCommand::Deactivate).await {
|
||||
warn!("Failed to deactivate screen lock: {}", err);
|
||||
}
|
||||
inhibit_fd = Some(register_sleep_lock(&manager_proxy).await?);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn do_bscreensaver_command(command: BCommand) -> anyhow::Result<()> {
|
||||
task::block_on(async {
|
||||
bscreensaver_command(command)
|
||||
})?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn register_sleep_lock<'a>(manager_proxy: &ManagerProxy<'a>) -> anyhow::Result<zbus::zvariant::OwnedFd> {
|
||||
debug!("Registering sleep lock");
|
||||
// ManagerProxy uses RawFd for the return value, which rust's type system thinks is an i32,
|
||||
// which means the generated proxy uses the wrong dbus type signature. So instead, use a raw
|
||||
// Proxy instance and do it all ourselves.
|
||||
Ok((*manager_proxy).call("Inhibit", &(InhibitType::Sleep, "bscreensaver", "blank before sleep", "delay")).await?)
|
||||
}
|
Reference in New Issue
Block a user