egui-winit: fix unsafe API of Clipboard::new (#2765)

* egui-winit: fix unsafe API of Clipboard::new

The old API allowed passing an arbitrary pointer. The new
API still breaks safety by allowing the object to outlive
the input, but is at least safer.

* Update crates/egui-winit/src/clipboard.rs

Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>

* Fix typo

* Update crates/egui-winit/src/clipboard.rs

Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>

* cargo fmt

* egui-winit: fix init_smithay_clipboard

---------

Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>
This commit is contained in:
Diggory Hardy 2023-03-30 09:21:07 +01:00 committed by GitHub
parent 9ddf7abeee
commit fb726aaabb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 36 additions and 42 deletions

View File

@ -3,7 +3,7 @@ All notable changes to the `egui-winit` integration will be noted in this file.
## Unreleased ## Unreleased
* Fix unsafe API: remove `State::new_with_wayland_display`; change `Clipboard::new` to take `&EventLoopWindowTarget<T>`.
## 0.21.1 - 2023-02-12 ## 0.21.1 - 2023-02-12
* Fixed crash when window position is in an invalid state, which could happen e.g. due to changes in monitor size or DPI ([#2722](https://github.com/emilk/egui/issues/2722)). * Fixed crash when window position is in an invalid state, which could happen e.g. due to changes in monitor size or DPI ([#2722](https://github.com/emilk/egui/issues/2722)).

View File

@ -1,4 +1,4 @@
use std::os::raw::c_void; use winit::event_loop::EventLoopWindowTarget;
/// Handles interfacing with the OS clipboard. /// Handles interfacing with the OS clipboard.
/// ///
@ -25,8 +25,12 @@ pub struct Clipboard {
} }
impl Clipboard { impl Clipboard {
#[allow(unused_variables)] /// Construct a new instance
pub fn new(#[allow(unused_variables)] wayland_display: Option<*mut c_void>) -> Self { ///
/// # Safety
///
/// The returned `Clipboard` must not outlive the input `_event_loop`.
pub fn new<T>(_event_loop: &EventLoopWindowTarget<T>) -> Self {
Self { Self {
#[cfg(all(feature = "arboard", not(target_os = "android")))] #[cfg(all(feature = "arboard", not(target_os = "android")))]
arboard: init_arboard(), arboard: init_arboard(),
@ -41,7 +45,7 @@ impl Clipboard {
), ),
feature = "smithay-clipboard" feature = "smithay-clipboard"
))] ))]
smithay: init_smithay_clipboard(wayland_display), smithay: init_smithay_clipboard(_event_loop),
clipboard: Default::default(), clipboard: Default::default(),
} }
@ -132,15 +136,28 @@ fn init_arboard() -> Option<arboard::Clipboard> {
), ),
feature = "smithay-clipboard" feature = "smithay-clipboard"
))] ))]
fn init_smithay_clipboard( fn init_smithay_clipboard<T>(
wayland_display: Option<*mut c_void>, _event_loop: &EventLoopWindowTarget<T>,
) -> Option<smithay_clipboard::Clipboard> { ) -> Option<smithay_clipboard::Clipboard> {
if let Some(display) = wayland_display { // Note: ideally "smithay-clipboard" would imply "wayland", but it doesn't.
tracing::debug!("Initializing smithay clipboard…"); #[cfg(feature = "wayland")]
#[allow(unsafe_code)] {
Some(unsafe { smithay_clipboard::Clipboard::new(display) }) use winit::platform::wayland::EventLoopWindowTargetExtWayland as _;
} else { if let Some(display) = _event_loop.wayland_display() {
tracing::debug!("Cannot initialize smithay clipboard without a display handle"); tracing::debug!("Initializing smithay clipboard…");
#[allow(unsafe_code)]
Some(unsafe { smithay_clipboard::Clipboard::new(display) })
} else {
tracing::debug!("Cannot initialize smithay clipboard without a display handle");
None
}
}
#[cfg(not(feature = "wayland"))]
{
tracing::debug!(
"You need to enable the 'wayland' feature of 'egui-winit' to get a working clipboard"
);
None None
} }
} }

View File

@ -9,8 +9,6 @@
#![allow(clippy::manual_range_contains)] #![allow(clippy::manual_range_contains)]
use std::os::raw::c_void;
#[cfg(feature = "accesskit")] #[cfg(feature = "accesskit")]
pub use accesskit_winit; pub use accesskit_winit;
pub use egui; pub use egui;
@ -85,11 +83,12 @@ pub struct State {
} }
impl State { impl State {
/// Construct a new instance
///
/// # Safety
///
/// The returned `State` must not outlive the input `_event_loop`.
pub fn new<T>(event_loop: &EventLoopWindowTarget<T>) -> Self { pub fn new<T>(event_loop: &EventLoopWindowTarget<T>) -> Self {
Self::new_with_wayland_display(wayland_display(event_loop))
}
pub fn new_with_wayland_display(wayland_display: Option<*mut c_void>) -> Self {
let egui_input = egui::RawInput { let egui_input = egui::RawInput {
has_focus: false, // winit will tell us when we have focus has_focus: false, // winit will tell us when we have focus
..Default::default() ..Default::default()
@ -103,7 +102,7 @@ impl State {
current_cursor_icon: None, current_cursor_icon: None,
current_pixels_per_point: 1.0, current_pixels_per_point: 1.0,
clipboard: clipboard::Clipboard::new(wayland_display), clipboard: clipboard::Clipboard::new(event_loop),
simulate_touch_screen: false, simulate_touch_screen: false,
pointer_touch_id: None, pointer_touch_id: None,
@ -871,28 +870,6 @@ fn translate_cursor(cursor_icon: egui::CursorIcon) -> Option<winit::window::Curs
} }
} }
/// Returns a Wayland display handle if the target is running Wayland
fn wayland_display<T>(_event_loop: &EventLoopWindowTarget<T>) -> Option<*mut c_void> {
#[cfg(feature = "wayland")]
#[cfg(any(
target_os = "linux",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "netbsd",
target_os = "openbsd"
))]
{
use winit::platform::wayland::EventLoopWindowTargetExtWayland as _;
return _event_loop.wayland_display();
}
#[allow(unreachable_code)]
{
let _ = _event_loop;
None
}
}
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
/// Profiling macro for feature "puffin" /// Profiling macro for feature "puffin"