mirror of
https://github.com/italicsjenga/winit-sonoma-fix.git
synced 2024-12-23 22:01:31 +11:00
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:
parent
cbf61e5cb9
commit
b16042a047
|
@ -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,
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)),
|
||||
},
|
||||
))),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue