utils: add cast_* methods to allow more type-safe casting

Relying on just `as_any` was error prone and will become redundant in
the future, once upcasting will be stable, we also won't to impose a
restriction on to which concrete type we're casting, since casting
to a type that doesn't implement a base trait doesn't make much
sense.

Co-authored-by: Kirill Chibisov <contact@kchibisov.com>
This commit is contained in:
Mads Marquart 2025-03-11 14:35:25 +01:00 committed by GitHub
parent 5cada36ae8
commit 16d5f46db1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
19 changed files with 158 additions and 136 deletions

View file

@ -76,8 +76,8 @@ changelog entry.
### Changed ### Changed
- Change `ActiveEventLoop` to be a trait. - Change `ActiveEventLoop` and `Window` to be traits, and added `cast_ref`/`cast_mut`/`cast`
- Change `Window` to be a trait. methods to extract the backend type from those.
- `ActiveEventLoop::create_window` now returns `Box<dyn Window>`. - `ActiveEventLoop::create_window` now returns `Box<dyn Window>`.
- `ApplicationHandler` now uses `dyn ActiveEventLoop`. - `ApplicationHandler` now uses `dyn ActiveEventLoop`.
- On Web, let events wake up event loop immediately when using `ControlFlow::Poll`. - On Web, let events wake up event loop immediately when using `ControlFlow::Poll`.

View file

@ -25,7 +25,7 @@ use crate::application::ApplicationHandler;
use crate::error::{EventLoopError, RequestError}; use crate::error::{EventLoopError, RequestError};
use crate::monitor::MonitorHandle; use crate::monitor::MonitorHandle;
use crate::platform_impl; use crate::platform_impl;
use crate::utils::AsAny; use crate::utils::{impl_dyn_casting, AsAny};
use crate::window::{CustomCursor, CustomCursorSource, Theme, Window, WindowAttributes}; use crate::window::{CustomCursor, CustomCursorSource, Theme, Window, WindowAttributes};
/// Provides a way to retrieve events from the system and from the windows that were registered to /// Provides a way to retrieve events from the system and from the windows that were registered to
@ -406,6 +406,8 @@ impl HasDisplayHandle for dyn ActiveEventLoop + '_ {
} }
} }
impl_dyn_casting!(ActiveEventLoop);
/// A proxy for the underlying display handle. /// A proxy for the underlying display handle.
/// ///
/// The purpose of this type is to provide a cheaply cloneable handle to the underlying /// The purpose of this type is to provide a cheaply cloneable handle to the underlying

View file

@ -12,7 +12,7 @@ use std::ops::Deref;
use std::sync::Arc; use std::sync::Arc;
use crate::dpi::{PhysicalPosition, PhysicalSize}; use crate::dpi::{PhysicalPosition, PhysicalSize};
use crate::utils::AsAny; use crate::utils::{impl_dyn_casting, AsAny};
/// Handle to a monitor. /// Handle to a monitor.
/// ///
@ -148,6 +148,8 @@ impl PartialEq for dyn MonitorHandleProvider + '_ {
impl Eq for dyn MonitorHandleProvider + '_ {} impl Eq for dyn MonitorHandleProvider + '_ {}
impl_dyn_casting!(MonitorHandleProvider);
/// Describes a fullscreen video mode of a monitor. /// Describes a fullscreen video mode of a monitor.
/// ///
/// Can be acquired with [`MonitorHandleProvider::video_modes`]. /// Can be acquired with [`MonitorHandleProvider::video_modes`].

View file

@ -101,20 +101,19 @@ pub trait WindowExtAndroid {
impl WindowExtAndroid for dyn Window + '_ { impl WindowExtAndroid for dyn Window + '_ {
fn content_rect(&self) -> Rect { fn content_rect(&self) -> Rect {
let window = self.as_any().downcast_ref::<crate::platform_impl::Window>().unwrap(); let window = self.cast_ref::<crate::platform_impl::Window>().unwrap();
window.content_rect() window.content_rect()
} }
fn config(&self) -> ConfigurationRef { fn config(&self) -> ConfigurationRef {
let window = self.as_any().downcast_ref::<crate::platform_impl::Window>().unwrap(); let window = self.cast_ref::<crate::platform_impl::Window>().unwrap();
window.config() window.config()
} }
} }
impl ActiveEventLoopExtAndroid for dyn ActiveEventLoop + '_ { impl ActiveEventLoopExtAndroid for dyn ActiveEventLoop + '_ {
fn android_app(&self) -> &AndroidApp { fn android_app(&self) -> &AndroidApp {
let event_loop = let event_loop = self.cast_ref::<crate::platform_impl::ActiveEventLoop>().unwrap();
self.as_any().downcast_ref::<crate::platform_impl::ActiveEventLoop>().unwrap();
&event_loop.app &event_loop.app
} }
} }

View file

