use std::error::Error as StdError;
use std::fmt;
use copypasta::x11_clipboard::{Clipboard, Selection, X11ClipboardContext};
use libc::fork;
use x11_clipboard::Clipboard as X11Clipboard;
use crate::display::DisplayServer;
use crate::prelude::*;
pub type ClipboardContext = X11ForkClipboardContext;
pub struct X11ForkClipboardContext<S = Clipboard>(X11ClipboardContext<S>)
where
S: Selection;
impl X11ForkClipboardContext {
pub fn new() -> crate::ClipResult<Self> {
Ok(Self(X11ClipboardContext::new()?))
}
}
impl<S> ClipboardProvider for X11ForkClipboardContext<S>
where
S: Selection,
{
fn get_contents(&mut self) -> crate::ClipResult<String> {
self.0.get_contents()
}
fn set_contents(&mut self, contents: String) -> crate::ClipResult<()> {
match unsafe { fork() } {
-1 => Err(Error::Fork.into()),
0 => {
let clip = X11Clipboard::new().expect("failed to obtain X11 clipboard context");
clip.store(
S::atom(&clip.setter.atoms),
clip.setter.atoms.utf8_string,
contents,
)
.expect("failed to set clipboard contents through forked process");
clip.load_wait(
S::atom(&clip.getter.atoms),
clip.getter.atoms.utf8_string,
clip.getter.atoms.property,
)
.expect("failed to wait on new clipboard value in forked process");
std::process::exit(0)
}
_pid => Ok(()),
}
}
}
impl<S> ClipboardProviderExt for X11ForkClipboardContext<S>
where
S: Selection,
{
fn display_server(&self) -> Option<DisplayServer> {
Some(DisplayServer::X11)
}
fn has_bin_lifetime(&self) -> bool {
false
}
}
#[derive(Debug)]
#[non_exhaustive]
pub enum Error {
Fork,
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Error::Fork => write!(f, "Failed to fork process to set clipboard"),
}
}
}
impl StdError for Error {
fn source(&self) -> Option<&(dyn StdError + 'static)> {
match self {
Error::Fork => None,
}
}
}