use std::ffi::c_int; use std::mem; use std::sync::atomic::{AtomicBool, Ordering}; use std::{thread, time::Duration}; #[repr(C)] struct Winsize { ws_row: u16, ws_col: u16, ws_xpixel: u16, ws_ypixel: u16, } const SIGWINCH: c_int = 28; const STDOUT_FILENO: c_int = 1; // Value for TIOCGWINSZ was taken from asm-generic/ioctls.h const TIOCGWINSZ: c_int = 0x5413; extern "C" { fn ioctl(fd: c_int, request: c_int, ...) -> c_int; fn signal(sig: c_int, handler: extern "C" fn(c_int)) -> extern "C" fn(c_int); } fn get_terminal_size() -> std::io::Result<(u16, u16)> { unsafe { let mut ws: Winsize = mem::zeroed(); let res = ioctl(STDOUT_FILENO, TIOCGWINSZ, &mut ws); if res == -1 { Err(std::io::Error::last_os_error()) } else { Ok((ws.ws_col, ws.ws_row)) } } } static RESIZED: AtomicBool = AtomicBool::new(false); extern "C" fn handle_sigwinch(_: c_int) { // RESIZED.store(true, Ordering::SeqCst); RESIZED.store(true, Ordering::SeqCst); } fn main() -> std::io::Result<()> { unsafe { signal(SIGWINCH, handle_sigwinch); } println!("Listening for terminal resize events. Press Ctrl+C to quit."); let (mut last_cols, mut last_rows) = get_terminal_size()?; println!("Initial terminal size: {} cols × {} rows", last_cols, last_rows); loop { if RESIZED.swap(false, Ordering::SeqCst) { // Swap the value with guarantees if let Ok((cols, rows)) = get_terminal_size() { if cols != last_cols || rows != last_rows { println!("Terminal resized: {} cols × {} rows", cols, rows); last_cols = cols; last_rows = rows; } } } thread::sleep(Duration::from_millis(100)); } }