@ -214,25 +214,25 @@ pub trait WindowExtIOS {
impl WindowExtIOS for dyn Window + '_ { impl WindowExtIOS for dyn Window + '_ {
#[inline] #[inline]
fn set_scale_factor(&self, scale_factor: f64) { fn set_scale_factor(&self, scale_factor: f64) {
let window = self.as_any().downcast_ref::<crate::platform_impl::Window>().unwrap(); let window = self.cast_ref::<crate::platform_impl::Window>().unwrap();
window.maybe_wait_on_main(move |w| w.set_scale_factor(scale_factor)); window.maybe_wait_on_main(move |w| w.set_scale_factor(scale_factor));
} }
#[inline] #[inline]
fn set_valid_orientations(&self, valid_orientations: ValidOrientations) { fn set_valid_orientations(&self, valid_orientations: ValidOrientations) {
let window = self.as_any().downcast_ref::<crate::platform_impl::Window>().unwrap(); let window = self.cast_ref::<crate::platform_impl::Window>().unwrap();
window.maybe_wait_on_main(move |w| w.set_valid_orientations(valid_orientations)); window.maybe_wait_on_main(move |w| w.set_valid_orientations(valid_orientations));
} }
#[inline] #[inline]
fn set_prefers_home_indicator_hidden(&self, hidden: bool) { fn set_prefers_home_indicator_hidden(&self, hidden: bool) {
let window = self.as_any().downcast_ref::<crate::platform_impl::Window>().unwrap(); let window = self.cast_ref::<crate::platform_impl::Window>().unwrap();
window.maybe_wait_on_main(move |w| w.set_prefers_home_indicator_hidden(hidden)); window.maybe_wait_on_main(move |w| w.set_prefers_home_indicator_hidden(hidden));
} }
#[inline] #[inline]
fn set_preferred_screen_edges_deferring_system_gestures(&self, edges: ScreenEdge) { fn set_preferred_screen_edges_deferring_system_gestures(&self, edges: ScreenEdge) {
let window = self.as_any().downcast_ref::<crate::platform_impl::Window>().unwrap(); let window = self.cast_ref::<crate::platform_impl::Window>().unwrap();
window.maybe_wait_on_main(move |w| { window.maybe_wait_on_main(move |w| {
w.set_preferred_screen_edges_deferring_system_gestures(edges) w.set_preferred_screen_edges_deferring_system_gestures(edges)
}); });
@ -240,19 +240,19 @@ impl WindowExtIOS for dyn Window + '_ {
#[inline] #[inline]
fn set_prefers_status_bar_hidden(&self, hidden: bool) { fn set_prefers_status_bar_hidden(&self, hidden: bool) {
let window = self.as_any().downcast_ref::<crate::platform_impl::Window>().unwrap(); let window = self.cast_ref::<crate::platform_impl::Window>().unwrap();
window.maybe_wait_on_main(move |w| w.set_prefers_status_bar_hidden(hidden)); window.maybe_wait_on_main(move |w| w.set_prefers_status_bar_hidden(hidden));
} }
#[inline] #[inline]
fn set_preferred_status_bar_style(&self, status_bar_style: StatusBarStyle) { fn set_preferred_status_bar_style(&self, status_bar_style: StatusBarStyle) {
let window = self.as_any().downcast_ref::<crate::platform_impl::Window>().unwrap(); let window = self.cast_ref::<crate::platform_impl::Window>().unwrap();
window.maybe_wait_on_main(move |w| w.set_preferred_status_bar_style(status_bar_style)) window.maybe_wait_on_main(move |w| w.set_preferred_status_bar_style(status_bar_style))
} }
#[inline] #[inline]
fn recognize_pinch_gesture(&self, should_recognize: bool) { fn recognize_pinch_gesture(&self, should_recognize: bool) {
let window = self.as_any().downcast_ref::<crate::platform_impl::Window>().unwrap(); let window = self.cast_ref::<crate::platform_impl::Window>().unwrap();
window.maybe_wait_on_main(move |w| w.recognize_pinch_gesture(should_recognize)); window.maybe_wait_on_main(move |w| w.recognize_pinch_gesture(should_recognize));
} }
@ -263,7 +263,7 @@ impl WindowExtIOS for dyn Window + '_ {
minimum_number_of_touches: u8, minimum_number_of_touches: u8,
maximum_number_of_touches: u8, maximum_number_of_touches: u8,
) { ) {
let window = self.as_any().downcast_ref::<crate::platform_impl::Window>().unwrap(); let window = self.cast_ref::<crate::platform_impl::Window>().unwrap();
window.maybe_wait_on_main(move |w| { window.maybe_wait_on_main(move |w| {
w.recognize_pan_gesture( w.recognize_pan_gesture(
should_recognize, should_recognize,
@ -275,13 +275,13 @@ impl WindowExtIOS for dyn Window + '_ {
#[inline] #[inline]
fn recognize_doubletap_gesture(&self, should_recognize: bool) { fn recognize_doubletap_gesture(&self, should_recognize: bool) {
let window = self.as_any().downcast_ref::<crate::platform_impl::Window>().unwrap(); let window = self.cast_ref::<crate::platform_impl::Window>().unwrap();
window.maybe_wait_on_main(move |w| w.recognize_doubletap_gesture(should_recognize)); window.maybe_wait_on_main(move |w| w.recognize_doubletap_gesture(should_recognize));
} }
#[inline] #[inline]
fn recognize_rotation_gesture(&self, should_recognize: bool) { fn recognize_rotation_gesture(&self, should_recognize: bool) {
let window = self.as_any().downcast_ref::<crate::platform_impl::Window>().unwrap(); let window = self.cast_ref::<crate::platform_impl::Window>().unwrap();
window.maybe_wait_on_main(move |w| w.recognize_rotation_gesture(should_recognize)); window.maybe_wait_on_main(move |w| w.recognize_rotation_gesture(should_recognize));
} }
} }
@ -398,13 +398,13 @@ impl MonitorHandleExtIOS for MonitorHandle {
fn ui_screen(&self) -> *mut c_void { fn ui_screen(&self) -> *mut c_void {
// SAFETY: The marker is only used to get the pointer of the screen // SAFETY: The marker is only used to get the pointer of the screen
let mtm = unsafe { objc2::MainThreadMarker::new_unchecked() }; let mtm = unsafe { objc2::MainThreadMarker::new_unchecked() };
let monitor = self.as_any().downcast_ref::<IosMonitorHandle>().unwrap(); let monitor = self.cast_ref::<IosMonitorHandle>().unwrap();
objc2::rc::Retained::as_ptr(monitor.ui_screen(mtm)) as *mut c_void objc2::rc::Retained::as_ptr(monitor.ui_screen(mtm)) as *mut c_void
} }
#[inline] #[inline]
fn preferred_video_mode(&self) -> VideoMode { fn preferred_video_mode(&self) -> VideoMode {
let monitor = self.as_any().downcast_ref::<IosMonitorHandle>().unwrap(); let monitor = self.cast_ref::<IosMonitorHandle>().unwrap();
monitor.preferred_video_mode() monitor.preferred_video_mode()
} }
} }

View file

@ -168,109 +168,109 @@ pub trait WindowExtMacOS {
impl WindowExtMacOS for dyn Window + '_ { impl WindowExtMacOS for dyn Window + '_ {
#[inline] #[inline]
fn simple_fullscreen(&self) -> bool { fn simple_fullscreen(&self) -> bool {
let window = self.as_any().downcast_ref::<crate::platform_impl::Window>().unwrap(); let window = self.cast_ref::<crate::platform_impl::Window>().unwrap();
window.maybe_wait_on_main(|w| w.simple_fullscreen()) window.maybe_wait_on_main(|w| w.simple_fullscreen())
} }
#[inline] #[inline]
fn set_simple_fullscreen(&self, fullscreen: bool) -> bool { fn set_simple_fullscreen(&self, fullscreen: bool) -> bool {
let window = self.as_any().downcast_ref::<crate::platform_impl::Window>().unwrap(); let window = self.cast_ref::<crate::platform_impl::Window>().unwrap();
window.maybe_wait_on_main(move |w| w.set_simple_fullscreen(fullscreen)) window.maybe_wait_on_main(move |w| w.set_simple_fullscreen(fullscreen))
} }
#[inline] #[inline]
fn has_shadow(&self) -> bool { fn has_shadow(&self) -> bool {
let window = self.as_any().downcast_ref::<crate::platform_impl::Window>().unwrap(); let window = self.cast_ref::<crate::platform_impl::Window>().unwrap();
window.maybe_wait_on_main(|w| w.has_shadow()) window.maybe_wait_on_main(|w| w.has_shadow())
} }
#[inline] #[inline]
fn set_has_shadow(&self, has_shadow: bool) { fn set_has_shadow(&self, has_shadow: bool) {
let window = self.as_any().downcast_ref::<crate::platform_impl::Window>().unwrap(); let window = self.cast_ref::<crate::platform_impl::Window>().unwrap();
window.maybe_wait_on_main(move |w| w.set_has_shadow(has_shadow)); window.maybe_wait_on_main(move |w| w.set_has_shadow(has_shadow));
} }
#[inline] #[inline]
fn set_tabbing_identifier(&self, identifier: &str) { fn set_tabbing_identifier(&self, identifier: &str) {
let window = self.as_any().downcast_ref::<crate::platform_impl::Window>().unwrap(); let window = self.cast_ref::<crate::platform_impl::Window>().unwrap();
window.maybe_wait_on_main(|w| w.set_tabbing_identifier(identifier)) window.maybe_wait_on_main(|w| w.set_tabbing_identifier(identifier))
} }
#[inline] #[inline]
fn tabbing_identifier(&self) -> String { fn tabbing_identifier(&self) -> String {
let window = self.as_any().downcast_ref::<crate::platform_impl::Window>().unwrap(); let window = self.cast_ref::<crate::platform_impl::Window>().unwrap();
window.maybe_wait_on_main(|w| w.tabbing_identifier()) window.maybe_wait_on_main(|w| w.tabbing_identifier())
} }
#[inline] #[inline]
fn select_next_tab(&self) { fn select_next_tab(&self) {
let window = self.as_any().downcast_ref::<crate::platform_impl::Window>().unwrap(); let window = self.cast_ref::<crate::platform_impl::Window>().unwrap();
window.maybe_wait_on_main(|w| w.select_next_tab()); window.maybe_wait_on_main(|w| w.select_next_tab());
} }
#[inline] #[inline]
fn select_previous_tab(&self) { fn select_previous_tab(&self) {
let window = self.as_any().downcast_ref::<crate::platform_impl::Window>().unwrap(); let window = self.cast_ref::<crate::platform_impl::Window>().unwrap();
window.maybe_wait_on_main(|w| w.select_previous_tab()); window.maybe_wait_on_main(|w| w.select_previous_tab());
} }
#[inline] #[inline]
fn select_tab_at_index(&self, index: usize) { fn select_tab_at_index(&self, index: usize) {
let window = self.as_any().downcast_ref::<crate::platform_impl::Window>().unwrap(); let window = self.cast_ref::<crate::platform_impl::Window>().unwrap();
window.maybe_wait_on_main(move |w| w.select_tab_at_index(index)); window.maybe_wait_on_main(move |w| w.select_tab_at_index(index));
} }
#[inline] #[inline]
fn num_tabs(&self) -> usize { fn num_tabs(&self) -> usize {
let window = self.as_any().downcast_ref::<crate::platform_impl::Window>().unwrap(); let window = self.cast_ref::<crate::platform_impl::Window>().unwrap();
window.maybe_wait_on_main(|w| w.num_tabs()) window.maybe_wait_on_main(|w| w.num_tabs())
} }
#[inline] #[inline]
fn is_document_edited(&self) -> bool { fn is_document_edited(&self) -> bool {
let window = self.as_any().downcast_ref::<crate::platform_impl::Window>().unwrap(); let window = self.cast_ref::<crate::platform_impl::Window>().unwrap();
window.maybe_wait_on_main(|w| w.is_document_edited()) window.maybe_wait_on_main(|w| w.is_document_edited())
} }
#[inline] #[inline]
fn set_document_edited(&self, edited: bool) { fn set_document_edited(&self, edited: bool) {
let window = self.as_any().downcast_ref::<crate::platform_impl::Window>().unwrap(); let window = self.cast_ref::<crate::platform_impl::Window>().unwrap();
window.maybe_wait_on_main(move |w| w.set_document_edited(edited)); window.maybe_wait_on_main(move |w| w.set_document_edited(edited));
} }
#[inline] #[inline]
fn set_option_as_alt(&self, option_as_alt: OptionAsAlt) { fn set_option_as_alt(&self, option_as_alt: OptionAsAlt) {
let window = self.as_any().downcast_ref::<crate::platform_impl::Window>().unwrap(); let window = self.cast_ref::<crate::platform_impl::Window>().unwrap();
window.maybe_wait_on_main(move |w| w.set_option_as_alt(option_as_alt)); window.maybe_wait_on_main(move |w| w.set_option_as_alt(option_as_alt));
} }
#[inline] #[inline]
fn option_as_alt(&self) -> OptionAsAlt { fn option_as_alt(&self) -> OptionAsAlt {
let window = self.as_any().downcast_ref::<crate::platform_impl::Window>().unwrap(); let window = self.cast_ref::<crate::platform_impl::Window>().unwrap();
window.maybe_wait_on_main(|w| w.option_as_alt()) window.maybe_wait_on_main(|w| w.option_as_alt())
} }
#[inline] #[inline]
fn set_borderless_game(&self, borderless_game: bool) { fn set_borderless_game(&self, borderless_game: bool) {
let window = self.as_any().downcast_ref::<crate::platform_impl::Window>().unwrap(); let window = self.cast_ref::<crate::platform_impl::Window>().unwrap();
window.maybe_wait_on_main(|w| w.set_borderless_game(borderless_game)) window.maybe_wait_on_main(|w| w.set_borderless_game(borderless_game))
} }
#[inline] #[inline]
fn is_borderless_game(&self) -> bool { fn is_borderless_game(&self) -> bool {
let window = self.as_any().downcast_ref::<crate::platform_impl::Window>().unwrap(); let window = self.cast_ref::<crate::platform_impl::Window>().unwrap();
window.maybe_wait_on_main(|w| w.is_borderless_game()) window.maybe_wait_on_main(|w| w.is_borderless_game())
} }
#[inline] #[inline]
fn set_unified_titlebar(&self, unified_titlebar: bool) { fn set_unified_titlebar(&self, unified_titlebar: bool) {
let window = self.as_any().downcast_ref::<crate::platform_impl::Window>().unwrap(); let window = self.cast_ref::<crate::platform_impl::Window>().unwrap();
window.maybe_wait_on_main(|w| w.set_unified_titlebar(unified_titlebar)) window.maybe_wait_on_main(|w| w.set_unified_titlebar(unified_titlebar))
} }
#[inline] #[inline]
fn unified_titlebar(&self) -> bool { fn unified_titlebar(&self) -> bool {
let window = self.as_any().downcast_ref::<crate::platform_impl::Window>().unwrap(); let window = self.cast_ref::<crate::platform_impl::Window>().unwrap();
window.maybe_wait_on_main(|w| w.unified_titlebar()) window.maybe_wait_on_main(|w| w.unified_titlebar())
} }
} }
@ -506,7 +506,7 @@ pub trait MonitorHandleExtMacOS {
impl MonitorHandleExtMacOS for MonitorHandle { impl MonitorHandleExtMacOS for MonitorHandle {
fn ns_screen(&self) -> Option<*mut c_void> { fn ns_screen(&self) -> Option<*mut c_void> {
let monitor = self.as_any().downcast_ref::<MacOsMonitorHandle>().unwrap(); let monitor = self.cast_ref::<MacOsMonitorHandle>().unwrap();
// SAFETY: We only use the marker to get a pointer // SAFETY: We only use the marker to get a pointer
let mtm = unsafe { objc2::MainThreadMarker::new_unchecked() }; let mtm = unsafe { objc2::MainThreadMarker::new_unchecked() };
monitor.ns_screen(mtm).map(|s| objc2::rc::Retained::as_ptr(&s) as _) monitor.ns_screen(mtm).map(|s| objc2::rc::Retained::as_ptr(&s) as _)
@ -532,32 +532,28 @@ pub trait ActiveEventLoopExtMacOS {
impl ActiveEventLoopExtMacOS for dyn ActiveEventLoop + '_ { impl ActiveEventLoopExtMacOS for dyn ActiveEventLoop + '_ {
fn hide_application(&self) { fn hide_application(&self) {
let event_loop = self let event_loop = self
.as_any() .cast_ref::<crate::platform_impl::ActiveEventLoop>()
.downcast_ref::<crate::platform_impl::ActiveEventLoop>()
.expect("non macOS event loop on macOS"); .expect("non macOS event loop on macOS");
event_loop.hide_application() event_loop.hide_application()
} }
fn hide_other_applications(&self) { fn hide_other_applications(&self) {
let event_loop = self let event_loop = self
.as_any() .cast_ref::<crate::platform_impl::ActiveEventLoop>()
.downcast_ref::<crate::platform_impl::ActiveEventLoop>()
.expect("non macOS event loop on macOS"); .expect("non macOS event loop on macOS");
event_loop.hide_other_applications() event_loop.hide_other_applications()
} }
fn set_allows_automatic_window_tabbing(&self, enabled: bool) { fn set_allows_automatic_window_tabbing(&self, enabled: bool) {
let event_loop = self let event_loop = self
.as_any() .cast_ref::<crate::platform_impl::ActiveEventLoop>()
.downcast_ref::<crate::platform_impl::ActiveEventLoop>()
.expect("non macOS event loop on macOS"); .expect("non macOS event loop on macOS");
event_loop.set_allows_automatic_window_tabbing(enabled); event_loop.set_allows_automatic_window_tabbing(enabled);
} }
fn allows_automatic_window_tabbing(&self) -> bool { fn allows_automatic_window_tabbing(&self) -> bool {
let event_loop = self let event_loop = self
.as_any() .cast_ref::<crate::platform_impl::ActiveEventLoop>()
.downcast_ref::<crate::platform_impl::ActiveEventLoop>()
.expect("non macOS event loop on macOS"); .expect("non macOS event loop on macOS");
event_loop.allows_automatic_window_tabbing() event_loop.allows_automatic_window_tabbing()
} }

View file

@ -75,15 +75,12 @@ impl EventLoopExtStartupNotify for dyn ActiveEventLoop + '_ {
impl WindowExtStartupNotify for dyn Window + '_ { impl WindowExtStartupNotify for dyn Window + '_ {
fn request_activation_token(&self) -> Result<AsyncRequestSerial, RequestError> { fn request_activation_token(&self) -> Result<AsyncRequestSerial, RequestError> {
#[cfg(wayland_platform)] #[cfg(wayland_platform)]
if let Some(window) = self.as_any().downcast_ref::<crate::platform_impl::wayland::Window>() if let Some(window) = self.cast_ref::<crate::platform_impl::wayland::Window>() {
{
return window.request_activation_token(); return window.request_activation_token();
} }
#[cfg(x11_platform)] #[cfg(x11_platform)]
if let Some(window) = if let Some(window) = self.cast_ref::<crate::platform_impl::x11::window::Window>() {
self.as_any().downcast_ref::<crate::platform_impl::x11::window::Window>()
{
return window.request_activation_token(); return window.request_activation_token();
} }

View file

@ -26,7 +26,7 @@ pub trait ActiveEventLoopExtWayland {
impl ActiveEventLoopExtWayland for dyn ActiveEventLoop + '_ { impl ActiveEventLoopExtWayland for dyn ActiveEventLoop + '_ {
#[inline] #[inline]
fn is_wayland(&self) -> bool { fn is_wayland(&self) -> bool {
self.as_any().downcast_ref::<crate::platform_impl::wayland::ActiveEventLoop>().is_some() self.cast_ref::<crate::platform_impl::wayland::ActiveEventLoop>().is_some()
} }
} }

View file

@ -105,29 +105,23 @@ pub trait WindowExtWeb {
impl WindowExtWeb for dyn Window + '_ { impl WindowExtWeb for dyn Window + '_ {
#[inline] #[inline]
fn canvas(&self) -> Option<Ref<'_, HtmlCanvasElement>> { fn canvas(&self) -> Option<Ref<'_, HtmlCanvasElement>> {
self.as_any() self.cast_ref::<crate::platform_impl::Window>().expect("non Web window on Web").canvas()
.downcast_ref::<crate::platform_impl::Window>()
.expect("non Web window on Web")
.canvas()
} }
fn prevent_default(&self) -> bool { fn prevent_default(&self) -> bool {
self.as_any() self.cast_ref::<crate::platform_impl::Window>()
.downcast_ref::<crate::platform_impl::Window>()
.expect("non Web window on Web") .expect("non Web window on Web")
.prevent_default() .prevent_default()
} }
fn set_prevent_default(&self, prevent_default: bool) { fn set_prevent_default(&self, prevent_default: bool) {
self.as_any() self.cast_ref::<crate::platform_impl::Window>()
.downcast_ref::<crate::platform_impl::Window>()
.expect("non Web window on Web") .expect("non Web window on Web")
.set_prevent_default(prevent_default) .set_prevent_default(prevent_default)
} }
fn is_cursor_lock_raw(&self) -> bool { fn is_cursor_lock_raw(&self) -> bool {
self.as_any() self.cast_ref::<crate::platform_impl::Window>()
.downcast_ref::<crate::platform_impl::Window>()
.expect("non Web window on Web") .expect("non Web window on Web")
.is_cursor_lock_raw() .is_cursor_lock_raw()
} }
@ -371,8 +365,7 @@ impl ActiveEventLoopExtWeb for dyn ActiveEventLoop + '_ {
#[inline] #[inline]
fn create_custom_cursor_async(&self, source: CustomCursorSource) -> CustomCursorFuture { fn create_custom_cursor_async(&self, source: CustomCursorSource) -> CustomCursorFuture {
let event_loop = self let event_loop = self
.as_any() .cast_ref::<crate::platform_impl::ActiveEventLoop>()
.downcast_ref::<crate::platform_impl::ActiveEventLoop>()
.expect("non Web event loop on Web"); .expect("non Web event loop on Web");
event_loop.create_custom_cursor_async(source) event_loop.create_custom_cursor_async(source)
} }
@ -380,8 +373,7 @@ impl ActiveEventLoopExtWeb for dyn ActiveEventLoop + '_ {
#[inline] #[inline]
fn set_poll_strategy(&self, strategy: PollStrategy) { fn set_poll_strategy(&self, strategy: PollStrategy) {
let event_loop = self let event_loop = self
.as_any() .cast_ref::<crate::platform_impl::ActiveEventLoop>()
.downcast_ref::<crate::platform_impl::ActiveEventLoop>()
.expect("non Web event loop on Web"); .expect("non Web event loop on Web");
event_loop.set_poll_strategy(strategy); event_loop.set_poll_strategy(strategy);
} }
@ -389,8 +381,7 @@ impl ActiveEventLoopExtWeb for dyn ActiveEventLoop + '_ {
#[inline] #[inline]
fn poll_strategy(&self) -> PollStrategy { fn poll_strategy(&self) -> PollStrategy {
let event_loop = self let event_loop = self
.as_any() .cast_ref::<crate::platform_impl::ActiveEventLoop>()
.downcast_ref::<crate::platform_impl::ActiveEventLoop>()
.expect("non Web event loop on Web"); .expect("non Web event loop on Web");
event_loop.poll_strategy() event_loop.poll_strategy()
} }
@ -398,8 +389,7 @@ impl ActiveEventLoopExtWeb for dyn ActiveEventLoop + '_ {
#[inline] #[inline]
fn set_wait_until_strategy(&self, strategy: WaitUntilStrategy) { fn set_wait_until_strategy(&self, strategy: WaitUntilStrategy) {
let event_loop = self let event_loop = self
.as_any() .cast_ref::<crate::platform_impl::ActiveEventLoop>()
.downcast_ref::<crate::platform_impl::ActiveEventLoop>()
.expect("non Web event loop on Web"); .expect("non Web event loop on Web");
event_loop.set_wait_until_strategy(strategy); event_loop.set_wait_until_strategy(strategy);
} }
@ -407,8 +397,7 @@ impl ActiveEventLoopExtWeb for dyn ActiveEventLoop + '_ {
#[inline] #[inline]
fn wait_until_strategy(&self) -> WaitUntilStrategy { fn wait_until_strategy(&self) -> WaitUntilStrategy {
let event_loop = self let event_loop = self
.as_any() .cast_ref::<crate::platform_impl::ActiveEventLoop>()
.downcast_ref::<crate::platform_impl::ActiveEventLoop>()
.expect("non Web event loop on Web"); .expect("non Web event loop on Web");
event_loop.wait_until_strategy() event_loop.wait_until_strategy()
} }
@ -416,8 +405,7 @@ impl ActiveEventLoopExtWeb for dyn ActiveEventLoop + '_ {
#[inline] #[inline]
fn is_cursor_lock_raw(&self) -> bool { fn is_cursor_lock_raw(&self) -> bool {
let event_loop = self let event_loop = self
.as_any() .cast_ref::<crate::platform_impl::ActiveEventLoop>()
.downcast_ref::<crate::platform_impl::ActiveEventLoop>()
.expect("non Web event loop on Web"); .expect("non Web event loop on Web");
event_loop.is_cursor_lock_raw() event_loop.is_cursor_lock_raw()
} }
@ -425,8 +413,7 @@ impl ActiveEventLoopExtWeb for dyn ActiveEventLoop + '_ {
#[inline] #[inline]
fn has_multiple_screens(&self) -> Result<bool, NotSupportedError> { fn has_multiple_screens(&self) -> Result<bool, NotSupportedError> {
let event_loop = self let event_loop = self
.as_any() .cast_ref::<crate::platform_impl::ActiveEventLoop>()
.downcast_ref::<crate::platform_impl::ActiveEventLoop>()
.expect("non Web event loop on Web"); .expect("non Web event loop on Web");
event_loop.has_multiple_screens() event_loop.has_multiple_screens()
} }
@ -434,8 +421,7 @@ impl ActiveEventLoopExtWeb for dyn ActiveEventLoop + '_ {
#[inline] #[inline]
fn request_detailed_monitor_permission(&self) -> MonitorPermissionFuture { fn request_detailed_monitor_permission(&self) -> MonitorPermissionFuture {
let event_loop = self let event_loop = self
.as_any() .cast_ref::<crate::platform_impl::ActiveEventLoop>()
.downcast_ref::<crate::platform_impl::ActiveEventLoop>()
.expect("non Web event loop on Web"); .expect("non Web event loop on Web");
MonitorPermissionFuture(event_loop.request_detailed_monitor_permission()) MonitorPermissionFuture(event_loop.request_detailed_monitor_permission())
} }
@ -443,8 +429,7 @@ impl ActiveEventLoopExtWeb for dyn ActiveEventLoop + '_ {
#[inline] #[inline]
fn has_detailed_monitor_permission(&self) -> bool { fn has_detailed_monitor_permission(&self) -> bool {
let event_loop = self let event_loop = self
.as_any() .cast_ref::<crate::platform_impl::ActiveEventLoop>()
.downcast_ref::<crate::platform_impl::ActiveEventLoop>()
.expect("non Web event loop on Web"); .expect("non Web event loop on Web");
event_loop.has_detailed_monitor_permission() event_loop.has_detailed_monitor_permission()
} }
@ -696,28 +681,24 @@ pub trait MonitorHandleExtWeb {
impl MonitorHandleExtWeb for dyn MonitorHandleProvider + '_ { impl MonitorHandleExtWeb for dyn MonitorHandleProvider + '_ {
fn is_internal(&self) -> Option<bool> { fn is_internal(&self) -> Option<bool> {
self.as_any().downcast_ref::<WebMonitorHandle>().unwrap().is_internal() self.cast_ref::<WebMonitorHandle>().unwrap().is_internal()
} }
fn orientation(&self) -> OrientationData { fn orientation(&self) -> OrientationData {
self.as_any().downcast_ref::<WebMonitorHandle>().unwrap().orientation() self.cast_ref::<WebMonitorHandle>().unwrap().orientation()
} }
fn request_lock(&self, orientation_lock: OrientationLock) -> OrientationLockFuture { fn request_lock(&self, orientation_lock: OrientationLock) -> OrientationLockFuture {
let future = self let future = self.cast_ref::<WebMonitorHandle>().unwrap().request_lock(orientation_lock);
.as_any()
.downcast_ref::<WebMonitorHandle>()
.unwrap()
.request_lock(orientation_lock);
OrientationLockFuture(future) OrientationLockFuture(future)
} }
fn unlock(&self) -> Result<(), OrientationLockError> { fn unlock(&self) -> Result<(), OrientationLockError> {
self.as_any().downcast_ref::<WebMonitorHandle>().unwrap().unlock() self.cast_ref::<WebMonitorHandle>().unwrap().unlock()
} }
fn is_detailed(&self) -> bool { fn is_detailed(&self) -> bool {
self.as_any().downcast_ref::<WebMonitorHandle>().unwrap().is_detailed() self.cast_ref::<WebMonitorHandle>().unwrap().is_detailed()
} }
} }

View file

@ -343,37 +343,37 @@ pub trait WindowExtWindows {
impl WindowExtWindows for dyn Window + '_ { impl WindowExtWindows for dyn Window + '_ {
#[inline] #[inline]
fn set_enable(&self, enabled: bool) { fn set_enable(&self, enabled: bool) {
let window = self.as_any().downcast_ref::<crate::platform_impl::Window>().unwrap(); let window = self.cast_ref::<crate::platform_impl::Window>().unwrap();
window.set_enable(enabled) window.set_enable(enabled)
} }
#[inline] #[inline]
fn set_taskbar_icon(&self, taskbar_icon: Option<Icon>) { fn set_taskbar_icon(&self, taskbar_icon: Option<Icon>) {
let window = self.as_any().downcast_ref::<crate::platform_impl::Window>().unwrap(); let window = self.cast_ref::<crate::platform_impl::Window>().unwrap();
window.set_taskbar_icon(taskbar_icon) window.set_taskbar_icon(taskbar_icon)
} }
#[inline] #[inline]
fn set_skip_taskbar(&self, skip: bool) { fn set_skip_taskbar(&self, skip: bool) {
let window = self.as_any().downcast_ref::<crate::platform_impl::Window>().unwrap(); let window = self.cast_ref::<crate::platform_impl::Window>().unwrap();
window.set_skip_taskbar(skip) window.set_skip_taskbar(skip)
} }
#[inline] #[inline]
fn set_undecorated_shadow(&self, shadow: bool) { fn set_undecorated_shadow(&self, shadow: bool) {
let window = self.as_any().downcast_ref::<crate::platform_impl::Window>().unwrap(); let window = self.cast_ref::<crate::platform_impl::Window>().unwrap();
window.set_undecorated_shadow(shadow) window.set_undecorated_shadow(shadow)
} }
#[inline] #[inline]
fn set_system_backdrop(&self, backdrop_type: BackdropType) { fn set_system_backdrop(&self, backdrop_type: BackdropType) {
let window = self.as_any().downcast_ref::<crate::platform_impl::Window>().unwrap(); let window = self.cast_ref::<crate::platform_impl::Window>().unwrap();
window.set_system_backdrop(backdrop_type) window.set_system_backdrop(backdrop_type)
} }
#[inline] #[inline]
fn set_border_color(&self, color: Option<Color>) { fn set_border_color(&self, color: Option<Color>) {
let window = self.as_any().downcast_ref::<crate::platform_impl::Window>().unwrap(); let window = self.cast_ref::<crate::platform_impl::Window>().unwrap();
window.set_border_color(color.unwrap_or(Color::NONE)) window.set_border_color(color.unwrap_or(Color::NONE))
} }
@ -382,26 +382,26 @@ impl WindowExtWindows for dyn Window + '_ {
// The windows docs don't mention NONE as a valid options but it works in practice and is // The windows docs don't mention NONE as a valid options but it works in practice and is
// useful to circumvent the Windows option "Show accent color on title bars and // useful to circumvent the Windows option "Show accent color on title bars and
// window borders" // window borders"
let window = self.as_any().downcast_ref::<crate::platform_impl::Window>().unwrap(); let window = self.cast_ref::<crate::platform_impl::Window>().unwrap();
window.set_title_background_color(color.unwrap_or(Color::NONE)) window.set_title_background_color(color.unwrap_or(Color::NONE))
} }
#[inline] #[inline]
fn set_title_text_color(&self, color: Color) { fn set_title_text_color(&self, color: Color) {
let window = self.as_any().downcast_ref::<crate::platform_impl::Window>().unwrap(); let window = self.cast_ref::<crate::platform_impl::Window>().unwrap();
window.set_title_text_color(color) window.set_title_text_color(color)
} }
#[inline] #[inline]
fn set_corner_preference(&self, preference: CornerPreference) { fn set_corner_preference(&self, preference: CornerPreference) {
let window = self.as_any().downcast_ref::<crate::platform_impl::Window>().unwrap(); let window = self.cast_ref::<crate::platform_impl::Window>().unwrap();
window.set_corner_preference(preference) window.set_corner_preference(preference)
} }
unsafe fn window_handle_any_thread( unsafe fn window_handle_any_thread(
&self, &self,
) -> Result<rwh_06::WindowHandle<'_>, rwh_06::HandleError> { ) -> Result<rwh_06::WindowHandle<'_>, rwh_06::HandleError> {
let window = self.as_any().downcast_ref::<crate::platform_impl::Window>().unwrap(); let window = self.cast_ref::<crate::platform_impl::Window>().unwrap();
unsafe { unsafe {
let handle = window.rwh_06_no_thread_check()?; let handle = window.rwh_06_no_thread_check()?;

View file

@ -91,7 +91,7 @@ pub trait ActiveEventLoopExtX11 {
impl ActiveEventLoopExtX11 for dyn ActiveEventLoop + '_ { impl ActiveEventLoopExtX11 for dyn ActiveEventLoop + '_ {
#[inline] #[inline]
fn is_x11(&self) -> bool { fn is_x11(&self) -> bool {
self.as_any().downcast_ref::<crate::platform_impl::x11::ActiveEventLoop>().is_some() self.cast_ref::<crate::platform_impl::x11::ActiveEventLoop>().is_some()
} }
} }

View file

@ -556,7 +556,7 @@ fn new_window(
let screen = match attrs.fullscreen.clone() { let screen = match attrs.fullscreen.clone() {
Some(Fullscreen::Borderless(Some(monitor))) Some(Fullscreen::Borderless(Some(monitor)))
| Some(Fullscreen::Exclusive(monitor, _)) => { | Some(Fullscreen::Exclusive(monitor, _)) => {
let monitor = monitor.as_any().downcast_ref::<MonitorHandle>().unwrap(); let monitor = monitor.cast_ref::<MonitorHandle>().unwrap();
monitor.ns_screen(mtm).or_else(|| NSScreen::mainScreen(mtm)) monitor.ns_screen(mtm).or_else(|| NSScreen::mainScreen(mtm))
}, },
Some(Fullscreen::Borderless(None)) => NSScreen::mainScreen(mtm), Some(Fullscreen::Borderless(None)) => NSScreen::mainScreen(mtm),
@ -1460,7 +1460,7 @@ impl WindowDelegate {
if let Some(ref fullscreen) = fullscreen { if let Some(ref fullscreen) = fullscreen {
let new_screen = match fullscreen { let new_screen = match fullscreen {
Fullscreen::Borderless(Some(monitor)) | Fullscreen::Exclusive(monitor, _) => { Fullscreen::Borderless(Some(monitor)) | Fullscreen::Exclusive(monitor, _) => {
let monitor = monitor.as_any().downcast_ref::<MonitorHandle>().unwrap(); let monitor = monitor.cast_ref::<MonitorHandle>().unwrap();
monitor.ns_screen(mtm) monitor.ns_screen(mtm)
}, },
Fullscreen::Borderless(None) => { Fullscreen::Borderless(None) => {
@ -1519,7 +1519,7 @@ impl WindowDelegate {
cgerr(CGDisplayCapture(display_id)).unwrap(); cgerr(CGDisplayCapture(display_id)).unwrap();
} }
let monitor = monitor.as_any().downcast_ref::<MonitorHandle>().unwrap(); let monitor = monitor.cast_ref::<MonitorHandle>().unwrap();
let video_mode = let video_mode =
match monitor.video_mode_handles().find(|mode| &mode.mode == video_mode) { match monitor.video_mode_handles().find(|mode| &mode.mode == video_mode) {
Some(video_mode) => video_mode, Some(video_mode) => video_mode,
@ -1587,7 +1587,7 @@ impl WindowDelegate {
toggle_fullscreen(self.window()); toggle_fullscreen(self.window());
}, },
(Some(Fullscreen::Exclusive(monitor, _)), None) => { (Some(Fullscreen::Exclusive(monitor, _)), None) => {
let monitor = monitor.as_any().downcast_ref::<MonitorHandle>().unwrap(); let monitor = monitor.cast_ref::<MonitorHandle>().unwrap();
restore_and_release_display(monitor); restore_and_release_display(monitor);
toggle_fullscreen(self.window()); toggle_fullscreen(self.window());
}, },
@ -1618,7 +1618,7 @@ impl WindowDelegate {
); );
app.setPresentationOptions(presentation_options); app.setPresentationOptions(presentation_options);
let monitor = monitor.as_any().downcast_ref::<MonitorHandle>().unwrap(); let monitor = monitor.cast_ref::<MonitorHandle>().unwrap();
restore_and_release_display(monitor); restore_and_release_display(monitor);
// Restore the normal window level following the Borderless fullscreen // Restore the normal window level following the Borderless fullscreen

View file

@ -81,7 +81,7 @@ impl WinitUIWindow {
match window_attributes.fullscreen.clone() { match window_attributes.fullscreen.clone() {
Some(Fullscreen::Exclusive(monitor, ref video_mode)) => { Some(Fullscreen::Exclusive(monitor, ref video_mode)) => {
let monitor = monitor.as_any().downcast_ref::<MonitorHandle>().unwrap(); let monitor = monitor.cast_ref::<MonitorHandle>().unwrap();
let screen = monitor.ui_screen(mtm); let screen = monitor.ui_screen(mtm);
if let Some(video_mode) = if let Some(video_mode) =
monitor.video_modes_handles().find(|mode| &mode.mode == video_mode) monitor.video_modes_handles().find(|mode| &mode.mode == video_mode)
@ -91,7 +91,7 @@ impl WinitUIWindow {
this.setScreen(screen); this.setScreen(screen);
}, },
Some(Fullscreen::Borderless(Some(ref monitor))) => { Some(Fullscreen::Borderless(Some(ref monitor))) => {
let monitor = monitor.as_any().downcast_ref::<MonitorHandle>().unwrap(); let monitor = monitor.cast_ref::<MonitorHandle>().unwrap();
let screen = monitor.ui_screen(mtm); let screen = monitor.ui_screen(mtm);
this.setScreen(screen); this.setScreen(screen);
}, },
@ -306,7 +306,7 @@ impl Inner {
let mtm = MainThreadMarker::new().unwrap(); let mtm = MainThreadMarker::new().unwrap();
let uiscreen = match &monitor { let uiscreen = match &monitor {
Some(Fullscreen::Exclusive(monitor, video_mode)) => { Some(Fullscreen::Exclusive(monitor, video_mode)) => {
let monitor = monitor.as_any().downcast_ref::<MonitorHandle>().unwrap(); let monitor = monitor.cast_ref::<MonitorHandle>().unwrap();
let uiscreen = monitor.ui_screen(mtm); let uiscreen = monitor.ui_screen(mtm);
if let Some(video_mode) = if let Some(video_mode) =
monitor.video_modes_handles().find(|mode| &mode.mode == video_mode) monitor.video_modes_handles().find(|mode| &mode.mode == video_mode)
@ -316,7 +316,7 @@ impl Inner {
uiscreen.clone() uiscreen.clone()
}, },
Some(Fullscreen::Borderless(Some(monitor))) => { Some(Fullscreen::Borderless(Some(monitor))) => {
monitor.as_any().downcast_ref::<MonitorHandle>().unwrap().ui_screen(mtm).clone() monitor.cast_ref::<MonitorHandle>().unwrap().ui_screen(mtm).clone()
}, },
Some(Fullscreen::Borderless(None)) => { Some(Fullscreen::Borderless(None)) => {
self.current_monitor_inner().ui_screen(mtm).clone() self.current_monitor_inner().ui_screen(mtm).clone()
@ -492,7 +492,7 @@ impl Window {
let screen = match fullscreen { let screen = match fullscreen {
Some(Fullscreen::Exclusive(ref monitor, _)) Some(Fullscreen::Exclusive(ref monitor, _))
| Some(Fullscreen::Borderless(Some(ref monitor))) => { | Some(Fullscreen::Borderless(Some(ref monitor))) => {
let monitor = monitor.as_any().downcast_ref::<MonitorHandle>().unwrap(); let monitor = monitor.cast_ref::<MonitorHandle>().unwrap();
monitor.ui_screen(mtm) monitor.ui_screen(mtm)
}, },
Some(Fullscreen::Borderless(None)) | None => &main_screen, Some(Fullscreen::Borderless(None)) | None => &main_screen,

View file

@ -23,7 +23,6 @@ use crate::event::{Ime, WindowEvent};
use crate::event_loop::AsyncRequestSerial; use crate::event_loop::AsyncRequestSerial;
use crate::monitor::{Fullscreen, MonitorHandle as CoreMonitorHandle}; use crate::monitor::{Fullscreen, MonitorHandle as CoreMonitorHandle};
use crate::platform_impl::wayland::output; use crate::platform_impl::wayland::output;
use crate::utils::AsAny;
use crate::window::{ use crate::window::{
Cursor, CursorGrabMode, ImePurpose, ResizeDirection, Theme, UserAttentionType, Cursor, CursorGrabMode, ImePurpose, ResizeDirection, Theme, UserAttentionType,
Window as CoreWindow, WindowAttributes, WindowButtons, WindowId, WindowLevel, Window as CoreWindow, WindowAttributes, WindowButtons, WindowId, WindowLevel,
@ -146,10 +145,7 @@ impl Window {
#[cfg_attr(not(x11_platform), allow(clippy::bind_instead_of_map))] #[cfg_attr(not(x11_platform), allow(clippy::bind_instead_of_map))]
Some(Fullscreen::Borderless(monitor)) => { Some(Fullscreen::Borderless(monitor)) => {
let output = monitor.as_ref().and_then(|monitor| { let output = monitor.as_ref().and_then(|monitor| {
monitor monitor.cast_ref::<output::MonitorHandle>().map(|handle| &handle.proxy)
.as_any()
.downcast_ref::<output::MonitorHandle>()
.map(|handle| &handle.proxy)
}); });
window.set_fullscreen(output) window.set_fullscreen(output)
@ -446,10 +442,7 @@ impl CoreWindow for Window {
#[cfg_attr(not(x11_platform), allow(clippy::bind_instead_of_map))] #[cfg_attr(not(x11_platform), allow(clippy::bind_instead_of_map))]
Some(Fullscreen::Borderless(monitor)) => { Some(Fullscreen::Borderless(monitor)) => {
let output = monitor.as_ref().and_then(|monitor| { let output = monitor.as_ref().and_then(|monitor| {
monitor monitor.cast_ref::<output::MonitorHandle>().map(|handle| &handle.proxy)
.as_any()
.downcast_ref::<output::MonitorHandle>()
.map(|handle| &handle.proxy)
}); });
self.window.set_fullscreen(output) self.window.set_fullscreen(output)

View file

@ -1067,13 +1067,11 @@ impl UnownedWindow {
let (monitor, video_mode): (Cow<'_, X11MonitorHandle>, Option<&VideoMode>) = let (monitor, video_mode): (Cow<'_, X11MonitorHandle>, Option<&VideoMode>) =
match &fullscreen { match &fullscreen {
Fullscreen::Exclusive(monitor, video_mode) => { Fullscreen::Exclusive(monitor, video_mode) => {
let monitor = let monitor = monitor.cast_ref::<X11MonitorHandle>().unwrap();
monitor.as_any().downcast_ref::<X11MonitorHandle>().unwrap();
(Cow::Borrowed(monitor), Some(video_mode)) (Cow::Borrowed(monitor), Some(video_mode))
}, },
Fullscreen::Borderless(Some(monitor)) => { Fullscreen::Borderless(Some(monitor)) => {
let monitor = let monitor = monitor.cast_ref::<X11MonitorHandle>().unwrap();
monitor.as_any().downcast_ref::<X11MonitorHandle>().unwrap();
(Cow::Borrowed(monitor), None) (Cow::Borrowed(monitor), None)
}, },
Fullscreen::Borderless(None) => { Fullscreen::Borderless(None) => {

View file

@ -65,7 +65,7 @@ pub(crate) fn request_fullscreen(
return; return;
} }
let monitor = monitor.as_any().downcast_ref::<MonitorHandle>().unwrap(); let monitor = monitor.cast_ref::<MonitorHandle>().unwrap();
if let Some(monitor) = monitor.detailed(main_thread) { if let Some(monitor) = monitor.detailed(main_thread) {
let options: FullscreenOptions = Object::new().unchecked_into(); let options: FullscreenOptions = Object::new().unchecked_into();

View file

@ -790,7 +790,7 @@ impl CoreWindow for Window {
// fullscreen // fullscreen
match (&old_fullscreen, &fullscreen) { match (&old_fullscreen, &fullscreen) {
(_, Some(Fullscreen::Exclusive(monitor, video_mode))) => { (_, Some(Fullscreen::Exclusive(monitor, video_mode))) => {
let monitor = monitor.as_any().downcast_ref::<MonitorHandle>().unwrap(); let monitor = monitor.cast_ref::<MonitorHandle>().unwrap();
let video_mode = let video_mode =
match monitor.video_mode_handles().find(|mode| &mode.mode == video_mode) { match monitor.video_mode_handles().find(|mode| &mode.mode == video_mode) {
Some(monitor) => monitor, Some(monitor) => monitor,
@ -882,9 +882,9 @@ impl CoreWindow for Window {
let monitor = match &fullscreen { let monitor = match &fullscreen {
Fullscreen::Exclusive(monitor, _) Fullscreen::Exclusive(monitor, _)
| Fullscreen::Borderless(Some(monitor)) => Some(Cow::Borrowed( | Fullscreen::Borderless(Some(monitor)) => {
monitor.as_any().downcast_ref::<MonitorHandle>().unwrap(), Some(Cow::Borrowed(monitor.cast_ref::<MonitorHandle>().unwrap()))
)), },
Fullscreen::Borderless(None) => None, Fullscreen::Borderless(None) => None,
}; };

View file

@ -28,19 +28,71 @@ impl<T> Deref for Lazy<T> {
} }
} }
pub trait AsAny { // NOTE: This is `pub`, but isn't actually exposed outside the crate.
fn as_any(&self) -> &dyn Any; // NOTE: Marked as `#[doc(hidden)]` and underscored, because they can be quite difficult to use
fn as_any_mut(&mut self) -> &mut dyn Any; // correctly, see discussion in #4160.
// FIXME: Remove and replace with a coercion once rust-lang/rust#65991 is in MSRV (1.86).
#[doc(hidden)]
pub trait AsAny: Any {
#[doc(hidden)]
fn __as_any(&self) -> &dyn Any;
#[doc(hidden)]
fn __as_any_mut(&mut self) -> &mut dyn Any;
#[doc(hidden)]
fn __into_any(self: Box<Self>) -> Box<dyn Any>;
} }
impl<T: Any> AsAny for T { impl<T: Any> AsAny for T {
#[inline(always)] #[inline(always)]
fn as_any(&self) -> &dyn Any { fn __as_any(&self) -> &dyn Any {
self self
} }
#[inline(always)] #[inline(always)]
fn as_any_mut(&mut self) -> &mut dyn Any { fn __as_any_mut(&mut self) -> &mut dyn Any {
self
}
#[inline(always)]
fn __into_any(self: Box<Self>) -> Box<dyn Any> {
self self
} }
} }
macro_rules! impl_dyn_casting {
($trait:ident) => {
impl dyn $trait + '_ {
/// Downcast to the backend concrete type.
///
/// Returns `None` if the object was not from that backend.
pub fn cast_ref<T: $trait>(&self) -> Option<&T> {
let this: &dyn std::any::Any = self.__as_any();
this.downcast_ref::<T>()
}
/// Mutable downcast to the backend concrete type.
///
/// Returns `None` if the object was not from that backend.
pub fn cast_mut<T: $trait>(&mut self) -> Option<&mut T> {
let this: &mut dyn std::any::Any = self.__as_any_mut();
this.downcast_mut::<T>()
}
/// Owned downcast to the backend concrete type.
///
/// Returns `Err` with `self` if the object was not from that backend.
pub fn cast<T: $trait>(self: Box<Self>) -> Result<Box<T>, Box<Self>> {
let reference: &dyn std::any::Any = self.__as_any();
if reference.is::<T>() {
let this: Box<dyn std::any::Any> = self.__into_any();
// Unwrap is okay, we just checked the type of `self` is `T`.
Ok(this.downcast::<T>().unwrap())
} else {
Err(self)
}
}
}
};
}
pub(crate) use impl_dyn_casting;

View file

@ -12,7 +12,7 @@ use crate::error::RequestError;
pub use crate::icon::{BadIcon, Icon}; pub use crate::icon::{BadIcon, Icon};
use crate::monitor::{Fullscreen, MonitorHandle}; use crate::monitor::{Fullscreen, MonitorHandle};
use crate::platform_impl::PlatformSpecificWindowAttributes; use crate::platform_impl::PlatformSpecificWindowAttributes;
use crate::utils::AsAny; use crate::utils::{impl_dyn_casting, AsAny};
/// Identifier of a window. Unique for each window. /// Identifier of a window. Unique for each window.
/// ///
@ -1335,7 +1335,7 @@ pub trait Window: AsAny + Send + Sync + fmt::Debug {
fn rwh_06_window_handle(&self) -> &dyn rwh_06::HasWindowHandle; fn rwh_06_window_handle(&self) -> &dyn rwh_06::HasWindowHandle;
} }
impl dyn Window { impl dyn Window + '_ {
/// Create a new [`WindowAttributes`] which allows modifying the window's attributes before /// Create a new [`WindowAttributes`] which allows modifying the window's attributes before
/// creation. /// creation.
pub fn default_attributes() -> WindowAttributes { pub fn default_attributes() -> WindowAttributes {
@ -1343,6 +1343,8 @@ impl dyn Window {
} }
} }
impl_dyn_casting!(Window);
impl PartialEq for dyn Window + '_ { impl PartialEq for dyn Window + '_ {
fn eq(&self, other: &dyn Window) -> bool { fn eq(&self, other: &dyn Window) -> bool {
self.id().eq(&other.id()) self.id().eq(&other.id())