Add login1 LidClosed monitoring

This commit is contained in:
Ivan Molodetskikh
2025-10-18 09:13:41 +03:00
parent a4f5c90cf0
commit 8c8447918f
3 changed files with 135 additions and 0 deletions
+105
View File
@@ -0,0 +1,105 @@
use futures_util::StreamExt;
use zbus::fdo;
use zbus::names::InterfaceName;
pub enum Login1ToNiri {
LidClosedChanged(bool),
}
pub fn start(
to_niri: calloop::channel::Sender<Login1ToNiri>,
) -> anyhow::Result<zbus::blocking::Connection> {
let conn = zbus::blocking::Connection::system()?;
let async_conn = conn.inner().clone();
let future = async move {
let proxy = fdo::PropertiesProxy::new(
&async_conn,
"org.freedesktop.login1",
"/org/freedesktop/login1",
)
.await;
let proxy = match proxy {
Ok(x) => x,
Err(err) => {
warn!("error creating PropertiesProxy: {err:?}");
return;
}
};
let mut props_changed = match proxy.receive_properties_changed().await {
Ok(x) => x,
Err(err) => {
warn!("error subscribing to PropertiesChanged: {err:?}");
return;
}
};
let props = proxy
.get_all(InterfaceName::try_from("org.freedesktop.login1.Manager").unwrap())
.await;
let mut props = match props {
Ok(x) => x,
Err(err) => {
warn!("error receiving initial properties: {err:?}");
return;
}
};
trace!("initial properties: {props:?}");
let mut lid_closed = props
.remove("LidClosed")
.and_then(|value| bool::try_from(value).ok())
.unwrap_or_default();
if let Err(err) = to_niri.send(Login1ToNiri::LidClosedChanged(lid_closed)) {
warn!("error sending initial lid state to niri: {err:?}");
return;
};
while let Some(signal) = props_changed.next().await {
let args = match signal.args() {
Ok(args) => args,
Err(err) => {
warn!("error parsing PropertiesChanged args: {err:?}");
return;
}
};
let mut new_lid_closed = lid_closed;
let mut changed = false;
for (name, value) in args.changed_properties() {
trace!("changed property: {name} => {value:?}");
if *name != "LidClosed" {
continue;
}
new_lid_closed = bool::try_from(value).unwrap_or(new_lid_closed);
changed = true;
}
if !changed {
continue;
}
if new_lid_closed == lid_closed {
continue;
}
lid_closed = new_lid_closed;
if let Err(err) = to_niri.send(Login1ToNiri::LidClosedChanged(lid_closed)) {
warn!("error sending message to niri: {err:?}");
return;
};
}
};
let task = conn
.inner()
.executor()
.spawn(future, "monitor login1 property changes");
task.detach();
Ok(conn)
}
+18
View File
@@ -5,6 +5,7 @@ use crate::niri::State;
pub mod freedesktop_a11y;
pub mod freedesktop_locale1;
pub mod freedesktop_login1;
pub mod freedesktop_screensaver;
pub mod gnome_shell_introspect;
pub mod gnome_shell_screenshot;
@@ -35,6 +36,7 @@ pub struct DBusServers {
pub conn_introspect: Option<Connection>,
#[cfg(feature = "xdp-gnome-screencast")]
pub conn_screen_cast: Option<Connection>,
pub conn_login1: Option<Connection>,
pub conn_locale1: Option<Connection>,
pub conn_keyboard_monitor: Option<Connection>,
}
@@ -136,6 +138,22 @@ impl DBusServers {
}
}
let (to_niri, from_login1) = calloop::channel::channel();
niri.event_loop
.insert_source(from_login1, move |event, _, state| match event {
calloop::channel::Event::Msg(msg) => state.on_login1_msg(msg),
calloop::channel::Event::Closed => (),
})
.unwrap();
match freedesktop_login1::start(to_niri) {
Ok(conn) => {
dbus.conn_login1 = Some(conn);
}
Err(err) => {
warn!("error starting login1 watcher: {err:?}");
}
}
let (to_niri, from_locale1) = calloop::channel::channel();
niri.event_loop
.insert_source(from_locale1, move |event, _, state| match event {
+12
View File
@@ -120,6 +120,8 @@ use crate::cursor::{CursorManager, CursorTextureCache, RenderCursor, XCursor};
#[cfg(feature = "dbus")]
use crate::dbus::freedesktop_locale1::Locale1ToNiri;
#[cfg(feature = "dbus")]
use crate::dbus::freedesktop_login1::Login1ToNiri;
#[cfg(feature = "dbus")]
use crate::dbus::gnome_shell_introspect::{self, IntrospectToNiri, NiriToIntrospect};
#[cfg(feature = "dbus")]
use crate::dbus::gnome_shell_screenshot::{NiriToScreenshot, ScreenshotToNiri};
@@ -726,6 +728,8 @@ impl State {
self.niri.notified_activity_this_iteration = false;
}
// We monitor both libinput and logind: libinput is always there (including without DBus), but
// it misses some switch events (e.g. after unsuspend) on some systems.
pub fn set_lid_closed(&mut self, is_closed: bool) {
if self.niri.is_lid_closed == is_closed {
return;
@@ -2298,6 +2302,14 @@ impl State {
}
}
#[cfg(feature = "dbus")]
pub fn on_login1_msg(&mut self, msg: Login1ToNiri) {
let Login1ToNiri::LidClosedChanged(is_closed) = msg;
trace!("login1 lid {}", if is_closed { "closed" } else { "opened" });
self.set_lid_closed(is_closed);
}
#[cfg(feature = "dbus")]
pub fn on_locale1_msg(&mut self, msg: Locale1ToNiri) {
let Locale1ToNiri::XkbChanged(xkb) = msg;