aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/main.rs1
-rw-r--r--src/niri.rs89
-rw-r--r--src/tests/server.rs1
3 files changed, 91 insertions, 0 deletions
diff --git a/src/main.rs b/src/main.rs
index d036c2a8..bdc6df46 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -216,6 +216,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
display,
false,
true,
+ cli.session,
)
.unwrap();
diff --git a/src/niri.rs b/src/niri.rs
index 9bc83302..80e97baf 100644
--- a/src/niri.rs
+++ b/src/niri.rs
@@ -193,6 +193,9 @@ pub struct Niri {
pub stop_signal: LoopSignal,
pub display_handle: DisplayHandle,
+ /// Whether niri was run with `--session`
+ pub is_session_instance: bool,
+
/// Name of the Wayland socket.
///
/// This is `None` when creating `Niri` without a Wayland socket.
@@ -360,6 +363,9 @@ pub struct Niri {
pub lock_state: LockState,
+ // State that we last sent to the logind LockedHint.
+ pub locked_hint: Option<bool>,
+
pub screenshot_ui: ScreenshotUi,
pub config_error_notification: ConfigErrorNotification,
pub hotkey_overlay: HotkeyOverlay,
@@ -629,6 +635,7 @@ impl State {
display: Display<State>,
headless: bool,
create_wayland_socket: bool,
+ is_session_instance: bool,
) -> Result<Self, Box<dyn std::error::Error>> {
let _span = tracy_client::span!("State::new");
@@ -657,6 +664,7 @@ impl State {
display,
&backend,
create_wayland_socket,
+ is_session_instance,
);
backend.init(&mut niri);
@@ -690,6 +698,9 @@ impl State {
self.niri.display_handle.flush_clients().unwrap();
}
+ #[cfg(feature = "dbus")]
+ self.niri.update_locked_hint();
+
// Clear the time so it's fetched afresh next iteration.
self.niri.clock.clear();
self.niri.pointer_inactivity_timer_got_reset = false;
@@ -2225,6 +2236,7 @@ impl Niri {
display: Display<State>,
backend: &Backend,
create_wayland_socket: bool,
+ is_session_instance: bool,
) -> Self {
let _span = tracy_client::span!("Niri::new");
@@ -2495,6 +2507,7 @@ impl Niri {
stop_signal,
socket_name,
display_handle,
+ is_session_instance,
start_time: Instant::now(),
is_at_startup: true,
clock: animation_clock,
@@ -2594,6 +2607,7 @@ impl Niri {
mods_with_finger_scroll_binds,
lock_state: LockState::Unlocked,
+ locked_hint: None,
screenshot_ui,
config_error_notification,
@@ -5741,6 +5755,81 @@ impl Niri {
self.queue_redraw_all();
}
+ #[cfg(feature = "dbus")]
+ fn update_locked_hint(&mut self) {
+ use std::sync::LazyLock;
+
+ if !self.is_session_instance {
+ return;
+ }
+
+ static XDG_SESSION_ID: LazyLock<Option<String>> = LazyLock::new(|| {
+ let id = std::env::var("XDG_SESSION_ID").ok();
+ if id.is_none() {
+ warn!(
+ "env var 'XDG_SESSION_ID' is unset or invalid; logind LockedHint won't be set"
+ );
+ }
+ id
+ });
+
+ let Some(session_id) = &*XDG_SESSION_ID else {
+ return;
+ };
+
+ fn call(session_id: &str, locked: bool) -> anyhow::Result<()> {
+ let conn = zbus::blocking::Connection::system()
+ .context("error connecting to the system bus")?;
+
+ let message = conn
+ .call_method(
+ Some("org.freedesktop.login1"),
+ "/org/freedesktop/login1",
+ Some("org.freedesktop.login1.Manager"),
+ "GetSession",
+ &(session_id),
+ )
+ .context("failed to call GetSession")?;
+
+ let message_body = message.body();
+ let session_path: zbus::zvariant::ObjectPath = message_body
+ .deserialize()
+ .context("failed to deserialize GetSession reply")?;
+
+ conn.call_method(
+ Some("org.freedesktop.login1"),
+ session_path,
+ Some("org.freedesktop.login1.Session"),
+ "SetLockedHint",
+ &(locked),
+ )
+ .context("failed to call SetLockedHint")?;
+
+ Ok(())
+ }
+
+ let locked = self.is_locked();
+ if self.locked_hint.is_some_and(|h| h == locked) {
+ return;
+ }
+
+ self.locked_hint = Some(locked);
+
+ let res = thread::Builder::new()
+ .name("Logind LockedHint Updater".to_owned())
+ .spawn(move || {
+ let _span = tracy_client::span!("LockedHint");
+
+ if let Err(err) = call(session_id, locked) {
+ warn!("failed to set logind LockedHint: {err:?}");
+ }
+ });
+
+ if let Err(err) = res {
+ warn!("error spawning a thread to set logind LockedHint: {err:?}");
+ }
+ }
+
pub fn new_lock_surface(&mut self, surface: LockSurface, output: &Output) {
let lock = match &self.lock_state {
LockState::Unlocked => {
diff --git a/src/tests/server.rs b/src/tests/server.rs
index ea1f913b..40f6c1c7 100644
--- a/src/tests/server.rs
+++ b/src/tests/server.rs
@@ -23,6 +23,7 @@ impl Server {
display,
true,
false,
+ false,
)
.unwrap();