Skip to content

Commit

Permalink
feat: Add AnyThread wrapper
Browse files Browse the repository at this point in the history
This type can be used to ignore thread affinity for types that already
take `HasWindowHandle`.

Signed-off-by: John Nunley <dev@notgull.net>
  • Loading branch information
notgull committed Mar 23, 2024
1 parent d6747eb commit 3414f53
Showing 1 changed file with 91 additions and 1 deletion.
92 changes: 91 additions & 1 deletion src/platform/windows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
//!
//! The supported OS version is Windows 7 or higher, though Windows 10 is
//! tested regularly.
use std::{ffi::c_void, path::Path};
use std::{borrow::Borrow, ffi::c_void, path::Path};

use crate::{
dpi::PhysicalSize,
Expand Down Expand Up @@ -105,6 +105,62 @@ pub enum CornerPreference {
RoundSmall = 3,
}

/// A wrapper around a [`Window`] that ignores thread-specific window handle limitations.
///
/// See [`WindowBorrowExtWindows::any_thread`] for more information.
#[derive(Debug)]
pub struct AnyThread<W>(W);

impl<W: Borrow<Window>> AnyThread<W> {
/// Get a reference to the inner window.
#[inline]
pub fn get_ref(&self) -> &Window {
self.0.borrow()
}

/// Get a reference to the inner object.
#[inline]
pub fn inner(&self) -> &W {
&self.0
}

/// Unwrap and get the inner window.
#[inline]
pub fn into_inner(self) -> W {
self.0
}
}

impl<W: Borrow<Window>> AsRef<Window> for AnyThread<W> {
fn as_ref(&self) -> &Window {
self.get_ref()
}
}

impl<W: Borrow<Window>> Borrow<Window> for AnyThread<W> {
fn borrow(&self) -> &Window {
self.get_ref()
}
}

impl<W: Borrow<Window>> std::ops::Deref for AnyThread<W> {
type Target = Window;

fn deref(&self) -> &Self::Target {
self.get_ref()
}
}

#[cfg(feature = "rwh_06")]
impl<W: Borrow<Window>> rwh_06::HasWindowHandle for AnyThread<W> {
fn window_handle(&self) -> Result<rwh_06::WindowHandle<'_>, rwh_06::HandleError> {
// SAFETY: The top level user has asserted this is only used safely.
unsafe {
self.get_ref().window_handle_any_thread()
}
}
}

/// Additional methods on `EventLoop` that are specific to Windows.
pub trait EventLoopBuilderExtWindows {
/// Whether to allow the event loop to be created off of the main thread.
Expand Down Expand Up @@ -265,6 +321,11 @@ pub trait WindowExtWindows {
/// However in some cases you may already know that you are using the window handle for
/// operations that are guaranteed to be thread-safe. In which case this function aims
/// to provide an escape hatch so these functions are still accessible from other threads.
///
/// # Safety
///
/// It is the responsibility of the user to only pass the window handle into thread-safe
/// Win32 APIs.
///
/// [`SetWindowSubclass`]: https://learn.microsoft.com/en-us/windows/win32/api/commctrl/nf-commctrl-setwindowsubclass
/// [`GetDC`]: https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getdc
Expand Down Expand Up @@ -363,6 +424,35 @@ impl WindowExtWindows for Window {
}
}

/// Additional methods for anything that dereference to [`Window`].
///
/// [`Window`]: crate::window::Window
pub trait WindowBorrowExtWindows : Borrow<Window> + Sized {
/// Create an object that allows accessing the inner window handle in a thread-unsafe way.
///
/// It is possible to call [`window_handle_any_thread`] to get around Windows's thread
/// affinity limitations. However, it may be desired to pass the [`Window`] into something
/// that requires the [`HasWindowHandle`] trait, while ignoring thread affinity limitations.
///
/// This function wraps anything that implements `Borrow<Window>` into a structure that
/// uses the inner window handle as a mean of implementing [`HasWindowHandle`]. It wraps
/// `Window`, `&Window`, `Arc<Window>`, and other reference types.
///
/// # Safety
///
/// It is the responsibility of the user to only pass the window handle into thread-safe
/// Win32 APIs.
///
/// [`window_handle_any_thread`]: WindowExtWindows::window_handle_any_thread
/// [`Window`]: crate::window::Window
/// [`HasWindowHandle`]: rwh_06::HasWindowHandle
unsafe fn any_thread(self) -> AnyThread<Self> {
AnyThread(self)
}
}

impl<W: Borrow<Window> + Sized> WindowBorrowExtWindows for W {}

/// Additional methods on `WindowAttributes` that are specific to Windows.
#[allow(rustdoc::broken_intra_doc_links)]
pub trait WindowAttributesExtWindows {
Expand Down

0 comments on commit 3414f53

Please # to comment.