ClSlaid 62563ad8a1
Merge branch 'feat/x11/clipboard-file/init' into feat/osx/clipboard-file
Signed-off-by: ClSlaid <cailue@bupt.edu.cn>
2023-10-30 15:34:40 +08:00

98 lines
2.7 KiB
Rust

use std::{collections::BTreeSet, path::PathBuf};
use cacao::pasteboard::{Pasteboard, PasteboardName};
use hbb_common::log;
use parking_lot::Mutex;
use crate::{platform::unix::send_format_list, CliprdrError};
use super::SysClipboard;
#[inline]
fn wait_file_list() -> Option<Vec<PathBuf>> {
let pb = Pasteboard::named(PasteboardName::General);
pb.get_file_urls()
.ok()
.map(|v| v.into_iter().map(|nsurl| nsurl.pathbuf()).collect())
}
#[inline]
fn set_file_list(file_list: &[PathBuf]) -> Result<(), CliprdrError> {
let pb = Pasteboard::named(PasteboardName::General);
pb.set_files(file_list.to_vec())
.map_err(|_| CliprdrError::ClipboardInternalError)
}
pub struct NsPasteboard {
ignore_path: PathBuf,
former_file_list: Mutex<Vec<PathBuf>>,
}
impl NsPasteboard {
pub fn new(ignore_path: &PathBuf) -> Result<Self, CliprdrError> {
Ok(Self {
ignore_path: ignore_path.to_owned(),
former_file_list: Mutex::new(vec![]),
})
}
}
impl SysClipboard for NsPasteboard {
fn set_file_list(&self, paths: &[PathBuf]) -> Result<(), CliprdrError> {
*self.former_file_list.lock() = paths.to_vec();
set_file_list(paths)
}
fn start(&self) {
{
*self.former_file_list.lock() = vec![];
}
loop {
let file_list = match wait_file_list() {
Some(v) => v,
None => {
std::thread::sleep(std::time::Duration::from_millis(100));
continue;
}
};
let filtered = file_list
.into_iter()
.filter(|pb| !pb.starts_with(&self.ignore_path))
.collect::<Vec<_>>();
if filtered.is_empty() {
std::thread::sleep(std::time::Duration::from_millis(100));
continue;
}
{
let mut former = self.former_file_list.lock();
let filtered_st: BTreeSet<_> = filtered.iter().collect();
let former_st = former.iter().collect::<BTreeSet<_>>();
if filtered_st == former_st {
std::thread::sleep(std::time::Duration::from_millis(100));
continue;
}
*former = filtered;
}
if let Err(e) = send_format_list(0) {
log::warn!("failed to send format list: {}", e);
break;
}
std::thread::sleep(std::time::Duration::from_millis(100));
}
log::debug!("stop listening file related atoms on clipboard");
}
fn get_file_list(&self) -> Vec<PathBuf> {
self.former_file_list.lock().clone()
}
}