summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrabite <rabite@posteo.de>2020-02-14 18:44:54 +0100
committerrabite <rabite@posteo.de>2020-02-14 23:41:40 +0100
commitd143de245a4deebabbdad49f4f69a8c82537b958 (patch)
tree72e4bda68df3186b8aa316d25ca3a82ab1092158
parentcab23957ce69987aa6d9ef9c87e1603cd901b2e6 (diff)
kill media-previewer when image is deselected before it's done
-rw-r--r--src/fail.rs6
-rw-r--r--src/imgview.rs79
-rw-r--r--src/mediaview.rs12
-rw-r--r--src/preview.rs7
4 files changed, 81 insertions, 23 deletions
diff --git a/src/fail.rs b/src/fail.rs
index cf5acab..4e793ac 100644
--- a/src/fail.rs
+++ b/src/fail.rs
@@ -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![]);
diff --git a/src/imgview.rs b/src/imgview.rs
index 8674a5b..6143add 100644
--- a/src/imgview.rs
+++ b/src/imgview.rs
@@ -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 crate::fail::{HResult, ErrorCause};
+use crate::mediaview::MediaError;
-use std::path::{Path, PathBuf};
-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 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 output = std::str::from_utf8(&output)?;
- let output = output.lines()
- .map(|l| l.to_string())
- .collect();
+ 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);
+ }
}
diff --git a/src/mediaview.rs b/src/mediaview.rs
index 8fb773a..e1dd7de 100644
--- a/src/mediaview.rs
+++ b/src/mediaview.rs
@@ -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();
diff --git a/src/preview.rs b/src/preview.rs
index 2f1eebf..b31ee7c 100644
--- a/src/preview.rs
+++ b/src/preview.rs
@@ -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;