1 | //! Borrowable window handles based on the ones in this crate. |
2 | //! |
3 | //! These should be 100% safe to pass around and use, no possibility of dangling or invalidity. |
4 | |
5 | use core::borrow::Borrow; |
6 | use core::fmt; |
7 | use core::marker::PhantomData; |
8 | |
9 | use crate::{HandleError, RawDisplayHandle, RawWindowHandle}; |
10 | |
11 | /// A display that acts as a wrapper around a display handle. |
12 | /// |
13 | /// Objects that implement this trait should be able to return a [`DisplayHandle`] for the display |
14 | /// that they are associated with. This handle should last for the lifetime of the object, and should |
15 | /// return an error if the application is inactive. |
16 | /// |
17 | /// Implementors of this trait will be windowing systems, like [`winit`] and [`sdl2`]. These windowing |
18 | /// systems should implement this trait on types that represent the top-level display server. It |
19 | /// should be implemented by tying the lifetime of the [`DisplayHandle`] to the lifetime of the |
20 | /// display object. |
21 | /// |
22 | /// Users of this trait will include graphics libraries, like [`wgpu`] and [`glutin`]. These APIs |
23 | /// should be generic over a type that implements `HasDisplayHandle`, and should use the |
24 | /// [`DisplayHandle`] type to access the display handle. |
25 | /// |
26 | /// Note that these requirements are not enforced on `HasDisplayHandle`, rather, they are enforced on the |
27 | /// constructors of [`DisplayHandle`]. This is because the `HasDisplayHandle` trait is safe to implement. |
28 | /// |
29 | /// [`winit`]: https://crates.io/crates/winit |
30 | /// [`sdl2`]: https://crates.io/crates/sdl2 |
31 | /// [`wgpu`]: https://crates.io/crates/wgpu |
32 | /// [`glutin`]: https://crates.io/crates/glutin |
33 | pub trait HasDisplayHandle { |
34 | /// Get a handle to the display controller of the windowing system. |
35 | fn display_handle(&self) -> Result<DisplayHandle<'_>, HandleError>; |
36 | } |
37 | |
38 | impl<H: HasDisplayHandle + ?Sized> HasDisplayHandle for &H { |
39 | fn display_handle(&self) -> Result<DisplayHandle<'_>, HandleError> { |
40 | (**self).display_handle() |
41 | } |
42 | } |
43 | |
44 | impl<H: HasDisplayHandle + ?Sized> HasDisplayHandle for &mut H { |
45 | fn display_handle(&self) -> Result<DisplayHandle<'_>, HandleError> { |
46 | (**self).display_handle() |
47 | } |
48 | } |
49 | |
50 | #[cfg (feature = "alloc" )] |
51 | #[cfg_attr (docsrs, doc(cfg(feature = "alloc" )))] |
52 | impl<H: HasDisplayHandle + ?Sized> HasDisplayHandle for alloc::boxed::Box<H> { |
53 | fn display_handle(&self) -> Result<DisplayHandle<'_>, HandleError> { |
54 | (**self).display_handle() |
55 | } |
56 | } |
57 | |
58 | #[cfg (feature = "alloc" )] |
59 | #[cfg_attr (docsrs, doc(cfg(feature = "alloc" )))] |
60 | impl<H: HasDisplayHandle + ?Sized> HasDisplayHandle for alloc::rc::Rc<H> { |
61 | fn display_handle(&self) -> Result<DisplayHandle<'_>, HandleError> { |
62 | (**self).display_handle() |
63 | } |
64 | } |
65 | |
66 | #[cfg (feature = "alloc" )] |
67 | #[cfg_attr (docsrs, doc(cfg(feature = "alloc" )))] |
68 | impl<H: HasDisplayHandle + ?Sized> HasDisplayHandle for alloc::sync::Arc<H> { |
69 | fn display_handle(&self) -> Result<DisplayHandle<'_>, HandleError> { |
70 | (**self).display_handle() |
71 | } |
72 | } |
73 | |
74 | /// The handle to the display controller of the windowing system. |
75 | /// |
76 | /// This is the primary return type of the [`HasDisplayHandle`] trait. It is guaranteed to contain |
77 | /// a valid platform-specific display handle for its lifetime. |
78 | #[repr (transparent)] |
79 | #[derive (PartialEq, Eq, Hash, Copy, Clone)] |
80 | pub struct DisplayHandle<'a> { |
81 | raw: RawDisplayHandle, |
82 | _marker: PhantomData<&'a ()>, |
83 | } |
84 | |
85 | impl fmt::Debug for DisplayHandle<'_> { |
86 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
87 | f.debug_tuple(name:"DisplayHandle" ).field(&self.raw).finish() |
88 | } |
89 | } |
90 | |
91 | impl<'a> DisplayHandle<'a> { |
92 | /// Create a `DisplayHandle` from a [`RawDisplayHandle`]. |
93 | /// |
94 | /// # Safety |
95 | /// |
96 | /// Users can safely assume that non-`null`/`0` fields are valid handles, and it is up to the |
97 | /// implementer of this trait to ensure that condition is upheld. |
98 | /// |
99 | /// Despite that qualification, implementors should still make a best-effort attempt to fill in all |
100 | /// available fields. If an implementation doesn't, and a downstream user needs the field, it should |
101 | /// try to derive the field from other fields the implementer *does* provide via whatever methods the |
102 | /// platform provides. |
103 | /// |
104 | /// It is not possible to invalidate a [`DisplayHandle`] on any platform without additional unsafe code. |
105 | pub unsafe fn borrow_raw(raw: RawDisplayHandle) -> Self { |
106 | Self { |
107 | raw, |
108 | _marker: PhantomData, |
109 | } |
110 | } |
111 | |
112 | /// Get the underlying raw display handle. |
113 | pub fn as_raw(&self) -> RawDisplayHandle { |
114 | self.raw |
115 | } |
116 | } |
117 | |
118 | impl AsRef<RawDisplayHandle> for DisplayHandle<'_> { |
119 | fn as_ref(&self) -> &RawDisplayHandle { |
120 | &self.raw |
121 | } |
122 | } |
123 | |
124 | impl Borrow<RawDisplayHandle> for DisplayHandle<'_> { |
125 | fn borrow(&self) -> &RawDisplayHandle { |
126 | &self.raw |
127 | } |
128 | } |
129 | |
130 | impl From<DisplayHandle<'_>> for RawDisplayHandle { |
131 | fn from(handle: DisplayHandle<'_>) -> Self { |
132 | handle.raw |
133 | } |
134 | } |
135 | |
136 | impl<'a> HasDisplayHandle for DisplayHandle<'a> { |
137 | fn display_handle(&self) -> Result<DisplayHandle<'_>, HandleError> { |
138 | Ok(*self) |
139 | } |
140 | } |
141 | |
142 | /// A handle to a window. |
143 | /// |
144 | /// Objects that implement this trait should be able to return a [`WindowHandle`] for the window |
145 | /// that they are associated with. This handle should last for the lifetime of the object, and should |
146 | /// return an error if the application is inactive. |
147 | /// |
148 | /// Implementors of this trait will be windowing systems, like [`winit`] and [`sdl2`]. These windowing |
149 | /// systems should implement this trait on types that represent windows. |
150 | /// |
151 | /// Users of this trait will include graphics libraries, like [`wgpu`] and [`glutin`]. These APIs |
152 | /// should be generic over a type that implements `HasWindowHandle`, and should use the |
153 | /// [`WindowHandle`] type to access the window handle. The window handle should be acquired and held |
154 | /// while the window is being used, in order to ensure that the window is not deleted while it is in |
155 | /// use. |
156 | /// |
157 | /// [`winit`]: https://crates.io/crates/winit |
158 | /// [`sdl2`]: https://crates.io/crates/sdl2 |
159 | /// [`wgpu`]: https://crates.io/crates/wgpu |
160 | /// [`glutin`]: https://crates.io/crates/glutin |
161 | pub trait HasWindowHandle { |
162 | /// Get a handle to the window. |
163 | fn window_handle(&self) -> Result<WindowHandle<'_>, HandleError>; |
164 | } |
165 | |
166 | impl<H: HasWindowHandle + ?Sized> HasWindowHandle for &H { |
167 | fn window_handle(&self) -> Result<WindowHandle<'_>, HandleError> { |
168 | (**self).window_handle() |
169 | } |
170 | } |
171 | |
172 | impl<H: HasWindowHandle + ?Sized> HasWindowHandle for &mut H { |
173 | fn window_handle(&self) -> Result<WindowHandle<'_>, HandleError> { |
174 | (**self).window_handle() |
175 | } |
176 | } |
177 | |
178 | #[cfg (feature = "alloc" )] |
179 | #[cfg_attr (docsrs, doc(cfg(feature = "alloc" )))] |
180 | impl<H: HasWindowHandle + ?Sized> HasWindowHandle for alloc::boxed::Box<H> { |
181 | fn window_handle(&self) -> Result<WindowHandle<'_>, HandleError> { |
182 | (**self).window_handle() |
183 | } |
184 | } |
185 | |
186 | #[cfg (feature = "alloc" )] |
187 | #[cfg_attr (docsrs, doc(cfg(feature = "alloc" )))] |
188 | impl<H: HasWindowHandle + ?Sized> HasWindowHandle for alloc::rc::Rc<H> { |
189 | fn window_handle(&self) -> Result<WindowHandle<'_>, HandleError> { |
190 | (**self).window_handle() |
191 | } |
192 | } |
193 | |
194 | #[cfg (feature = "alloc" )] |
195 | #[cfg_attr (docsrs, doc(cfg(feature = "alloc" )))] |
196 | impl<H: HasWindowHandle + ?Sized> HasWindowHandle for alloc::sync::Arc<H> { |
197 | fn window_handle(&self) -> Result<WindowHandle<'_>, HandleError> { |
198 | (**self).window_handle() |
199 | } |
200 | } |
201 | |
202 | /// The handle to a window. |
203 | /// |
204 | /// This is the primary return type of the [`HasWindowHandle`] trait. All *pointers* within this type |
205 | /// are guaranteed to be valid and not dangling for the lifetime of the handle. This excludes window IDs |
206 | /// like XIDs and the window ID for web platforms. See the documentation on the [`HasWindowHandle`] |
207 | /// trait for more information about these safety requirements. |
208 | /// |
209 | /// This handle is guaranteed to be safe and valid. |
210 | #[derive (PartialEq, Eq, Hash, Copy, Clone)] |
211 | pub struct WindowHandle<'a> { |
212 | raw: RawWindowHandle, |
213 | _marker: PhantomData<&'a ()>, |
214 | } |
215 | |
216 | impl fmt::Debug for WindowHandle<'_> { |
217 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
218 | f.debug_tuple(name:"WindowHandle" ).field(&self.raw).finish() |
219 | } |
220 | } |
221 | |
222 | impl<'a> WindowHandle<'a> { |
223 | /// Borrow a `WindowHandle` from a [`RawWindowHandle`]. |
224 | /// |
225 | /// # Safety |
226 | /// |
227 | /// Users can safely assume that non-`null`/`0` fields are valid handles, and it is up to the |
228 | /// implementer of this trait to ensure that condition is upheld. |
229 | /// |
230 | /// Despite that qualification, implementers should still make a best-effort attempt to fill in all |
231 | /// available fields. If an implementation doesn't, and a downstream user needs the field, it should |
232 | /// try to derive the field from other fields the implementer *does* provide via whatever methods the |
233 | /// platform provides. |
234 | /// |
235 | /// Note that this guarantee only applies to *pointers*, and not any window ID types in the handle. |
236 | /// This includes Window IDs (XIDs) from X11 and the window ID for web platforms. There is no way for |
237 | /// Rust to enforce any kind of invariant on these types, since: |
238 | /// |
239 | /// - For all three listed platforms, it is possible for safe code in the same process to delete |
240 | /// the window. |
241 | /// - For X11, it is possible for code in a different process to delete the window. In fact, it is |
242 | /// possible for code on a different *machine* to delete the window. |
243 | /// |
244 | /// It is *also* possible for the window to be replaced with another, valid-but-different window. User |
245 | /// code should be aware of this possibility, and should be ready to soundly handle the possible error |
246 | /// conditions that can arise from this. |
247 | pub unsafe fn borrow_raw(raw: RawWindowHandle) -> Self { |
248 | Self { |
249 | raw, |
250 | _marker: PhantomData, |
251 | } |
252 | } |
253 | |
254 | /// Get the underlying raw window handle. |
255 | pub fn as_raw(&self) -> RawWindowHandle { |
256 | self.raw.clone() |
257 | } |
258 | } |
259 | |
260 | impl AsRef<RawWindowHandle> for WindowHandle<'_> { |
261 | fn as_ref(&self) -> &RawWindowHandle { |
262 | &self.raw |
263 | } |
264 | } |
265 | |
266 | impl Borrow<RawWindowHandle> for WindowHandle<'_> { |
267 | fn borrow(&self) -> &RawWindowHandle { |
268 | &self.raw |
269 | } |
270 | } |
271 | |
272 | impl From<WindowHandle<'_>> for RawWindowHandle { |
273 | fn from(handle: WindowHandle<'_>) -> Self { |
274 | handle.raw |
275 | } |
276 | } |
277 | |
278 | impl HasWindowHandle for WindowHandle<'_> { |
279 | fn window_handle(&self) -> Result<Self, HandleError> { |
280 | Ok(*self) |
281 | } |
282 | } |
283 | |