mirror of
https://github.com/rustdesk/rustdesk.git
synced 2024-11-24 04:12:20 +08:00
patch(0): implement cliprdr for macos
Signed-off-by: ClSlaid <cailue@bupt.edu.cn>
This commit is contained in:
parent
f6a137cd43
commit
2bb1310094
@ -18,12 +18,17 @@ hbb_common = { path = "../hbb_common" }
|
|||||||
parking_lot = {version = "0.12"}
|
parking_lot = {version = "0.12"}
|
||||||
|
|
||||||
[target.'cfg(any(target_os = "linux", target_os = "macos"))'.dependencies]
|
[target.'cfg(any(target_os = "linux", target_os = "macos"))'.dependencies]
|
||||||
once_cell = "1.18"
|
|
||||||
x11rb = {version = "0.12", features = ["all-extensions"]}
|
|
||||||
rand = {version = "0.8"}
|
rand = {version = "0.8"}
|
||||||
fuser = {version = "0.13"}
|
fuser = {version = "0.13"}
|
||||||
libc = {version = "0.2"}
|
libc = {version = "0.2"}
|
||||||
dashmap = "5.5"
|
dashmap = "5.5"
|
||||||
percent-encoding = "2.3"
|
percent-encoding = "2.3"
|
||||||
utf16string = "0.2"
|
utf16string = "0.2"
|
||||||
|
|
||||||
|
[target.'cfg(target_os = "linux")'.dependencies]
|
||||||
x11-clipboard = {git="https://github.com/clslaid/x11-clipboard", branch = "feat/store-batch"}
|
x11-clipboard = {git="https://github.com/clslaid/x11-clipboard", branch = "feat/store-batch"}
|
||||||
|
once_cell = "1.18"
|
||||||
|
x11rb = {version = "0.12", features = ["all-extensions"]}
|
||||||
|
|
||||||
|
[target.'cfg(target_os = "macos")'.dependencies]
|
||||||
|
cacao = {git="https://github.com/clslaid/cacao", branch = "feat/set-file-urls"}
|
||||||
|
@ -1,13 +1,9 @@
|
|||||||
|
#[cfg(target_os = "windows")]
|
||||||
fn build_c_impl() {
|
fn build_c_impl() {
|
||||||
#[cfg(not(target_os = "linux"))]
|
|
||||||
let mut build = cc::Build::new();
|
let mut build = cc::Build::new();
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
|
||||||
build.file("src/windows/wf_cliprdr.c");
|
build.file("src/windows/wf_cliprdr.c");
|
||||||
#[cfg(target_os = "macos")]
|
|
||||||
build.file("src/OSX/Clipboard.m");
|
|
||||||
|
|
||||||
#[cfg(not(target_os = "linux"))]
|
|
||||||
{
|
{
|
||||||
build.flag_if_supported("-Wno-c++0x-extensions");
|
build.flag_if_supported("-Wno-c++0x-extensions");
|
||||||
build.flag_if_supported("-Wno-return-type-c-linkage");
|
build.flag_if_supported("-Wno-return-type-c-linkage");
|
||||||
@ -30,12 +26,10 @@ fn build_c_impl() {
|
|||||||
build.compile("mycliprdr");
|
build.compile("mycliprdr");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
|
||||||
println!("cargo:rerun-if-changed=src/windows/wf_cliprdr.c");
|
println!("cargo:rerun-if-changed=src/windows/wf_cliprdr.c");
|
||||||
#[cfg(target_os = "macos")]
|
|
||||||
println!("cargo:rerun-if-changed=src/OSX/Clipboard.m");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
build_c_impl();
|
build_c_impl();
|
||||||
}
|
}
|
||||||
|
@ -1,11 +0,0 @@
|
|||||||
#include "../cliprdr.h"
|
|
||||||
|
|
||||||
void mac_cliprdr_init(CliprdrClientContext *cliprdr)
|
|
||||||
{
|
|
||||||
(void)cliprdr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void mac_cliprdr_uninit(CliprdrClientContext *cliprdr)
|
|
||||||
{
|
|
||||||
(void)cliprdr;
|
|
||||||
}
|
|
@ -19,7 +19,7 @@ pub fn create_cliprdr_context(
|
|||||||
pub mod fuse;
|
pub mod fuse;
|
||||||
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||||
pub mod unix;
|
pub mod unix;
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||||
pub fn create_cliprdr_context(
|
pub fn create_cliprdr_context(
|
||||||
enable_files: bool,
|
enable_files: bool,
|
||||||
_enable_others: bool,
|
_enable_others: bool,
|
||||||
@ -48,11 +48,11 @@ pub fn create_cliprdr_context(
|
|||||||
log::warn!("umount {:?} may fail: {:?}", mnt_path, e);
|
log::warn!("umount {:?} may fail: {:?}", mnt_path, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
let linux_ctx = unix::ClipboardContext::new(timeout, mnt_path.parse().unwrap())?;
|
let unix_ctx = unix::ClipboardContext::new(timeout, mnt_path.parse().unwrap())?;
|
||||||
log::debug!("start cliprdr FUSE");
|
log::debug!("start cliprdr FUSE");
|
||||||
linux_ctx.run().expect("failed to start cliprdr FUSE");
|
unix_ctx.run().expect("failed to start cliprdr FUSE");
|
||||||
|
|
||||||
Ok(Box::new(linux_ctx) as Box<_>)
|
Ok(Box::new(unix_ctx) as Box<_>)
|
||||||
}
|
}
|
||||||
|
|
||||||
struct DummyCliprdrContext {}
|
struct DummyCliprdrContext {}
|
||||||
|
@ -24,8 +24,14 @@ use self::url::{encode_path_to_uri, parse_plain_uri_list};
|
|||||||
use super::fuse::FuseServer;
|
use super::fuse::FuseServer;
|
||||||
|
|
||||||
#[cfg(not(feature = "wayland"))]
|
#[cfg(not(feature = "wayland"))]
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
/// clipboard implementation of x11
|
||||||
pub mod x11;
|
pub mod x11;
|
||||||
|
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
/// clipboard implementation of macos
|
||||||
|
pub mod ns_clipboard;
|
||||||
|
|
||||||
pub mod local_file;
|
pub mod local_file;
|
||||||
pub mod url;
|
pub mod url;
|
||||||
|
|
||||||
@ -66,6 +72,7 @@ trait SysClipboard: Send + Sync {
|
|||||||
fn get_file_list(&self) -> Vec<PathBuf>;
|
fn get_file_list(&self) -> Vec<PathBuf>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
fn get_sys_clipboard(ignore_path: &PathBuf) -> Result<Box<dyn SysClipboard>, CliprdrError> {
|
fn get_sys_clipboard(ignore_path: &PathBuf) -> Result<Box<dyn SysClipboard>, CliprdrError> {
|
||||||
#[cfg(feature = "wayland")]
|
#[cfg(feature = "wayland")]
|
||||||
{
|
{
|
||||||
@ -73,12 +80,19 @@ fn get_sys_clipboard(ignore_path: &PathBuf) -> Result<Box<dyn SysClipboard>, Cli
|
|||||||
}
|
}
|
||||||
#[cfg(not(feature = "wayland"))]
|
#[cfg(not(feature = "wayland"))]
|
||||||
{
|
{
|
||||||
pub use x11::*;
|
use x11::*;
|
||||||
let x11_clip = X11Clipboard::new(ignore_path)?;
|
let x11_clip = X11Clipboard::new(ignore_path)?;
|
||||||
Ok(Box::new(x11_clip) as Box<_>)
|
Ok(Box::new(x11_clip) as Box<_>)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
fn get_sys_clipboard(ignore_path: &PathBuf) -> Result<Box<dyn SysClipboard>, CliprdrError> {
|
||||||
|
use ns_clipboard::*;
|
||||||
|
let ns_pb = NSPasteboard::new(ignore_path)?;
|
||||||
|
Ok(Box::new(ns_pb) as Box<_>)
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum FileContentsRequest {
|
enum FileContentsRequest {
|
||||||
Size {
|
Size {
|
||||||
|
113
libs/clipboard/src/platform/unix/ns_clipboard.rs
Normal file
113
libs/clipboard/src/platform/unix/ns_clipboard.rs
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
use std::{
|
||||||
|
collections::BTreeSet,
|
||||||
|
path::PathBuf,
|
||||||
|
sync::atomic::{AtomicBool, Ordering},
|
||||||
|
};
|
||||||
|
|
||||||
|
use cacao::pasteboard::{Pasteboard, PasteboardName};
|
||||||
|
use parking_lot::Mutex;
|
||||||
|
|
||||||
|
use crate::{platform::unix::send_format_list, CliprdrError};
|
||||||
|
|
||||||
|
use super::SysClipboard;
|
||||||
|
|
||||||
|
pub struct NsPasteboard {
|
||||||
|
stopped: AtomicBool,
|
||||||
|
pasteboard: Pasteboard,
|
||||||
|
ignore_path: PathBuf,
|
||||||
|
|
||||||
|
former_file_list: Mutex<Vec<PathBuf>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NsPasteboard {
|
||||||
|
pub fn new(ignore_path: &PathBuf) -> Result<Self, CliprdrError> {
|
||||||
|
let pasteboard = Pasteboard::named(PasteboardName::General);
|
||||||
|
Ok(Self {
|
||||||
|
stopped: AtomicBool::new(false),
|
||||||
|
ignore_path: ignore_path.to_owned(),
|
||||||
|
pasteboard,
|
||||||
|
former_file_list: Mutex::new(vec![]),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn wait_file_list(&self) -> Option<Vec<PathBuf>> {
|
||||||
|
self.pasteboard
|
||||||
|
.get_file_urls()
|
||||||
|
.ok()
|
||||||
|
.map(|v| v.into_iter().map(|nsurl| nsurl.to_path_buf()).collect())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn is_stopped(&self) -> bool {
|
||||||
|
self.stopped.load(Ordering::Relaxed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SysClipboard for NsPasteboard {
|
||||||
|
fn set_file_list(&self, paths: &[PathBuf]) -> Result<(), CliprdrError> {
|
||||||
|
*self.former_file_list.lock() = paths.to_vec();
|
||||||
|
let uri_list: Vec<String> = paths.iter().map(encode_path_to_uri).collect();
|
||||||
|
let uri_list = uri_list.join("\n");
|
||||||
|
let uri_list = uri_list.as_bytes().to_vec();
|
||||||
|
self.pasteboard
|
||||||
|
.set_file_urls(uri_list)
|
||||||
|
.map_err(|_| CliprdrError::ClipboardInternalError)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn start(&self) {
|
||||||
|
self.stopped.store(false, Ordering::Relaxed);
|
||||||
|
|
||||||
|
loop {
|
||||||
|
if self.is_stopped() {
|
||||||
|
std::thread::sleep(std::time::Duration::from_millis(100));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let file_list = match self.wait_file_list() {
|
||||||
|
Some(v) => v,
|
||||||
|
None => {
|
||||||
|
std::thread::sleep(std::time::Duration::from_millis(100));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let filtered = paths
|
||||||
|
.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 stop(&self) {
|
||||||
|
self.stopped.store(true, Ordering::Relaxed);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_file_list(&self) -> Vec<PathBuf> {
|
||||||
|
self.former_file_list.lock().clone()
|
||||||
|
}
|
||||||
|
}
|
@ -122,6 +122,11 @@ impl SysClipboard for X11Clipboard {
|
|||||||
self.stop.store(false, Ordering::Relaxed);
|
self.stop.store(false, Ordering::Relaxed);
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
|
if self.is_stopped() {
|
||||||
|
std::thread::sleep(std::time::Duration::from_millis(100));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
let sth = match self.wait_file_list() {
|
let sth = match self.wait_file_list() {
|
||||||
Ok(sth) => sth,
|
Ok(sth) => sth,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
@ -131,11 +136,6 @@ impl SysClipboard for X11Clipboard {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if self.is_stopped() {
|
|
||||||
std::thread::sleep(std::time::Duration::from_millis(100));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let Some(paths) = sth else {
|
let Some(paths) = sth else {
|
||||||
// just sleep
|
// just sleep
|
||||||
std::thread::sleep(std::time::Duration::from_millis(100));
|
std::thread::sleep(std::time::Duration::from_millis(100));
|
||||||
|
Loading…
Reference in New Issue
Block a user