use crate::api::ImageData;
use anyhow::Result;
const MAX_IMAGE_BYTES: usize = 5 * 1024 * 1024;
pub struct Clipboard {
#[cfg(not(target_os = "linux"))]
inner: arboard::Clipboard,
}
impl Clipboard {
pub fn new() -> Result<Self> {
Ok(Self {
#[cfg(not(target_os = "linux"))]
inner: arboard::Clipboard::new()?,
})
}
pub fn get_text(&mut self) -> Result<Option<String>> {
#[cfg(not(target_os = "linux"))]
{
match self.inner.get_text() {
Ok(text) => Ok(Some(text)),
Err(arboard::Error::ContentNotAvailable) => Ok(None),
Err(e) => Err(anyhow::anyhow!("Clipboard error: {}", e)),
}
}
#[cfg(target_os = "linux")]
{
Ok(get_text_linux())
}
}
pub fn get_image(&mut self) -> Result<Option<ImageData>> {
#[cfg(not(target_os = "linux"))]
{
match self.inner.get_image() {
Ok(img) => {
let bytes = img.bytes.into_owned();
if bytes.len() > MAX_IMAGE_BYTES {
return Err(anyhow::anyhow!(
"Clipboard image too large: {} bytes (max {}MB)",
bytes.len(),
MAX_IMAGE_BYTES / 1024 / 1024
));
}
Ok(Some(ImageData::new(bytes)))
}
Err(arboard::Error::ContentNotAvailable) => Ok(None),
Err(e) => Err(anyhow::anyhow!("Clipboard error: {}", e)),
}
}
#[cfg(target_os = "linux")]
{
Ok(get_image_linux())
}
}
pub fn has_image(&mut self) -> bool {
self.get_image().ok().flatten().is_some()
}
}
#[cfg(target_os = "linux")]
fn get_text_linux() -> Option<String> {
if let Ok(output) = std::process::Command::new("wl-paste").output() {
if output.status.success() {
return Some(String::from_utf8_lossy(&output.stdout).to_string());
}
}
if let Ok(output) = std::process::Command::new("xclip")
.args(["-selection", "clipboard", "-o"])
.output()
{
if output.status.success() {
return Some(String::from_utf8_lossy(&output.stdout).to_string());
}
}
None
}
#[cfg(target_os = "linux")]
fn get_image_linux() -> Option<ImageData> {
if let Ok(output) = std::process::Command::new("wl-paste")
.args(["--type", "image/png"])
.output()
{
if output.status.success() && !output.stdout.is_empty() {
if output.stdout.len() <= MAX_IMAGE_BYTES {
return Some(ImageData::new(output.stdout));
}
}
}
if let Ok(output) = std::process::Command::new("xclip")
.args(["-selection", "clipboard", "-t", "image/png", "-o"])
.output()
{
if output.status.success() && !output.stdout.is_empty() {
if output.stdout.len() <= MAX_IMAGE_BYTES {
return Some(ImageData::new(output.stdout));
}
}
}
None
}