monitor: refactor MonitorHandle to store dyn object

This also alters `VideoMode` to be a regular object and not reference
the `MonitorHandle`, since it's a static data.

Given that `VideoMode` set may change during runtime keeping the
reference as a some sort of validity may not be idea and propagating
errors when changing video mode could be more reliable.
This commit is contained in:
Kirill Chibisov 2024-09-21 20:27:12 +03:00
parent be1baf164c
commit f1c5afd84e
43 changed files with 726 additions and 826 deletions

View file

@ -28,7 +28,7 @@ use crate::event_loop::{
ActiveEventLoop as RootActiveEventLoop, ControlFlow, DeviceEvents,
EventLoopProxy as CoreEventLoopProxy, OwnedDisplayHandle as CoreOwnedDisplayHandle,
};
use crate::monitor::MonitorHandle as RootMonitorHandle;
use crate::monitor::MonitorHandle as CoreMonitorHandle;
use crate::platform_impl::Window;
use crate::window::{CustomCursor, CustomCursorSource, Theme, Window as CoreWindow};
@ -56,14 +56,18 @@ impl RootActiveEventLoop for ActiveEventLoop {
Err(NotSupportedError::new("create_custom_cursor is not supported").into())
}
fn available_monitors(&self) -> Box<dyn Iterator<Item = RootMonitorHandle>> {
Box::new(monitor::uiscreens(self.mtm).into_iter().map(|inner| RootMonitorHandle { inner }))
fn available_monitors(&self) -> Box<dyn Iterator<Item = CoreMonitorHandle>> {
Box::new(
monitor::uiscreens(self.mtm)
.into_iter()
.map(|monitor| CoreMonitorHandle(Arc::new(monitor))),
)
}
fn primary_monitor(&self) -> Option<crate::monitor::MonitorHandle> {
#[allow(deprecated)]
let monitor = MonitorHandle::new(UIScreen::mainScreen(self.mtm));
Some(RootMonitorHandle { inner: monitor })
Some(CoreMonitorHandle(Arc::new(monitor)))
}
fn listen_device_events(&self, _allowed: DeviceEvents) {}

View file

@ -18,7 +18,6 @@ pub(crate) use crate::cursor::{
NoCustomCursor as PlatformCustomCursor, NoCustomCursor as PlatformCustomCursorSource,
};
pub(crate) use crate::icon::NoIcon as PlatformIcon;
pub(crate) use crate::platform_impl::Fullscreen;
#[derive(Debug)]
pub enum OsError {}

View file

@ -11,7 +11,7 @@ use objc2_foundation::NSInteger;
use objc2_ui_kit::{UIScreen, UIScreenMode};
use crate::dpi::PhysicalPosition;
use crate::monitor::VideoMode;
use crate::monitor::{MonitorHandleProvider, VideoMode};
// Workaround for `MainThreadBound` implementing almost no traits
#[derive(Debug)]
@ -76,6 +76,60 @@ pub struct MonitorHandle {
ui_screen: MainThreadBound<Retained<UIScreen>>,
}
impl MonitorHandleProvider for MonitorHandle {
fn id(&self) -> u128 {
self.native_id() as _
}
fn native_id(&self) -> u64 {
// SAFETY: Only getting the pointer.
let mtm = unsafe { MainThreadMarker::new_unchecked() };
Retained::as_ptr(self.ui_screen.get(mtm)) as u64
}
fn name(&self) -> Option<std::borrow::Cow<'_, str>> {
run_on_main(|mtm| {
#[allow(deprecated)]
let main = UIScreen::mainScreen(mtm);
if *self.ui_screen(mtm) == main {
Some("Primary".into())
} else if Some(self.ui_screen(mtm)) == main.mirroredScreen().as_ref() {
Some("Mirrored".into())
} else {
#[allow(deprecated)]
UIScreen::screens(mtm)
.iter()
.position(|rhs| rhs == *self.ui_screen(mtm))
.map(|idx| idx.to_string().into())
}
})
}
fn position(&self) -> Option<PhysicalPosition<i32>> {
let bounds = self.ui_screen.get_on_main(|ui_screen| ui_screen.nativeBounds());
Some((bounds.origin.x as f64, bounds.origin.y as f64).into())
}
fn scale_factor(&self) -> f64 {
self.ui_screen.get_on_main(|ui_screen| ui_screen.nativeScale()) as f64
}
fn current_video_mode(&self) -> Option<VideoMode> {
Some(run_on_main(|mtm| {
VideoModeHandle::new(
self.ui_screen(mtm).clone(),
self.ui_screen(mtm).currentMode().unwrap(),
mtm,
)
.mode
}))
}
fn video_modes(&self) -> Box<dyn Iterator<Item = VideoMode>> {
Box::new(self.video_modes())
}
}
impl Clone for MonitorHandle {
fn clone(&self) -> Self {
run_on_main(|mtm| Self {
@ -137,44 +191,6 @@ impl MonitorHandle {
Self { ui_screen: MainThreadBound::new(ui_screen, mtm) }
}
pub fn name(&self) -> Option<String> {
run_on_main(|mtm| {
#[allow(deprecated)]
let main = UIScreen::mainScreen(mtm);
if *self.ui_screen(mtm) == main {
Some("Primary".to_string())
} else if Some(self.ui_screen(mtm)) == main.mirroredScreen().as_ref() {
Some("Mirrored".to_string())
} else {
#[allow(deprecated)]
UIScreen::screens(mtm)
.iter()
.position(|rhs| rhs == *self.ui_screen(mtm))
.map(|idx| idx.to_string())
}
})
}
pub fn position(&self) -> Option<PhysicalPosition<i32>> {
let bounds = self.ui_screen.get_on_main(|ui_screen| ui_screen.nativeBounds());
Some((bounds.origin.x as f64, bounds.origin.y as f64).into())
}
pub fn scale_factor(&self) -> f64 {
self.ui_screen.get_on_main(|ui_screen| ui_screen.nativeScale()) as f64
}
pub fn current_video_mode(&self) -> Option<VideoMode> {
Some(run_on_main(|mtm| {
VideoModeHandle::new(
self.ui_screen(mtm).clone(),
self.ui_screen(mtm).currentMode().unwrap(),
mtm,
)
.mode
}))
}
pub fn video_modes_handles(&self) -> impl Iterator<Item = VideoModeHandle> {
run_on_main(|mtm| {
let ui_screen = self.ui_screen(mtm);

View file

@ -1,6 +1,7 @@
#![allow(clippy::unnecessary_cast)]
use std::collections::VecDeque;
use std::sync::Arc;
use dispatch2::MainThreadBound;
use objc2::rc::Retained;
@ -16,7 +17,7 @@ use tracing::{debug, warn};
use super::app_state::EventWrapper;
use super::view::WinitView;
use super::view_controller::WinitViewController;
use super::{app_state, monitor, ActiveEventLoop, Fullscreen, MonitorHandle};
use super::{app_state, monitor, ActiveEventLoop, MonitorHandle};
use crate::cursor::Cursor;
use crate::dpi::{
LogicalInsets, LogicalPosition, LogicalSize, PhysicalInsets, PhysicalPosition, PhysicalSize,
@ -25,7 +26,7 @@ use crate::dpi::{
use crate::error::{NotSupportedError, RequestError};
use crate::event::WindowEvent;
use crate::icon::Icon;
use crate::monitor::MonitorHandle as CoreMonitorHandle;
use crate::monitor::{Fullscreen, MonitorHandle as CoreMonitorHandle};
use crate::platform::ios::{ScreenEdge, StatusBarStyle, ValidOrientations};
use crate::window::{
CursorGrabMode, ImePurpose, ResizeDirection, Theme, UserAttentionType, Window as CoreWindow,
@ -78,8 +79,9 @@ impl WinitUIWindow {
this.setRootViewController(Some(view_controller));
match window_attributes.fullscreen.clone().map(Into::into) {
Some(Fullscreen::Exclusive(ref monitor, ref video_mode)) => {
match window_attributes.fullscreen.clone() {
Some(Fullscreen::Exclusive(monitor, ref video_mode)) => {
let monitor = monitor.as_any().downcast_ref::<MonitorHandle>().unwrap();
let screen = monitor.ui_screen(mtm);
if let Some(video_mode) =
monitor.video_modes_handles().find(|mode| &mode.mode == video_mode)
@ -89,6 +91,7 @@ impl WinitUIWindow {
this.setScreen(screen);
},
Some(Fullscreen::Borderless(Some(ref monitor))) => {
let monitor = monitor.as_any().downcast_ref::<MonitorHandle>().unwrap();
let screen = monitor.ui_screen(mtm);
this.setScreen(screen);
},
@ -303,6 +306,7 @@ impl Inner {
let mtm = MainThreadMarker::new().unwrap();
let uiscreen = match &monitor {
Some(Fullscreen::Exclusive(monitor, video_mode)) => {
let monitor = monitor.as_any().downcast_ref::<MonitorHandle>().unwrap();
let uiscreen = monitor.ui_screen(mtm);
if let Some(video_mode) =
monitor.video_modes_handles().find(|mode| &mode.mode == video_mode)
@ -311,7 +315,9 @@ impl Inner {
}
uiscreen.clone()
},
Some(Fullscreen::Borderless(Some(monitor))) => monitor.ui_screen(mtm).clone(),
Some(Fullscreen::Borderless(Some(monitor))) => {
monitor.as_any().downcast_ref::<MonitorHandle>().unwrap().ui_screen(mtm).clone()
},
Some(Fullscreen::Borderless(None)) => {
self.current_monitor_inner().ui_screen(mtm).clone()
},
@ -349,7 +355,7 @@ impl Inner {
&& screen_space_bounds.size.width == screen_bounds.size.width
&& screen_space_bounds.size.height == screen_bounds.size.height
{
Some(Fullscreen::Borderless(Some(monitor)))
Some(Fullscreen::Borderless(Some(CoreMonitorHandle(Arc::new(monitor)))))
} else {
None
}
@ -482,10 +488,13 @@ impl Window {
#[allow(deprecated)]
let main_screen = UIScreen::mainScreen(mtm);
let fullscreen = window_attributes.fullscreen.clone().map(Into::into);
let fullscreen = window_attributes.fullscreen.clone();
let screen = match fullscreen {
Some(Fullscreen::Exclusive(ref monitor, _)) => monitor.ui_screen(mtm),
Some(Fullscreen::Borderless(Some(ref monitor))) => monitor.ui_screen(mtm),
Some(Fullscreen::Exclusive(ref monitor, _))
| Some(Fullscreen::Borderless(Some(ref monitor))) => {
let monitor = monitor.as_any().downcast_ref::<MonitorHandle>().unwrap();
monitor.ui_screen(mtm)
},
Some(Fullscreen::Borderless(None)) | None => &main_screen,
};
@ -670,12 +679,12 @@ impl CoreWindow for Window {
self.maybe_wait_on_main(|delegate| delegate.is_maximized())
}
fn set_fullscreen(&self, fullscreen: Option<crate::window::Fullscreen>) {
self.maybe_wait_on_main(|delegate| delegate.set_fullscreen(fullscreen.map(Into::into)))
fn set_fullscreen(&self, fullscreen: Option<Fullscreen>) {
self.maybe_wait_on_main(|delegate| delegate.set_fullscreen(fullscreen))
}
fn fullscreen(&self) -> Option<crate::window::Fullscreen> {
self.maybe_wait_on_main(|delegate| delegate.fullscreen().map(Into::into))
fn fullscreen(&self) -> Option<Fullscreen> {
self.maybe_wait_on_main(|delegate| delegate.fullscreen())
}
fn set_decorations(&self, decorations: bool) {
@ -771,21 +780,24 @@ impl CoreWindow for Window {
fn current_monitor(&self) -> Option<CoreMonitorHandle> {
self.maybe_wait_on_main(|delegate| {
delegate.current_monitor().map(|inner| CoreMonitorHandle { inner })
delegate.current_monitor().map(|monitor| CoreMonitorHandle(Arc::new(monitor)))
})
}
fn available_monitors(&self) -> Box<dyn Iterator<Item = CoreMonitorHandle>> {
self.maybe_wait_on_main(|delegate| {
Box::new(
delegate.available_monitors().into_iter().map(|inner| CoreMonitorHandle { inner }),
delegate
.available_monitors()
.into_iter()
.map(|monitor| CoreMonitorHandle(Arc::new(monitor))),
)
})
}
fn primary_monitor(&self) -> Option<CoreMonitorHandle> {
self.maybe_wait_on_main(|delegate| {
delegate.primary_monitor().map(|inner| CoreMonitorHandle { inner })
delegate.primary_monitor().map(|monitor| CoreMonitorHandle(Arc::new(monitor)))
})
}