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 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<Event<Never>>,
queued_events: &'a mut Vec<EventWrapper>,
},
}
impl Event<Never> {
impl Event<'static, Never> {
fn is_redraw(&self) -> bool {
if let Event::RedrawRequested(_) = self {
true
@ -65,12 +66,12 @@ impl Event<Never> {
enum AppStateImpl {
NotLaunched {
queued_windows: Vec<id>,
queued_events: Vec<Event<Never>>,
queued_events: Vec<EventWrapper>,
queued_gpu_redraws: HashSet<id>,
},
Launching {
queued_windows: Vec<id>,
queued_events: Vec<Event<Never>>,
queued_events: Vec<EventWrapper>,
queued_event_handler: Box<dyn EventHandler>,
queued_gpu_redraws: HashSet<id>,
},
@ -81,7 +82,7 @@ enum AppStateImpl {
},
// special state to deal with reentrancy and prevent mutable aliasing.
InUserCallback {
queued_events: Vec<Event<Never>>,
queued_events: Vec<EventWrapper>,
queued_gpu_redraws: HashSet<id>,
},
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() {
AppStateImpl::Launching {
queued_windows,
@ -245,7 +246,7 @@ impl AppState {
(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
// 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<Never>) {
pub unsafe fn handle_nonuser_event(event: EventWrapper) {
handle_nonuser_events(std::iter::once(event))
}
// 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 event_handler, active_control_flow, processing_redraws) =
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;
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<I: IntoIterator<Item = Event<Never>>>(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<Event<Never>> = 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<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 {
timer: CFRunLoopTimerRef,
}

View file

@ -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<T: 'static> {
receiver: Receiver<T>,
sender_to_clone: Sender<T>,
@ -69,7 +85,7 @@ impl<T: 'static> EventLoop<T> {
pub fn run<F>(self, event_handler: F) -> !
where
F: 'static + FnMut(Event<T>, &RootEventLoopWindowTarget<T>, &mut ControlFlow),
F: 'static + FnMut(Event<'_, T>, &RootEventLoopWindowTarget<T>, &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<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);
}
@ -296,10 +312,10 @@ impl<F, T: 'static> Debug for EventLoopHandler<F, T> {
impl<F, T> EventHandler for EventLoopHandler<F, T>
where
F: 'static + FnMut(Event<T>, &RootEventLoopWindowTarget<T>, &mut ControlFlow),
F: 'static + FnMut(Event<'_, T>, &RootEventLoopWindowTarget<T>, &mut ControlFlow),
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)(
event.map_nonuser_event().unwrap(),
&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 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 {

View file

@ -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)
}
}

View file

@ -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);

View file

@ -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<LogicalPosition, NotSupportedError> {
pub fn inner_position(&self) -> Result<PhysicalPosition, NotSupportedError> {
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<LogicalPosition, NotSupportedError> {
pub fn outer_position(&self) -> Result<PhysicalPosition, NotSupportedError> {
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<LogicalSize>) {
pub fn set_min_inner_size(&self, _dimensions: Option<Size>) {
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")
}
@ -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)),
},
))),
);
}