Commit 5d5ec436eb31
tarball6 files changed+131-4
@@ -201,6 +201,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
201201
checksum = "f27ae1dd37df86211c42e150270f82743308803d90a6f6e6651cd730d5e1732f"202202
203203
[[package]]204
+name = "dbus"205
+version = "0.9.12"206
+source = "registry+https://github.com/rust-lang/crates.io-index"207
+checksum = "3ab69f03cc8c4340c9c8e315114e1658e6775a9b16a04357973aa21cec22b32e"208
+dependencies = [209
+ "libc",210
+ "libdbus-sys",211
+ "windows-sys 0.61.2",212
+]213
+214
+[[package]]204215
name = "downcast-rs"205216
version = "1.2.1"206217
source = "registry+https://github.com/rust-lang/crates.io-index"@@ -452,6 +463,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
452463
checksum = "ce5d3ddc6d3fa000eb1536d85e147bfe31aacaba692ed6a876f95cb7c855be78"453464
454465
[[package]]466
+name = "libdbus-sys"467
+version = "0.2.7"468
+source = "registry+https://github.com/rust-lang/crates.io-index"469
+checksum = "328c4789d42200f1eeec05bd86c9c13c7f091d2ba9a6ea35acdf51f31bc0f043"470
+dependencies = [471
+ "pkg-config",472
+]473
+474
+[[package]]455475
name = "libloading"456476
version = "0.8.9"457477
source = "registry+https://github.com/rust-lang/crates.io-index"@@ -544,6 +564,7 @@ name = "monolith"
544564
version = "0.0.0"545565
dependencies = [546566
"calloop-wayland-source",567
+ "dbus",547568
"input",548569
"libc",549570
"monolith-config",@@ -22,6 +22,7 @@ monolith-planner.workspace = true
2222
monolith-protocols.workspace = true2323
monolith-render-vk.workspace = true2424
libc = "0.2"25
+dbus = "0.9"2526
# Raises the libinput bindings smithay uses. 1.23 brings custom acceleration,2627
# and below 1.27 reading a sticky drag lock default panics.2728
input = { version = "0.10", default-features = false, features = ["libinput_1_27"] }@@ -0,0 +1,92 @@
1
+//! The system bus connection to logind, for taking over the lid switch and2
+//! for suspending or powering off through it.3
+4
+use dbus::arg::OwnedFd;5
+use dbus::blocking::SyncConnection;6
+use std::process::Command;7
+use std::sync::Arc;8
+use std::time::Duration;9
+10
+const DEST: &str = "org.freedesktop.login1";11
+const PATH: &str = "/org/freedesktop/login1";12
+const MANAGER: &str = "org.freedesktop.login1.Manager";13
+const TIMEOUT: Duration = Duration::from_secs(2);14
+15
+pub struct Logind {16
+ conn: Arc<SyncConnection>,17
+ /// Held so that logind leaves the lid switch to us. Closing it releases18
+ /// the inhibitor.19
+ _lid_lock: OwnedFd,20
+}21
+22
+#[derive(Clone, Copy)]23
+pub enum Action {24
+ Suspend,25
+ Poweroff,26
+}27
+28
+impl Action {29
+ fn method(self) -> &'static str {30
+ match self {31
+ Action::Suspend => "Suspend",32
+ Action::Poweroff => "PowerOff",33
+ }34
+ }35
+36
+ pub fn verb(self) -> &'static str {37
+ match self {38
+ Action::Suspend => "suspend",39
+ Action::Poweroff => "poweroff",40
+ }41
+ }42
+}43
+44
+impl Logind {45
+ pub fn connect() -> Result<Self, dbus::Error> {46
+ let conn = Arc::new(SyncConnection::new_system()?);47
+ let proxy = conn.with_proxy(DEST, PATH, TIMEOUT);48
+ let (fd,): (OwnedFd,) = proxy.method_call(49
+ MANAGER,50
+ "Inhibit",51
+ (52
+ "handle-lid-switch",53
+ "monolith",54
+ "monolith handles the lid",55
+ "block",56
+ ),57
+ )?;58
+ Ok(Self {59
+ conn,60
+ _lid_lock: fd,61
+ })62
+ }63
+64
+ /// Asks logind to run the action without waiting for the reply, and falls65
+ /// back to systemctl if the call fails. The call can take as long as the66
+ /// timeout, so it stays off the event loop.67
+ pub fn act(&self, action: Action) {68
+ let conn = self.conn.clone();69
+ let spawned = std::thread::Builder::new()70
+ .name("logind".into())71
+ .spawn(move || {72
+ let proxy = conn.with_proxy(DEST, PATH, TIMEOUT);73
+ let called: Result<(), dbus::Error> =74
+ proxy.method_call(MANAGER, action.method(), (false,));75
+ if let Err(e) = called {76
+ tracing::warn!("logind {} failed, using systemctl: {e}", action.verb());77
+ systemctl(action);78
+ }79
+ });80
+ if let Err(e) = spawned {81
+ tracing::warn!("could not start the logind thread: {e}");82
+ }83
+ }84
+}85
+86
+fn systemctl(action: Action) {87
+ match Command::new("systemctl").arg(action.verb()).status() {88
+ Ok(s) if !s.success() => tracing::warn!("systemctl {} exited with {s}", action.verb()),89
+ Ok(_) => {}90
+ Err(e) => tracing::warn!("systemctl {} failed: {e}", action.verb()),91
+ }92
+}@@ -17,6 +17,7 @@ mod ipc;
1717
mod launch;1818
mod layers;1919
mod lock;20
+mod logind;2021
mod nested;2122
mod pacing;2223
mod popups;@@ -275,6 +276,12 @@ fn run(
275276
signals::init(&event_loop)?;276277
xwayland::init(&mut state);277278
state.configure_idle();279
+ if gpu.is_some() {280
+ match logind::Logind::connect() {281
+ Ok(logind) => state.services.power.logind = Some(logind),282
+ Err(e) => tracing::warn!("cannot take the lid switch from logind: {e}"),283
+ }284
+ }278285
tracing::info!(socket = ?state.core.socket_name, device = state.renderer.device_name(), "monolith running");279286
280287
if gpu.is_some() {@@ -2,6 +2,7 @@
22
//! wlr-output-power-management all end up here, and the backend is told what33
//! came out.44
5
+use crate::logind::{Action, Logind};56
use crate::state::{State, now_ns};67
use monolith_config::LidAction;78
use monolith_protocols::output_power::{OutputPowerHandler, OutputPowerState};@@ -13,6 +14,8 @@ use std::time::Duration;
1314
1415
#[derive(Default)]1516
pub struct Power {17
+ /// Absent on the nested backend, or when the system bus is unreachable.18
+ pub logind: Option<Logind>,1619
/// Every output is dark until the next input.1720
idle_blanked: bool,1821
/// Outputs switched off by name, which input does not wake.@@ -141,12 +144,14 @@ impl State {
141144
return;142145
}143146
power.lid_acted = true;144
- let verb = match self.settings.config.lid.close {145
- LidAction::Suspend => "suspend",146
- LidAction::Poweroff => "poweroff",147
+ let action = match self.settings.config.lid.close {148
+ LidAction::Suspend => Action::Suspend,149
+ LidAction::Poweroff => Action::Poweroff,147150
LidAction::Ignore => return,148151
};149
- if let Err(e) = self.spawn(&["systemctl".into(), verb.into()]) {152
+ if let Some(logind) = &power.logind {153
+ logind.act(action);154
+ } else if let Err(e) = self.spawn(&["systemctl".into(), action.verb().into()]) {150155
tracing::warn!("lid close action failed: {e}");151156
}152157
}@@ -47,6 +47,7 @@
4747
libgbm4848
libdrm4949
udev50
+ dbus5051
];5152
};5253
cargoArtifacts = craneLib.buildDepsOnly commonArgs;