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 1196a11a90..572fbaba53 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 1cade1f07c..93392efc89 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 426fd9bdbf..434cc34b1c 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 e08776dc21..78cc7021f8 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 54ca1342f6..f5898bbfb9 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 28197a1f78..4c6e0404ce 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 3856123949..816e757154 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 65bea82f13..3950507461 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 62c85d19bc..aa7acb2a6f 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 937e9c12b6..4d54499871 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 79e3abf21e..2cc9d27d52 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 260b592e5c..3b290dd3c1 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 3d23351efe..a70dacd048 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 ef5da8baaa..4df1b490d0 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 7cce3a76c8..5ae4e21a3e 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},