Skip to content

Commit 308f8a4

Browse files
committed
Fix clipboard on Wayland
arboard advertises that it works with Wayland, but in reality it only works with Wayland terminal applications. To make the clipboard work with applications that draw Wayland surfaces, arboard isn't going to work. Copypasta does support Wayland's graphical clipboard, but the usage isn't documented. However, for the reasons mentioned in #1474 the move from Copypasta to arboard makes sense. To resolve the issue, this commit brings in an optional dependency smithay-clipboard, that is a crate that correctly handles the Wayland clipboard in graphical applications. It is used by default if a Wayland window handle is found. If for some reason the handle to the Wayland window handle cannot be fetched, arboard is used as a backup.
1 parent b008b14 commit 308f8a4

File tree

4 files changed

+77
-10
lines changed

4 files changed

+77
-10
lines changed

Cargo.lock

+11
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

egui-winit/Cargo.toml

+4-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ bytemuck = ["egui/bytemuck"]
2525

2626
# enable cut/copy/paste to OS clipboard.
2727
# if disabled a clipboard will be simulated so you can still copy/paste within the egui app.
28-
clipboard = ["arboard"]
28+
clipboard = ["arboard", "smithay-clipboard"]
2929

3030
# enable opening links in a browser when an egui hyperlink is clicked.
3131
links = ["webbrowser"]
@@ -55,3 +55,6 @@ webbrowser = { version = "0.7", optional = true }
5555

5656
# feature screen_reader
5757
tts = { version = "0.20", optional = true } # stuck on old version due to compilation problems on linux
58+
59+
[target.'cfg(unix)'.dependencies]
60+
smithay-clipboard = { version = "0.6.3", optional = true }

egui-winit/src/clipboard.rs

+41-6
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use std::os::raw::c_void;
2+
13
/// Handles interfacing with the OS clipboard.
24
///
35
/// If the "clipboard" feature is off, or we cannot connect to the OS clipboard,
@@ -6,23 +8,37 @@ pub struct Clipboard {
68
#[cfg(feature = "arboard")]
79
arboard: Option<arboard::Clipboard>,
810

11+
#[cfg(all(unix, feature = "smithay-clipboard"))]
12+
smithay: Option<smithay_clipboard::Clipboard>,
13+
914
/// Fallback manual clipboard.
1015
clipboard: String,
1116
}
1217

13-
impl Default for Clipboard {
14-
fn default() -> Self {
18+
impl Clipboard {
19+
#[allow(unused_variables)]
20+
pub fn new(#[allow(unused_variables)] wayland_display: Option<*mut c_void>) -> Self {
1521
Self {
1622
#[cfg(feature = "arboard")]
1723
arboard: init_arboard(),
18-
19-
clipboard: String::default(),
24+
#[cfg(all(unix, feature = "smithay-clipboard"))]
25+
smithay: init_smithay_clipboard(wayland_display),
26+
clipboard: Default::default(),
2027
}
2128
}
22-
}
2329

24-
impl Clipboard {
2530
pub fn get(&mut self) -> Option<String> {
31+
#[cfg(all(unix, feature = "smithay-clipboard"))]
32+
if let Some(clipboard) = &mut self.smithay {
33+
return match clipboard.load() {
34+
Ok(text) => Some(text),
35+
Err(err) => {
36+
tracing::error!("Paste error: {}", err);
37+
None
38+
}
39+
};
40+
}
41+
2642
#[cfg(feature = "arboard")]
2743
if let Some(clipboard) = &mut self.arboard {
2844
return match clipboard.get_text() {
@@ -38,6 +54,12 @@ impl Clipboard {
3854
}
3955

4056
pub fn set(&mut self, text: String) {
57+
#[cfg(all(unix, feature = "smithay-clipboard"))]
58+
if let Some(clipboard) = &mut self.smithay {
59+
clipboard.store(text);
60+
return;
61+
}
62+
4163
#[cfg(feature = "arboard")]
4264
if let Some(clipboard) = &mut self.arboard {
4365
if let Err(err) = clipboard.set_text(text) {
@@ -60,3 +82,16 @@ fn init_arboard() -> Option<arboard::Clipboard> {
6082
}
6183
}
6284
}
85+
86+
#[cfg(all(unix, feature = "smithay-clipboard"))]
87+
fn init_smithay_clipboard(
88+
wayland_display: Option<*mut c_void>,
89+
) -> Option<smithay_clipboard::Clipboard> {
90+
if let Some(display) = wayland_display {
91+
#[allow(unsafe_code)]
92+
Some(unsafe { smithay_clipboard::Clipboard::new(display) })
93+
} else {
94+
tracing::error!("Cannot initialize smithay clipboard without a display handle!");
95+
None
96+
}
97+
}

egui-winit/src/lib.rs

+21-3
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
66
#![allow(clippy::manual_range_contains)]
77

8+
use std::os::raw::c_void;
9+
810
pub use egui;
911
pub use winit;
1012

@@ -14,6 +16,9 @@ mod window_settings;
1416

1517
pub use window_settings::WindowSettings;
1618

19+
#[cfg(unix)]
20+
use winit::platform::unix::WindowExtUnix;
21+
1722
pub fn native_pixels_per_point(window: &winit::window::Window) -> f32 {
1823
window.scale_factor() as f32
1924
}
@@ -53,13 +58,26 @@ impl State {
5358
/// * `max_texture_side`: e.g. `GL_MAX_TEXTURE_SIZE`
5459
/// * the native `pixels_per_point` (dpi scaling).
5560
pub fn new(max_texture_side: usize, window: &winit::window::Window) -> Self {
56-
Self::from_pixels_per_point(max_texture_side, native_pixels_per_point(window))
61+
#[cfg(unix)]
62+
let wayland_display = window.wayland_display();
63+
#[cfg(not(unix))]
64+
let wayland_display = None;
65+
66+
Self::from_pixels_per_point(
67+
max_texture_side,
68+
native_pixels_per_point(window),
69+
wayland_display,
70+
)
5771
}
5872

5973
/// Initialize with:
6074
/// * `max_texture_side`: e.g. `GL_MAX_TEXTURE_SIZE`
6175
/// * the given `pixels_per_point` (dpi scaling).
62-
pub fn from_pixels_per_point(max_texture_side: usize, pixels_per_point: f32) -> Self {
76+
pub fn from_pixels_per_point(
77+
max_texture_side: usize,
78+
pixels_per_point: f32,
79+
wayland_display: Option<*mut c_void>,
80+
) -> Self {
6381
Self {
6482
start_time: instant::Instant::now(),
6583
egui_input: egui::RawInput {
@@ -72,7 +90,7 @@ impl State {
7290
current_cursor_icon: egui::CursorIcon::Default,
7391
current_pixels_per_point: pixels_per_point,
7492

75-
clipboard: Default::default(),
93+
clipboard: clipboard::Clipboard::new(wayland_display),
7694
screen_reader: screen_reader::ScreenReader::default(),
7795

7896
simulate_touch_screen: false,

0 commit comments

Comments
 (0)