iOS: Dpi overhaul (#1223)

* WIP - Make EL2 DPI changes and implement on Windows (#895)

* Modify DPI API publicly and on Windows

* Add generic Position and make dpi creation functions const

* Make examples work

* Fix fullscreen windows not appearing

* Replace Logical coordinates in window events with Physical coordinates

* Update HiDpiFactorChanged

* Document to_static

* On Windows, make AdjustRect calls DPI-aware when possible (#1015)

* Use AdjustWidowRectExForDPI when available

* Prioritize presevering logical size when handling WM_DPICHANGED

* Format

* Add changelog entry

* macOS: Dpi overhaul (#997)

* WIP - Make EL2 DPI changes and implement on Windows (#895)

* Modify DPI API publicly and on Windows

* Add generic Position and make dpi creation functions const

* Make examples work

* Fix fullscreen windows not appearing

* Replace Logical coordinates in window events with Physical coordinates

* Update HiDpiFactorChanged

* Document to_static

* fix app_state errors

* fixes hidpi related errors in window_delegate

* fix bad merge

* dpi_factor edits in window_delegate

* fixes type and lifetime errors in window and window_delegate

* applies fmt

* complies with @aleksijuvani requested changes

* modifies Handler lifetimes

* fixes lifetime isues, adds propper handling for HiDpiChanged

* applies fmt

* restore original lifetimes

* solution is somewhere out there

* applies fmt

* pass as references

* resolves issue with HANDLER

* crate visible type error

* fixes visibility issues

* applies fmt

* deals with warnings

* simplifies new_inner_size setting algorthm

* moves proxy instead of referencing it and removes double deref from proxy.ns_window

* makes @Osspial tests (https://github.com/rust-windowing/winit/pull/997\#discussion_r301852354) pass

* complies with @aleksijuvani suggested changes

* makes max window size std::f32::MAX

* On Windows, fix new DPI API not setting window size properly (#1130)

* First attempt

* Second attempt

* Maintain cursor horizontal ratio

* Fix DPI change handling when maximized

* Revert window example

* Make new DPI code more understandable

* Format

* Implement DPI Usability Upgrades for X11 and Wayland (#1098)

* Fix compile errors

* Use `mio` for the X11 event loop

* Removes `calloop` from the X11 event loop, as the method of draining a
  source using a closure provided to the `calloop::EventLoop` instance
  conflicts with the need to deliver events directly to the callback
  provided to `EventLoop::run`, in order to respond to the value provided by
  `WindowEvent::HiDpiFactorChanged`.

* Implement interactive `HiDpiFactorChanged` event for X11

* Implement interactive `HiDpiFactorChanged` event for Wayland

* Run cargo fmt

* Fix Wayland not processing events from EventQueue

* Backport #981

* some lifetime tinkering

* finishes lifetime tinkering

* fixes all type errors

* adds support ffi functions

* adds wrappers for nonstatic events

* replaces events with event wrappers

* reimplementing hidpichanged event in app_state

* implements HiDpiFactorChanged for iOS

* applies formatter

* complies with @aleksijuvani requested changes

* resolves conflicts

* applies fmt

* removes merge blurp

* corrects state of CHANGELOG

* fix fmt check error

* fixes hidpi_factor for armv7-apple-ios
This commit is contained in:
Bogaevsky 2019-10-18 18:31:26 +03:00 committed by Osspial
parent cbf61e5cb9
commit b16042a047
6 changed files with 267 additions and 117 deletions

View file

@ -12,15 +12,16 @@ use std::{
use objc::runtime::{BOOL, YES}; use objc::runtime::{BOOL, YES};
use crate::{ use crate::{
event::{Event, StartCause}, dpi::LogicalSize,
event::{Event, StartCause, WindowEvent},
event_loop::ControlFlow, event_loop::ControlFlow,
platform_impl::platform::{ platform_impl::platform::{
event_loop::{EventHandler, Never}, event_loop::{EventHandler, EventProxy, EventWrapper, Never},
ffi::{ ffi::{
id, kCFRunLoopCommonModes, CFAbsoluteTimeGetCurrent, CFRelease, CFRunLoopAddTimer, id, kCFRunLoopCommonModes, CFAbsoluteTimeGetCurrent, CFRelease, CFRunLoopAddTimer,
CFRunLoopGetMain, CFRunLoopRef, CFRunLoopTimerCreate, CFRunLoopTimerInvalidate, CFRunLoopGetMain, CFRunLoopRef, CFRunLoopTimerCreate, CFRunLoopTimerInvalidate,
CFRunLoopTimerRef, CFRunLoopTimerSetNextFireDate, NSInteger, NSOperatingSystemVersion, CFRunLoopTimerRef, CFRunLoopTimerSetNextFireDate, CGRect, CGSize, NSInteger,
NSUInteger, NSOperatingSystemVersion, NSUInteger,
}, },
}, },
window::WindowId as RootWindowId, window::WindowId as RootWindowId,
@ -45,11 +46,11 @@ enum UserCallbackTransitionResult<'a> {
processing_redraws: bool, processing_redraws: bool,
}, },
ReentrancyPrevented { ReentrancyPrevented {
queued_events: &'a mut Vec<Event<Never>>, queued_events: &'a mut Vec<EventWrapper>,
}, },
} }
impl Event<Never> { impl Event<'static, Never> {
fn is_redraw(&self) -> bool { fn is_redraw(&self) -> bool {
if let Event::RedrawRequested(_) = self { if let Event::RedrawRequested(_) = self {
true true
@ -65,12 +66,12 @@ impl Event<Never> {
enum AppStateImpl { enum AppStateImpl {
NotLaunched { NotLaunched {
queued_windows: Vec<id>, queued_windows: Vec<id>,
queued_events: Vec<Event<Never>>, queued_events: Vec<EventWrapper>,
queued_gpu_redraws: HashSet<id>, queued_gpu_redraws: HashSet<id>,
}, },
Launching { Launching {
queued_windows: Vec<id>, queued_windows: Vec<id>,
queued_events: Vec<Event<Never>>, queued_events: Vec<EventWrapper>,
queued_event_handler: Box<dyn EventHandler>, queued_event_handler: Box<dyn EventHandler>,
queued_gpu_redraws: HashSet<id>, queued_gpu_redraws: HashSet<id>,
}, },
@ -81,7 +82,7 @@ enum AppStateImpl {
}, },
// special state to deal with reentrancy and prevent mutable aliasing. // special state to deal with reentrancy and prevent mutable aliasing.
InUserCallback { InUserCallback {
queued_events: Vec<Event<Never>>, queued_events: Vec<EventWrapper>,
queued_gpu_redraws: HashSet<id>, queued_gpu_redraws: HashSet<id>,
}, },
ProcessingRedraws { ProcessingRedraws {
@ -222,7 +223,7 @@ impl AppState {
}); });
} }
fn did_finish_launching_transition(&mut self) -> (Vec<id>, Vec<Event<Never>>) { fn did_finish_launching_transition(&mut self) -> (Vec<id>, Vec<EventWrapper>) {
let (windows, events, event_handler, queued_gpu_redraws) = match self.take_state() { let (windows, events, event_handler, queued_gpu_redraws) = match self.take_state() {
AppStateImpl::Launching { AppStateImpl::Launching {
queued_windows, queued_windows,
@ -245,7 +246,7 @@ impl AppState {
(windows, events) (windows, events)
} }
fn wakeup_transition(&mut self) -> Option<Event<Never>> { fn wakeup_transition(&mut self) -> Option<EventWrapper> {
// before `AppState::did_finish_launching` is called, pretend there is no running // before `AppState::did_finish_launching` is called, pretend there is no running
// event loop. // event loop.
if !self.has_launched() { if !self.has_launched() {
@ -258,7 +259,10 @@ impl AppState {
AppStateImpl::PollFinished { AppStateImpl::PollFinished {
waiting_event_handler, waiting_event_handler,
}, },
) => (waiting_event_handler, Event::NewEvents(StartCause::Poll)), ) => (
waiting_event_handler,
EventWrapper::StaticEvent(Event::NewEvents(StartCause::Poll)),
),
( (
ControlFlow::Wait, ControlFlow::Wait,
AppStateImpl::Waiting { AppStateImpl::Waiting {
@ -267,10 +271,10 @@ impl AppState {
}, },
) => ( ) => (
waiting_event_handler, waiting_event_handler,
Event::NewEvents(StartCause::WaitCancelled { EventWrapper::StaticEvent(Event::NewEvents(StartCause::WaitCancelled {
start, start,
requested_resume: None, requested_resume: None,
}), })),
), ),
( (
ControlFlow::WaitUntil(requested_resume), ControlFlow::WaitUntil(requested_resume),
@ -280,15 +284,15 @@ impl AppState {
}, },
) => { ) => {
let event = if Instant::now() >= requested_resume { let event = if Instant::now() >= requested_resume {
Event::NewEvents(StartCause::ResumeTimeReached { EventWrapper::StaticEvent(Event::NewEvents(StartCause::ResumeTimeReached {
start, start,
requested_resume, requested_resume,
}) }))
} else { } else {
Event::NewEvents(StartCause::WaitCancelled { EventWrapper::StaticEvent(Event::NewEvents(StartCause::WaitCancelled {
start, start,
requested_resume: Some(requested_resume), requested_resume: Some(requested_resume),
}) }))
}; };
(waiting_event_handler, event) (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 (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); handle_nonuser_events(events);
// the above window dance hack, could possibly trigger new windows to be created. // 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 // requires main thread
pub unsafe fn handle_nonuser_event(event: Event<Never>) { pub unsafe fn handle_nonuser_event(event: EventWrapper) {
handle_nonuser_events(std::iter::once(event)) handle_nonuser_events(std::iter::once(event))
} }
// requires main thread // requires main thread
pub unsafe fn handle_nonuser_events<I: IntoIterator<Item = Event<Never>>>(events: I) { pub unsafe fn handle_nonuser_events<I: IntoIterator<Item = EventWrapper>>(events: I) {
let mut this = AppState::get_mut(); let mut this = AppState::get_mut();
let (mut event_handler, active_control_flow, processing_redraws) = let (mut event_handler, active_control_flow, processing_redraws) =
match this.try_user_callback_transition() { match this.try_user_callback_transition() {
@ -638,16 +645,23 @@ pub unsafe fn handle_nonuser_events<I: IntoIterator<Item = Event<Never>>>(events
let mut control_flow = this.control_flow; let mut control_flow = this.control_flow;
drop(this); drop(this);
for event in events { for wrapper in events {
if !processing_redraws && event.is_redraw() { match wrapper {
log::info!("processing `RedrawRequested` during the main event loop"); EventWrapper::StaticEvent(event) => {
} else if processing_redraws && !event.is_redraw() { if !processing_redraws && event.is_redraw() {
log::warn!( log::info!("processing `RedrawRequested` during the main event loop");
"processing non `RedrawRequested` event after the main event loop: {:#?}", } else if processing_redraws && !event.is_redraw() {
event 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 { loop {
@ -688,16 +702,23 @@ pub unsafe fn handle_nonuser_events<I: IntoIterator<Item = Event<Never>>>(events
} }
drop(this); drop(this);
for event in queued_events { for wrapper in queued_events {
if !processing_redraws && event.is_redraw() { match wrapper {
log::info!("processing `RedrawRequested` during the main event loop"); EventWrapper::StaticEvent(event) => {
} else if processing_redraws && !event.is_redraw() { if !processing_redraws && event.is_redraw() {
log::warn!( log::info!("processing `RedrawRequested` during the main event loop");
"processing non-`RedrawRequested` event after the main event loop: {:#?}", } else if processing_redraws && !event.is_redraw() {
event 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); drop(this);
for event in queued_events { for wrapper in queued_events {
event_handler.handle_nonuser_event(event, &mut control_flow) 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); 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" // User events are always sent out at the end of the "MainEventLoop"
handle_user_events(); handle_user_events();
handle_nonuser_event(Event::MainEventsCleared); handle_nonuser_event(EventWrapper::StaticEvent(Event::MainEventsCleared));
let mut this = AppState::get_mut(); let mut this = AppState::get_mut();
let mut redraw_events: Vec<Event<Never>> = this let mut redraw_events: Vec<Event<Never>> = this
.main_events_cleared_transition() .main_events_cleared_transition()
.into_iter() .into_iter()
.map(|window| Event::RedrawRequested(RootWindowId(window.into()))) .map(|window| EventWrapper::StaticEvent(Event::RedrawRequested(RootWindowId(window.into()))))
.collect(); .collect();
if !redraw_events.is_empty() { if !redraw_events.is_empty() {
@ -804,6 +832,67 @@ pub unsafe fn terminated() {
event_handler.handle_nonuser_event(Event::LoopDestroyed, &mut control_flow) event_handler.handle_nonuser_event(Event::LoopDestroyed, &mut control_flow)
} }
fn handle_event_proxy(
event_handler: &mut Box<dyn EventHandler>,
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<dyn EventHandler>,
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 { struct EventLoopWaker {
timer: CFRunLoopTimerRef, timer: CFRunLoopTimerRef,
} }

View file

@ -8,6 +8,7 @@ use std::{
}; };
use crate::{ use crate::{
dpi::LogicalSize,
event::Event, event::Event,
event_loop::{ event_loop::{
ControlFlow, EventLoopClosed, EventLoopWindowTarget as RootEventLoopWindowTarget, ControlFlow, EventLoopClosed, EventLoopWindowTarget as RootEventLoopWindowTarget,
@ -28,6 +29,21 @@ use crate::platform_impl::platform::{
monitor, view, MonitorHandle, 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<T: 'static> { pub struct EventLoopWindowTarget<T: 'static> {
receiver: Receiver<T>, receiver: Receiver<T>,
sender_to_clone: Sender<T>, sender_to_clone: Sender<T>,
@ -69,7 +85,7 @@ impl<T: 'static> EventLoop<T> {
pub fn run<F>(self, event_handler: F) -> ! pub fn run<F>(self, event_handler: F) -> !
where where
F: 'static + FnMut(Event<T>, &RootEventLoopWindowTarget<T>, &mut ControlFlow), F: 'static + FnMut(Event<'_, T>, &RootEventLoopWindowTarget<T>, &mut ControlFlow),
{ {
unsafe { unsafe {
let application: *mut c_void = msg_send![class!(UIApplication), sharedApplication]; let application: *mut c_void = msg_send![class!(UIApplication), sharedApplication];
@ -277,7 +293,7 @@ fn setup_control_flow_observers() {
pub enum Never {} pub enum Never {}
pub trait EventHandler: Debug { pub trait EventHandler: Debug {
fn handle_nonuser_event(&mut self, event: Event<Never>, 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); fn handle_user_events(&mut self, control_flow: &mut ControlFlow);
} }
@ -296,10 +312,10 @@ impl<F, T: 'static> Debug for EventLoopHandler<F, T> {
impl<F, T> EventHandler for EventLoopHandler<F, T> impl<F, T> EventHandler for EventLoopHandler<F, T>
where where
F: 'static + FnMut(Event<T>, &RootEventLoopWindowTarget<T>, &mut ControlFlow), F: 'static + FnMut(Event<'_, T>, &RootEventLoopWindowTarget<T>, &mut ControlFlow),
T: 'static, T: 'static,
{ {
fn handle_nonuser_event(&mut self, event: Event<Never>, control_flow: &mut ControlFlow) { fn handle_nonuser_event(&mut self, event: Event<'_, Never>, control_flow: &mut ControlFlow) {
(self.f)( (self.f)(
event.map_nonuser_event().unwrap(), event.map_nonuser_event().unwrap(),
&self.event_loop, &self.event_loop,

View file

@ -4,7 +4,10 @@ use std::{convert::TryInto, ffi::CString, ops::BitOr, os::raw::*};
use objc::{runtime::Object, Encode, Encoding}; 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 type id = *mut Object;
pub const nil: id = 0 as id; pub const nil: id = 0 as id;
@ -39,6 +42,15 @@ pub struct CGSize {
pub height: CGFloat, pub height: CGFloat,
} }
impl CGSize {
pub fn new(size: LogicalSize) -> CGSize {
CGSize {
width: size.width as _,
height: size.height as _,
}
}
}
#[repr(C)] #[repr(C)]
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct CGRect { pub struct CGRect {
@ -46,6 +58,12 @@ pub struct CGRect {
pub size: CGSize, pub size: CGSize,
} }
impl CGRect {
pub fn new(origin: CGPoint, size: CGSize) -> CGRect {
CGRect { origin, size }
}
}
unsafe impl Encode for CGRect { unsafe impl Encode for CGRect {
fn encode() -> Encoding { fn encode() -> Encoding {
unsafe { unsafe {

View file

@ -219,7 +219,7 @@ impl Inner {
pub fn size(&self) -> PhysicalSize { pub fn size(&self) -> PhysicalSize {
unsafe { unsafe {
let bounds: CGRect = msg_send![self.ui_screen(), nativeBounds]; 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)
} }
} }

View file

@ -10,7 +10,7 @@ use crate::{
platform::ios::MonitorHandleExtIOS, platform::ios::MonitorHandleExtIOS,
platform_impl::platform::{ platform_impl::platform::{
app_state::{self, OSCapabilities}, app_state::{self, OSCapabilities},
event_loop, event_loop::{self, EventProxy, EventWrapper},
ffi::{ ffi::{
id, nil, CGFloat, CGPoint, CGRect, UIForceTouchCapability, UIInterfaceOrientationMask, id, nil, CGFloat, CGPoint, CGRect, UIForceTouchCapability, UIInterfaceOrientationMask,
UIRectEdge, UITouchPhase, UITouchType, 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]; let window: id = msg_send![object, window];
assert!(!window.is_null()); assert!(!window.is_null());
app_state::handle_nonuser_events( app_state::handle_nonuser_events(
std::iter::once(Event::RedrawRequested(RootWindowId(window.into()))) std::iter::once(EventWrapper::StaticEvent(Event::RedrawRequested(RootWindowId(window.into()))))
.chain(std::iter::once(Event::RedrawEventsCleared)), .chain(std::iter::once(EventWrapper::StaticEvent(Event::RedrawEventsCleared))),
); );
let superclass: &'static Class = msg_send![object, superclass]; let superclass: &'static Class = msg_send![object, superclass];
let () = msg_send![super(object, superclass), drawRect: rect]; 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_space: id = msg_send![screen, coordinateSpace];
let screen_frame: CGRect = let screen_frame: CGRect =
msg_send![object, convertRect:bounds toCoordinateSpace:screen_space]; msg_send![object, convertRect:bounds toCoordinateSpace:screen_space];
let dpi_factor: CGFloat = msg_send![screen, scale];
let size = crate::dpi::LogicalSize { let size = crate::dpi::LogicalSize {
width: screen_frame.size.width as _, width: screen_frame.size.width as _,
height: screen_frame.size.height 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()), window_id: RootWindowId(window.into()),
event: WindowEvent::Resized(size), 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 // `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 // 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 // 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!( assert!(
!hidpi_factor.is_nan() !dpi_factor.is_nan()
&& hidpi_factor.is_finite() && dpi_factor.is_finite()
&& hidpi_factor.is_sign_positive() && dpi_factor.is_sign_positive()
&& hidpi_factor > 0.0, && dpi_factor > 0.0,
"invalid hidpi_factor set on UIView", "invalid hidpi_factor set on UIView",
); );
let hidpi_factor: f64 = dpi_factor.into();
let bounds: CGRect = msg_send![object, bounds]; let bounds: CGRect = msg_send![object, bounds];
let screen: id = msg_send![window, screen]; let screen: id = msg_send![window, screen];
let screen_space: id = msg_send![screen, coordinateSpace]; 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 _, height: screen_frame.size.height as _,
}; };
app_state::handle_nonuser_events( app_state::handle_nonuser_events(
std::iter::once(Event::WindowEvent { std::iter::once(EventWrapper::EventProxy(
window_id: RootWindowId(window.into()), EventProxy::HiDpiFactorChangedProxy {
event: WindowEvent::HiDpiFactorChanged(hidpi_factor as _), window_id: window,
}) hidpi_factor,
.chain(std::iter::once(Event::WindowEvent { suggested_size: size,
window_id: RootWindowId(window.into()), },
event: WindowEvent::Resized(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), _ => panic!("unexpected touch phase: {:?}", phase as i32),
}; };
touch_events.push(Event::WindowEvent { touch_events.push(EventWrapper::StaticEvent(Event::WindowEvent {
window_id: RootWindowId(window.into()), window_id: RootWindowId(window.into()),
event: WindowEvent::Touch(Touch { event: WindowEvent::Touch(Touch {
device_id: RootDeviceId(DeviceId { uiscreen }), device_id: RootDeviceId(DeviceId { uiscreen }),
@ -247,7 +255,7 @@ unsafe fn get_view_class(root_view_class: &'static Class) -> &'static Class {
force, force,
phase, phase,
}), }),
}); }));
} }
app_state::handle_nonuser_events(touch_events); 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) { extern "C" fn become_key_window(object: &Object, _: Sel) {
unsafe { unsafe {
app_state::handle_nonuser_event(Event::WindowEvent { app_state::handle_nonuser_event(EventWrapper::StaticEvent(Event::WindowEvent {
window_id: RootWindowId(object.into()), window_id: RootWindowId(object.into()),
event: WindowEvent::Focused(true), event: WindowEvent::Focused(true),
}); }));
let () = msg_send![super(object, class!(UIWindow)), becomeKeyWindow]; let () = msg_send![super(object, class!(UIWindow)), becomeKeyWindow];
} }
} }
extern "C" fn resign_key_window(object: &Object, _: Sel) { extern "C" fn resign_key_window(object: &Object, _: Sel) {
unsafe { unsafe {
app_state::handle_nonuser_event(Event::WindowEvent { app_state::handle_nonuser_event(EventWrapper::StaticEvent(Event::WindowEvent {
window_id: RootWindowId(object.into()), window_id: RootWindowId(object.into()),
event: WindowEvent::Focused(false), event: WindowEvent::Focused(false),
}); }));
let () = msg_send![super(object, class!(UIWindow)), resignKeyWindow]; 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]; let () = msg_send![uiscreen, setCurrentMode: video_mode.video_mode.screen_mode.0];
msg_send![window, setScreen:video_mode.monitor().ui_screen()] msg_send![window, setScreen:video_mode.monitor().ui_screen()]
} }
Some(Fullscreen::Borderless(ref monitor)) => { Some(Fullscreen::Borderless(ref monitor)) => msg_send![window, setScreen:monitor.ui_screen()],
msg_send![window, setScreen:monitor.ui_screen()]
}
None => (), None => (),
} }
@ -518,11 +524,11 @@ pub fn create_delegate_class() {
} }
extern "C" fn did_become_active(_: &Object, _: Sel, _: id) { 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) { 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) {} 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)]; let is_winit_window: BOOL = msg_send![window, isKindOfClass: class!(WinitUIWindow)];
if is_winit_window == YES { if is_winit_window == YES {
events.push(Event::WindowEvent { events.push(EventWrapper::StaticEvent(Event::WindowEvent {
window_id: RootWindowId(window.into()), window_id: RootWindowId(window.into()),
event: WindowEvent::Destroyed, event: WindowEvent::Destroyed,
}); }));
} }
} }
app_state::handle_nonuser_events(events); app_state::handle_nonuser_events(events);

View file

@ -7,14 +7,15 @@ use std::{
use objc::runtime::{Class, Object, BOOL, NO, YES}; use objc::runtime::{Class, Object, BOOL, NO, YES};
use crate::{ use crate::{
dpi::{self, LogicalPosition, LogicalSize}, dpi::{self, LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize, Position, Size},
error::{ExternalError, NotSupportedError, OsError as RootOsError}, error::{ExternalError, NotSupportedError, OsError as RootOsError},
event::{Event, WindowEvent}, event::{Event, WindowEvent},
icon::Icon, icon::Icon,
monitor::MonitorHandle as RootMonitorHandle, monitor::MonitorHandle as RootMonitorHandle,
platform::ios::{MonitorHandleExtIOS, ScreenEdge, ValidOrientations}, platform::ios::{MonitorHandleExtIOS, ScreenEdge, ValidOrientations},
platform_impl::platform::{ platform_impl::platform::{
app_state, event_loop, app_state,
event_loop::{self, EventProxy, EventWrapper},
ffi::{ ffi::{
id, CGFloat, CGPoint, CGRect, CGSize, UIEdgeInsets, UIInterfaceOrientationMask, id, CGFloat, CGPoint, CGRect, CGSize, UIEdgeInsets, UIInterfaceOrientationMask,
UIRectEdge, UIScreenOverscanCompensation, UIRectEdge, UIScreenOverscanCompensation,
@ -75,28 +76,34 @@ impl Inner {
} }
} }
pub fn inner_position(&self) -> Result<LogicalPosition, NotSupportedError> { pub fn inner_position(&self) -> Result<PhysicalPosition, NotSupportedError> {
unsafe { unsafe {
let safe_area = self.safe_area_screen_space(); let safe_area = self.safe_area_screen_space();
Ok(LogicalPosition { let position = LogicalPosition {
x: safe_area.origin.x as _, x: safe_area.origin.x as _,
y: safe_area.origin.y 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<LogicalPosition, NotSupportedError> { pub fn outer_position(&self) -> Result<PhysicalPosition, NotSupportedError> {
unsafe { unsafe {
let screen_frame = self.screen_frame(); let screen_frame = self.screen_frame();
Ok(LogicalPosition { let position = LogicalPosition {
x: screen_frame.origin.x as _, x: screen_frame.origin.x as _,
y: screen_frame.origin.y 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 { unsafe {
let dpi_factor = self.hidpi_factor();
let position = physical_position.to_logical(dpi_factor);
let screen_frame = self.screen_frame(); let screen_frame = self.screen_frame();
let new_screen_frame = CGRect { let new_screen_frame = CGRect {
origin: CGPoint { origin: CGPoint {
@ -110,35 +117,39 @@ impl Inner {
} }
} }
pub fn inner_size(&self) -> LogicalSize { pub fn inner_size(&self) -> PhysicalSize {
unsafe { unsafe {
let dpi_factor = self.hidpi_factor();
let safe_area = self.safe_area_screen_space(); let safe_area = self.safe_area_screen_space();
LogicalSize { let size = LogicalSize {
width: safe_area.size.width as _, width: safe_area.size.width as _,
height: safe_area.size.height 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 { unsafe {
let dpi_factor = self.hidpi_factor();
let screen_frame = self.screen_frame(); let screen_frame = self.screen_frame();
LogicalSize { let size = LogicalSize {
width: screen_frame.size.width as _, width: screen_frame.size.width as _,
height: screen_frame.size.height 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"); unimplemented!("not clear what `Window::set_inner_size` means on iOS");
} }
pub fn set_min_inner_size(&self, _dimensions: Option<LogicalSize>) { pub fn set_min_inner_size(&self, _dimensions: Option<Size>) {
warn!("`Window::set_min_inner_size` is ignored on iOS") warn!("`Window::set_min_inner_size` is ignored on iOS")
} }
pub fn set_max_inner_size(&self, _dimensions: Option<LogicalSize>) { pub fn set_max_inner_size(&self, _dimensions: Option<Size>) {
warn!("`Window::set_max_inner_size` is ignored on iOS") warn!("`Window::set_max_inner_size` is ignored on iOS")
} }
@ -157,7 +168,7 @@ impl Inner {
debug!("`Window::set_cursor_icon` ignored on iOS") 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())) Err(ExternalError::NotSupported(NotSupportedError::new()))
} }
@ -243,7 +254,7 @@ impl Inner {
warn!("`Window::set_window_icon` is ignored on iOS") 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") warn!("`Window::set_ime_position` is ignored on iOS")
} }
@ -343,13 +354,17 @@ impl Window {
let screen_bounds: CGRect = msg_send![screen, bounds]; let screen_bounds: CGRect = msg_send![screen, bounds];
let frame = match window_attributes.inner_size { let frame = match window_attributes.inner_size {
Some(dim) => CGRect { Some(dim) => {
origin: screen_bounds.origin, let dpi_factor = msg_send![screen, scale];
size: CGSize { let size = dim.to_logical(dpi_factor);
width: dim.width as _, CGRect {
height: dim.height as _, origin: screen_bounds.origin,
}, size: CGSize {
}, width: size.width as _,
height: size.height as _,
},
}
}
None => screen_bounds, None => screen_bounds,
}; };
@ -385,7 +400,8 @@ impl Window {
// Like the Windows and macOS backends, we send a `HiDpiFactorChanged` and `Resized` // Like the Windows and macOS backends, we send a `HiDpiFactorChanged` and `Resized`
// event on window creation if the DPI factor != 1.0 // 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 { if hidpi_factor != 1.0 {
let bounds: CGRect = msg_send![view, bounds]; let bounds: CGRect = msg_send![view, bounds];
let screen: id = msg_send![window, screen]; let screen: id = msg_send![window, screen];
@ -397,14 +413,19 @@ impl Window {
height: screen_frame.size.height as _, height: screen_frame.size.height as _,
}; };
app_state::handle_nonuser_events( app_state::handle_nonuser_events(
std::iter::once(Event::WindowEvent { std::iter::once(EventWrapper::EventProxy(
window_id: RootWindowId(window.into()), EventProxy::HiDpiFactorChangedProxy {
event: WindowEvent::HiDpiFactorChanged(hidpi_factor as _), window_id: window,
}) hidpi_factor,
.chain(std::iter::once(Event::WindowEvent { suggested_size: size,
window_id: RootWindowId(window.into()), },
event: WindowEvent::Resized(size), ))
})), .chain(std::iter::once(EventWrapper::StaticEvent(
Event::WindowEvent {
window_id: RootWindowId(window.into()),
event: WindowEvent::Resized(size.to_physical(hidpi_factor)),
},
))),
); );
} }