use anyhow::Result;
use gpui::{Bounds, DisplayId, Pixels, PlatformDisplay, px, size};
use gpui_apple::main_thread_marker;
use objc2::rc::Retained;
use objc2_core_foundation::CGRect;
use objc2_ui_kit::UIScreen;
use std::time::Duration;
use uuid::Uuid;
#[derive(Debug)]
pub(crate) struct IosDisplay {
screen: Retained<UIScreen>,
}
unsafe impl Send for IosDisplay {}
unsafe impl Sync for IosDisplay {}
impl IosDisplay {
pub fn from_screen(screen: Retained<UIScreen>) -> Self {
Self { screen }
}
#[allow(deprecated)] pub fn main() -> Self {
let screen =
UIScreen::mainScreen(main_thread_marker().expect("UIKit requires the main thread"));
Self { screen }
}
#[allow(deprecated)] pub fn all() -> impl Iterator<Item = Self> {
let screens =
UIScreen::screens(main_thread_marker().expect("UIKit requires the main thread"));
screens.to_vec().into_iter().map(|screen| Self { screen })
}
fn bounds_in_points(&self) -> CGRect {
self.screen.bounds()
}
pub fn native_scale(&self) -> f32 {
self.screen.nativeScale() as f32
}
pub fn scale(&self) -> f32 {
self.screen.scale() as f32
}
}
impl PlatformDisplay for IosDisplay {
fn refresh_interval(&self) -> Option<Duration> {
gpui::refresh_interval_from_hz(self.screen.maximumFramesPerSecond() as f64)
}
fn id(&self) -> DisplayId {
DisplayId::new(Retained::as_ptr(&self.screen) as u64)
}
fn uuid(&self) -> Result<Uuid> {
let bounds = self.bounds_in_points();
let scale = self.native_scale();
let bytes = format!(
"ios-screen-{}-{}-{}",
bounds.size.width as u32,
bounds.size.height as u32,
(scale * 100.0) as u32
);
Ok(Uuid::new_v5(&Uuid::NAMESPACE_OID, bytes.as_bytes()))
}
fn bounds(&self) -> Bounds<Pixels> {
let bounds = self.bounds_in_points();
Bounds {
origin: Default::default(),
size: size(px(bounds.size.width as f32), px(bounds.size.height as f32)),
}
}
}