diff --git a/Cargo.lock b/Cargo.lock index f67bb3b1..1f4843e1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -746,7 +746,8 @@ dependencies = [ "crossbeam 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "melib 0.4.1", "nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", - "signal-hook 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "signal-hook 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "signal-hook-registry 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "ui 0.4.1", "xdg 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1523,16 +1524,16 @@ dependencies = [ [[package]] name = "signal-hook" -version = "0.1.10" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.64 (registry+https://github.com/rust-lang/crates.io-index)", - "signal-hook-registry 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "signal-hook-registry 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "signal-hook-registry" -version = "1.1.1" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "arc-swap 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2299,8 +2300,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum serde_derive 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)" = "46a3223d0c9ba936b61c0d2e3e559e3217dbfb8d65d06d26e8b3c25de38bae3e" "checksum serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)" = "5a23aa71d4a4d43fdbfaac00eff68ba8a06a51759a89ac3304323e800c4dd40d" "checksum serde_urlencoded 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9ec5d77e2d4c73717816afac02670d5c4f534ea95ed430442cad02e7a6e32c97" -"checksum signal-hook 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4f61c4d59f3aaa9f61bba6450a9b80ba48362fd7d651689e7a10c453b1f6dc68" -"checksum signal-hook-registry 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1797d48f38f91643908bb14e35e79928f9f4b3cefb2420a564dde0991b4358dc" +"checksum signal-hook 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "7a9c17dd3ba2d36023a5c9472ecddeda07e27fd0b05436e8c1e0c8f178185652" +"checksum signal-hook-registry 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94f478ede9f64724c5d173d7bb56099ec3e2d9fc2774aac65d34b8b890405f41" "checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" "checksum smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "f7b0758c52e15a8b5e3691eae6cc559f08eee9406e548a4477ba4e67770a82b6" "checksum smallvec 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44e59e0c9fa00817912ae6e4e6e3c4fe04455e75699d06eedc7d85917ed8e8f4" diff --git a/Cargo.toml b/Cargo.toml index f45e1fec..29108971 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,8 @@ path = "src/bin.rs" [dependencies] xdg = "2.1.0" crossbeam = "0.7.2" -signal-hook = "0.1.10" +signal-hook = "0.1.12" +signal-hook-registry = "1.2.0" nix = "*" melib = { path = "melib", version = "*" } ui = { path = "ui", version = "*" } diff --git a/src/bin.rs b/src/bin.rs index d031c92a..953b03ff 100644 --- a/src/bin.rs +++ b/src/bin.rs @@ -42,12 +42,23 @@ use ui::*; use nix; use std::os::raw::c_int; + use xdg; fn notify( signals: &[c_int], sender: crossbeam::channel::Sender, ) -> std::result::Result, std::io::Error> { + let alarm_sender = sender.clone(); + let alarm_handler = move |info: &nix::libc::siginfo_t| { + let value = unsafe { info.si_value().sival_ptr as u8 }; + alarm_sender + .send(ThreadEvent::UIEvent(UIEvent::Timer(value))) + .unwrap(); + }; + unsafe { + signal_hook_registry::register_sigaction(signal_hook::SIGALRM, alarm_handler)?; + } let (s, r) = crossbeam::channel::bounded(100); let signals = signal_hook::iterator::Signals::new(signals)?; std::thread::spawn(move || { @@ -218,22 +229,21 @@ fn run_app() -> Result<()> { std::env::set_var("MELI_CONFIG", config_location); } - /* Create the application State. */ - let mut state = State::new()?; - - let receiver = state.receiver(); - let sender = state.sender(); - + /* Create a channel to communicate with other threads. The main process is the sole receiver. + * */ + let (sender, receiver) = crossbeam::channel::bounded(32 * ::std::mem::size_of::()); /* Catch SIGWINCH to handle terminal resizing */ let signals = &[ - signal_hook::SIGALRM, /* Catch SIGWINCH to handle terminal resizing */ signal_hook::SIGWINCH, /* Catch SIGCHLD to handle embed applications status change */ signal_hook::SIGCHLD, ]; - let signal_recvr = notify(signals, sender)?; + let signal_recvr = notify(signals, sender.clone())?; + + /* Create the application State. */ + let mut state = State::new(sender, receiver.clone())?; let window = Box::new(Tabbed::new(vec![ Box::new(listing::Listing::new(&state.context.accounts)), @@ -388,10 +398,6 @@ fn run_app() -> Result<()> { state.redraw(); } }, - signal_hook::SIGALRM => { - state.rcv_event(UIEvent::Timer); - state.redraw(); - }, other => { debug!("got other signal: {:?}", other); } diff --git a/ui/src/lib.rs b/ui/src/lib.rs index 3fbc37c8..98d23ed6 100644 --- a/ui/src/lib.rs +++ b/ui/src/lib.rs @@ -191,9 +191,12 @@ pub mod timer { use libc::sigevent; use libc::{itimerspec, timespec}; use nix::sys::signal::{SigEvent, SigevNotify}; + use std::cell::RefCell; use std::convert::TryInto; use std::time::Duration; + thread_local!(static TIMER_IDS: RefCell = RefCell::new(0)); + #[allow(non_camel_case_types)] pub type timer_t = libc::intptr_t; @@ -215,6 +218,7 @@ pub mod timer { timer_id: timer_t, interval: Duration, value: Duration, + pub si_value: u8, } impl Drop for PosixTimer { @@ -255,6 +259,35 @@ pub mod timer { } } + pub fn set_value(&mut self, value: Duration) { + let spec = itimerspec { + it_interval: timespec { + tv_sec: self.interval.as_secs().try_into().unwrap_or(0), + tv_nsec: self.interval.subsec_nanos().try_into().unwrap_or(0), + }, + it_value: timespec { + tv_sec: value.as_secs().try_into().unwrap_or(0), + tv_nsec: value.subsec_nanos().try_into().unwrap_or(0), + }, + }; + let ret = + unsafe { timer_settime(self.timer_id, 0, &spec as *const _, std::ptr::null_mut()) }; + if ret != 0 { + match ret { + libc::EFAULT => { + panic!( + "EFAULT: new_value, old_value, or curr_value is not a valid pointer." + ); + } + libc::EINVAL => { + panic!("EINVAL: timerid is invalid."); + } + _ => {} + } + } + self.value = value; + } + pub fn set_interval(&mut self, interval: Duration) { let spec = itimerspec { it_interval: timespec { @@ -320,9 +353,15 @@ pub mod timer { ) -> Result { let mut timer_id = Default::default(); + let mut si_value = 0; + TIMER_IDS.with(|t| { + si_value = *t.borrow_mut(); + *t.borrow_mut() += 1; + }); + let sigev_notify = SigevNotify::SigevSignal { signal, - si_value: 0, + si_value: si_value as isize, }; let event = SigEvent::new(sigev_notify); @@ -382,6 +421,7 @@ pub mod timer { timer_id, interval, value, + si_value, }) } } diff --git a/ui/src/state.rs b/ui/src/state.rs index 360f08eb..1067f2e0 100644 --- a/ui/src/state.rs +++ b/ui/src/state.rs @@ -32,7 +32,7 @@ use super::*; use crate::plugins::PluginManager; use melib::backends::{FolderHash, NotifyFn}; -use crossbeam::channel::{bounded, unbounded, Receiver, Sender}; +use crossbeam::channel::{unbounded, Receiver, Sender}; use fnv::FnvHashMap; use std::env; use std::io::Write; @@ -199,11 +199,7 @@ impl Drop for State { } impl State { - pub fn new() -> Result { - /* Create a channel to communicate with other threads. The main process is the sole receiver. - * */ - let (sender, receiver) = bounded(32 * ::std::mem::size_of::()); - + pub fn new(sender: Sender, receiver: Receiver) -> Result { /* * Create async channel to block the input-thread if we need to fork and stop it from reading * stdin, see get_events() for details diff --git a/ui/src/types.rs b/ui/src/types.rs index 166b17e1..e8c76ec6 100644 --- a/ui/src/types.rs +++ b/ui/src/types.rs @@ -106,6 +106,7 @@ pub enum UIEvent { EnvelopeUpdate(EnvelopeHash), EnvelopeRename(EnvelopeHash, EnvelopeHash), // old_hash, new_hash EnvelopeRemove(EnvelopeHash), + Timer(u8), } impl From for UIEvent {