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
- Change `ActiveEventLoop` to be a trait.
- Change `Window` to be a trait.
- Change `ActiveEventLoop` and `Window` to be traits, and added `cast_ref`/`cast_mut`/`cast`
methods to extract the backend type from those.
- `ActiveEventLoop::create_window` now returns `Box<dyn Window>`.
- `ApplicationHandler` now uses `dyn ActiveEventLoop`.
- 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::monitor::MonitorHandle;
use crate::platform_impl;
use crate::utils::AsAny;
use crate::utils::{impl_dyn_casting, AsAny};
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
@ -406,6 +406,8 @@ impl HasDisplayHandle for dyn ActiveEventLoop + '_ {
}
}
impl_dyn_casting!(ActiveEventLoop);
/// A proxy for the underlying display handle.
///
/// 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 crate::dpi::{PhysicalPosition, PhysicalSize};
use crate::utils::AsAny;
use crate::utils::{impl_dyn_casting, AsAny};
/// Handle to a monitor.
///
@ -148,6 +148,8 @@ impl PartialEq for dyn MonitorHandleProvider + '_ {
impl Eq for dyn MonitorHandleProvider + '_ {}
impl_dyn_casting!(MonitorHandleProvider);
/// Describes a fullscreen video mode of a monitor.
///
/// Can be acquired with [`MonitorHandleProvider::video_modes`].

View file

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

View file

@ -214,25 +214,25 @@ pub trait WindowExtIOS {
impl WindowExtIOS for dyn Window + '_ {
#[inline]
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));
}
#[inline]
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));
}
#[inline]
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));
}
#[inline]
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| {
w.set_preferred_screen_edges_deferring_system_gestures(edges)
});
@ -240,19 +240,19 @@ impl WindowExtIOS for dyn Window + '_ {
#[inline]
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));
}
#[inline]
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))
}
#[inline]
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));
}
@ -263,7 +263,7 @@ impl WindowExtIOS for dyn Window + '_ {
minimum_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| {
w.recognize_pan_gesture(
should_recognize,
@ -275,13 +275,13 @@ impl WindowExtIOS for dyn Window + '_ {
#[inline]
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));
}
#[inline]
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));
}
}
@ -398,13 +398,13 @@ impl MonitorHandleExtIOS for MonitorHandle {
fn ui_screen(&self) -> *mut c_void {
// SAFETY: The marker is only used to get the pointer of the screen
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
}
#[inline]
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()
}
}

View file

