diff --git a/src/files.rs b/src/files.rs index efe1543..8478beb 100644 --- a/src/files.rs +++ b/src/files.rs @@ -4,7 +4,7 @@ use std::ops::Index; use std::fs::Metadata; use std::os::unix::fs::MetadataExt; use std::path::{Path, PathBuf}; -use std::sync::{Arc, Mutex, RwLock}; +use std::sync::{Arc, RwLock}; use std::sync::mpsc::Sender; use std::hash::{Hash, Hasher}; use std::str::FromStr; @@ -42,22 +42,13 @@ lazy_static! { static ref COLORS: LsColors = LsColors::from_env().unwrap_or_default(); static ref TAGS: RwLock<(bool, Vec)> = RwLock::new((false, vec![])); static ref ICONS: Icons = Icons::new(); - static ref IOPOOL: Mutex> = Mutex::new(None); + static ref IOTICK_CLIENTS: AtomicUsize = AtomicUsize::default(); static ref IOTICK: AtomicUsize = AtomicUsize::default(); - static ref TICKING: AtomicBool = AtomicBool::new(false); -} - -pub fn tick() { - IOTICK.fetch_add(1, Ordering::Relaxed); -} - -pub fn get_tick() -> usize { - IOTICK.load(Ordering::Relaxed) } pub fn tick_str() -> &'static str { // Using mod 5 for that nice nonlinear look - match get_tick() % 5 { + match IOTICK.load(Ordering::Relaxed) % 5 { 0 => " ", 1 => ". ", 2 => ".. ", @@ -65,12 +56,44 @@ pub fn tick_str() -> &'static str { } } -pub fn is_ticking() -> bool { - TICKING.load(Ordering::Acquire) +pub fn start_ticking(sender: Sender) { + use std::time::Duration; + + IOTICK_CLIENTS.fetch_add(1, Ordering::Relaxed); + if IOTICK_CLIENTS.load(Ordering::Acquire) == 1 { + std::thread::spawn(move || { + IOTICK.store(0, Ordering::Relaxed); + + // Gently slow down refreshes + let backoff = Duration::from_millis(10); + let mut cooldown = Duration::from_millis(10); + + loop { + IOTICK.fetch_add(1, Ordering::Relaxed); + + // Send refresh event before sleeping + sender.send(crate::widget::Events::WidgetReady) + .unwrap(); + + // All jobs done? + if IOTICK_CLIENTS.load(Ordering::Acquire) == 0 { + IOTICK.store(0, Ordering::Relaxed); + return; + } + + std::thread::sleep(cooldown); + + // Slow down up to 1 second + if cooldown < Duration::from_millis(1000) { + cooldown += backoff; + } + } + }); + } } -pub fn set_ticking(val: bool) { - TICKING.store(val, Ordering::Release); +pub fn stop_ticking() { + IOTICK_CLIENTS.fetch_sub(1, Ordering::Relaxed); } #[derive(Fail, Debug, Clone)] @@ -415,7 +438,6 @@ impl Files { } pub fn run_jobs(&mut self, sender: Sender) { - use std::time::Duration; let jobs = std::mem::take(&mut self.jobs); let stale = self.stale .clone() @@ -425,68 +447,14 @@ impl Files { std::thread::spawn(move || { let pool = get_pool(); - let stop = AtomicBool::new(false); - let stop = &stop; let stale = &stale; - let ticker = move || { - // Gently slow down refreshes - let backoff = Duration::from_millis(10); - let mut cooldown = Duration::from_millis(10); - - loop { - // Send refresh event before sleeping - sender.send(crate::widget::Events::WidgetReady) - .unwrap(); - std::thread::sleep(cooldown); - - // Slow down up to 1 second - if cooldown < Duration::from_secs(1) { - cooldown += backoff; - } - - // All jobs done? - if stop.load(Ordering::Relaxed) { - crate::files::tick(); - std::thread::sleep(cooldown); - // Refresh one last time - sender.send(crate::widget::Events::WidgetReady) - .unwrap(); - crate::files::set_ticking(false); - return; - } - - crate::files::tick(); - } - }; - - // To allow calling without consuming, all while Sender can't be shared - let mut ticker = Some(ticker); - - // Finally this returns the ticker function as an Option - let mut ticker = move || { - // Only return ticker if no one's ticking - match !crate::files::is_ticking() { - true => { - crate::files::set_ticking(true); - ticker.take() - } - false => None - } - }; + start_ticking(sender); pool.scope_fifo(move |s| { - // Noop with other pool running ticker - ticker().map(|t| s.spawn_fifo(move |_| t())); - - let jobs_num = jobs.len(); - - for (i, (path, mslot, dirsize)) in jobs.into_iter() - .stop_stale(stale.clone()) - .enumerate() + for (path, mslot, dirsize) in jobs.into_iter() + .stop_stale(stale.clone()) { - ticker().map(|t| s.spawn_fifo(move |_| t())); - s.spawn_fifo(move |_| { if let Some(mslot) = mslot { if let Ok(meta) = std::fs::symlink_metadata(&path) { @@ -506,19 +474,11 @@ impl Files { dirsize.0.store(true, Ordering::Relaxed); dirsize.1.store(size, Ordering::Relaxed); }; - - // This is the last job, stop ticking - if jobs_num == i + 1 { - stop.store(true, Ordering::Relaxed); - } }); } + }); - // Stop ticking if loop breaks on stale - if stale.is_stale().unwrap_or(true) { - stop.store(true, Ordering::Relaxed); - } - }) + stop_ticking(); }); } diff --git a/src/preview.rs b/src/preview.rs index b31ee7c..7ba2010 100644 --- a/src/preview.rs +++ b/src/preview.rs @@ -74,11 +74,14 @@ impl AsyncWidget { let mut widget = Async::new(move |stale| closure(stale).map_err(|e| e.into())); widget.on_ready(move |_, stale| { + crate::files::stop_ticking(); if !stale.is_stale()? { sender.lock().map(|s| s.send(crate::widget::Events::WidgetReady)).ok(); } Ok(()) }).log(); + + crate::files::start_ticking(core.get_sender()); widget.run().log(); AsyncWidget { @@ -101,6 +104,7 @@ impl AsyncWidget { }); widget.on_ready(move |_, stale| { + crate::files::stop_ticking(); if !stale.is_stale()? { sender.lock() .map(|s| s.send(crate::widget::Events::WidgetReady)) @@ -109,6 +113,7 @@ impl AsyncWidget { Ok(()) }).log(); + crate::files::start_ticking(self.core.get_sender()); widget.run().log(); self.widget = widget; @@ -181,7 +186,7 @@ impl Widget for AsyncWidget { let clear = self.core.get_clearlist()?; let (xpos, ypos) = self.get_coordinates()?.u16position(); let pos = crate::term::goto_xy(xpos, ypos); - return Ok(clear + &pos + "...") + return Ok(clear + &pos + crate::files::tick_str()) } if self.is_stale()? {