use async_value::{Async, Stale};
use termion::event::Key;
use parking_lot::Mutex;
use std::sync::Arc;
use std::path::PathBuf;
use crate::files::{File, Files, Kind, Ticker};
use crate::fscache::FsCache;
use crate::listview::{ListView, FileSource};
use crate::textview::TextView;
use crate::widget::{Widget, WidgetCore};
use crate::coordinates::Coordinates;
use crate::fail::{HResult, HError, ErrorLog};
use crate::imgview::ImgView;
use crate::mediaview::MediaView;
pub type AsyncWidgetFn<W> = dyn FnOnce(&Stale, WidgetCore)
-> HResult<W> + Send + Sync;
lazy_static! {
static ref SUBPROC: Arc<Mutex<Option<u32>>> = Arc::new(Mutex::new(None));
}
fn kill_proc() -> HResult<()> {
// Kill media previewer if it still runs
ImgView::kill_running();
let mut pid = SUBPROC.lock();
pid.map(|pid|
// Do this in another thread so we can wait on process to exit with SIGHUP
std::thread::spawn(move || {
use nix::{unistd::Pid,
sys::signal::{killpg, Signal}};
let sleep_time = std::time::Duration::from_millis(50);
// Kill using process group, to clean up all child processes, too
let pid = Pid::from_raw(pid as i32);
killpg(pid, Signal::SIGTERM).ok();
std::thread::sleep(sleep_time);
killpg(pid, Signal::SIGKILL).ok();
})
);
*pid = None;
Ok(())
}
impl<W: Widget + Send + 'static> PartialEq for AsyncWidget<W> {
fn eq(&self, other: &AsyncWidget<W>) -> bool {
if self.get_coordinates().unwrap() ==
other.get_coordinates().unwrap() {
true
} else {
false
}
}
}
#[derive(Debug)]
pub struct AsyncWidget<W: Widget + Send + 'static> {
pub widget: Async<W>,
core: WidgetCore
}
impl<W: Widget + Send + 'static> AsyncWidget<W> {
pub fn new(core: &WidgetCore,
closure: impl FnOnce(&Stale) -> HResult<W> + Send + 'static)
-> AsyncWidget<W> {
let sender = Arc::new(Mutex::new(core.get_sender()));
let mut widget = Async::new(move |stale|
closure(stale).map_err(|e| e.into()));
widget.on_ready(move |_, stale| {
if !stale.is_stale()? {
sender.lock()
.send(crate::widget::Events::WidgetReady)
.map_err(HError::from)
.log();
}
Ok(())
}).log();
widget.run().log();
AsyncWidget {
widget: widget,
core: core.clone()
}
}
pub fn change_to(&mut self,
closure: impl FnOnce(&Stale,
WidgetCore)
-> HResult<W> + Send + 'static)
-> HResult<()> {
self.set_stale().log();
let sender = Mutex::new(self.get_core()?.get_sender());
let core = self.get_core()?.clone();
let mut widget = Async::new(move |stale| {
Ok(closure(stale, core.clone())?)
});
widget.on_ready(move |_, stale| {
if !stale.is_stale()? {
sender.lock()
.send(crate::widget::Events::WidgetReady)
.map_err(HError::from)
.log();
}
Ok(())
}).log();
widget.run().log();
self.widget = widget;
Ok(())
}
pub fn set_stale(&mut self) -> HResult<()> {
Ok(self.widget.set_stale()?)
}
pub fn is_stale(&self) -> HResult<bool> {
Ok(self.widget.is_stale()?)
}
pub fn get_stale(&self) -> Stale {
self.widget.get_stale()
}
pub fn widget(&self) -> HResult<&W> {
Ok(self.widget.get()?)
}
pub fn widget_mut(&mut self) -> HResult<&mut W> {
Ok(self.widget.get_mut()?)
}
pub fn take_widget(self) -> HResult<W> {
Ok(self.widget.value?)
}
pub fn ready(&self) -> bool {
self.widget().is_ok()
}
}
impl<T: Widget + Send + 'static> Widget for AsyncWidget<T> {
fn get_core(&self) -> HResult<&WidgetCore> {
Ok(&self.core)
}
fn get_core_mut(&mut self) -> HResult<&mut WidgetCore> {
Ok(&mut self.core)
}
fn set_coordinates(&mut self, coordinates: &Coordinates) -> HResult<()> {
self.core.coordinates = coordinates.clone();
if let Ok(widget) = self.widget_mut() {
widget.set_coordinates(&coordinates