Merge pull request #1243 from SusieeTheLinuxUser/fix/1239-wayland-clipboard

UI: Route text clipboard writes through egui (#1239)
This commit is contained in:
BFlat
2026-10-26 10:25:41 +07:00
committed by GitHub
4 changed files with 38 additions and 7 deletions
+3 -2
View File
@@ -269,14 +269,15 @@ fn main() -> eframe::Result {
let result = eframe::run_native(
"FigCraft",
options,
Box::new(move |_cc| {
Box::new(move |cc| {
with_app(|fig| fig.services.set_egui_context(&cc.egui_ctx));
Ok(Box::new(App {
queue,
ctx_slot,
title: String::new(),
recovery,
#[cfg(target_os = "macos")]
apple_events: apple_events.connect(&_cc.egui_ctx),
apple_events: apple_events.connect(&cc.egui_ctx),
}))
}),
);
+7 -2
View File
@@ -11,6 +11,7 @@ use serde_json::{Value, json};
pub struct Desktop {
clipboard: Option<arboard::Clipboard>,
egui_ctx: Option<egui::Context>,
/// Where the preferences live ([`config_dir`]).
dir: Option<PathBuf>,
pub prefs: Option<Prefs>,
@@ -61,6 +62,7 @@ impl Desktop {
let dark = Arc::new(AtomicU8::new(DARK_UNKNOWN));
Self {
clipboard: arboard::Clipboard::new().ok(),
egui_ctx: None,
dir,
prefs,
reduce_motion,
@@ -409,10 +411,13 @@ impl Services for Desktop {
remembering(self.last_folder.clone(), pick, true)
}
fn clipboard_set_text(&mut self, s: &str) {
if let Some(c) = self.clipboard.as_mut() {
let _ = c.set_text(s.to_string());
if let Some(ctx) = &self.egui_ctx {
ctx.copy_text(s.to_string());
}
}
fn set_egui_context(&mut self, ctx: &egui::Context) {
self.egui_ctx = Some(ctx.clone());
}
fn clipboard_get_text(&mut self) -> Option<String> {
read_clipboard(self.clipboard.as_mut()?, |c| c.get_text().ok())
}
+4 -3
View File
@@ -288,6 +288,8 @@ pub trait Services {
Box::pin(std::future::ready(None))
}
fn clipboard_set_text(&mut self, _s: &str) {}
/// Give native services access to the window context for platform clipboard output.
fn set_egui_context(&mut self, _ctx: &egui::Context) {}
fn clipboard_get_text(&mut self) -> Option<String> {
None
}
@@ -408,9 +410,8 @@ impl Wake for RepaintWaker {
pub struct NoServices;
impl Services for NoServices {}
/// Put `text` on the system clipboard through egui's output, which the browser shell writes while
/// it handles the copy event (the only time a page may write it). For shells without a clipboard
/// of their own.
/// Put `text` on the system clipboard through egui's platform output. Native integrations handle
/// it directly; the browser shell writes it while handling the copy event.
pub fn egui_copy_text(ctx: &egui::Context, text: &str) {
ctx.copy_text(text.to_string());
}
+24
View File
@@ -59,6 +59,30 @@ fn enter_edits_a_selected_text_with_all_of_it_selected_and_escape_keeps_the_laye
assert!(u.app.session.selection().is_empty());
}
#[test]
fn copying_and_cutting_selected_text_use_clipboard_service() {
use std::{cell::RefCell, rc::Rc};
struct Clipboard(Rc<RefCell<Vec<String>>>);
impl crate::Services for Clipboard {
fn clipboard_set_text(&mut self, text: &str) {
self.0.borrow_mut().push(text.to_string());
}
}
let mut s = Session::new();
let t = NodeId(s.execute("text.create", &json!({"text": "Hello world", "x": 20, "y": 20})).unwrap()["id"].as_u64().unwrap());
s.execute("select.set", &json!({"ids": [t]})).unwrap();
let mut u = Ui::new(s);
let copied = Rc::new(RefCell::new(Vec::new()));
u.app.services = Box::new(Clipboard(copied.clone()));
press(&mut u, Key::Enter);
u.frame_output(vec![Event::Copy]);
u.frame_output(vec![Event::Cut]);
assert_eq!(&*copied.borrow(), &["Hello world", "Hello world"]);
assert_eq!(u.app.session.doc().unwrap().node(t).unwrap().kind.text().unwrap().characters, "");
}
#[test]
fn a_new_file_takes_the_page_colour_of_the_theme_and_keeps_it() {
let mut s = Session::new();