diff --git a/CHANGELOG.md b/CHANGELOG.md index 1196a11a..572fbaba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,7 @@ Unreleased` header. - **Breaking:** Rename `VideoMode` to `VideoModeHandle` to represent that it doesn't hold static data. - **Breaking:** No longer export `platform::x11::XNotSupported`. - **Breaking:** Renamed `platform::x11::XWindowType` to `platform::x11::WindowType`. +- Add the `OwnedDisplayHandle` type for allowing safe display handle usage outside of trivial cases. # 0.29.10 diff --git a/src/event_loop.rs b/src/event_loop.rs index 1cade1f0..93392efc 100644 --- a/src/event_loop.rs +++ b/src/event_loop.rs @@ -367,6 +367,15 @@ impl EventLoopWindowTarget { pub fn exiting(&self) -> bool { self.p.exiting() } + + /// Gets a persistent reference to the underlying platform display. + /// + /// See the [`OwnedDisplayHandle`] type for more information. + pub fn owned_display_handle(&self) -> OwnedDisplayHandle { + OwnedDisplayHandle { + platform: self.p.owned_display_handle(), + } + } } #[cfg(feature = "rwh_06")] @@ -386,6 +395,52 @@ unsafe impl rwh_05::HasRawDisplayHandle for EventLoopWindowTarget { } } +/// A proxy for the underlying display handle. +/// +/// The purpose of this type is to provide a cheaply clonable handle to the underlying +/// display handle. This is often used by graphics APIs to connect to the underlying APIs. +/// It is difficult to keep a handle to the [`EventLoop`] type or the [`EventLoopWindowTarget`] +/// type. In contrast, this type involves no lifetimes and can be persisted for as long as +/// needed. +/// +/// For all platforms, this is one of the following: +/// +/// - A zero-sized type that is likely optimized out. +/// - A reference-counted pointer to the underlying type. +#[derive(Clone)] +pub struct OwnedDisplayHandle { + #[cfg_attr(not(any(feature = "rwh_05", feature = "rwh_06")), allow(dead_code))] + platform: platform_impl::OwnedDisplayHandle, +} + +impl fmt::Debug for OwnedDisplayHandle { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("OwnedDisplayHandle").finish_non_exhaustive() + } +} + +#[cfg(feature = "rwh_06")] +impl rwh_06::HasDisplayHandle for OwnedDisplayHandle { + #[inline] + fn display_handle(&self) -> Result, rwh_06::HandleError> { + let raw = self.platform.raw_display_handle_rwh_06()?; + + // SAFETY: The underlying display handle should be safe. + let handle = unsafe { rwh_06::DisplayHandle::borrow_raw(raw) }; + + Ok(handle) + } +} + +#[cfg(feature = "rwh_05")] +unsafe impl rwh_05::HasRawDisplayHandle for OwnedDisplayHandle { + #[inline] + fn raw_display_handle(&self) -> rwh_05::RawDisplayHandle { + self.platform.raw_display_handle_rwh_05() + } +} + /// Used to send custom events to [`EventLoop`]. pub struct EventLoopProxy { event_loop_proxy: platform_impl::EventLoopProxy, diff --git a/src/platform_impl/android/mod.rs b/src/platform_impl/android/mod.rs index 426fd9bd..434cc34b 100644 --- a/src/platform_impl/android/mod.rs +++ b/src/platform_impl/android/mod.rs @@ -721,6 +721,29 @@ impl EventLoopWindowTarget { pub(crate) fn exiting(&self) -> bool { self.exit.get() } + + pub(crate) fn owned_display_handle(&self) -> OwnedDisplayHandle { + OwnedDisplayHandle + } +} + +#[derive(Clone)] +pub(crate) struct OwnedDisplayHandle; + +impl OwnedDisplayHandle { + #[cfg(feature = "rwh_05")] + #[inline] + pub fn raw_display_handle_rwh_05(&self) -> rwh_05::RawDisplayHandle { + rwh_05::AndroidDisplayHandle::empty().into() + } + + #[cfg(feature = "rwh_06")] + #[inline] + pub fn raw_display_handle_rwh_06( + &self, + ) -> Result { + Ok(rwh_06::AndroidDisplayHandle::new().into()) + } } #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] diff --git a/src/platform_impl/ios/event_loop.rs b/src/platform_impl/ios/event_loop.rs index e08776dc..78cc7021 100644 --- a/src/platform_impl/ios/event_loop.rs +++ b/src/platform_impl/ios/event_loop.rs @@ -83,6 +83,29 @@ impl EventLoopWindowTarget { pub(crate) fn exiting(&self) -> bool { false } + + pub(crate) fn owned_display_handle(&self) -> OwnedDisplayHandle { + OwnedDisplayHandle + } +} + +#[derive(Clone)] +pub(crate) struct OwnedDisplayHandle; + +impl OwnedDisplayHandle { + #[cfg(feature = "rwh_05")] + #[inline] + pub fn raw_display_handle_rwh_05(&self) -> rwh_05::RawDisplayHandle { + rwh_05::UiKitDisplayHandle::empty().into() + } + + #[cfg(feature = "rwh_06")] + #[inline] + pub fn raw_display_handle_rwh_06( + &self, + ) -> Result { + Ok(rwh_06::UiKitDisplayHandle::new().into()) + } } pub struct EventLoop { diff --git a/src/platform_impl/ios/mod.rs b/src/platform_impl/ios/mod.rs index 54ca1342..f5898bbf 100644 --- a/src/platform_impl/ios/mod.rs +++ b/src/platform_impl/ios/mod.rs @@ -70,7 +70,8 @@ use std::fmt; pub(crate) use self::{ event_loop::{ - EventLoop, EventLoopProxy, EventLoopWindowTarget, PlatformSpecificEventLoopAttributes, + EventLoop, EventLoopProxy, EventLoopWindowTarget, OwnedDisplayHandle, + PlatformSpecificEventLoopAttributes, }, monitor::{MonitorHandle, VideoModeHandle}, window::{PlatformSpecificWindowBuilderAttributes, Window, WindowId}, diff --git a/src/platform_impl/linux/mod.rs b/src/platform_impl/linux/mod.rs index 28197a1f..4c6e0404 100644 --- a/src/platform_impl/linux/mod.rs +++ b/src/platform_impl/linux/mod.rs @@ -902,6 +902,15 @@ impl EventLoopWindowTarget { x11_or_wayland!(match self; Self(evlp) => evlp.exiting()) } + pub(crate) fn owned_display_handle(&self) -> OwnedDisplayHandle { + match self { + #[cfg(x11_platform)] + Self::X(conn) => OwnedDisplayHandle::X(conn.x_connection().clone()), + #[cfg(wayland_platform)] + Self::Wayland(conn) => OwnedDisplayHandle::Wayland(conn.connection.clone()), + } + } + fn set_exit_code(&self, code: i32) { x11_or_wayland!(match self; Self(evlp) => evlp.set_exit_code(code)) } @@ -911,6 +920,67 @@ impl EventLoopWindowTarget { } } +#[derive(Clone)] +#[allow(dead_code)] +pub(crate) enum OwnedDisplayHandle { + #[cfg(x11_platform)] + X(Arc), + #[cfg(wayland_platform)] + Wayland(wayland_client::Connection), +} + +impl OwnedDisplayHandle { + #[cfg(feature = "rwh_05")] + #[inline] + pub fn raw_display_handle_rwh_05(&self) -> rwh_05::RawDisplayHandle { + match self { + #[cfg(x11_platform)] + Self::X(xconn) => { + let mut xlib_handle = rwh_05::XlibDisplayHandle::empty(); + xlib_handle.display = xconn.display.cast(); + xlib_handle.screen = xconn.default_screen_index() as _; + xlib_handle.into() + } + + #[cfg(wayland_platform)] + Self::Wayland(conn) => { + use sctk::reexports::client::Proxy; + + let mut wayland_handle = rwh_05::WaylandDisplayHandle::empty(); + wayland_handle.display = conn.display().id().as_ptr() as *mut _; + wayland_handle.into() + } + } + } + + #[cfg(feature = "rwh_06")] + #[inline] + pub fn raw_display_handle_rwh_06( + &self, + ) -> Result { + use std::ptr::NonNull; + + match self { + #[cfg(x11_platform)] + Self::X(xconn) => Ok(rwh_06::XlibDisplayHandle::new( + NonNull::new(xconn.display.cast()), + xconn.default_screen_index() as _, + ) + .into()), + + #[cfg(wayland_platform)] + Self::Wayland(conn) => { + use sctk::reexports::client::Proxy; + + Ok(rwh_06::WaylandDisplayHandle::new( + NonNull::new(conn.display().id().as_ptr().cast()).unwrap(), + ) + .into()) + } + } + } +} + /// Returns the minimum `Option`, taking into account that `None` /// equates to an infinite timeout, not a zero timeout (so can't just use /// `Option::min`) diff --git a/src/platform_impl/macos/event_loop.rs b/src/platform_impl/macos/event_loop.rs index 38561239..816e7571 100644 --- a/src/platform_impl/macos/event_loop.rs +++ b/src/platform_impl/macos/event_loop.rs @@ -128,6 +128,10 @@ impl EventLoopWindowTarget { pub(crate) fn exiting(&self) -> bool { self.delegate.exiting() } + + pub(crate) fn owned_display_handle(&self) -> OwnedDisplayHandle { + OwnedDisplayHandle + } } impl EventLoopWindowTarget { @@ -460,6 +464,25 @@ impl EventLoop { } } +#[derive(Clone)] +pub(crate) struct OwnedDisplayHandle; + +impl OwnedDisplayHandle { + #[cfg(feature = "rwh_05")] + #[inline] + pub fn raw_display_handle_rwh_05(&self) -> rwh_05::RawDisplayHandle { + rwh_05::AppKitDisplayHandle::empty().into() + } + + #[cfg(feature = "rwh_06")] + #[inline] + pub fn raw_display_handle_rwh_06( + &self, + ) -> Result { + Ok(rwh_06::AppKitDisplayHandle::new().into()) + } +} + pub(super) fn stop_app_immediately(app: &NSApplication) { autoreleasepool(|_| { app.stop(None); diff --git a/src/platform_impl/macos/mod.rs b/src/platform_impl/macos/mod.rs index 65bea82f..39505074 100644 --- a/src/platform_impl/macos/mod.rs +++ b/src/platform_impl/macos/mod.rs @@ -19,7 +19,8 @@ use std::fmt; pub(crate) use self::{ event::{physicalkey_to_scancode, scancode_to_physicalkey, KeyEventExtra}, event_loop::{ - EventLoop, EventLoopProxy, EventLoopWindowTarget, PlatformSpecificEventLoopAttributes, + EventLoop, EventLoopProxy, EventLoopWindowTarget, OwnedDisplayHandle, + PlatformSpecificEventLoopAttributes, }, monitor::{MonitorHandle, VideoModeHandle}, window::WindowId, diff --git a/src/platform_impl/orbital/event_loop.rs b/src/platform_impl/orbital/event_loop.rs index 62c85d19..aa7acb2a 100644 --- a/src/platform_impl/orbital/event_loop.rs +++ b/src/platform_impl/orbital/event_loop.rs @@ -771,4 +771,27 @@ impl EventLoopWindowTarget { pub(crate) fn exiting(&self) -> bool { self.exit.get() } + + pub(crate) fn owned_display_handle(&self) -> OwnedDisplayHandle { + OwnedDisplayHandle + } +} + +#[derive(Clone)] +pub(crate) struct OwnedDisplayHandle; + +impl OwnedDisplayHandle { + #[cfg(feature = "rwh_05")] + #[inline] + pub fn raw_display_handle_rwh_05(&self) -> rwh_05::RawDisplayHandle { + rwh_05::OrbitalDisplayHandle::empty().into() + } + + #[cfg(feature = "rwh_06")] + #[inline] + pub fn raw_display_handle_rwh_06( + &self, + ) -> Result { + Ok(rwh_06::OrbitalDisplayHandle::new().into()) + } } diff --git a/src/platform_impl/orbital/mod.rs b/src/platform_impl/orbital/mod.rs index 937e9c12..4d544998 100644 --- a/src/platform_impl/orbital/mod.rs +++ b/src/platform_impl/orbital/mod.rs @@ -6,7 +6,9 @@ use std::sync::Arc; use crate::dpi::{PhysicalPosition, PhysicalSize}; -pub use self::event_loop::{EventLoop, EventLoopProxy, EventLoopWindowTarget}; +pub(crate) use self::event_loop::{ + EventLoop, EventLoopProxy, EventLoopWindowTarget, OwnedDisplayHandle, +}; mod event_loop; pub use self::window::Window; diff --git a/src/platform_impl/web/event_loop/mod.rs b/src/platform_impl/web/event_loop/mod.rs index 79e3abf2..2cc9d27d 100644 --- a/src/platform_impl/web/event_loop/mod.rs +++ b/src/platform_impl/web/event_loop/mod.rs @@ -12,8 +12,8 @@ pub(crate) mod runner; mod state; mod window_target; -pub use proxy::EventLoopProxy; -pub use window_target::EventLoopWindowTarget; +pub(crate) use proxy::EventLoopProxy; +pub(crate) use window_target::{EventLoopWindowTarget, OwnedDisplayHandle}; pub struct EventLoop { elw: RootEventLoopWindowTarget, diff --git a/src/platform_impl/web/event_loop/window_target.rs b/src/platform_impl/web/event_loop/window_target.rs index 260b592e..3b290dd3 100644 --- a/src/platform_impl/web/event_loop/window_target.rs +++ b/src/platform_impl/web/event_loop/window_target.rs @@ -704,4 +704,27 @@ impl EventLoopWindowTarget { pub(crate) fn waker(&self) -> Waker> { self.runner.waker() } + + pub(crate) fn owned_display_handle(&self) -> OwnedDisplayHandle { + OwnedDisplayHandle + } +} + +#[derive(Clone)] +pub(crate) struct OwnedDisplayHandle; + +impl OwnedDisplayHandle { + #[cfg(feature = "rwh_05")] + #[inline] + pub fn raw_display_handle_rwh_05(&self) -> rwh_05::RawDisplayHandle { + rwh_05::WebDisplayHandle::empty().into() + } + + #[cfg(feature = "rwh_06")] + #[inline] + pub fn raw_display_handle_rwh_06( + &self, + ) -> Result { + Ok(rwh_06::WebDisplayHandle::new().into()) + } } diff --git a/src/platform_impl/web/mod.rs b/src/platform_impl/web/mod.rs index 3d23351e..a70dacd0 100644 --- a/src/platform_impl/web/mod.rs +++ b/src/platform_impl/web/mod.rs @@ -33,7 +33,8 @@ mod backend; pub use self::device::DeviceId; pub use self::error::OsError; pub(crate) use self::event_loop::{ - EventLoop, EventLoopProxy, EventLoopWindowTarget, PlatformSpecificEventLoopAttributes, + EventLoop, EventLoopProxy, EventLoopWindowTarget, OwnedDisplayHandle, + PlatformSpecificEventLoopAttributes, }; pub use self::monitor::{MonitorHandle, VideoModeHandle}; pub use self::window::{PlatformSpecificWindowBuilderAttributes, Window, WindowId}; diff --git a/src/platform_impl/windows/event_loop.rs b/src/platform_impl/windows/event_loop.rs index ef5da8ba..4df1b490 100644 --- a/src/platform_impl/windows/event_loop.rs +++ b/src/platform_impl/windows/event_loop.rs @@ -584,11 +584,34 @@ impl EventLoopWindowTarget { self.runner_shared.clear_exit(); } + pub(crate) fn owned_display_handle(&self) -> OwnedDisplayHandle { + OwnedDisplayHandle + } + fn exit_code(&self) -> Option { self.runner_shared.exit_code() } } +#[derive(Clone)] +pub(crate) struct OwnedDisplayHandle; + +impl OwnedDisplayHandle { + #[cfg(feature = "rwh_05")] + #[inline] + pub fn raw_display_handle_rwh_05(&self) -> rwh_05::RawDisplayHandle { + rwh_05::WindowsDisplayHandle::empty().into() + } + + #[cfg(feature = "rwh_06")] + #[inline] + pub fn raw_display_handle_rwh_06( + &self, + ) -> Result { + Ok(rwh_06::WindowsDisplayHandle::new().into()) + } +} + /// Returns the id of the main thread. /// /// Windows has no real API to check if the current executing thread is the "main thread", unlike diff --git a/src/platform_impl/windows/mod.rs b/src/platform_impl/windows/mod.rs index 7cce3a76..5ae4e21a 100644 --- a/src/platform_impl/windows/mod.rs +++ b/src/platform_impl/windows/mod.rs @@ -8,7 +8,8 @@ use windows_sys::Win32::{ pub(crate) use self::{ event_loop::{ - EventLoop, EventLoopProxy, EventLoopWindowTarget, PlatformSpecificEventLoopAttributes, + EventLoop, EventLoopProxy, EventLoopWindowTarget, OwnedDisplayHandle, + PlatformSpecificEventLoopAttributes, }, icon::{SelectedCursor, WinIcon}, keyboard::{physicalkey_to_scancode, scancode_to_physicalkey},