From 6df972d1084b865b8cbd8e70c379231849ec25d9 Mon Sep 17 00:00:00 2001 From: John Nunley Date: Mon, 15 Jan 2024 11:58:11 -0800 Subject: [PATCH] feat: Add an owned display handle type This was supposed to be rolled out with the rwh v0.6 update, but it was left behind for some reason. I've added this type back. Signed-off-by: John Nunley --- CHANGELOG.md | 1 + src/event_loop.rs | 55 +++++++++++++++ src/platform_impl/android/mod.rs | 23 ++++++ src/platform_impl/ios/event_loop.rs | 23 ++++++ src/platform_impl/ios/mod.rs | 3 +- src/platform_impl/linux/mod.rs | 70 +++++++++++++++++++ src/platform_impl/macos/event_loop.rs | 23 ++++++ src/platform_impl/macos/mod.rs | 3 +- src/platform_impl/orbital/event_loop.rs | 23 ++++++ src/platform_impl/orbital/mod.rs | 4 +- src/platform_impl/web/event_loop/mod.rs | 4 +- .../web/event_loop/window_target.rs | 23 ++++++ src/platform_impl/web/mod.rs | 3 +- src/platform_impl/windows/event_loop.rs | 23 ++++++ src/platform_impl/windows/mod.rs | 3 +- 15 files changed, 277 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1196a11a9..572fbaba5 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 1cade1f07..93392efc8 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 426fd9bdb..434cc34b1 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 e08776dc2..78cc7021f 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 54ca1342f..f5898bbfb 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 28197a1f7..4c6e0404c 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 385612394..816e75715 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 65bea82f1..395050746 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 62c85d19b..aa7acb2a6 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 937e9c12b..4d5449987 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 79e3abf21..2cc9d27d5 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 260b592e5..3b290dd3c 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 3d23351ef..a70dacd04 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 ef5da8baa..4df1b490d 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 7cce3a76c..5ae4e21a3 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},