diff --git a/Cargo.lock b/Cargo.lock index b33580b569e..66f145448a2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1180,6 +1180,7 @@ dependencies = [ "instant", "puffin", "serde", + "smithay-clipboard", "tracing", "tts", "webbrowser", @@ -3308,6 +3309,16 @@ dependencies = [ "wayland-protocols", ] +[[package]] +name = "smithay-clipboard" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "610b551bd25378bfd2b8e7a0fcbd83d427e8f2f6a40c47ae0f70688e9949dd55" +dependencies = [ + "smithay-client-toolkit", + "wayland-client", +] + [[package]] name = "socket2" version = "0.4.4" diff --git a/egui-winit/Cargo.toml b/egui-winit/Cargo.toml index b999ef19ee5..7889093b8fd 100644 --- a/egui-winit/Cargo.toml +++ b/egui-winit/Cargo.toml @@ -25,7 +25,7 @@ bytemuck = ["egui/bytemuck"] # enable cut/copy/paste to OS clipboard. # if disabled a clipboard will be simulated so you can still copy/paste within the egui app. -clipboard = ["arboard"] +clipboard = ["arboard", "smithay-clipboard"] # enable opening links in a browser when an egui hyperlink is clicked. links = ["webbrowser"] @@ -55,3 +55,6 @@ webbrowser = { version = "0.7", optional = true } # feature screen_reader tts = { version = "0.20", optional = true } # stuck on old version due to compilation problems on linux + +[target.'cfg(any(target_os="linux", target_os="dragonfly", target_os="freebsd", target_os="netbsd", target_os="openbsd"))'.dependencies] +smithay-clipboard = { version = "0.6.3", optional = true } diff --git a/egui-winit/src/clipboard.rs b/egui-winit/src/clipboard.rs index 8737bfd9f96..ef11b12f788 100644 --- a/egui-winit/src/clipboard.rs +++ b/egui-winit/src/clipboard.rs @@ -1,3 +1,5 @@ +use std::os::raw::c_void; + /// Handles interfacing with the OS clipboard. /// /// If the "clipboard" feature is off, or we cannot connect to the OS clipboard, @@ -6,23 +8,64 @@ pub struct Clipboard { #[cfg(feature = "arboard")] arboard: Option, + #[cfg(all( + any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" + ), + feature = "smithay-clipboard" + ))] + smithay: Option, + /// Fallback manual clipboard. clipboard: String, } -impl Default for Clipboard { - fn default() -> Self { +impl Clipboard { + #[allow(unused_variables)] + pub fn new(#[allow(unused_variables)] wayland_display: Option<*mut c_void>) -> Self { Self { #[cfg(feature = "arboard")] arboard: init_arboard(), - - clipboard: String::default(), + #[cfg(all( + any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" + ), + feature = "smithay-clipboard" + ))] + smithay: init_smithay_clipboard(wayland_display), + clipboard: Default::default(), } } -} -impl Clipboard { pub fn get(&mut self) -> Option { + #[cfg(all( + any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" + ), + feature = "smithay-clipboard" + ))] + if let Some(clipboard) = &mut self.smithay { + return match clipboard.load() { + Ok(text) => Some(text), + Err(err) => { + tracing::error!("Paste error: {}", err); + None + } + }; + } + #[cfg(feature = "arboard")] if let Some(clipboard) = &mut self.arboard { return match clipboard.get_text() { @@ -38,6 +81,21 @@ impl Clipboard { } pub fn set(&mut self, text: String) { + #[cfg(all( + any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" + ), + feature = "smithay-clipboard" + ))] + if let Some(clipboard) = &mut self.smithay { + clipboard.store(text); + return; + } + #[cfg(feature = "arboard")] if let Some(clipboard) = &mut self.arboard { if let Err(err) = clipboard.set_text(text) { @@ -60,3 +118,25 @@ fn init_arboard() -> Option { } } } + +#[cfg(all( + any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" + ), + feature = "smithay-clipboard" +))] +fn init_smithay_clipboard( + wayland_display: Option<*mut c_void>, +) -> Option { + if let Some(display) = wayland_display { + #[allow(unsafe_code)] + Some(unsafe { smithay_clipboard::Clipboard::new(display) }) + } else { + tracing::error!("Cannot initialize smithay clipboard without a display handle!"); + None + } +} diff --git a/egui-winit/src/lib.rs b/egui-winit/src/lib.rs index 4286af84c2e..9210aed7aa6 100644 --- a/egui-winit/src/lib.rs +++ b/egui-winit/src/lib.rs @@ -5,6 +5,8 @@ #![allow(clippy::manual_range_contains)] +use std::os::raw::c_void; + pub use egui; pub use winit; @@ -14,6 +16,15 @@ mod window_settings; pub use window_settings::WindowSettings; +#[cfg(any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" +))] +use winit::platform::unix::WindowExtUnix; + pub fn native_pixels_per_point(window: &winit::window::Window) -> f32 { window.scale_factor() as f32 } @@ -53,13 +64,21 @@ impl State { /// * `max_texture_side`: e.g. `GL_MAX_TEXTURE_SIZE` /// * the native `pixels_per_point` (dpi scaling). pub fn new(max_texture_side: usize, window: &winit::window::Window) -> Self { - Self::from_pixels_per_point(max_texture_side, native_pixels_per_point(window)) + Self::from_pixels_per_point( + max_texture_side, + native_pixels_per_point(window), + get_wayland_display(window), + ) } /// Initialize with: /// * `max_texture_side`: e.g. `GL_MAX_TEXTURE_SIZE` /// * the given `pixels_per_point` (dpi scaling). - pub fn from_pixels_per_point(max_texture_side: usize, pixels_per_point: f32) -> Self { + pub fn from_pixels_per_point( + max_texture_side: usize, + pixels_per_point: f32, + wayland_display: Option<*mut c_void>, + ) -> Self { Self { start_time: instant::Instant::now(), egui_input: egui::RawInput { @@ -72,7 +91,7 @@ impl State { current_cursor_icon: egui::CursorIcon::Default, current_pixels_per_point: pixels_per_point, - clipboard: Default::default(), + clipboard: clipboard::Clipboard::new(wayland_display), screen_reader: screen_reader::ScreenReader::default(), simulate_touch_screen: false, @@ -659,6 +678,23 @@ fn translate_cursor(cursor_icon: egui::CursorIcon) -> Option Option<*mut c_void> { + #[cfg(any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" + ))] + { + return window.wayland_display(); + } + + #[allow(unreachable_code)] + None +} + // --------------------------------------------------------------------------- /// Profiling macro for feature "puffin"