diff options
| author | Ogulcan Celik <ogulcancelik@gmail.com> | 2026-07-26 15:05:28 +0300 |
|---|---|---|
| committer | Ogulcan Celik <ogulcancelik@gmail.com> | 2026-07-26 15:05:28 +0300 |
| commit | 61f6400675b065bf8f801816ed78c1f3206bcc06 (patch) | |
| tree | 05bfa3914ab9079dd94f2bb0c3e64e6b79bf5aa7 /src/platform/mod.rs | |
| parent | 19cd372f2544f56af9be1f24a67cb229e82bb63d (diff) | |
fix: repaint after transient terminal resizes
Diffstat (limited to 'src/platform/mod.rs')
| -rw-r--r-- | src/platform/mod.rs | 52 |
1 files changed, 52 insertions, 0 deletions
diff --git a/src/platform/mod.rs b/src/platform/mod.rs index 9b763223..ba92ca63 100644 --- a/src/platform/mod.rs +++ b/src/platform/mod.rs @@ -78,6 +78,45 @@ pub fn current_process_is_detached_server_daemon() -> bool { unsafe { libc::getsid(0) == libc::getpid() } } +/// Raised by the SIGWINCH handler, consumed by the host resize watcher. +#[cfg(unix)] +static TERMINAL_RESIZE_SIGNALLED: std::sync::atomic::AtomicBool = + std::sync::atomic::AtomicBool::new(false); + +#[cfg(unix)] +extern "C" fn record_terminal_resize_signal(_signal: libc::c_int) { + TERMINAL_RESIZE_SIGNALLED.store(true, std::sync::atomic::Ordering::Release); +} + +/// Records SIGWINCH events that size polling can miss. +#[cfg(unix)] +pub(crate) fn watch_terminal_resize_signal() { + let mut action: libc::sigaction = unsafe { std::mem::zeroed() }; + action.sa_sigaction = + record_terminal_resize_signal as extern "C" fn(libc::c_int) as libc::sighandler_t; + // Keep blocking stdin and socket reads from failing with EINTR. + action.sa_flags = libc::SA_RESTART; + unsafe { + libc::sigemptyset(&mut action.sa_mask); + libc::sigaction(libc::SIGWINCH, &action, std::ptr::null_mut()); + } +} + +#[cfg(not(unix))] +pub(crate) fn watch_terminal_resize_signal() {} + +/// Returns whether a terminal size change was signalled since the last call. +#[cfg(unix)] +pub(crate) fn take_terminal_resize_signal() -> bool { + TERMINAL_RESIZE_SIGNALLED.swap(false, std::sync::atomic::Ordering::AcqRel) +} + +/// Windows relies on size polling. +#[cfg(not(unix))] +pub(crate) fn take_terminal_resize_signal() -> bool { + false +} + #[cfg(unix)] #[derive(Debug, Clone, PartialEq, Eq)] pub struct ClipboardCommand { @@ -313,6 +352,19 @@ mod tests { use super::*; #[test] + fn terminal_resize_signal_is_recorded_once_per_delivery() { + watch_terminal_resize_signal(); + assert!(!take_terminal_resize_signal()); + + unsafe { + libc::raise(libc::SIGWINCH); + } + + assert!(take_terminal_resize_signal()); + assert!(!take_terminal_resize_signal()); + } + + #[test] fn pane_shell_process_names_reject_exec_replacement_programs() { for shell in ["bash", "-zsh", "/bin/fish", "pwsh", "powershell.exe"] { assert!(is_pane_shell_process_name(shell), "{shell}"); |
