From ec77e15f626c7666606501be4070a779e32cd96b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benoi=CC=82t=20Rouleau?= Date: Sun, 14 Jun 2026 01:48:20 -0400 Subject: [PATCH] ios: report view pixel size + contentScaleFactor as dpi_scale MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit draw_in_rect reported UIScreen.bounds * UIScreen.scale as the rendered size. On real iPhone / iPad that matches the view's framebuffer (the view fills the screen), but on iOS-on-Mac the view can be a window smaller than the Mac display — so screen_width / screen_height overstated the real rendering surface and apps drew at the wrong scale in windowed mode. Switch to the view's own bounds * contentScaleFactor, which is correct in both cases. Also populate native_display().dpi_scale with the view's contentScaleFactor — upstream left it at the 1.0 default on iOS, which breaks higher-level APIs (e.g. macroquad's screen_width() divides by dpi_scale to return density-independent units). With this change, iOS joins macOS in reporting a real content scale, and the same dp-positioned UI lands at matching screen positions across both platforms. --- src/native/ios.rs | 37 ++++++++++++++++--------------------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/src/native/ios.rs b/src/native/ios.rs index 53bf8539..683c7c7a 100644 --- a/src/native/ios.rs +++ b/src/native/ios.rs @@ -326,32 +326,27 @@ pub fn define_glk_or_mtk_view_dlg(superclass: &Class) -> *const Class { payload.init_event_handler(); } - let main_screen: ObjcId = unsafe { msg_send![class!(UIScreen), mainScreen] }; - let screen_rect: NSRect = unsafe { msg_send![main_screen, bounds] }; - let high_dpi = native_display().lock().unwrap().high_dpi; - - let (screen_width, screen_height) = if high_dpi { - let scale: f64 = unsafe { msg_send![main_screen, scale] }; - - ( - (screen_rect.size.width * scale) as i32, - (screen_rect.size.height * scale) as i32, - ) - } else { - let content_scale_factor: f64 = unsafe { msg_send![payload.view, contentScaleFactor] }; - ( - (screen_rect.size.width * content_scale_factor) as i32, - (screen_rect.size.height * content_scale_factor) as i32, - ) + // Measure the view, not the device screen — iOS-on-Mac + // windowed mode has view < UIScreen. + let view_bounds: NSRect = unsafe { msg_send![payload.view, bounds] }; + let content_scale_factor: f64 = + unsafe { msg_send![payload.view, contentScaleFactor] }; + let screen_width = (view_bounds.size.width * content_scale_factor) as i32; + let screen_height = (view_bounds.size.height * content_scale_factor) as i32; + let dpi_scale = content_scale_factor as f32; + + let needs_update = { + let d = native_display().lock().unwrap(); + d.screen_width != screen_width + || d.screen_height != screen_height + || d.dpi_scale != dpi_scale }; - - if native_display().lock().unwrap().screen_width != screen_width - || native_display().lock().unwrap().screen_height != screen_height - { + if needs_update { { let mut d = native_display().lock().unwrap(); d.screen_width = screen_width; d.screen_height = screen_height; + d.dpi_scale = dpi_scale; } send_message(Message::Resize { width: screen_width,