pub struct DetachedHandoff<Msg> { /* private fields */ }Expand description
Hands the terminal to a program until it writes its first line on standard output, then
takes the screen back and leaves the program running in the background as a LiveChild.
Everything up to the first line is a Handoff: the screen is released,
the notice printed, the program gets a process group of its own that is the terminal’s
foreground, so it can ask on the terminal and the keys’ signals (Ctrl-C at a password
prompt) reach it and not the application. Unlike a handoff the program’s standard input and
output are pipes to the application; only its standard error is the terminal. pkexec
and sudo ask on the controlling terminal itself, not on standard input, so they still can.
The first line is the program saying it is ready: the terminal’s foreground goes back to the
application, the screen is taken back and drawn again in full, and
DetachedOutcome::Detached arrives with the child and that line. Every later line arrives
through DetachedHandoff::on_line, and ChildLine::Ended after the last.
A program that ends before its first line, such as pkexec after a cancelled or wrong
password (codes 126 and 127), gives DetachedOutcome::Finished as a handoff would.
use qframe::prelude::*;
use qframe::runtime::{ChildLine, DetachedHandoff, DetachedOutcome, LiveChild};
enum Msg {
Start,
Started(DetachedOutcome),
Helper(ChildLine),
}
fn update(helper: &mut Option<LiveChild>, msg: Msg) -> Command<Msg> {
match msg {
// The helper asks for the password through pkexec, then prints `ready` and serves
// one request per line until its input ends.
Msg::Start => Command::handoff_detached(
DetachedHandoff::new("pkexec", Msg::Started)
.args(["/usr/lib/example/helper", "--serve"])
.notice("Asking for permission to manage packages…")
.on_line(Msg::Helper),
),
Msg::Started(DetachedOutcome::Detached { child, first_line: _ }) => {
let _ = child.write_line("list-updates");
*helper = Some(child);
Command::none()
}
Msg::Started(_) | Msg::Helper(_) => Command::none(),
}
}Implementations§
Source§impl<Msg: Send + 'static> DetachedHandoff<Msg>
impl<Msg: Send + 'static> DetachedHandoff<Msg>
Sourcepub fn new(
program: impl Into<OsString>,
on_start: impl FnOnce(DetachedOutcome) -> Msg + Send + 'static,
) -> Self
pub fn new( program: impl Into<OsString>, on_start: impl FnOnce(DetachedOutcome) -> Msg + Send + 'static, ) -> Self
Runs program, delivering on_start(outcome) once the application has the screen back:
after the program’s first line, or after its end when it wrote none.
Sourcepub fn args(self, args: impl IntoIterator<Item = impl Into<OsString>>) -> Self
pub fn args(self, args: impl IntoIterator<Item = impl Into<OsString>>) -> Self
Adds several arguments, in order.
Sourcepub fn dir(self, dir: impl Into<PathBuf>) -> Self
pub fn dir(self, dir: impl Into<PathBuf>) -> Self
Runs the program in dir instead of the application’s working directory.
Sourcepub fn env(self, key: impl Into<OsString>, value: impl Into<OsString>) -> Self
pub fn env(self, key: impl Into<OsString>, value: impl Into<OsString>) -> Self
Sets an environment variable for the program. The rest of the environment is inherited.
Sourcepub fn notice(self, text: impl Into<String>) -> Self
pub fn notice(self, text: impl Into<String>) -> Self
A line printed on the cleared screen before the program starts, so the user knows why the application stepped aside.
Sourcepub fn pause(self, pause: bool) -> Self
pub fn pause(self, pause: bool) -> Self
Waits for a key press when the program ends without a first line, so what it wrote on the terminal — why a password was refused — can be read. A program that detaches never waits for it. Off by default.
Sourcepub fn on_line(
self,
message: impl Fn(ChildLine) -> Msg + Send + Sync + 'static,
) -> Self
pub fn on_line( self, message: impl Fn(ChildLine) -> Msg + Send + Sync + 'static, ) -> Self
Turns the program’s later output into messages: each line after the first as
ChildLine::Line, then ChildLine::Ended once its output closed and it ended. The
lines keep coming for the program’s whole life, however long after the handoff.
Without it the output is read and dropped.
Auto Trait Implementations§
impl<Msg> !RefUnwindSafe for DetachedHandoff<Msg>
impl<Msg> !Sync for DetachedHandoff<Msg>
impl<Msg> !UnwindSafe for DetachedHandoff<Msg>
impl<Msg> Freeze for DetachedHandoff<Msg>
impl<Msg> Send for DetachedHandoff<Msg>
impl<Msg> Unpin for DetachedHandoff<Msg>
impl<Msg> UnsafeUnpin for DetachedHandoff<Msg>where
Box<dyn FnOnce(DetachedOutcome) -> Msg + Send>: UnsafeUnpin,
Option<Arc<dyn Fn(ChildLine) -> Msg + Send + Sync>>: UnsafeUnpin,
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more