@ -168,109 +168,109 @@ pub trait WindowExtMacOS {
impl WindowExtMacOS for dyn Window + '_ {
#[inline]
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())
}
#[inline]
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))
}
#[inline]
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())
}
#[inline]
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));
}
#[inline]
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))
}
#[inline]
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())
}
#[inline]
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());
}
#[inline]
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());
}
#[inline]
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));
}
#[inline]
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())
}
#[inline]
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())
}
#[inline]
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));
}
#[inline]
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));
}
#[inline]
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())
}
#[inline]
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))
}
#[inline]
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())
}
#[inline]
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))
}
#[inline]
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())
}
}
@ -506,7 +506,7 @@ pub trait MonitorHandleExtMacOS {
impl MonitorHandleExtMacOS for MonitorHandle {
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
let mtm = unsafe { objc2::MainThreadMarker::new_unchecked() };
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 + '_ {
fn hide_application(&self) {
let event_loop = self
.as_any()
.downcast_ref::<crate::platform_impl::ActiveEventLoop>()
.cast_ref::<crate::platform_impl::ActiveEventLoop>()
.expect("non macOS event loop on macOS");
event_loop.hide_application()
}
fn hide_other_applications(&self) {
let event_loop = self
.as_any()
.downcast_ref::<crate::platform_impl::ActiveEventLoop>()
.cast_ref::<crate::platform_impl::ActiveEventLoop>()
.expect("non macOS event loop on macOS");
event_loop.hide_other_applications()
}
fn set_allows_automatic_window_tabbing(&self, enabled: bool) {
let event_loop = self
.as_any()
.downcast_ref::<crate::platform_impl::ActiveEventLoop>()
.cast_ref::<crate::platform_impl::ActiveEventLoop>()
.expect("non macOS event loop on macOS");
event_loop.set_allows_automatic_window_tabbing(enabled);
}
fn allows_automatic_window_tabbing(&self) -> bool {
let event_loop = self
.as_any()
.downcast_ref::<crate::platform_impl::ActiveEventLoop>()
.cast_ref::<crate::platform_impl::ActiveEventLoop>()
.expect("non macOS event loop on macOS");
event_loop.allows_automatic_window_tabbing()
}

View file

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

View file

@ -26,7 +26,7 @@ pub trait ActiveEventLoopExtWayland {
impl ActiveEventLoopExtWayland for dyn ActiveEventLoop + '_ {
#[inline]
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 + '_ {
#[inline]
fn canvas(&self) -> Option<Ref<'_, HtmlCanvasElement>> {
self.as_any()
.downcast_ref::<crate::platform_impl::Window>()
.expect("non Web window on Web")
.canvas()
self.cast_ref::<crate::platform_impl::Window>().expect("non Web window on Web").canvas()
}
fn prevent_default(&self) -> bool {
self.as_any()
.downcast_ref::<crate::platform_impl::Window>()
self.cast_ref::<crate::platform_impl::Window>()
.expect("non Web window on Web")
.prevent_default()
}
fn set_prevent_default(&self, prevent_default: bool) {
self.as_any()
.downcast_ref::<crate::platform_impl::Window>()
self.cast_ref::<crate::platform_impl::Window>()
.expect("non Web window on Web")
.set_prevent_default(prevent_default)
}
fn is_cursor_lock_raw(&self) -> bool {
self.as_any()
.downcast_ref::<crate::platform_impl::Window>()
self.cast_ref::<crate::platform_impl::Window>()
.expect("non Web window on Web")
.is_cursor_lock_raw()
}
@ -371,8 +365,7 @@ impl ActiveEventLoopExtWeb for dyn ActiveEventLoop + '_ {
#[inline]
fn create_custom_cursor_async(&self, source: CustomCursorSource) -> CustomCursorFuture {
let event_loop = self
.as_any()
.downcast_ref::<crate::platform_impl::ActiveEventLoop>()
.cast_ref::<crate::platform_impl::ActiveEventLoop>()
.expect("non Web event loop on Web");
event_loop.create_custom_cursor_async(source)
}
@ -380,8 +373,7 @@ impl ActiveEventLoopExtWeb for dyn ActiveEventLoop + '_ {
#[inline]
fn set_poll_strategy(&self, strategy: PollStrategy) {
let event_loop = self
.as_any()
.downcast_ref::<crate::platform_impl::ActiveEventLoop>()
.cast_ref::<crate::platform_impl::ActiveEventLoop>()
.expect("non Web event loop on Web");
event_loop.set_poll_strategy(strategy);
}
@ -389,8 +381,7 @@ impl ActiveEventLoopExtWeb for dyn ActiveEventLoop + '_ {
#[inline]
fn poll_strategy(&self) -> PollStrategy {
let event_loop = self
.as_any()
.downcast_ref::<crate::platform_impl::ActiveEventLoop>()
.cast_ref::<crate::platform_impl::ActiveEventLoop>()
.expect("non Web event loop on Web");
event_loop.poll_strategy()
}
@ -398,8 +389,7 @@ impl ActiveEventLoopExtWeb for dyn ActiveEventLoop + '_ {
#[inline]
fn set_wait_until_strategy(&self, strategy: WaitUntilStrategy) {
let event_loop = self
.as_any()
.downcast_ref::<crate::platform_impl::ActiveEventLoop>()
.cast_ref::<crate::platform_impl::ActiveEventLoop>()
.expect("non Web event loop on Web");
event_loop.set_wait_until_strategy(strategy);
}
@ -407,8 +397,7 @@ impl ActiveEventLoopExtWeb for dyn ActiveEventLoop + '_ {
#[inline]
fn wait_until_strategy(&self) -> WaitUntilStrategy {
let event_loop = self
.as_any()
.downcast_ref::<crate::platform_impl::ActiveEventLoop>()
.cast_ref::<crate::platform_impl::ActiveEventLoop>()
.expect("non Web event loop on Web");
event_loop.wait_until_strategy()
}
@ -416,8 +405,7 @@ impl ActiveEventLoopExtWeb for dyn ActiveEventLoop + '_ {
#[inline]
fn is_cursor_lock_raw(&self) -> bool {
let event_loop = self
.as_any()
.downcast_ref::<crate::platform_impl::ActiveEventLoop>()
.cast_ref::<crate::platform_impl::ActiveEventLoop>()
.expect("non Web event loop on Web");
event_loop.is_cursor_lock_raw()
}
@ -425,8 +413,7 @@ impl ActiveEventLoopExtWeb for dyn ActiveEventLoop + '_ {
#[inline]
fn has_multiple_screens(&self) -> Result<bool, NotSupportedError> {
let event_loop = self
.as_any()
.downcast_ref::<crate::platform_impl::ActiveEventLoop>()
.cast_ref::<crate::platform_impl::ActiveEventLoop>()
.expect("non Web event loop on Web");
event_loop.has_multiple_screens()
}
@ -434,8 +421,7 @@ impl ActiveEventLoopExtWeb for dyn ActiveEventLoop + '_ {
#[inline]
fn request_detailed_monitor_permission(&self) -> MonitorPermissionFuture {
let event_loop = self
.as_any()
.downcast_ref::<crate::platform_impl::ActiveEventLoop>()
.cast_ref::<crate::platform_impl::ActiveEventLoop>()
.expect("non Web event loop on Web");
MonitorPermissionFuture(event_loop.request_detailed_monitor_permission())
}
@ -443,8 +429,7 @@ impl ActiveEventLoopExtWeb for dyn ActiveEventLoop + '_ {
#[inline]
fn has_detailed_monitor_permission(&self) -> bool {
let event_loop = self
.as_any()
.downcast_ref::<crate::platform_impl::ActiveEventLoop>()
.cast_ref::<crate::platform_impl::ActiveEventLoop>()
.expect("non Web event loop on Web");
event_loop.has_detailed_monitor_permission()
}
@ -696,28 +681,24 @@ pub trait MonitorHandleExtWeb {
impl MonitorHandleExtWeb for dyn MonitorHandleProvider + '_ {
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 {
self.as_any().downcast_ref::<WebMonitorHandle>().unwrap().orientation()
self.cast_ref::<WebMonitorHandle>().unwrap().orientation()
}
fn request_lock(&self, orientation_lock: OrientationLock) -> OrientationLockFuture {
let future = self
.as_any()
.downcast_ref::<WebMonitorHandle>()
.unwrap()
.request_lock(orientation_lock);
let future = self.cast_ref::<WebMonitorHandle>().unwrap().request_lock(orientation_lock);
OrientationLockFuture(future)
}
fn unlock(&self) -> Result<(), OrientationLockError> {
self.as_any().downcast_ref::<WebMonitorHandle>().unwrap().unlock()
self.cast_ref::<WebMonitorHandle>().unwrap().unlock()
}
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 + '_ {
#[inline]
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)
}
#[inline]
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)
}
#[inline]
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)
}
#[inline]
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)
}
#[inline]
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)
}
#[inline]
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))
}
@ -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
// useful to circumvent the Windows option "Show accent color on title bars and
// 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))
}
#[inline]
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)
}
#[inline]
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)
}
unsafe fn window_handle_any_thread(
&self,
) -> 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 {
let handle = window.rwh_06_no_thread_check()?;

View file

@ -91,7 +91,7 @@ pub trait ActiveEventLoopExtX11 {
impl ActiveEventLoopExtX11 for dyn ActiveEventLoop + '_ {
#[inline]
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() {
Some(Fullscreen::Borderless(Some(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))
},
Some(Fullscreen::Borderless(None)) => NSScreen::mainScreen(mtm),
@ -1460,7 +1460,7 @@ impl WindowDelegate {
if let Some(ref fullscreen) = fullscreen {
let new_screen = match fullscreen {
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)
},
Fullscreen::Borderless(None) => {
@ -1519,7 +1519,7 @@ impl WindowDelegate {
cgerr(CGDisplayCapture(display_id)).unwrap();
}
let monitor = monitor.as_any().downcast_ref::<MonitorHandle>().unwrap();
let monitor = monitor.cast_ref::<MonitorHandle>().unwrap();
let video_mode =
match monitor.video_mode_handles().find(|mode| &mode.mode == video_mode) {
Some(video_mode) => video_mode,
@ -1587,7 +1587,7 @@ impl WindowDelegate {
toggle_fullscreen(self.window());
},
(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);
toggle_fullscreen(self.window());
},
@ -1618,7 +1618,7 @@ impl WindowDelegate {
);
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 the normal window level following the Borderless fullscreen

View file

@ -81,7 +81,7 @@ impl WinitUIWindow {
match window_attributes.fullscreen.clone() {
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);
if let Some(video_mode) =
monitor.video_modes_handles().find(|mode| &mode.mode == video_mode)
@ -91,7 +91,7 @@ impl WinitUIWindow {
this.setScreen(screen);
},
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);
this.setScreen(screen);
},
@ -306,7 +306,7 @@ impl Inner {
let mtm = MainThreadMarker::new().unwrap();
let uiscreen = match &monitor {
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);
if let Some(video_mode) =
monitor.video_modes_handles().find(|mode| &mode.mode == video_mode)
@ -316,7 +316,7 @@ impl Inner {
uiscreen.clone()
},
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)) => {
self.current_monitor_inner().ui_screen(mtm).clone()
@ -492,7 +492,7 @@ impl Window {
let screen = match fullscreen {
Some(Fullscreen::Exclusive(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)
},
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::monitor::{Fullscreen, MonitorHandle as CoreMonitorHandle};
use crate::platform_impl::wayland::output;
use crate::utils::AsAny;
use crate::window::{
Cursor, CursorGrabMode, ImePurpose, ResizeDirection, Theme, UserAttentionType,
Window as CoreWindow, WindowAttributes, WindowButtons, WindowId, WindowLevel,
@ -146,10 +145,7 @@ impl Window {
#[cfg_attr(not(x11_platform), allow(clippy::bind_instead_of_map))]
Some(Fullscreen::Borderless(monitor)) => {
let output = monitor.as_ref().and_then(|monitor| {
monitor
.as_any()
.downcast_ref::<output::MonitorHandle>()
.map(|handle| &handle.proxy)
monitor.cast_ref::<output::MonitorHandle>().map(|handle| &handle.proxy)
});
window.set_fullscreen(output)
@ -446,10 +442,7 @@ impl CoreWindow for Window {
#[cfg_attr(not(x11_platform), allow(clippy::bind_instead_of_map))]
Some(Fullscreen::Borderless(monitor)) => {
let output = monitor.as_ref().and_then(|monitor| {
monitor
.as_any()
.downcast_ref::<output::MonitorHandle>()
.map(|handle| &handle.proxy)
monitor.cast_ref::<output::MonitorHandle>().map(|handle| &handle.proxy)
});
self.window.set_fullscreen(output)

View file

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

View file

@ -65,7 +65,7 @@ pub(crate) fn request_fullscreen(
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) {
let options: FullscreenOptions = Object::new().unchecked_into();

View file

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

View file

@ -28,19 +28,71 @@ impl<T> Deref for Lazy<T> {
}
}
pub trait AsAny {
fn as_any(&self) -> &dyn Any;
fn as_any_mut(&mut self) -> &mut dyn Any;
// NOTE: This is `pub`, but isn't actually exposed outside the crate.
// NOTE: Marked as `#[doc(hidden)]` and underscored, because they can be quite difficult to use
// 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 {
#[inline(always)]
fn as_any(&self) -> &dyn Any {
fn __as_any(&self) -> &dyn Any {
self
}
#[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
}
}
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};
use crate::monitor::{Fullscreen, MonitorHandle};
use crate::platform_impl::PlatformSpecificWindowAttributes;
use crate::utils::AsAny;
use crate::utils::{impl_dyn_casting, AsAny};
/// 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;
}
impl dyn Window {
impl dyn Window + '_ {
/// Create a new [`WindowAttributes`] which allows modifying the window's attributes before
/// creation.
pub fn default_attributes() -> WindowAttributes {
@ -1343,6 +1343,8 @@ impl dyn Window {
}
}
impl_dyn_casting!(Window);
impl PartialEq for dyn Window + '_ {
fn eq(&self, other: &dyn Window) -> bool {
self.id().eq(&other.id())