linux: clipboard (#8822)

Linux clipboard implementation with `copypasta`.


Release Notes:

- Added linux clipboard support
This commit is contained in:
Rom Grk 2024-03-04 11:00:24 -05:00 committed by GitHub
parent 33ef5b7731
commit 996f1036fc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 216 additions and 9 deletions

View file

@ -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>>;
}

View file

@ -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();

View file

@ -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 {

View file

@ -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: