|
|
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));
|
|
|
}
|
|
|
}
|
|
|
|