mirror of
https://github.com/zed-industries/zed.git
synced 2025-02-12 05:27:07 +00:00
linux: clipboard (#8822)
Linux clipboard implementation with `copypasta`. Release Notes: - Added linux clipboard support
This commit is contained in:
parent
33ef5b7731
commit
996f1036fc
6 changed files with 216 additions and 9 deletions
158
Cargo.lock
generated
158
Cargo.lock
generated
|
@ -2141,6 +2141,16 @@ dependencies = [
|
|||
"util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clipboard-win"
|
||||
version = "3.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9fdf5e01086b6be750428ba4a40619f847eb2e95756eee84b18e06e5f0b50342"
|
||||
dependencies = [
|
||||
"lazy-bytes-cast",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clock"
|
||||
version = "0.1.0"
|
||||
|
@ -2490,6 +2500,20 @@ dependencies = [
|
|||
"zed_actions",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "copypasta"
|
||||
version = "0.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "deb85422867ca93da58b7f95fb5c0c10f6183ed6e1ef8841568968a896d3a858"
|
||||
dependencies = [
|
||||
"clipboard-win",
|
||||
"objc",
|
||||
"objc-foundation",
|
||||
"objc_id",
|
||||
"smithay-clipboard",
|
||||
"x11-clipboard",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation"
|
||||
version = "0.9.4"
|
||||
|
@ -4147,6 +4171,16 @@ dependencies = [
|
|||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gethostname"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0176e0459c2e4a1fe232f984bca6890e681076abb9934f6cea7c326f3fc47818"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-targets 0.48.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.1.16"
|
||||
|
@ -4325,6 +4359,7 @@ dependencies = [
|
|||
"cbindgen",
|
||||
"cocoa",
|
||||
"collections",
|
||||
"copypasta",
|
||||
"core-foundation",
|
||||
"core-graphics",
|
||||
"core-text",
|
||||
|
@ -5333,6 +5368,12 @@ dependencies = [
|
|||
"util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy-bytes-cast"
|
||||
version = "5.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "10257499f089cd156ad82d0a9cd57d9501fa2c989068992a97eb3c27836f206b"
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
|
@ -5733,6 +5774,15 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memmap2"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fe751422e4a8caa417e13c3ea66452215d7d63e19e604f4980461212f3ae1322"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memoffset"
|
||||
version = "0.7.1"
|
||||
|
@ -6376,6 +6426,17 @@ dependencies = [
|
|||
"objc_exception",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc-foundation"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9"
|
||||
dependencies = [
|
||||
"block",
|
||||
"objc",
|
||||
"objc_id",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc_exception"
|
||||
version = "0.1.2"
|
||||
|
@ -6385,6 +6446,15 @@ dependencies = [
|
|||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc_id"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b"
|
||||
dependencies = [
|
||||
"objc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.32.1"
|
||||
|
@ -8915,6 +8985,42 @@ version = "1.11.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a"
|
||||
|
||||
[[package]]
|
||||
name = "smithay-client-toolkit"
|
||||
version = "0.18.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "922fd3eeab3bd820d76537ce8f582b1cf951eceb5475c28500c7457d9d17f53a"
|
||||
dependencies = [
|
||||
"bitflags 2.4.2",
|
||||
"calloop",
|
||||
"calloop-wayland-source",
|
||||
"cursor-icon",
|
||||
"libc",
|
||||
"log",
|
||||
"memmap2 0.9.4",
|
||||
"rustix 0.38.30",
|
||||
"thiserror",
|
||||
"wayland-backend",
|
||||
"wayland-client",
|
||||
"wayland-csd-frame",
|
||||
"wayland-cursor",
|
||||
"wayland-protocols",
|
||||
"wayland-protocols-wlr",
|
||||
"wayland-scanner",
|
||||
"xkeysym",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smithay-clipboard"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c091e7354ea8059d6ad99eace06dd13ddeedbb0ac72d40a9a6e7ff790525882d"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"smithay-client-toolkit",
|
||||
"wayland-backend",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smol"
|
||||
version = "1.3.0"
|
||||
|
@ -11730,6 +11836,17 @@ dependencies = [
|
|||
"wayland-scanner",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wayland-csd-frame"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "625c5029dbd43d25e6aa9615e88b829a5cad13b2819c4ae129fdbb7c31ab4c7e"
|
||||
dependencies = [
|
||||
"bitflags 2.4.2",
|
||||
"cursor-icon",
|
||||
"wayland-backend",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wayland-cursor"
|
||||
version = "0.31.1"
|
||||
|
@ -11753,6 +11870,19 @@ dependencies = [
|
|||
"wayland-scanner",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wayland-protocols-wlr"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ad1f61b76b6c2d8742e10f9ba5c3737f6530b4c243132c2a2ccc8aa96fe25cd6"
|
||||
dependencies = [
|
||||
"bitflags 2.4.2",
|
||||
"wayland-backend",
|
||||
"wayland-client",
|
||||
"wayland-protocols",
|
||||
"wayland-scanner",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wayland-scanner"
|
||||
version = "0.31.1"
|
||||
|
@ -11772,6 +11902,7 @@ checksum = "15a0c8eaff5216d07f226cb7a549159267f3467b289d9a2e52fd3ef5aae2b7af"
|
|||
dependencies = [
|
||||
"dlib",
|
||||
"log",
|
||||
"once_cell",
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
|
@ -12417,6 +12548,33 @@ dependencies = [
|
|||
"tap",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "x11-clipboard"
|
||||
version = "0.9.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b98785a09322d7446e28a13203d2cae1059a0dd3dfb32cb06d0a225f023d8286"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"x11rb",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "x11rb"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8f25ead8c7e4cba123243a6367da5d3990e0d3affa708ea19dce96356bd9f1a"
|
||||
dependencies = [
|
||||
"gethostname",
|
||||
"rustix 0.38.30",
|
||||
"x11rb-protocol",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "x11rb-protocol"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e63e71c4b8bd9ffec2c963173a4dc4cbde9ee96961d4fcb4429db9929b606c34"
|
||||
|
||||
[[package]]
|
||||
name = "xattr"
|
||||
version = "0.2.3"
|
||||
|
|
|
@ -113,6 +113,7 @@ xkbcommon = { version = "0.7", features = ["wayland", "x11"] }
|
|||
as-raw-xcb-connection = "1"
|
||||
calloop = "0.12.4"
|
||||
calloop-wayland-source = "0.2.0"
|
||||
copypasta = "0.10.1"
|
||||
oo7 = "0.3.0"
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
|
||||
use copypasta::ClipboardProvider;
|
||||
|
||||
use crate::platform::PlatformWindow;
|
||||
use crate::{AnyWindowHandle, CursorStyle, DisplayId, PlatformDisplay, WindowOptions};
|
||||
|
||||
|
@ -12,4 +15,6 @@ pub trait Client {
|
|||
options: WindowOptions,
|
||||
) -> Box<dyn PlatformWindow>;
|
||||
fn set_cursor_style(&self, style: CursorStyle);
|
||||
fn get_clipboard(&self) -> Rc<RefCell<dyn ClipboardProvider>>;
|
||||
fn get_primary(&self) -> Rc<RefCell<dyn ClipboardProvider>>;
|
||||
}
|
||||
|
|
|
@ -354,12 +354,21 @@ impl Platform for LinuxPlatform {
|
|||
false
|
||||
}
|
||||
|
||||
// todo(linux)
|
||||
fn write_to_clipboard(&self, item: ClipboardItem) {}
|
||||
fn write_to_clipboard(&self, item: ClipboardItem) {
|
||||
let clipboard = self.client.get_clipboard();
|
||||
clipboard.borrow_mut().set_contents(item.text);
|
||||
}
|
||||
|
||||
// todo(linux)
|
||||
fn read_from_clipboard(&self) -> Option<ClipboardItem> {
|
||||
None
|
||||
let clipboard = self.client.get_clipboard();
|
||||
let contents = clipboard.borrow_mut().get_contents();
|
||||
match contents {
|
||||
Ok(text) => Some(ClipboardItem {
|
||||
metadata: None,
|
||||
text,
|
||||
}),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
//todo!(linux)
|
||||
|
@ -382,6 +391,8 @@ impl Platform for LinuxPlatform {
|
|||
})
|
||||
}
|
||||
|
||||
//todo!(linux): add trait methods for accessing the primary selection
|
||||
|
||||
//todo!(linux)
|
||||
fn read_credentials(&self, url: &str) -> Task<Result<Option<(String, Vec<u8>)>>> {
|
||||
let url = url.to_string();
|
||||
|
|
|
@ -6,6 +6,8 @@ use std::time::Duration;
|
|||
use calloop::timer::{TimeoutAction, Timer};
|
||||
use calloop::LoopHandle;
|
||||
use calloop_wayland_source::WaylandSource;
|
||||
use copypasta::wayland_clipboard::{create_clipboards_from_external, Clipboard, Primary};
|
||||
use copypasta::ClipboardProvider;
|
||||
use wayland_backend::client::ObjectId;
|
||||
use wayland_backend::protocol::WEnum;
|
||||
use wayland_client::globals::{registry_queue_init, GlobalListContents};
|
||||
|
@ -74,6 +76,8 @@ pub(crate) struct CursorState {
|
|||
pub(crate) struct WaylandClientState {
|
||||
client_state_inner: Rc<RefCell<WaylandClientStateInner>>,
|
||||
cursor_state: Rc<RefCell<CursorState>>,
|
||||
clipboard: Rc<RefCell<Clipboard>>,
|
||||
primary: Rc<RefCell<Primary>>,
|
||||
}
|
||||
|
||||
pub(crate) struct KeyRepeat {
|
||||
|
@ -111,6 +115,9 @@ impl WaylandClient {
|
|||
}
|
||||
});
|
||||
|
||||
let display = conn.backend().display_ptr() as *mut std::ffi::c_void;
|
||||
let (primary, clipboard) = unsafe { create_clipboards_from_external(display) };
|
||||
|
||||
let mut state_inner = Rc::new(RefCell::new(WaylandClientStateInner {
|
||||
compositor: globals.bind(&qh, 1..=1, ()).unwrap(),
|
||||
wm_base: globals.bind(&qh, 1..=1, ()).unwrap(),
|
||||
|
@ -152,20 +159,20 @@ impl WaylandClient {
|
|||
let mut state = WaylandClientState {
|
||||
client_state_inner: Rc::clone(&state_inner),
|
||||
cursor_state: Rc::clone(&cursor_state),
|
||||
clipboard: Rc::new(RefCell::new(clipboard)),
|
||||
primary: Rc::new(RefCell::new(primary)),
|
||||
};
|
||||
let mut state_loop = state.clone();
|
||||
linux_platform_inner
|
||||
.loop_handle
|
||||
.insert_source(source, move |_, queue, _| {
|
||||
queue.dispatch_pending(&mut state)
|
||||
queue.dispatch_pending(&mut state_loop)
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
Self {
|
||||
platform_inner: linux_platform_inner,
|
||||
state: WaylandClientState {
|
||||
client_state_inner: state_inner,
|
||||
cursor_state,
|
||||
},
|
||||
state,
|
||||
qh: Arc::new(qh),
|
||||
}
|
||||
}
|
||||
|
@ -265,6 +272,14 @@ impl Client for WaylandClient {
|
|||
let mut cursor_state = self.state.cursor_state.borrow_mut();
|
||||
cursor_state.cursor_icon_name = cursor_icon_name;
|
||||
}
|
||||
|
||||
fn get_clipboard(&self) -> Rc<RefCell<dyn ClipboardProvider>> {
|
||||
self.state.clipboard.clone()
|
||||
}
|
||||
|
||||
fn get_primary(&self) -> Rc<RefCell<dyn ClipboardProvider>> {
|
||||
self.state.primary.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl Dispatch<wl_registry::WlRegistry, GlobalListContents> for WaylandClientState {
|
||||
|
|
|
@ -6,6 +6,8 @@ use xcb::{x, Xid as _};
|
|||
use xkbcommon::xkb;
|
||||
|
||||
use collections::HashMap;
|
||||
use copypasta::x11_clipboard::{Clipboard, Primary, X11ClipboardContext};
|
||||
use copypasta::ClipboardProvider;
|
||||
|
||||
use crate::platform::linux::client::Client;
|
||||
use crate::platform::{LinuxPlatformInner, PlatformWindow};
|
||||
|
@ -28,6 +30,8 @@ struct WindowRef {
|
|||
struct X11ClientState {
|
||||
windows: HashMap<x::Window, WindowRef>,
|
||||
xkb: xkbcommon::xkb::State,
|
||||
clipboard: Rc<RefCell<X11ClipboardContext<Clipboard>>>,
|
||||
primary: Rc<RefCell<X11ClipboardContext<Primary>>>,
|
||||
}
|
||||
|
||||
pub(crate) struct X11Client {
|
||||
|
@ -70,6 +74,9 @@ impl X11Client {
|
|||
xkb::x11::state_new_from_device(&xkb_keymap, &xcb_connection, xkb_device_id)
|
||||
};
|
||||
|
||||
let clipboard = X11ClipboardContext::<Clipboard>::new().unwrap();
|
||||
let primary = X11ClipboardContext::<Primary>::new().unwrap();
|
||||
|
||||
let client: Rc<X11Client> = Rc::new(Self {
|
||||
platform_inner: inner.clone(),
|
||||
xcb_connection: Rc::clone(&xcb_connection),
|
||||
|
@ -78,6 +85,8 @@ impl X11Client {
|
|||
state: RefCell::new(X11ClientState {
|
||||
windows: HashMap::default(),
|
||||
xkb: xkb_state,
|
||||
clipboard: Rc::new(RefCell::new(clipboard)),
|
||||
primary: Rc::new(RefCell::new(primary)),
|
||||
}),
|
||||
});
|
||||
|
||||
|
@ -354,6 +363,14 @@ impl Client for X11Client {
|
|||
|
||||
//todo!(linux)
|
||||
fn set_cursor_style(&self, _style: CursorStyle) {}
|
||||
|
||||
fn get_clipboard(&self) -> Rc<RefCell<dyn ClipboardProvider>> {
|
||||
self.state.borrow().clipboard.clone()
|
||||
}
|
||||
|
||||
fn get_primary(&self) -> Rc<RefCell<dyn ClipboardProvider>> {
|
||||
self.state.borrow().primary.clone()
|
||||
}
|
||||
}
|
||||
|
||||
// Adatpted from:
|
||||
|
|
Loading…
Reference in a new issue