From ef1d92a10857e2ab42da2fa87394d4d716397452 Mon Sep 17 00:00:00 2001 From: pagedmov Date: Sat, 21 Mar 2026 03:54:15 -0400 Subject: [PATCH] Fix screensaver idle timeout overflow by using 1s poll intervals with deadline tracking instead of direct millisecond conversion --- Cargo.lock | 2 +- Cargo.toml | 2 +- flake.nix | 2 +- src/main.rs | 17 +++++++++++++++-- 4 files changed, 18 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cd79d53..3373a4d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -573,7 +573,7 @@ dependencies = [ [[package]] name = "shed" -version = "0.6.1" +version = "0.6.2" dependencies = [ "ariadne", "bitflags", diff --git a/Cargo.toml b/Cargo.toml index 5678222..ace4aea 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ name = "shed" description = "A linux shell written in rust" publish = false -version = "0.6.1" +version = "0.6.2" edition = "2024" diff --git a/flake.nix b/flake.nix index 4beda02..f53aa37 100644 --- a/flake.nix +++ b/flake.nix @@ -14,7 +14,7 @@ { packages.default = pkgs.rustPlatform.buildRustPackage { pname = "shed"; - version = "0.6.1"; + version = "0.6.2"; src = self; diff --git a/src/main.rs b/src/main.rs index 8a9eae4..ee50b00 100644 --- a/src/main.rs +++ b/src/main.rs @@ -23,6 +23,7 @@ pub mod testutil; use std::os::fd::BorrowedFd; use std::process::ExitCode; use std::sync::atomic::Ordering; +use std::time::Duration; use nix::errno::Errno; use nix::poll::{PollFd, PollFlags, PollTimeout, poll}; @@ -255,6 +256,8 @@ fn shed_interactive(args: ShedArgs) -> ShResult<()> { readline.writer.flush_write("\x1b[?2004h")?; // enable bracketed paste mode + let mut screensaver_deadline: Option = None; + // Main poll loop loop { write_meta(|m| { @@ -317,8 +320,15 @@ fn shed_interactive(args: ShedArgs) -> ShResult<()> { let screensaver_idle_time = read_shopts(|o| o.prompt.screensaver_idle_time); if screensaver_idle_time > 0 && !screensaver_cmd.is_empty() { exec_if_timeout = Some(screensaver_cmd); - PollTimeout::from((screensaver_idle_time * 1000) as u16) + if screensaver_deadline.is_none() { + screensaver_deadline = Some(Instant::now() + Duration::from_secs(screensaver_idle_time as u64)); + } + // We unfortunately cant just set the PollTimeout to use 'idle_time * 1000' as the timeout + // because u16 overflows after 65 seconds (65535 ms). + // So we set a one second timeout and check against the Instant in 'screensaver_deadline' + PollTimeout::from(1000u16) } else { + screensaver_deadline = None; PollTimeout::MAX } } else { @@ -328,7 +338,9 @@ fn shed_interactive(args: ShedArgs) -> ShResult<()> { match poll(&mut fds, timeout) { Ok(0) => { // We timed out. - if let Some(cmd) = exec_if_timeout { + if let Some(cmd) = exec_if_timeout + && screensaver_deadline.is_some_and(|d| Instant::now() >= d) { + screensaver_deadline = None; let prepared = ReadlineEvent::Line(cmd.clone()); let saved_hist_opt = read_shopts(|o| o.core.auto_hist); let _guard = scopeguard::guard(saved_hist_opt, |opt| { @@ -420,6 +432,7 @@ fn shed_interactive(args: ShedArgs) -> ShResult<()> { } Ok(n) => { readline.feed_bytes(&buffer[..n]); + screensaver_deadline = None; } Err(Errno::EINTR) => { // Interrupted, continue to handle signals