|
| 1 | +use raw_window_handle::{ |
| 2 | + HasRawDisplayHandle, HasRawWindowHandle, RawDisplayHandle, RawWindowHandle, |
| 3 | +}; |
| 4 | + |
| 5 | +/// A wrapper over [`RawWindowHandle`] and [`RawDisplayHandle`] that allows us to safely pass it across threads. |
| 6 | +/// |
| 7 | +/// Depending on the platform, the underlying pointer-containing handle cannot be used on all threads, |
| 8 | +/// and so we cannot simply make it (or any type that has a safe operation to get a [`RawWindowHandle`] or [`RawDisplayHandle`]) |
| 9 | +/// thread-safe. |
| 10 | +#[derive(Debug, Clone)] |
| 11 | +pub struct RawHandleWrapper { |
| 12 | + pub window_handle: RawWindowHandle, |
| 13 | + pub display_handle: RawDisplayHandle, |
| 14 | +} |
| 15 | + |
| 16 | +impl RawHandleWrapper { |
| 17 | + /// Returns a [`HasRawWindowHandle`] + [`HasRawDisplayHandle`] impl, which exposes [`RawWindowHandle`] and [`RawDisplayHandle`]. |
| 18 | + /// |
| 19 | + /// # Safety |
| 20 | + /// |
| 21 | + /// Some platforms have constraints on where/how this handle can be used. For example, some platforms don't support doing window |
| 22 | + /// operations off of the main thread. The caller must ensure the [`RawHandleWrapper`] is only used in valid contexts. |
| 23 | + pub unsafe fn get_handle(&self) -> ThreadLockedRawWindowHandleWrapper { |
| 24 | + ThreadLockedRawWindowHandleWrapper(self.clone()) |
| 25 | + } |
| 26 | + |
| 27 | + pub fn get_display_handle(&self) -> RawDisplayHandle { |
| 28 | + self.display_handle |
| 29 | + } |
| 30 | + |
| 31 | + pub fn get_window_handle(&self) -> RawWindowHandle { |
| 32 | + self.window_handle |
| 33 | + } |
| 34 | +} |
| 35 | + |
| 36 | +// SAFETY: [`RawHandleWrapper`] is just a normal "raw pointer", which doesn't impl Send/Sync. However the pointer is only |
| 37 | +// exposed via an unsafe method that forces the user to make a call for a given platform. (ex: some platforms don't |
| 38 | +// support doing window operations off of the main thread). |
| 39 | +// A recommendation for this pattern (and more context) is available here: |
| 40 | +// https://github.com/rust-windowing/raw-window-handle/issues/59 |
| 41 | +unsafe impl Send for RawHandleWrapper {} |
| 42 | +unsafe impl Sync for RawHandleWrapper {} |
| 43 | + |
| 44 | +/// A [`RawHandleWrapper`] that cannot be sent across threads. |
| 45 | +/// |
| 46 | +/// This safely exposes [`RawWindowHandle`] and [`RawDisplayHandle`], but care must be taken to ensure that the construction itself is correct. |
| 47 | +/// |
| 48 | +/// This can only be constructed via the [`RawHandleWrapper::get_handle()`] method; |
| 49 | +/// be sure to read the safety docs there about platform-specific limitations. |
| 50 | +/// In many cases, this should only be constructed on the main thread. |
| 51 | +pub struct ThreadLockedRawWindowHandleWrapper(RawHandleWrapper); |
| 52 | + |
| 53 | +// SAFETY: the caller has validated that this is a valid context to get [`RawHandleWrapper`] |
| 54 | +// as otherwise an instance of this type could not have been constructed |
| 55 | +// NOTE: we cannot simply impl HasRawWindowHandle for RawHandleWrapper, |
| 56 | +// as the `raw_window_handle` method is safe. We cannot guarantee that all calls |
| 57 | +// of this method are correct (as it may be off the main thread on an incompatible platform), |
| 58 | +// and so exposing a safe method to get a [`RawWindowHandle`] directly would be UB. |
| 59 | +unsafe impl HasRawWindowHandle for ThreadLockedRawWindowHandleWrapper { |
| 60 | + fn raw_window_handle(&self) -> RawWindowHandle { |
| 61 | + self.0.get_window_handle() |
| 62 | + } |
| 63 | +} |
| 64 | + |
| 65 | +// SAFETY: the caller has validated that this is a valid context to get [`RawDisplayHandle`] |
| 66 | +// as otherwise an instance of this type could not have been constructed |
| 67 | +// NOTE: we cannot simply impl HasRawDisplayHandle for RawHandleWrapper, |
| 68 | +// as the `raw_display_handle` method is safe. We cannot guarantee that all calls |
| 69 | +// of this method are correct (as it may be off the main thread on an incompatible platform), |
| 70 | +// and so exposing a safe method to get a [`RawDisplayHandle`] directly would be UB. |
| 71 | +unsafe impl HasRawDisplayHandle for ThreadLockedRawWindowHandleWrapper { |
| 72 | + fn raw_display_handle(&self) -> RawDisplayHandle { |
| 73 | + self.0.get_display_handle() |
| 74 | + } |
| 75 | +} |
0 commit comments