2018-07-20 03:54:45 +00:00
|
|
|
use std::sync::atomic::{AtomicBool, Ordering};
|
|
|
|
use std::sync::Arc;
|
|
|
|
use std::thread;
|
|
|
|
|
|
|
|
use crossbeam_channel::{Receiver, Sender};
|
|
|
|
use signal_hook::iterator::Signals;
|
|
|
|
|
|
|
|
use backend::InputRequest;
|
|
|
|
use event::Event;
|
|
|
|
|
|
|
|
/// This starts a new thread to listen for SIGWINCH signals
|
|
|
|
///
|
|
|
|
/// As long as `resize_running` is true, it will listen for SIGWINCH, and,
|
|
|
|
/// when detected, it wil set `needs_resize` to true and send an event to
|
|
|
|
/// `resize_sender`. It will also consume an event from `resize_requests`
|
|
|
|
/// afterward, to keep the balance in the force.
|
|
|
|
#[cfg(unix)]
|
|
|
|
pub fn start_resize_thread(
|
|
|
|
signals: Signals, resize_sender: Sender<Option<Event>>,
|
|
|
|
resize_requests: Receiver<InputRequest>, resize_running: Arc<AtomicBool>,
|
|
|
|
needs_resize: Option<Arc<AtomicBool>>,
|
|
|
|
) {
|
|
|
|
thread::spawn(move || {
|
|
|
|
// This thread will listen to SIGWINCH events and report them.
|
|
|
|
while resize_running.load(Ordering::Relaxed) {
|
|
|
|
// We know it will only contain SIGWINCH signals, so no need to check.
|
|
|
|
if signals.wait().count() > 0 {
|
|
|
|
// Tell ncurses about the new terminal size.
|
|
|
|
// Well, do the actual resizing later on, in the main thread.
|
|
|
|
// Ncurses isn't really thread-safe so calling resize_term() can crash
|
|
|
|
// other calls like clear() or refresh().
|
|
|
|
if let Some(ref needs_resize) = needs_resize {
|
|
|
|
needs_resize.store(true, Ordering::Relaxed);
|
|
|
|
}
|
|
|
|
|
2018-12-01 00:55:47 +00:00
|
|
|
resize_sender.send(Some(Event::WindowResize)).unwrap();
|
2018-07-20 03:54:45 +00:00
|
|
|
// We've sent the message.
|
|
|
|
// This means Cursive was listening, and will now soon be sending a new request.
|
|
|
|
// This means the input thread accepted a request, but hasn't sent a message yet.
|
|
|
|
// So we KNOW the input thread is not waiting for a new request.
|
|
|
|
|
|
|
|
// We sent an event for free, so pay for it now by consuming a request
|
2018-12-01 00:55:47 +00:00
|
|
|
while let Ok(InputRequest::Peek) = resize_requests.recv() {
|
2018-07-20 03:54:45 +00:00
|
|
|
// At this point Cursive will now listen for input.
|
|
|
|
// There is a chance the input thread will send his event before us.
|
|
|
|
// But without some extra atomic flag, it'd be hard to know.
|
|
|
|
// So instead, keep sending `None`
|
|
|
|
|
|
|
|
// Repeat until we receive a blocking call
|
2018-12-01 00:55:47 +00:00
|
|
|
resize_sender.send(None).unwrap();
|
2018-07-20 03:54:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|