#[cfg(feature = "signals_sigint")] use crate::Msg;
#[cfg(feature = "signals_sigint")] use signal_hook::consts::SIGINT;
#[cfg(feature = "signals_sigwinch")] use signal_hook::consts::SIGWINCH;
#[cfg(feature = "signals_sigwinch")] use signal_hook::SigId;
use std::sync::{
Arc,
atomic::{
AtomicBool,
Ordering::SeqCst,
},
};
#[cfg(feature = "signals_sigint")] use super::Progless;
#[cfg(feature = "signals_sigint")] use std::sync::OnceLock;
use super::ProglessInner;
#[cfg(feature = "signals_sigint")]
static SIGINT_HANLDER: OnceLock<Arc<AtomicBool>> = OnceLock::new();
#[cfg(feature = "signals_sigint")]
#[cfg_attr(docsrs, doc(cfg(feature = "signals_sigint")))]
impl Progless {
#[must_use]
pub fn sigint_two_strike() -> &'static Arc<AtomicBool> {
SIGINT_HANLDER.get_or_init(sigint_two_strike)
}
#[must_use]
pub fn sigint_keepalive() -> &'static Arc<AtomicBool> {
SIGINT_HANLDER.get_or_init(sigint_keepalive)
}
}
pub(super) struct ProglessSignals {
#[cfg(feature = "signals_sigint")]
sigint: &'static Arc<AtomicBool>,
#[cfg(feature = "signals_sigwinch")]
sigwinch: Option<ResizeHandler>,
}
impl Default for ProglessSignals {
#[inline]
fn default() -> Self {
#[cfg(feature = "signals_sigint")]
let sigint = SIGINT_HANLDER.get_or_init(sigint_default);
#[cfg(feature = "signals_sigint")]
if ! sigint.load(SeqCst) { eprint!("{}", Progless::CURSOR_HIDE); }
Self {
#[cfg(feature = "signals_sigint")]
sigint,
#[cfg(feature = "signals_sigwinch")]
sigwinch: ResizeHandler::new(),
}
}
}
#[cfg(feature = "signals_sigint")]
impl Drop for ProglessSignals {
#[inline]
fn drop(&mut self) {
eprint!("{}", Progless::CURSOR_UNHIDE);
}
}
impl ProglessSignals {
pub(super) fn pretick(&self, inner: &Arc<ProglessInner>) -> bool {
#[cfg(feature = "signals_sigwinch")]
if
self.sigwinch.as_ref().is_none_or(|e| e.switch.swap(false, SeqCst)) &&
! inner.tick_resize()
{
return false;
}
#[cfg(feature = "signals_sigint")]
if self.sigint.load(SeqCst) && ! inner.sigint() {
return false;
}
true
}
}
#[cfg(feature = "signals_sigwinch")]
struct ResizeHandler {
switch: Arc<AtomicBool>,
id: SigId,
}
#[cfg(feature = "signals_sigwinch")]
impl Drop for ResizeHandler {
#[inline]
fn drop(&mut self) { signal_hook::low_level::unregister(self.id); }
}
#[cfg(feature = "signals_sigwinch")]
impl ResizeHandler {
fn new() -> Option<Self> {
let switch = Arc::new(AtomicBool::new(true));
let id = signal_hook::flag::register(SIGWINCH, Arc::clone(&switch)).ok()?;
Some(Self { switch, id })
}
}
#[cfg(feature = "signals_sigint")]
#[expect(unsafe_code, reason = "For signal listener.")]
fn sigint_default() -> Arc<AtomicBool> {
let switch = Arc::new(AtomicBool::new(false));
unsafe {
let t_switch = Arc::clone(&switch);
if signal_hook::low_level::register(SIGINT, move || {
if ! t_switch.swap(true, SeqCst) {
eprint!("{}", Progless::CURSOR_UNHIDE);
}
signal_hook::low_level::exit(1);
}).is_err() { sigint_error(); }
}
switch
}
#[cfg(feature = "signals_sigint")]
#[expect(unsafe_code, reason = "For signal listener.")]
fn sigint_two_strike() -> Arc<AtomicBool> {
let switch = Arc::new(AtomicBool::new(false));
unsafe {
let t_switch = Arc::clone(&switch);
if signal_hook::low_level::register(SIGINT, move ||
if t_switch.swap(true, SeqCst) { signal_hook::low_level::exit(1); }
else { eprint!("{}", Progless::CURSOR_UNHIDE); }
).is_err() { sigint_error(); }
}
switch
}
#[cfg(feature = "signals_sigint")]
#[expect(unsafe_code, reason = "For signal listener.")]
fn sigint_keepalive() -> Arc<AtomicBool> {
let switch = Arc::new(AtomicBool::new(false));
unsafe {
let t_switch = Arc::clone(&switch);
if signal_hook::low_level::register(SIGINT, move ||
if ! t_switch.swap(true, SeqCst) {
eprint!("{}", Progless::CURSOR_UNHIDE);
}
).is_err() { sigint_error(); }
}
switch
}
#[cfg(feature = "signals_sigint")]
#[inline]
fn sigint_error() -> ! {
Msg::error("Unable to register a SIGINT handler!").eprint();
std::process::exit(1);
}