kill media-previewer when image is deselected before it's done

This commit is contained in:
rabite 2020-02-14 18:44:54 +01:00
parent cab23957ce
commit d143de245a
4 changed files with 82 additions and 24 deletions

View File

@ -185,6 +185,12 @@ impl HError {
}
#[derive(Fail, Debug, Clone)]
pub enum ErrorCause {
#[fail(display = "{}", _0)]
Str(String)
}
lazy_static! {
static ref LOG: Mutex<Vec<LogEntry>> = Mutex::new(vec![]);

View File

@ -1,22 +1,25 @@
use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};
use std::io::{BufReader, BufRead};
use std::sync::atomic::{AtomicU32, Ordering};
use crate::widget::{Widget, WidgetCore};
use crate::coordinates::Coordinates;
use crate::fail::HResult;
use std::path::{Path, PathBuf};
use crate::fail::{HResult, ErrorCause};
use crate::mediaview::MediaError;
impl std::cmp::PartialEq for ImgView {
fn eq(&self, other: &Self) -> bool {
self.core == other.core &&
self.buffer == other.buffer
}
lazy_static! {
static ref PID: AtomicU32 = AtomicU32::new(0);
}
#[derive(Derivative)]
#[derivative(PartialEq)]
pub struct ImgView {
pub core: WidgetCore,
pub buffer: Vec<String>,
pub file: Option<PathBuf>
pub file: Option<PathBuf>,
}
impl ImgView {
@ -24,7 +27,7 @@ impl ImgView {
let mut view = ImgView {
core: core,
buffer: vec![],
file: Some(file.to_path_buf())
file: Some(file.to_path_buf()),
};
view.encode_file()?;
@ -40,7 +43,7 @@ impl ImgView {
let media_previewer = self.core.config().media_previewer;
let g_mode = self.core.config().graphics;
let output = std::process::Command::new(&media_previewer)
let mut previewer = Command::new(&media_previewer)
.arg(format!("{}", (xsize+1)))
.arg(format!("{}", (ysize+1)))
.arg(format!("{}", xpix))
@ -51,7 +54,10 @@ impl ImgView {
.arg(format!("true"))
.arg(format!("{}", g_mode))
.arg(file.to_string_lossy().to_string())
.output()
.stdin(Stdio::null())
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
.map_err(|e| {
let msg = format!("Couldn't run {}{}{}! Error: {:?}",
crate::term::color_red(),
@ -62,14 +68,37 @@ impl ImgView {
self.core.show_status(&msg).ok();
MediaError::NoPreviewer(msg)
})?
.stdout;
})?;
PID.store(previewer.id(), Ordering::Relaxed);
let output = std::str::from_utf8(&output)?;
let output = output.lines()
.map(|l| l.to_string())
.collect();
let stdout = previewer.stdout
.take()
.unwrap();
let output = BufReader::new(stdout)
.lines()
.collect::<Result<Vec<String>, _>>()?;
let stderr = previewer.stderr
.take()
.unwrap();
let stderr = BufReader::new(stderr)
.lines()
.collect::<Result<String, _>>()?;
let status = previewer.wait()?;
PID.store(0, Ordering::Relaxed);
if !status.success() {
match status.code() {
Some(code) => Err(MediaError::MediaViewerFailed(code,
ErrorCause::Str(stderr)))?,
None => Err(MediaError::MediaViewerKilled)?
}
}
self.buffer = output;
@ -83,6 +112,20 @@ impl ImgView {
pub fn lines(&self) -> usize {
self.buffer.len()
}
pub fn kill_running() {
use nix::{unistd::Pid,
sys::signal::{kill, Signal}};
let pid = PID.load(Ordering::Relaxed);
if pid == 0 { return; }
let pid = Pid::from_raw(pid as i32);
kill(pid, Signal::SIGTERM).ok();
PID.store(0, Ordering::Relaxed);
}
}

View File

@ -5,7 +5,7 @@ use failure::{self, Fail};
use crate::widget::{Widget, WidgetCore};
use crate::coordinates::Coordinates;
use crate::async_value::Stale;
use crate::fail::{HResult, HError, ErrorLog};
use crate::fail::{HResult, HError, ErrorLog, ErrorCause};
use crate::imgview::ImgView;
use std::path::{Path, PathBuf};
@ -18,7 +18,13 @@ use std::process::Child;
#[derive(Fail, Debug, Clone)]
pub enum MediaError {
#[fail(display = "{}", _0)]
NoPreviewer(String)
NoPreviewer(String),
#[fail(display = "No output could be read from {}", _0)]
NoOutput(String),
#[fail(display = "Media viewer exited with status code: {}", _0)]
MediaViewerFailed(i32, #[cause] ErrorCause),
#[fail(display = "Media viewer killed!")]
MediaViewerKilled,
}
impl From<MediaError> for HError {
@ -80,7 +86,7 @@ impl MediaView {
let imgview = ImgView {
core: core.clone(),
buffer: vec![],
file: None
file: None,
};
let (tx_cmd, rx_cmd) = channel();

View File

@ -23,6 +23,9 @@ lazy_static! {
}
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
@ -34,9 +37,9 @@ fn kill_proc() -> HResult<()> {
// Kill using process group, to clean up all child processes, too
let pid = Pid::from_raw(pid as i32);
killpg(pid, Signal::SIGTERM).log();
killpg(pid, Signal::SIGTERM).ok();
std::thread::sleep(sleep_time);
killpg(pid, Signal::SIGKILL).log();
killpg(pid, Signal::SIGKILL).ok();
})
);
*pid = None;