diff --git a/src/platform_impl/ios/app_state.rs b/src/platform_impl/ios/app_state.rs index e1b82be194..45b995e3a7 100644 --- a/src/platform_impl/ios/app_state.rs +++ b/src/platform_impl/ios/app_state.rs @@ -12,15 +12,16 @@ use std::{ use objc::runtime::{BOOL, YES}; use crate::{ - event::{Event, StartCause}, + dpi::LogicalSize, + event::{Event, StartCause, WindowEvent}, event_loop::ControlFlow, platform_impl::platform::{ - event_loop::{EventHandler, Never}, + event_loop::{EventHandler, EventProxy, EventWrapper, Never}, ffi::{ id, kCFRunLoopCommonModes, CFAbsoluteTimeGetCurrent, CFRelease, CFRunLoopAddTimer, CFRunLoopGetMain, CFRunLoopRef, CFRunLoopTimerCreate, CFRunLoopTimerInvalidate, - CFRunLoopTimerRef, CFRunLoopTimerSetNextFireDate, NSInteger, NSOperatingSystemVersion, - NSUInteger, + CFRunLoopTimerRef, CFRunLoopTimerSetNextFireDate, CGRect, CGSize, NSInteger, + NSOperatingSystemVersion, NSUInteger, }, }, window::WindowId as RootWindowId, @@ -45,11 +46,11 @@ enum UserCallbackTransitionResult<'a> { processing_redraws: bool, }, ReentrancyPrevented { - queued_events: &'a mut Vec>, + queued_events: &'a mut Vec, }, } -impl Event { +impl Event<'static, Never> { fn is_redraw(&self) -> bool { if let Event::RedrawRequested(_) = self { true @@ -65,12 +66,12 @@ impl Event { enum AppStateImpl { NotLaunched { queued_windows: Vec, - queued_events: Vec>, + queued_events: Vec, queued_gpu_redraws: HashSet, }, Launching { queued_windows: Vec, - queued_events: Vec>, + queued_events: Vec, queued_event_handler: Box, queued_gpu_redraws: HashSet, }, @@ -81,7 +82,7 @@ enum AppStateImpl { }, // special state to deal with reentrancy and prevent mutable aliasing. InUserCallback { - queued_events: Vec>, + queued_events: Vec, queued_gpu_redraws: HashSet, }, ProcessingRedraws { @@ -222,7 +223,7 @@ impl AppState { }); } - fn did_finish_launching_transition(&mut self) -> (Vec, Vec>) { + fn did_finish_launching_transition(&mut self) -> (Vec, Vec) { let (windows, events, event_handler, queued_gpu_redraws) = match self.take_state() { AppStateImpl::Launching { queued_windows, @@ -245,7 +246,7 @@ impl AppState { (windows, events) } - fn wakeup_transition(&mut self) -> Option> { + fn wakeup_transition(&mut self) -> Option { // before `AppState::did_finish_launching` is called, pretend there is no running // event loop. if !self.has_launched() { @@ -258,7 +259,10 @@ impl AppState { AppStateImpl::PollFinished { waiting_event_handler, }, - ) => (waiting_event_handler, Event::NewEvents(StartCause::Poll)), + ) => ( + waiting_event_handler, + EventWrapper::StaticEvent(Event::NewEvents(StartCause::Poll)), + ), ( ControlFlow::Wait, AppStateImpl::Waiting { @@ -267,10 +271,10 @@ impl AppState { }, ) => ( waiting_event_handler, - Event::NewEvents(StartCause::WaitCancelled { + EventWrapper::StaticEvent(Event::NewEvents(StartCause::WaitCancelled { start, requested_resume: None, - }), + })), ), ( ControlFlow::WaitUntil(requested_resume), @@ -280,15 +284,15 @@ impl AppState { }, ) => { let event = if Instant::now() >= requested_resume { - Event::NewEvents(StartCause::ResumeTimeReached { + EventWrapper::StaticEvent(Event::NewEvents(StartCause::ResumeTimeReached { start, requested_resume, - }) + })) } else { - Event::NewEvents(StartCause::WaitCancelled { + EventWrapper::StaticEvent(Event::NewEvents(StartCause::WaitCancelled { start, requested_resume: Some(requested_resume), - }) + })) }; (waiting_event_handler, event) } @@ -587,7 +591,10 @@ pub unsafe fn did_finish_launching() { let (windows, events) = AppState::get_mut().did_finish_launching_transition(); - let events = std::iter::once(Event::NewEvents(StartCause::Init)).chain(events); + let events = std::iter::once(EventWrapper::StaticEvent(Event::NewEvents( + StartCause::Init, + ))) + .chain(events); handle_nonuser_events(events); // the above window dance hack, could possibly trigger new windows to be created. @@ -616,12 +623,12 @@ pub unsafe fn handle_wakeup_transition() { } // requires main thread -pub unsafe fn handle_nonuser_event(event: Event) { +pub unsafe fn handle_nonuser_event(event: EventWrapper) { handle_nonuser_events(std::iter::once(event)) } // requires main thread -pub unsafe fn handle_nonuser_events>>(events: I) { +pub unsafe fn handle_nonuser_events>(events: I) { let mut this = AppState::get_mut(); let (mut event_handler, active_control_flow, processing_redraws) = match this.try_user_callback_transition() { @@ -638,16 +645,23 @@ pub unsafe fn handle_nonuser_events>>(events let mut control_flow = this.control_flow; drop(this); - for event in events { - if !processing_redraws && event.is_redraw() { - log::info!("processing `RedrawRequested` during the main event loop"); - } else if processing_redraws && !event.is_redraw() { - log::warn!( - "processing non `RedrawRequested` event after the main event loop: {:#?}", - event - ); + for wrapper in events { + match wrapper { + EventWrapper::StaticEvent(event) => { + if !processing_redraws && event.is_redraw() { + log::info!("processing `RedrawRequested` during the main event loop"); + } else if processing_redraws && !event.is_redraw() { + log::warn!( + "processing non `RedrawRequested` event after the main event loop: {:#?}", + event + ); + } + event_handler.handle_nonuser_event(event, &mut control_flow) + } + EventWrapper::EventProxy(proxy) => { + handle_event_proxy(&mut event_handler, control_flow, proxy) + } } - event_handler.handle_nonuser_event(event, &mut control_flow) } loop { @@ -688,16 +702,23 @@ pub unsafe fn handle_nonuser_events>>(events } drop(this); - for event in queued_events { - if !processing_redraws && event.is_redraw() { - log::info!("processing `RedrawRequested` during the main event loop"); - } else if processing_redraws && !event.is_redraw() { - log::warn!( - "processing non-`RedrawRequested` event after the main event loop: {:#?}", - event - ); + for wrapper in queued_events { + match wrapper { + EventWrapper::StaticEvent(event) => { + if !processing_redraws && event.is_redraw() { + log::info!("processing `RedrawRequested` during the main event loop"); + } else if processing_redraws && !event.is_redraw() { + log::warn!( + "processing non-`RedrawRequested` event after the main event loop: {:#?}", + event + ); + } + event_handler.handle_nonuser_event(event, &mut control_flow) + } + EventWrapper::EventProxy(proxy) => { + handle_event_proxy(&mut event_handler, control_flow, proxy) + } } - event_handler.handle_nonuser_event(event, &mut control_flow) } } } @@ -751,8 +772,15 @@ unsafe fn handle_user_events() { } drop(this); - for event in queued_events { - event_handler.handle_nonuser_event(event, &mut control_flow) + for wrapper in queued_events { + match wrapper { + EventWrapper::StaticEvent(event) => { + event_handler.handle_nonuser_event(event, &mut control_flow) + } + EventWrapper::EventProxy(proxy) => { + handle_event_proxy(&mut event_handler, control_flow, proxy) + } + } } event_handler.handle_user_events(&mut control_flow); } @@ -772,13 +800,13 @@ pub unsafe fn handle_main_events_cleared() { // User events are always sent out at the end of the "MainEventLoop" handle_user_events(); - handle_nonuser_event(Event::MainEventsCleared); + handle_nonuser_event(EventWrapper::StaticEvent(Event::MainEventsCleared)); let mut this = AppState::get_mut(); let mut redraw_events: Vec> = this .main_events_cleared_transition() .into_iter() - .map(|window| Event::RedrawRequested(RootWindowId(window.into()))) + .map(|window| EventWrapper::StaticEvent(Event::RedrawRequested(RootWindowId(window.into())))) .collect(); if !redraw_events.is_empty() { @@ -804,6 +832,67 @@ pub unsafe fn terminated() { event_handler.handle_nonuser_event(Event::LoopDestroyed, &mut control_flow) } +fn handle_event_proxy( + event_handler: &mut Box, + control_flow: ControlFlow, + proxy: EventProxy, +) { + match proxy { + EventProxy::HiDpiFactorChangedProxy { + suggested_size, + hidpi_factor, + window_id, + } => handle_hidpi_proxy( + event_handler, + control_flow, + suggested_size, + hidpi_factor, + window_id, + ), + } +} + +fn handle_hidpi_proxy( + event_handler: &mut Box, + mut control_flow: ControlFlow, + suggested_size: LogicalSize, + hidpi_factor: f64, + window_id: id, +) { + let size = suggested_size.to_physical(hidpi_factor); + let new_inner_size = &mut Some(size); + let event = Event::WindowEvent { + window_id: RootWindowId(window_id.into()), + event: WindowEvent::HiDpiFactorChanged { + hidpi_factor, + new_inner_size, + }, + }; + event_handler.handle_nonuser_event(event, &mut control_flow); + let (view, screen_frame) = get_view_and_screen_frame(window_id); + if let Some(physical_size) = new_inner_size { + let logical_size = physical_size.to_logical(hidpi_factor); + let size = CGSize::new(logical_size); + let new_frame: CGRect = CGRect::new(screen_frame.origin, size); + unsafe { + let () = msg_send![view, setFrame: new_frame]; + } + } +} + +fn get_view_and_screen_frame(window_id: id) -> (id, CGRect) { + unsafe { + let view_controller: id = msg_send![window_id, rootViewController]; + let view: id = msg_send![view_controller, view]; + let bounds: CGRect = msg_send![window_id, bounds]; + let screen: id = msg_send![window_id, screen]; + let screen_space: id = msg_send![screen, coordinateSpace]; + let screen_frame: CGRect = + msg_send![window_id, convertRect:bounds toCoordinateSpace:screen_space]; + (view, screen_frame) + } +} + struct EventLoopWaker { timer: CFRunLoopTimerRef, } diff --git a/src/platform_impl/ios/event_loop.rs b/src/platform_impl/ios/event_loop.rs index 657d29ebb4..869005191c 100644 --- a/src/platform_impl/ios/event_loop.rs +++ b/src/platform_impl/ios/event_loop.rs @@ -8,6 +8,7 @@ use std::{ }; use crate::{ + dpi::LogicalSize, event::Event, event_loop::{ ControlFlow, EventLoopClosed, EventLoopWindowTarget as RootEventLoopWindowTarget, @@ -28,6 +29,21 @@ use crate::platform_impl::platform::{ monitor, view, MonitorHandle, }; +#[derive(Debug)] +pub enum EventWrapper { + StaticEvent(Event<'static, Never>), + EventProxy(EventProxy), +} + +#[derive(Debug, PartialEq)] +pub enum EventProxy { + HiDpiFactorChangedProxy { + window_id: id, + suggested_size: LogicalSize, + hidpi_factor: f64, + }, +} + pub struct EventLoopWindowTarget { receiver: Receiver, sender_to_clone: Sender, @@ -69,7 +85,7 @@ impl EventLoop { pub fn run(self, event_handler: F) -> ! where - F: 'static + FnMut(Event, &RootEventLoopWindowTarget, &mut ControlFlow), + F: 'static + FnMut(Event<'_, T>, &RootEventLoopWindowTarget, &mut ControlFlow), { unsafe { let application: *mut c_void = msg_send![class!(UIApplication), sharedApplication]; @@ -277,7 +293,7 @@ fn setup_control_flow_observers() { pub enum Never {} pub trait EventHandler: Debug { - fn handle_nonuser_event(&mut self, event: Event, control_flow: &mut ControlFlow); + fn handle_nonuser_event(&mut self, event: Event<'_, Never>, control_flow: &mut ControlFlow); fn handle_user_events(&mut self, control_flow: &mut ControlFlow); } @@ -296,10 +312,10 @@ impl Debug for EventLoopHandler { impl EventHandler for EventLoopHandler where - F: 'static + FnMut(Event, &RootEventLoopWindowTarget, &mut ControlFlow), + F: 'static + FnMut(Event<'_, T>, &RootEventLoopWindowTarget, &mut ControlFlow), T: 'static, { - fn handle_nonuser_event(&mut self, event: Event, control_flow: &mut ControlFlow) { + fn handle_nonuser_event(&mut self, event: Event<'_, Never>, control_flow: &mut ControlFlow) { (self.f)( event.map_nonuser_event().unwrap(), &self.event_loop, diff --git a/src/platform_impl/ios/ffi.rs b/src/platform_impl/ios/ffi.rs index 4ecd47f7b2..c7cac81622 100644 --- a/src/platform_impl/ios/ffi.rs +++ b/src/platform_impl/ios/ffi.rs @@ -4,7 +4,10 @@ use std::{convert::TryInto, ffi::CString, ops::BitOr, os::raw::*}; use objc::{runtime::Object, Encode, Encoding}; -use crate::platform::ios::{Idiom, ScreenEdge, ValidOrientations}; +use crate::{ + dpi::LogicalSize, + platform::ios::{Idiom, ScreenEdge, ValidOrientations}, +}; pub type id = *mut Object; pub const nil: id = 0 as id; @@ -39,6 +42,15 @@ pub struct CGSize { pub height: CGFloat, } +impl CGSize { + pub fn new(size: LogicalSize) -> CGSize { + CGSize { + width: size.width as _, + height: size.height as _, + } + } +} + #[repr(C)] #[derive(Debug, Clone)] pub struct CGRect { @@ -46,6 +58,12 @@ pub struct CGRect { pub size: CGSize, } +impl CGRect { + pub fn new(origin: CGPoint, size: CGSize) -> CGRect { + CGRect { origin, size } + } +} + unsafe impl Encode for CGRect { fn encode() -> Encoding { unsafe { diff --git a/src/platform_impl/ios/monitor.rs b/src/platform_impl/ios/monitor.rs index ee455eaef8..71ad739083 100644 --- a/src/platform_impl/ios/monitor.rs +++ b/src/platform_impl/ios/monitor.rs @@ -219,7 +219,7 @@ impl Inner { pub fn size(&self) -> PhysicalSize { unsafe { let bounds: CGRect = msg_send![self.ui_screen(), nativeBounds]; - (bounds.size.width as f64, bounds.size.height as f64).into() + PhysicalSize::new(bounds.size.width as u32, bounds.size.height as u32) } } diff --git a/src/platform_impl/ios/view.rs b/src/platform_impl/ios/view.rs index 622b351bd7..e31a99ed65 100644 --- a/src/platform_impl/ios/view.rs +++ b/src/platform_impl/ios/view.rs @@ -10,7 +10,7 @@ use crate::{ platform::ios::MonitorHandleExtIOS, platform_impl::platform::{ app_state::{self, OSCapabilities}, - event_loop, + event_loop::{self, EventProxy, EventWrapper}, ffi::{ id, nil, CGFloat, CGPoint, CGRect, UIForceTouchCapability, UIInterfaceOrientationMask, UIRectEdge, UITouchPhase, UITouchType, @@ -103,8 +103,8 @@ unsafe fn get_view_class(root_view_class: &'static Class) -> &'static Class { let window: id = msg_send![object, window]; assert!(!window.is_null()); app_state::handle_nonuser_events( - std::iter::once(Event::RedrawRequested(RootWindowId(window.into()))) - .chain(std::iter::once(Event::RedrawEventsCleared)), + std::iter::once(EventWrapper::StaticEvent(Event::RedrawRequested(RootWindowId(window.into())))) + .chain(std::iter::once(EventWrapper::StaticEvent(Event::RedrawEventsCleared))), ); let superclass: &'static Class = msg_send![object, superclass]; let () = msg_send![super(object, superclass), drawRect: rect]; @@ -123,14 +123,16 @@ unsafe fn get_view_class(root_view_class: &'static Class) -> &'static Class { let screen_space: id = msg_send![screen, coordinateSpace]; let screen_frame: CGRect = msg_send![object, convertRect:bounds toCoordinateSpace:screen_space]; + let dpi_factor: CGFloat = msg_send![screen, scale]; let size = crate::dpi::LogicalSize { width: screen_frame.size.width as _, height: screen_frame.size.height as _, - }; - app_state::handle_nonuser_event(Event::WindowEvent { + } + .to_physical(dpi_factor.into()); + app_state::handle_nonuser_event(EventWrapper::StaticEvent(Event::WindowEvent { window_id: RootWindowId(window.into()), event: WindowEvent::Resized(size), - }); + })); } } @@ -156,14 +158,15 @@ unsafe fn get_view_class(root_view_class: &'static Class) -> &'static Class { // `setContentScaleFactor` may be called with a value of 0, which means "reset the // content scale factor to a device-specific default value", so we can't use the // parameter here. We can query the actual factor using the getter - let hidpi_factor: CGFloat = msg_send![object, contentScaleFactor]; + let dpi_factor: CGFloat = msg_send![object, contentScaleFactor]; assert!( - !hidpi_factor.is_nan() - && hidpi_factor.is_finite() - && hidpi_factor.is_sign_positive() - && hidpi_factor > 0.0, + !dpi_factor.is_nan() + && dpi_factor.is_finite() + && dpi_factor.is_sign_positive() + && dpi_factor > 0.0, "invalid hidpi_factor set on UIView", ); + let hidpi_factor: f64 = dpi_factor.into(); let bounds: CGRect = msg_send![object, bounds]; let screen: id = msg_send![window, screen]; let screen_space: id = msg_send![screen, coordinateSpace]; @@ -174,14 +177,19 @@ unsafe fn get_view_class(root_view_class: &'static Class) -> &'static Class { height: screen_frame.size.height as _, }; app_state::handle_nonuser_events( - std::iter::once(Event::WindowEvent { - window_id: RootWindowId(window.into()), - event: WindowEvent::HiDpiFactorChanged(hidpi_factor as _), - }) - .chain(std::iter::once(Event::WindowEvent { - window_id: RootWindowId(window.into()), - event: WindowEvent::Resized(size), - })), + std::iter::once(EventWrapper::EventProxy( + EventProxy::HiDpiFactorChangedProxy { + window_id: window, + hidpi_factor, + suggested_size: size, + }, + )) + .chain(std::iter::once(EventWrapper::StaticEvent( + Event::WindowEvent { + window_id: RootWindowId(window.into()), + event: WindowEvent::Resized(size.to_physical(hidpi_factor)), + }, + ))), ); } } @@ -238,7 +246,7 @@ unsafe fn get_view_class(root_view_class: &'static Class) -> &'static Class { _ => panic!("unexpected touch phase: {:?}", phase as i32), }; - touch_events.push(Event::WindowEvent { + touch_events.push(EventWrapper::StaticEvent(Event::WindowEvent { window_id: RootWindowId(window.into()), event: WindowEvent::Touch(Touch { device_id: RootDeviceId(DeviceId { uiscreen }), @@ -247,7 +255,7 @@ unsafe fn get_view_class(root_view_class: &'static Class) -> &'static Class { force, phase, }), - }); + })); } app_state::handle_nonuser_events(touch_events); } @@ -367,20 +375,20 @@ unsafe fn get_window_class() -> &'static Class { extern "C" fn become_key_window(object: &Object, _: Sel) { unsafe { - app_state::handle_nonuser_event(Event::WindowEvent { + app_state::handle_nonuser_event(EventWrapper::StaticEvent(Event::WindowEvent { window_id: RootWindowId(object.into()), event: WindowEvent::Focused(true), - }); + })); let () = msg_send![super(object, class!(UIWindow)), becomeKeyWindow]; } } extern "C" fn resign_key_window(object: &Object, _: Sel) { unsafe { - app_state::handle_nonuser_event(Event::WindowEvent { + app_state::handle_nonuser_event(EventWrapper::StaticEvent(Event::WindowEvent { window_id: RootWindowId(object.into()), event: WindowEvent::Focused(false), - }); + })); let () = msg_send![super(object, class!(UIWindow)), resignKeyWindow]; } } @@ -500,9 +508,7 @@ pub unsafe fn create_window( let () = msg_send![uiscreen, setCurrentMode: video_mode.video_mode.screen_mode.0]; msg_send![window, setScreen:video_mode.monitor().ui_screen()] } - Some(Fullscreen::Borderless(ref monitor)) => { - msg_send![window, setScreen:monitor.ui_screen()] - } + Some(Fullscreen::Borderless(ref monitor)) => msg_send![window, setScreen:monitor.ui_screen()], None => (), } @@ -518,11 +524,11 @@ pub fn create_delegate_class() { } extern "C" fn did_become_active(_: &Object, _: Sel, _: id) { - unsafe { app_state::handle_nonuser_event(Event::Resumed) } + unsafe { app_state::handle_nonuser_event(EventWrapper::StaticEvent(Event::Resumed)) } } extern "C" fn will_resign_active(_: &Object, _: Sel, _: id) { - unsafe { app_state::handle_nonuser_event(Event::Suspended) } + unsafe { app_state::handle_nonuser_event(EventWrapper::StaticEvent(Event::Suspended)) } } extern "C" fn will_enter_foreground(_: &Object, _: Sel, _: id) {} @@ -541,10 +547,10 @@ pub fn create_delegate_class() { } let is_winit_window: BOOL = msg_send![window, isKindOfClass: class!(WinitUIWindow)]; if is_winit_window == YES { - events.push(Event::WindowEvent { + events.push(EventWrapper::StaticEvent(Event::WindowEvent { window_id: RootWindowId(window.into()), event: WindowEvent::Destroyed, - }); + })); } } app_state::handle_nonuser_events(events); diff --git a/src/platform_impl/ios/window.rs b/src/platform_impl/ios/window.rs index d1ad03f55f..f24e61c0d7 100644 --- a/src/platform_impl/ios/window.rs +++ b/src/platform_impl/ios/window.rs @@ -7,14 +7,15 @@ use std::{ use objc::runtime::{Class, Object, BOOL, NO, YES}; use crate::{ - dpi::{self, LogicalPosition, LogicalSize}, + dpi::{self, LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize, Position, Size}, error::{ExternalError, NotSupportedError, OsError as RootOsError}, event::{Event, WindowEvent}, icon::Icon, monitor::MonitorHandle as RootMonitorHandle, platform::ios::{MonitorHandleExtIOS, ScreenEdge, ValidOrientations}, platform_impl::platform::{ - app_state, event_loop, + app_state, + event_loop::{self, EventProxy, EventWrapper}, ffi::{ id, CGFloat, CGPoint, CGRect, CGSize, UIEdgeInsets, UIInterfaceOrientationMask, UIRectEdge, UIScreenOverscanCompensation, @@ -75,28 +76,34 @@ impl Inner { } } - pub fn inner_position(&self) -> Result { + pub fn inner_position(&self) -> Result { unsafe { let safe_area = self.safe_area_screen_space(); - Ok(LogicalPosition { + let position = LogicalPosition { x: safe_area.origin.x as _, y: safe_area.origin.y as _, - }) + }; + let dpi_factor = self.hidpi_factor(); + Ok(position.to_physical(dpi_factor)) } } - pub fn outer_position(&self) -> Result { + pub fn outer_position(&self) -> Result { unsafe { let screen_frame = self.screen_frame(); - Ok(LogicalPosition { + let position = LogicalPosition { x: screen_frame.origin.x as _, y: screen_frame.origin.y as _, - }) + }; + let dpi_factor = self.hidpi_factor(); + Ok(position.to_physical(dpi_factor)) } } - pub fn set_outer_position(&self, position: LogicalPosition) { + pub fn set_outer_position(&self, physical_position: Position) { unsafe { + let dpi_factor = self.hidpi_factor(); + let position = physical_position.to_logical(dpi_factor); let screen_frame = self.screen_frame(); let new_screen_frame = CGRect { origin: CGPoint { @@ -110,35 +117,39 @@ impl Inner { } } - pub fn inner_size(&self) -> LogicalSize { + pub fn inner_size(&self) -> PhysicalSize { unsafe { + let dpi_factor = self.hidpi_factor(); let safe_area = self.safe_area_screen_space(); - LogicalSize { + let size = LogicalSize { width: safe_area.size.width as _, height: safe_area.size.height as _, - } + }; + size.to_physical(dpi_factor) } } - pub fn outer_size(&self) -> LogicalSize { + pub fn outer_size(&self) -> PhysicalSize { unsafe { + let dpi_factor = self.hidpi_factor(); let screen_frame = self.screen_frame(); - LogicalSize { + let size = LogicalSize { width: screen_frame.size.width as _, height: screen_frame.size.height as _, - } + }; + size.to_physical(dpi_factor) } } - pub fn set_inner_size(&self, _size: LogicalSize) { + pub fn set_inner_size(&self, _size: Size) { unimplemented!("not clear what `Window::set_inner_size` means on iOS"); } - pub fn set_min_inner_size(&self, _dimensions: Option) { + pub fn set_min_inner_size(&self, _dimensions: Option) { warn!("`Window::set_min_inner_size` is ignored on iOS") } - pub fn set_max_inner_size(&self, _dimensions: Option) { + pub fn set_max_inner_size(&self, _dimensions: Option) { warn!("`Window::set_max_inner_size` is ignored on iOS") } @@ -157,7 +168,7 @@ impl Inner { debug!("`Window::set_cursor_icon` ignored on iOS") } - pub fn set_cursor_position(&self, _position: LogicalPosition) -> Result<(), ExternalError> { + pub fn set_cursor_position(&self, _position: Position) -> Result<(), ExternalError> { Err(ExternalError::NotSupported(NotSupportedError::new())) } @@ -243,7 +254,7 @@ impl Inner { warn!("`Window::set_window_icon` is ignored on iOS") } - pub fn set_ime_position(&self, _position: LogicalPosition) { + pub fn set_ime_position(&self, _position: Position) { warn!("`Window::set_ime_position` is ignored on iOS") } @@ -343,13 +354,17 @@ impl Window { let screen_bounds: CGRect = msg_send![screen, bounds]; let frame = match window_attributes.inner_size { - Some(dim) => CGRect { - origin: screen_bounds.origin, - size: CGSize { - width: dim.width as _, - height: dim.height as _, - }, - }, + Some(dim) => { + let dpi_factor = msg_send![screen, scale]; + let size = dim.to_logical(dpi_factor); + CGRect { + origin: screen_bounds.origin, + size: CGSize { + width: size.width as _, + height: size.height as _, + }, + } + } None => screen_bounds, }; @@ -385,7 +400,8 @@ impl Window { // Like the Windows and macOS backends, we send a `HiDpiFactorChanged` and `Resized` // event on window creation if the DPI factor != 1.0 - let hidpi_factor: CGFloat = msg_send![view, contentScaleFactor]; + let dpi_factor: CGFloat = msg_send![view, contentScaleFactor]; + let hidpi_factor: f64 = dpi_factor.into(); if hidpi_factor != 1.0 { let bounds: CGRect = msg_send![view, bounds]; let screen: id = msg_send![window, screen]; @@ -397,14 +413,19 @@ impl Window { height: screen_frame.size.height as _, }; app_state::handle_nonuser_events( - std::iter::once(Event::WindowEvent { - window_id: RootWindowId(window.into()), - event: WindowEvent::HiDpiFactorChanged(hidpi_factor as _), - }) - .chain(std::iter::once(Event::WindowEvent { - window_id: RootWindowId(window.into()), - event: WindowEvent::Resized(size), - })), + std::iter::once(EventWrapper::EventProxy( + EventProxy::HiDpiFactorChangedProxy { + window_id: window, + hidpi_factor, + suggested_size: size, + }, + )) + .chain(std::iter::once(EventWrapper::StaticEvent( + Event::WindowEvent { + window_id: RootWindowId(window.into()), + event: WindowEvent::Resized(size.to_physical(hidpi_factor)), + }, + ))), ); }