2022-12-22 21:35:33 +02:00
|
|
|
#![allow(clippy::unnecessary_cast)]
|
|
|
|
|
|
2023-08-14 21:19:57 +02:00
|
|
|
use std::collections::VecDeque;
|
2019-05-25 18:10:41 -07:00
|
|
|
|
2024-05-27 14:49:22 +02:00
|
|
|
use objc2::rc::Retained;
|
2024-02-22 22:28:49 +01:00
|
|
|
use objc2::{class, declare_class, msg_send, msg_send_id, mutability, ClassType, DeclaredClass};
|
2024-05-06 17:09:38 +02:00
|
|
|
use objc2_foundation::{
|
2024-09-27 22:12:50 +02:00
|
|
|
CGFloat, CGPoint, CGRect, CGSize, MainThreadBound, MainThreadMarker, NSObject, NSObjectProtocol,
|
2024-05-06 17:09:38 +02:00
|
|
|
};
|
2024-05-27 14:49:22 +02:00
|
|
|
use objc2_ui_kit::{
|
|
|
|
|
UIApplication, UICoordinateSpace, UIResponder, UIScreen, UIScreenOverscanCompensation,
|
|
|
|
|
UIViewController, UIWindow,
|
|
|
|
|
};
|
2024-02-25 19:20:39 -08:00
|
|
|
use tracing::{debug, warn};
|
2019-06-21 11:33:15 -04:00
|
|
|
|
2023-08-27 17:04:39 +02:00
|
|
|
use super::app_state::EventWrapper;
|
2024-02-22 22:28:49 +01:00
|
|
|
use super::view::WinitView;
|
|
|
|
|
use super::view_controller::WinitViewController;
|
2024-06-24 13:26:49 +02:00
|
|
|
use super::{app_state, monitor, ActiveEventLoop, Fullscreen, MonitorHandle};
|
2023-12-25 07:20:52 +01:00
|
|
|
use crate::cursor::Cursor;
|
2024-02-26 14:52:00 +01:00
|
|
|
use crate::dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize, Position, Size};
|
2024-09-06 17:20:11 +03:00
|
|
|
use crate::error::{NotSupportedError, RequestError};
|
2019-09-16 21:27:46 +03:00
|
|
|
use crate::event::{Event, WindowEvent};
|
2019-06-21 11:33:15 -04:00
|
|
|
use crate::icon::Icon;
|
2024-08-23 23:40:27 +03:00
|
|
|
use crate::monitor::MonitorHandle as CoreMonitorHandle;
|
2023-10-20 12:26:10 +02:00
|
|
|
use crate::platform::ios::{ScreenEdge, StatusBarStyle, ValidOrientations};
|
2020-11-27 03:03:08 +01:00
|
|
|
use crate::window::{
|
2024-08-23 23:40:27 +03:00
|
|
|
CursorGrabMode, ImePurpose, ResizeDirection, Theme, UserAttentionType, Window as CoreWindow,
|
|
|
|
|
WindowAttributes, WindowButtons, WindowId as CoreWindowId, WindowLevel,
|
2019-05-25 18:10:41 -07:00
|
|
|
};
|
|
|
|
|
|
2024-02-22 22:28:49 +01:00
|
|
|
declare_class!(
|
|
|
|
|
#[derive(Debug, PartialEq, Eq, Hash)]
|
|
|
|
|
pub(crate) struct WinitUIWindow;
|
|
|
|
|
|
|
|
|
|
unsafe impl ClassType for WinitUIWindow {
|
|
|
|
|
#[inherits(UIResponder, NSObject)]
|
|
|
|
|
type Super = UIWindow;
|
2024-05-27 14:49:22 +02:00
|
|
|
type Mutability = mutability::MainThreadOnly;
|
2024-02-22 22:28:49 +01:00
|
|
|
const NAME: &'static str = "WinitUIWindow";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl DeclaredClass for WinitUIWindow {}
|
|
|
|
|
|
|
|
|
|
unsafe impl WinitUIWindow {
|
|
|
|
|
#[method(becomeKeyWindow)]
|
|
|
|
|
fn become_key_window(&self) {
|
|
|
|
|
let mtm = MainThreadMarker::new().unwrap();
|
|
|
|
|
app_state::handle_nonuser_event(
|
|
|
|
|
mtm,
|
|
|
|
|
EventWrapper::StaticEvent(Event::WindowEvent {
|
2024-08-23 23:40:27 +03:00
|
|
|
window_id: CoreWindowId(self.id()),
|
2024-02-22 22:28:49 +01:00
|
|
|
event: WindowEvent::Focused(true),
|
|
|
|
|
}),
|
|
|
|
|
);
|
|
|
|
|
let _: () = unsafe { msg_send![super(self), becomeKeyWindow] };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[method(resignKeyWindow)]
|
|
|
|
|
fn resign_key_window(&self) {
|
|
|
|
|
let mtm = MainThreadMarker::new().unwrap();
|
|
|
|
|
app_state::handle_nonuser_event(
|
|
|
|
|
mtm,
|
|
|
|
|
EventWrapper::StaticEvent(Event::WindowEvent {
|
2024-08-23 23:40:27 +03:00
|
|
|
window_id: CoreWindowId(self.id()),
|
2024-02-22 22:28:49 +01:00
|
|
|
event: WindowEvent::Focused(false),
|
|
|
|
|
}),
|
|
|
|
|
);
|
|
|
|
|
let _: () = unsafe { msg_send![super(self), resignKeyWindow] };
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
impl WinitUIWindow {
|
|
|
|
|
pub(crate) fn new(
|
|
|
|
|
mtm: MainThreadMarker,
|
|
|
|
|
window_attributes: &WindowAttributes,
|
|
|
|
|
frame: CGRect,
|
|
|
|
|
view_controller: &UIViewController,
|
2024-05-27 14:49:22 +02:00
|
|
|
) -> Retained<Self> {
|
2024-08-18 23:50:10 +02:00
|
|
|
// NOTE: This should only be created after the application has started launching,
|
|
|
|
|
// (`application:willFinishLaunchingWithOptions:` at the earliest), otherwise you'll run
|
|
|
|
|
// into very confusing issues with the window not being properly activated.
|
|
|
|
|
//
|
|
|
|
|
// Winit ensures this by not allowing access to `ActiveEventLoop` before handling events.
|
2024-05-27 14:49:22 +02:00
|
|
|
let this: Retained<Self> = unsafe { msg_send_id![mtm.alloc(), initWithFrame: frame] };
|
2024-02-22 22:28:49 +01:00
|
|
|
|
|
|
|
|
this.setRootViewController(Some(view_controller));
|
|
|
|
|
|
|
|
|
|
match window_attributes.fullscreen.clone().map(Into::into) {
|
|
|
|
|
Some(Fullscreen::Exclusive(ref video_mode)) => {
|
|
|
|
|
let monitor = video_mode.monitor();
|
|
|
|
|
let screen = monitor.ui_screen(mtm);
|
|
|
|
|
screen.setCurrentMode(Some(video_mode.screen_mode(mtm)));
|
|
|
|
|
this.setScreen(screen);
|
|
|
|
|
},
|
|
|
|
|
Some(Fullscreen::Borderless(Some(ref monitor))) => {
|
|
|
|
|
let screen = monitor.ui_screen(mtm);
|
|
|
|
|
this.setScreen(screen);
|
|
|
|
|
},
|
|
|
|
|
_ => (),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) fn id(&self) -> WindowId {
|
2024-09-27 22:12:50 +02:00
|
|
|
WindowId::from_window(self)
|
2024-02-22 22:28:49 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-25 18:10:41 -07:00
|
|
|
pub struct Inner {
|
2024-05-27 14:49:22 +02:00
|
|
|
window: Retained<WinitUIWindow>,
|
|
|
|
|
view_controller: Retained<WinitViewController>,
|
|
|
|
|
view: Retained<WinitView>,
|
2019-09-04 14:23:11 -07:00
|
|
|
gl_or_metal_backed: bool,
|
2019-05-25 18:10:41 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Inner {
|
|
|
|
|
pub fn set_title(&self, _title: &str) {
|
|
|
|
|
debug!("`Window::set_title` is ignored on iOS")
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-15 23:39:36 +03:00
|
|
|
pub fn set_transparent(&self, _transparent: bool) {
|
|
|
|
|
debug!("`Window::set_transparent` is ignored on iOS")
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-08 22:53:15 +03:00
|
|
|
pub fn set_blur(&self, _blur: bool) {
|
|
|
|
|
debug!("`Window::set_blur` is ignored on iOS")
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-29 21:29:54 -04:00
|
|
|
pub fn set_visible(&self, visible: bool) {
|
2022-12-28 18:36:32 +01:00
|
|
|
self.window.setHidden(!visible)
|
2019-05-25 18:10:41 -07:00
|
|
|
}
|
|
|
|
|
|
2022-02-17 20:44:14 +02:00
|
|
|
pub fn is_visible(&self) -> Option<bool> {
|
|
|
|
|
warn!("`Window::is_visible` is ignored on iOS");
|
|
|
|
|
None
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-25 18:10:41 -07:00
|
|
|
pub fn request_redraw(&self) {
|
2023-08-27 17:04:39 +02:00
|
|
|
if self.gl_or_metal_backed {
|
|
|
|
|
let mtm = MainThreadMarker::new().unwrap();
|
|
|
|
|
// `setNeedsDisplay` does nothing on UIViews which are directly backed by CAEAGLLayer or
|
|
|
|
|
// CAMetalLayer. Ordinarily the OS sets up a bunch of UIKit state before
|
|
|
|
|
// calling drawRect: on a UIView, but when using raw or gl/metal for drawing
|
|
|
|
|
// this work is completely avoided.
|
|
|
|
|
//
|
|
|
|
|
// The docs for `setNeedsDisplay` don't mention `CAMetalLayer`; however, this has been
|
|
|
|
|
// confirmed via testing.
|
|
|
|
|
//
|
|
|
|
|
// https://developer.apple.com/documentation/uikit/uiview/1622437-setneedsdisplay?language=objc
|
|
|
|
|
app_state::queue_gl_or_metal_redraw(mtm, self.window.clone());
|
|
|
|
|
} else {
|
|
|
|
|
self.view.setNeedsDisplay();
|
2019-05-25 18:10:41 -07:00
|
|
|
}
|
|
|
|
|
}
|
2019-05-29 21:29:54 -04:00
|
|
|
|
2023-06-22 08:08:53 +04:00
|
|
|
pub fn pre_present_notify(&self) {}
|
|
|
|
|
|
2024-09-06 17:20:11 +03:00
|
|
|
pub fn inner_position(&self) -> PhysicalPosition<i32> {
|
2023-08-14 21:19:57 +02:00
|
|
|
let safe_area = self.safe_area_screen_space();
|
|
|
|
|
let position =
|
|
|
|
|
LogicalPosition { x: safe_area.origin.x as f64, y: safe_area.origin.y as f64 };
|
|
|
|
|
let scale_factor = self.scale_factor();
|
2024-09-06 17:20:11 +03:00
|
|
|
position.to_physical(scale_factor)
|
2019-05-25 18:10:41 -07:00
|
|
|
}
|
|
|
|
|
|
2024-09-06 17:20:11 +03:00
|
|
|
pub fn outer_position(&self) -> PhysicalPosition<i32> {
|
2023-08-14 21:19:57 +02:00
|
|
|
let screen_frame = self.screen_frame();
|
|
|
|
|
let position =
|
|
|
|
|
LogicalPosition { x: screen_frame.origin.x as f64, y: screen_frame.origin.y as f64 };
|
|
|
|
|
let scale_factor = self.scale_factor();
|
2024-09-06 17:20:11 +03:00
|
|
|
position.to_physical(scale_factor)
|
2019-05-25 18:10:41 -07:00
|
|
|
}
|
|
|
|
|
|
2019-10-18 18:31:26 +03:00
|
|
|
pub fn set_outer_position(&self, physical_position: Position) {
|
2023-08-14 21:19:57 +02:00
|
|
|
let scale_factor = self.scale_factor();
|
|
|
|
|
let position = physical_position.to_logical::<f64>(scale_factor);
|
|
|
|
|
let screen_frame = self.screen_frame();
|
|
|
|
|
let new_screen_frame = CGRect {
|
|
|
|
|
origin: CGPoint { x: position.x as _, y: position.y as _ },
|
|
|
|
|
size: screen_frame.size,
|
|
|
|
|
};
|
|
|
|
|
let bounds = self.rect_from_screen_space(new_screen_frame);
|
|
|
|
|
self.window.setBounds(bounds);
|
2019-05-25 18:10:41 -07:00
|
|
|
}
|
|
|
|
|
|
2024-09-04 15:04:48 +02:00
|
|
|
pub fn surface_size(&self) -> PhysicalSize<u32> {
|
2023-08-14 21:19:57 +02:00
|
|
|
let scale_factor = self.scale_factor();
|
|
|
|
|
let safe_area = self.safe_area_screen_space();
|
|
|
|
|
let size = LogicalSize {
|
|
|
|
|
width: safe_area.size.width as f64,
|
|
|
|
|
height: safe_area.size.height as f64,
|
|
|
|
|
};
|
|
|
|
|
size.to_physical(scale_factor)
|
2019-05-25 18:10:41 -07:00
|
|
|
}
|
|
|
|
|
|
2020-01-04 01:33:07 -05:00
|
|
|
pub fn outer_size(&self) -> PhysicalSize<u32> {
|
2023-08-14 21:19:57 +02:00
|
|
|
let scale_factor = self.scale_factor();
|
|
|
|
|
let screen_frame = self.screen_frame();
|
|
|
|
|
let size = LogicalSize {
|
|
|
|
|
width: screen_frame.size.width as f64,
|
|
|
|
|
height: screen_frame.size.height as f64,
|
|
|
|
|
};
|
|
|
|
|
size.to_physical(scale_factor)
|
2019-05-25 18:10:41 -07:00
|
|
|
}
|
|
|
|
|
|
2024-09-04 15:04:48 +02:00
|
|
|
pub fn request_surface_size(&self, _size: Size) -> Option<PhysicalSize<u32>> {
|
|
|
|
|
Some(self.surface_size())
|
2019-05-25 18:10:41 -07:00
|
|
|
}
|
|
|
|
|
|
2024-09-04 15:04:48 +02:00
|
|
|
pub fn set_min_surface_size(&self, _dimensions: Option<Size>) {
|
|
|
|
|
warn!("`Window::set_min_surface_size` is ignored on iOS")
|
2019-05-25 18:10:41 -07:00
|
|
|
}
|
|
|
|
|
|
2024-09-04 15:04:48 +02:00
|
|
|
pub fn set_max_surface_size(&self, _dimensions: Option<Size>) {
|
|
|
|
|
warn!("`Window::set_max_surface_size` is ignored on iOS")
|
2019-05-25 18:10:41 -07:00
|
|
|
}
|
|
|
|
|
|
2024-09-04 15:04:48 +02:00
|
|
|
pub fn surface_resize_increments(&self) -> Option<PhysicalSize<u32>> {
|
2022-09-03 21:50:22 +03:00
|
|
|
None
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
2024-09-04 15:04:48 +02:00
|
|
|
pub fn set_surface_resize_increments(&self, _increments: Option<Size>) {
|
|
|
|
|
warn!("`Window::set_surface_resize_increments` is ignored on iOS")
|
2022-09-03 21:50:22 +03:00
|
|
|
}
|
|
|
|
|
|
2019-05-25 18:10:41 -07:00
|
|
|
pub fn set_resizable(&self, _resizable: bool) {
|
|
|
|
|
warn!("`Window::set_resizable` is ignored on iOS")
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-17 17:03:17 +02:00
|
|
|
pub fn is_resizable(&self) -> bool {
|
|
|
|
|
warn!("`Window::is_resizable` is ignored on iOS");
|
|
|
|
|
false
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-29 12:03:51 +02:00
|
|
|
#[inline]
|
|
|
|
|
pub fn set_enabled_buttons(&self, _buttons: WindowButtons) {
|
|
|
|
|
warn!("`Window::set_enabled_buttons` is ignored on iOS");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn enabled_buttons(&self) -> WindowButtons {
|
|
|
|
|
warn!("`Window::enabled_buttons` is ignored on iOS");
|
|
|
|
|
WindowButtons::all()
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-03 14:52:27 -05:00
|
|
|
pub fn scale_factor(&self) -> f64 {
|
2022-12-28 18:36:32 +01:00
|
|
|
self.view.contentScaleFactor() as _
|
2019-05-25 18:10:41 -07:00
|
|
|
}
|
|
|
|
|
|
2023-12-25 07:20:52 +01:00
|
|
|
pub fn set_cursor(&self, _cursor: Cursor) {
|
|
|
|
|
debug!("`Window::set_cursor` ignored on iOS")
|
2023-12-16 22:02:17 +02:00
|
|
|
}
|
|
|
|
|
|
2024-09-06 17:20:11 +03:00
|
|
|
pub fn set_cursor_position(&self, _position: Position) -> Result<(), NotSupportedError> {
|
|
|
|
|
Err(NotSupportedError::new("set_cursor_position is not supported"))
|
2019-05-25 18:10:41 -07:00
|
|
|
}
|
|
|
|
|
|
2024-09-06 17:20:11 +03:00
|
|
|
pub fn set_cursor_grab(&self, _: CursorGrabMode) -> Result<(), NotSupportedError> {
|
|
|
|
|
Err(NotSupportedError::new("set_cursor_grab is not supported"))
|
2019-05-25 18:10:41 -07:00
|
|
|
}
|
|
|
|
|
|
2019-05-29 21:29:54 -04:00
|
|
|
pub fn set_cursor_visible(&self, _visible: bool) {
|
|
|
|
|
debug!("`Window::set_cursor_visible` is ignored on iOS")
|
2019-05-25 18:10:41 -07:00
|
|
|
}
|
|
|
|
|
|
2024-09-06 17:20:11 +03:00
|
|
|
pub fn drag_window(&self) -> Result<(), NotSupportedError> {
|
|
|
|
|
Err(NotSupportedError::new("drag_window is not supported"))
|
2021-03-07 10:43:23 +01:00
|
|
|
}
|
|
|
|
|
|
2024-09-06 17:20:11 +03:00
|
|
|
pub fn drag_resize_window(&self, _direction: ResizeDirection) -> Result<(), NotSupportedError> {
|
|
|
|
|
Err(NotSupportedError::new("drag_resize_window is not supported"))
|
2023-01-11 18:07:09 +01:00
|
|
|
}
|
|
|
|
|
|
2023-10-11 01:16:16 +03:30
|
|
|
#[inline]
|
|
|
|
|
pub fn show_window_menu(&self, _position: Position) {}
|
|
|
|
|
|
2024-09-06 17:20:11 +03:00
|
|
|
pub fn set_cursor_hittest(&self, _hittest: bool) -> Result<(), NotSupportedError> {
|
|
|
|
|
Err(NotSupportedError::new("set_cursor_hittest is not supported"))
|
2022-04-12 19:10:46 +02:00
|
|
|
}
|
|
|
|
|
|
2019-12-22 01:04:11 -05:00
|
|
|
pub fn set_minimized(&self, _minimized: bool) {
|
|
|
|
|
warn!("`Window::set_minimized` is ignored on iOS")
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-19 23:39:04 +02:00
|
|
|
pub fn is_minimized(&self) -> Option<bool> {
|
|
|
|
|
warn!("`Window::is_minimized` is ignored on iOS");
|
|
|
|
|
None
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-25 18:10:41 -07:00
|
|
|
pub fn set_maximized(&self, _maximized: bool) {
|
|
|
|
|
warn!("`Window::set_maximized` is ignored on iOS")
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-27 20:01:17 +02:00
|
|
|
pub fn is_maximized(&self) -> bool {
|
|
|
|
|
warn!("`Window::is_maximized` is ignored on iOS");
|
|
|
|
|
false
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-21 10:04:28 +02:00
|
|
|
pub(crate) fn set_fullscreen(&self, monitor: Option<Fullscreen>) {
|
2023-08-27 17:04:39 +02:00
|
|
|
let mtm = MainThreadMarker::new().unwrap();
|
2022-12-28 18:36:32 +01:00
|
|
|
let uiscreen = match &monitor {
|
|
|
|
|
Some(Fullscreen::Exclusive(video_mode)) => {
|
2023-08-27 17:04:39 +02:00
|
|
|
let uiscreen = video_mode.monitor.ui_screen(mtm);
|
|
|
|
|
uiscreen.setCurrentMode(Some(video_mode.screen_mode(mtm)));
|
2022-12-28 18:36:32 +01:00
|
|
|
uiscreen.clone()
|
2019-05-25 18:10:41 -07:00
|
|
|
},
|
2023-08-27 17:04:39 +02:00
|
|
|
Some(Fullscreen::Borderless(Some(monitor))) => monitor.ui_screen(mtm).clone(),
|
|
|
|
|
Some(Fullscreen::Borderless(None)) => {
|
|
|
|
|
self.current_monitor_inner().ui_screen(mtm).clone()
|
|
|
|
|
},
|
2022-12-28 18:36:32 +01:00
|
|
|
None => {
|
|
|
|
|
warn!("`Window::set_fullscreen(None)` ignored on iOS");
|
|
|
|
|
return;
|
|
|
|
|
},
|
|
|
|
|
};
|
2019-08-06 23:47:00 +03:00
|
|
|
|
2022-12-28 18:36:32 +01:00
|
|
|
// this is pretty slow on iOS, so avoid doing it if we can
|
|
|
|
|
let current = self.window.screen();
|
|
|
|
|
if uiscreen != current {
|
|
|
|
|
self.window.setScreen(&uiscreen);
|
2019-05-25 18:10:41 -07:00
|
|
|
}
|
2022-12-28 18:36:32 +01:00
|
|
|
|
|
|
|
|
let bounds = uiscreen.bounds();
|
|
|
|
|
self.window.setFrame(bounds);
|
|
|
|
|
|
|
|
|
|
// For external displays, we must disable overscan compensation or
|
|
|
|
|
// the displayed image will have giant black bars surrounding it on
|
|
|
|
|
// each side
|
|
|
|
|
uiscreen.setOverscanCompensation(UIScreenOverscanCompensation::None);
|
2019-05-25 18:10:41 -07:00
|
|
|
}
|
|
|
|
|
|
2022-09-21 10:04:28 +02:00
|
|
|
pub(crate) fn fullscreen(&self) -> Option<Fullscreen> {
|
2023-08-27 17:04:39 +02:00
|
|
|
let mtm = MainThreadMarker::new().unwrap();
|
2023-08-14 21:19:57 +02:00
|
|
|
let monitor = self.current_monitor_inner();
|
2023-08-27 17:04:39 +02:00
|
|
|
let uiscreen = monitor.ui_screen(mtm);
|
2023-08-14 21:19:57 +02:00
|
|
|
let screen_space_bounds = self.screen_frame();
|
|
|
|
|
let screen_bounds = uiscreen.bounds();
|
|
|
|
|
|
|
|
|
|
// TODO: track fullscreen instead of relying on brittle float comparisons
|
|
|
|
|
if screen_space_bounds.origin.x == screen_bounds.origin.x
|
|
|
|
|
&& screen_space_bounds.origin.y == screen_bounds.origin.y
|
|
|
|
|
&& screen_space_bounds.size.width == screen_bounds.size.width
|
|
|
|
|
&& screen_space_bounds.size.height == screen_bounds.size.height
|
|
|
|
|
{
|
|
|
|
|
Some(Fullscreen::Borderless(Some(monitor)))
|
|
|
|
|
} else {
|
|
|
|
|
None
|
2019-05-25 18:10:41 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-28 07:50:34 +00:00
|
|
|
pub fn set_decorations(&self, _decorations: bool) {}
|
2019-05-25 18:10:41 -07:00
|
|
|
|
2022-02-17 15:31:13 +02:00
|
|
|
pub fn is_decorated(&self) -> bool {
|
|
|
|
|
true
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-26 03:50:58 +02:00
|
|
|
pub fn set_window_level(&self, _level: WindowLevel) {
|
|
|
|
|
warn!("`Window::set_window_level` is ignored on iOS")
|
2019-05-25 18:10:41 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn set_window_icon(&self, _icon: Option<Icon>) {
|
|
|
|
|
warn!("`Window::set_window_icon` is ignored on iOS")
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-22 19:12:14 +00:00
|
|
|
pub fn set_ime_cursor_area(&self, _position: Position, _size: Size) {
|
|
|
|
|
warn!("`Window::set_ime_cursor_area` is ignored on iOS")
|
2019-05-25 18:10:41 -07:00
|
|
|
}
|
|
|
|
|
|
2024-08-19 22:04:29 +02:00
|
|
|
/// Show / hide the keyboard. To show the keyboard, we call `becomeFirstResponder`,
|
|
|
|
|
/// requesting focus for the [WinitView]. Since [WinitView] implements
|
|
|
|
|
/// [objc2_ui_kit::UIKeyInput], the keyboard will be shown.
|
|
|
|
|
/// <https://developer.apple.com/documentation/uikit/uiresponder/1621113-becomefirstresponder>
|
|
|
|
|
pub fn set_ime_allowed(&self, allowed: bool) {
|
|
|
|
|
if allowed {
|
|
|
|
|
unsafe {
|
|
|
|
|
self.view.becomeFirstResponder();
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
unsafe {
|
|
|
|
|
self.view.resignFirstResponder();
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-05-07 05:29:25 +03:00
|
|
|
}
|
|
|
|
|
|
2023-01-29 16:46:46 +01:00
|
|
|
pub fn set_ime_purpose(&self, _purpose: ImePurpose) {
|
2024-08-19 22:04:29 +02:00
|
|
|
warn!("`Window::set_ime_purpose` is ignored on iOS")
|
2023-01-29 16:46:46 +01:00
|
|
|
}
|
|
|
|
|
|
2021-05-19 18:39:53 +02:00
|
|
|
pub fn focus_window(&self) {
|
|
|
|
|
warn!("`Window::set_focus` is ignored on iOS")
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-27 03:03:08 +01:00
|
|
|
pub fn request_user_attention(&self, _request_type: Option<UserAttentionType>) {
|
|
|
|
|
warn!("`Window::request_user_attention` is ignored on iOS")
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-07 20:09:24 +03:00
|
|
|
// Allow directly accessing the current monitor internally without unwrapping.
|
2022-09-21 10:04:28 +02:00
|
|
|
fn current_monitor_inner(&self) -> MonitorHandle {
|
2022-12-28 18:36:32 +01:00
|
|
|
MonitorHandle::new(self.window.screen())
|
2019-05-25 18:10:41 -07:00
|
|
|
}
|
|
|
|
|
|
2022-09-21 10:04:28 +02:00
|
|
|
pub fn current_monitor(&self) -> Option<MonitorHandle> {
|
2020-09-07 20:09:24 +03:00
|
|
|
Some(self.current_monitor_inner())
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-29 21:29:54 -04:00
|
|
|
pub fn available_monitors(&self) -> VecDeque<MonitorHandle> {
|
2022-12-28 18:36:32 +01:00
|
|
|
monitor::uiscreens(MainThreadMarker::new().unwrap())
|
2019-05-25 18:10:41 -07:00
|
|
|
}
|
|
|
|
|
|
2022-09-21 10:04:28 +02:00
|
|
|
pub fn primary_monitor(&self) -> Option<MonitorHandle> {
|
2024-05-27 14:49:22 +02:00
|
|
|
#[allow(deprecated)]
|
|
|
|
|
Some(MonitorHandle::new(UIScreen::mainScreen(MainThreadMarker::new().unwrap())))
|
2019-05-25 18:10:41 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn id(&self) -> WindowId {
|
2022-12-28 18:36:32 +01:00
|
|
|
self.window.id()
|
2019-05-25 18:10:41 -07:00
|
|
|
}
|
2019-08-14 07:57:16 -04:00
|
|
|
|
2023-10-14 19:07:39 -07:00
|
|
|
#[cfg(feature = "rwh_06")]
|
2023-12-22 22:33:50 +01:00
|
|
|
pub fn raw_window_handle_rwh_06(&self) -> rwh_06::RawWindowHandle {
|
2023-10-14 19:07:39 -07:00
|
|
|
let mut window_handle = rwh_06::UiKitWindowHandle::new({
|
2024-05-27 14:49:22 +02:00
|
|
|
let ui_view = Retained::as_ptr(&self.view) as _;
|
|
|
|
|
std::ptr::NonNull::new(ui_view).expect("Retained<T> should never be null")
|
2023-10-14 19:07:39 -07:00
|
|
|
});
|
|
|
|
|
window_handle.ui_view_controller =
|
2024-05-27 14:49:22 +02:00
|
|
|
std::ptr::NonNull::new(Retained::as_ptr(&self.view_controller) as _);
|
2023-12-22 22:33:50 +01:00
|
|
|
rwh_06::RawWindowHandle::UiKit(window_handle)
|
2023-10-14 19:07:39 -07:00
|
|
|
}
|
|
|
|
|
|
2022-10-19 03:34:36 +09:00
|
|
|
pub fn theme(&self) -> Option<Theme> {
|
|
|
|
|
warn!("`Window::theme` is ignored on iOS");
|
|
|
|
|
None
|
|
|
|
|
}
|
2022-11-03 10:11:37 -07:00
|
|
|
|
2023-09-01 23:14:16 +02:00
|
|
|
pub fn set_content_protected(&self, _protected: bool) {}
|
|
|
|
|
|
2023-01-17 03:30:14 +02:00
|
|
|
pub fn has_focus(&self) -> bool {
|
|
|
|
|
self.window.isKeyWindow()
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-29 11:05:51 +02:00
|
|
|
#[inline]
|
|
|
|
|
pub fn set_theme(&self, _theme: Option<Theme>) {
|
|
|
|
|
warn!("`Window::set_theme` is ignored on iOS");
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-03 10:11:37 -07:00
|
|
|
pub fn title(&self) -> String {
|
|
|
|
|
warn!("`Window::title` is ignored on iOS");
|
|
|
|
|
String::new()
|
|
|
|
|
}
|
2023-05-28 20:02:59 +02:00
|
|
|
|
|
|
|
|
pub fn reset_dead_keys(&self) {
|
|
|
|
|
// Noop
|
|
|
|
|
}
|
2019-05-25 18:10:41 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub struct Window {
|
2023-08-14 21:19:57 +02:00
|
|
|
inner: MainThreadBound<Inner>,
|
2019-05-25 18:10:41 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Window {
|
2024-01-13 21:36:53 +01:00
|
|
|
pub(crate) fn new(
|
2024-01-31 17:29:59 +04:00
|
|
|
event_loop: &ActiveEventLoop,
|
2019-05-25 18:10:41 -07:00
|
|
|
window_attributes: WindowAttributes,
|
2024-09-06 17:20:11 +03:00
|
|
|
) -> Result<Window, RequestError> {
|
2023-08-27 17:04:39 +02:00
|
|
|
let mtm = event_loop.mtm;
|
2022-12-28 18:36:32 +01:00
|
|
|
|
2024-09-04 15:04:48 +02:00
|
|
|
if window_attributes.min_surface_size.is_some() {
|
|
|
|
|
warn!("`WindowAttributes::min_surface_size` is ignored on iOS");
|
2019-05-25 18:10:41 -07:00
|
|
|
}
|
2024-09-04 15:04:48 +02:00
|
|
|
if window_attributes.max_surface_size.is_some() {
|
|
|
|
|
warn!("`WindowAttributes::max_surface_size` is ignored on iOS");
|
2019-05-25 18:10:41 -07:00
|
|
|
}
|
2022-11-26 03:50:58 +02:00
|
|
|
|
2019-05-25 18:10:41 -07:00
|
|
|
// TODO: transparency, visible
|
|
|
|
|
|
2024-05-27 14:49:22 +02:00
|
|
|
#[allow(deprecated)]
|
|
|
|
|
let main_screen = UIScreen::mainScreen(mtm);
|
2023-12-26 20:13:02 +01:00
|
|
|
let fullscreen = window_attributes.fullscreen.clone().map(Into::into);
|
2023-01-27 07:38:56 +02:00
|
|
|
let screen = match fullscreen {
|
2023-08-27 17:04:39 +02:00
|
|
|
Some(Fullscreen::Exclusive(ref video_mode)) => video_mode.monitor.ui_screen(mtm),
|
|
|
|
|
Some(Fullscreen::Borderless(Some(ref monitor))) => monitor.ui_screen(mtm),
|
2022-12-28 18:36:32 +01:00
|
|
|
Some(Fullscreen::Borderless(None)) | None => &main_screen,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let screen_bounds = screen.bounds();
|
|
|
|
|
|
2024-09-04 15:04:48 +02:00
|
|
|
let frame = match window_attributes.surface_size {
|
2022-12-28 18:36:32 +01:00
|
|
|
Some(dim) => {
|
|
|
|
|
let scale_factor = screen.scale();
|
|
|
|
|
let size = dim.to_logical::<f64>(scale_factor as f64);
|
|
|
|
|
CGRect {
|
|
|
|
|
origin: screen_bounds.origin,
|
|
|
|
|
size: CGSize { width: size.width as _, height: size.height as _ },
|
2019-10-18 18:31:26 +03:00
|
|
|
}
|
2022-12-28 18:36:32 +01:00
|
|
|
},
|
|
|
|
|
None => screen_bounds,
|
|
|
|
|
};
|
|
|
|
|
|
2024-01-17 23:37:28 +01:00
|
|
|
let view = WinitView::new(mtm, &window_attributes, frame);
|
2022-12-28 18:36:32 +01:00
|
|
|
|
2024-05-06 17:09:38 +02:00
|
|
|
let gl_or_metal_backed =
|
|
|
|
|
view.isKindOfClass(class!(CAMetalLayer)) || view.isKindOfClass(class!(CAEAGLLayer));
|
2022-12-28 18:36:32 +01:00
|
|
|
|
2024-01-17 23:37:28 +01:00
|
|
|
let view_controller = WinitViewController::new(mtm, &window_attributes, &view);
|
|
|
|
|
let window = WinitUIWindow::new(mtm, &window_attributes, frame, &view_controller);
|
2024-08-18 23:50:10 +02:00
|
|
|
window.makeKeyAndVisible();
|
2022-12-28 18:36:32 +01:00
|
|
|
|
2024-09-04 15:04:48 +02:00
|
|
|
// Like the Windows and macOS backends, we send a `ScaleFactorChanged` and `SurfaceResized`
|
2022-12-28 18:36:32 +01:00
|
|
|
// event on window creation if the DPI factor != 1.0
|
|
|
|
|
let scale_factor = view.contentScaleFactor();
|
|
|
|
|
let scale_factor = scale_factor as f64;
|
|
|
|
|
if scale_factor != 1.0 {
|
|
|
|
|
let bounds = view.bounds();
|
|
|
|
|
let screen = window.screen();
|
|
|
|
|
let screen_space = screen.coordinateSpace();
|
|
|
|
|
let screen_frame = view.convertRect_toCoordinateSpace(bounds, &screen_space);
|
2024-02-26 14:52:00 +01:00
|
|
|
let size = LogicalSize {
|
2023-08-27 17:04:39 +02:00
|
|
|
width: screen_frame.size.width as f64,
|
|
|
|
|
height: screen_frame.size.height as f64,
|
2019-05-25 18:10:41 -07:00
|
|
|
};
|
2024-08-23 23:40:27 +03:00
|
|
|
let window_id = CoreWindowId(window.id());
|
2023-08-27 17:04:39 +02:00
|
|
|
app_state::handle_nonuser_events(
|
|
|
|
|
mtm,
|
|
|
|
|
std::iter::once(EventWrapper::ScaleFactorChanged(app_state::ScaleFactorChanged {
|
2022-12-28 18:36:32 +01:00
|
|
|
window: window.clone(),
|
2020-01-03 14:52:27 -05:00
|
|
|
scale_factor,
|
2023-08-27 17:04:39 +02:00
|
|
|
suggested_size: size.to_physical(scale_factor),
|
|
|
|
|
}))
|
|
|
|
|
.chain(std::iter::once(EventWrapper::StaticEvent(
|
|
|
|
|
Event::WindowEvent {
|
|
|
|
|
window_id,
|
2024-09-04 15:04:48 +02:00
|
|
|
event: WindowEvent::SurfaceResized(size.to_physical(scale_factor)),
|
2023-08-27 17:04:39 +02:00
|
|
|
},
|
|
|
|
|
))),
|
|
|
|
|
);
|
2019-05-25 18:10:41 -07:00
|
|
|
}
|
2022-12-28 18:36:32 +01:00
|
|
|
|
2023-08-14 21:19:57 +02:00
|
|
|
let inner = Inner { window, view_controller, view, gl_or_metal_backed };
|
|
|
|
|
Ok(Window { inner: MainThreadBound::new(inner, mtm) })
|
2019-05-25 18:10:41 -07:00
|
|
|
}
|
2023-08-14 21:19:57 +02:00
|
|
|
|
|
|
|
|
pub(crate) fn maybe_wait_on_main<R: Send>(&self, f: impl FnOnce(&Inner) -> R + Send) -> R {
|
2023-12-23 18:04:24 +01:00
|
|
|
self.inner.get_on_main(|inner| f(inner))
|
2023-08-14 21:19:57 +02:00
|
|
|
}
|
2023-12-22 22:33:50 +01:00
|
|
|
|
|
|
|
|
#[cfg(feature = "rwh_06")]
|
|
|
|
|
#[inline]
|
|
|
|
|
pub(crate) fn raw_window_handle_rwh_06(
|
|
|
|
|
&self,
|
|
|
|
|
) -> Result<rwh_06::RawWindowHandle, rwh_06::HandleError> {
|
2023-12-22 23:18:35 +01:00
|
|
|
if let Some(mtm) = MainThreadMarker::new() {
|
|
|
|
|
Ok(self.inner.get(mtm).raw_window_handle_rwh_06())
|
|
|
|
|
} else {
|
|
|
|
|
Err(rwh_06::HandleError::Unavailable)
|
|
|
|
|
}
|
2023-12-22 22:33:50 +01:00
|
|
|
}
|
2023-12-26 20:13:02 +01:00
|
|
|
|
|
|
|
|
#[cfg(feature = "rwh_06")]
|
|
|
|
|
#[inline]
|
|
|
|
|
pub(crate) fn raw_display_handle_rwh_06(
|
|
|
|
|
&self,
|
|
|
|
|
) -> Result<rwh_06::RawDisplayHandle, rwh_06::HandleError> {
|
|
|
|
|
Ok(rwh_06::RawDisplayHandle::UiKit(rwh_06::UiKitDisplayHandle::new()))
|
|
|
|
|
}
|
2019-05-25 18:10:41 -07:00
|
|
|
}
|
|
|
|
|
|
2024-08-23 23:40:27 +03:00
|
|
|
#[cfg(feature = "rwh_06")]
|
|
|
|
|
impl rwh_06::HasDisplayHandle for Window {
|
|
|
|
|
fn display_handle(&self) -> Result<rwh_06::DisplayHandle<'_>, rwh_06::HandleError> {
|
|
|
|
|
let raw = self.raw_display_handle_rwh_06()?;
|
|
|
|
|
unsafe { Ok(rwh_06::DisplayHandle::borrow_raw(raw)) }
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(feature = "rwh_06")]
|
|
|
|
|
impl rwh_06::HasWindowHandle for Window {
|
|
|
|
|
fn window_handle(&self) -> Result<rwh_06::WindowHandle<'_>, rwh_06::HandleError> {
|
|
|
|
|
let raw = self.raw_window_handle_rwh_06()?;
|
|
|
|
|
unsafe { Ok(rwh_06::WindowHandle::borrow_raw(raw)) }
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl CoreWindow for Window {
|
|
|
|
|
fn id(&self) -> crate::window::WindowId {
|
|
|
|
|
self.maybe_wait_on_main(|delegate| crate::window::WindowId(delegate.id()))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn scale_factor(&self) -> f64 {
|
|
|
|
|
self.maybe_wait_on_main(|delegate| delegate.scale_factor())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn request_redraw(&self) {
|
|
|
|
|
self.maybe_wait_on_main(|delegate| delegate.request_redraw());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn pre_present_notify(&self) {
|
|
|
|
|
self.maybe_wait_on_main(|delegate| delegate.pre_present_notify());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn reset_dead_keys(&self) {
|
|
|
|
|
self.maybe_wait_on_main(|delegate| delegate.reset_dead_keys());
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-06 17:20:11 +03:00
|
|
|
fn inner_position(&self) -> Result<PhysicalPosition<i32>, RequestError> {
|
|
|
|
|
Ok(self.maybe_wait_on_main(|delegate| delegate.inner_position()))
|
2024-08-23 23:40:27 +03:00
|
|
|
}
|
|
|
|
|
|
2024-09-06 17:20:11 +03:00
|
|
|
fn outer_position(&self) -> Result<PhysicalPosition<i32>, RequestError> {
|
|
|
|
|
Ok(self.maybe_wait_on_main(|delegate| delegate.outer_position()))
|
2024-08-23 23:40:27 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn set_outer_position(&self, position: Position) {
|
|
|
|
|
self.maybe_wait_on_main(|delegate| delegate.set_outer_position(position));
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-06 17:20:11 +03:00
|
|
|
fn surface_size(&self) -> PhysicalSize<u32> {
|
2024-09-04 15:04:48 +02:00
|
|
|
self.maybe_wait_on_main(|delegate| delegate.surface_size())
|
2024-08-23 23:40:27 +03:00
|
|
|
}
|
|
|
|
|
|
2024-09-06 17:20:11 +03:00
|
|
|
fn request_surface_size(&self, size: Size) -> Option<PhysicalSize<u32>> {
|
2024-09-04 15:04:48 +02:00
|
|
|
self.maybe_wait_on_main(|delegate| delegate.request_surface_size(size))
|
2024-08-23 23:40:27 +03:00
|
|
|
}
|
|
|
|
|
|
2024-09-06 17:20:11 +03:00
|
|
|
fn outer_size(&self) -> PhysicalSize<u32> {
|
2024-08-23 23:40:27 +03:00
|
|
|
self.maybe_wait_on_main(|delegate| delegate.outer_size())
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-04 15:04:48 +02:00
|
|
|
fn set_min_surface_size(&self, min_size: Option<Size>) {
|
|
|
|
|
self.maybe_wait_on_main(|delegate| delegate.set_min_surface_size(min_size))
|
2024-08-23 23:40:27 +03:00
|
|
|
}
|
|
|
|
|
|
2024-09-04 15:04:48 +02:00
|
|
|
fn set_max_surface_size(&self, max_size: Option<Size>) {
|
|
|
|
|
self.maybe_wait_on_main(|delegate| delegate.set_max_surface_size(max_size));
|
2024-08-23 23:40:27 +03:00
|
|
|
}
|
|
|
|
|
|
2024-09-06 17:20:11 +03:00
|
|
|
fn surface_resize_increments(&self) -> Option<PhysicalSize<u32>> {
|
2024-09-04 15:04:48 +02:00
|
|
|
self.maybe_wait_on_main(|delegate| delegate.surface_resize_increments())
|
2024-08-23 23:40:27 +03:00
|
|
|
}
|
|
|
|
|
|
2024-09-04 15:04:48 +02:00
|
|
|
fn set_surface_resize_increments(&self, increments: Option<Size>) {
|
|
|
|
|
self.maybe_wait_on_main(|delegate| delegate.set_surface_resize_increments(increments));
|
2024-08-23 23:40:27 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn set_title(&self, title: &str) {
|
|
|
|
|
self.maybe_wait_on_main(|delegate| delegate.set_title(title));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn set_transparent(&self, transparent: bool) {
|
|
|
|
|
self.maybe_wait_on_main(|delegate| delegate.set_transparent(transparent));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn set_blur(&self, blur: bool) {
|
|
|
|
|
self.maybe_wait_on_main(|delegate| delegate.set_blur(blur));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn set_visible(&self, visible: bool) {
|
|
|
|
|
self.maybe_wait_on_main(|delegate| delegate.set_visible(visible));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn is_visible(&self) -> Option<bool> {
|
|
|
|
|
self.maybe_wait_on_main(|delegate| delegate.is_visible())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn set_resizable(&self, resizable: bool) {
|
|
|
|
|
self.maybe_wait_on_main(|delegate| delegate.set_resizable(resizable))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn is_resizable(&self) -> bool {
|
|
|
|
|
self.maybe_wait_on_main(|delegate| delegate.is_resizable())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn set_enabled_buttons(&self, buttons: WindowButtons) {
|
|
|
|
|
self.maybe_wait_on_main(|delegate| delegate.set_enabled_buttons(buttons))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn enabled_buttons(&self) -> WindowButtons {
|
|
|
|
|
self.maybe_wait_on_main(|delegate| delegate.enabled_buttons())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn set_minimized(&self, minimized: bool) {
|
|
|
|
|
self.maybe_wait_on_main(|delegate| delegate.set_minimized(minimized));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn is_minimized(&self) -> Option<bool> {
|
|
|
|
|
self.maybe_wait_on_main(|delegate| delegate.is_minimized())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn set_maximized(&self, maximized: bool) {
|
|
|
|
|
self.maybe_wait_on_main(|delegate| delegate.set_maximized(maximized));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn is_maximized(&self) -> bool {
|
|
|
|
|
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 fullscreen(&self) -> Option<crate::window::Fullscreen> {
|
|
|
|
|
self.maybe_wait_on_main(|delegate| delegate.fullscreen().map(Into::into))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn set_decorations(&self, decorations: bool) {
|
|
|
|
|
self.maybe_wait_on_main(|delegate| delegate.set_decorations(decorations));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn is_decorated(&self) -> bool {
|
|
|
|
|
self.maybe_wait_on_main(|delegate| delegate.is_decorated())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn set_window_level(&self, level: WindowLevel) {
|
|
|
|
|
self.maybe_wait_on_main(|delegate| delegate.set_window_level(level));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn set_window_icon(&self, window_icon: Option<Icon>) {
|
|
|
|
|
self.maybe_wait_on_main(|delegate| delegate.set_window_icon(window_icon));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn set_ime_cursor_area(&self, position: Position, size: Size) {
|
|
|
|
|
self.maybe_wait_on_main(|delegate| delegate.set_ime_cursor_area(position, size));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn set_ime_allowed(&self, allowed: bool) {
|
|
|
|
|
self.maybe_wait_on_main(|delegate| delegate.set_ime_allowed(allowed));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn set_ime_purpose(&self, purpose: ImePurpose) {
|
|
|
|
|
self.maybe_wait_on_main(|delegate| delegate.set_ime_purpose(purpose));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn focus_window(&self) {
|
|
|
|
|
self.maybe_wait_on_main(|delegate| delegate.focus_window());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn has_focus(&self) -> bool {
|
|
|
|
|
self.maybe_wait_on_main(|delegate| delegate.has_focus())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn request_user_attention(&self, request_type: Option<UserAttentionType>) {
|
|
|
|
|
self.maybe_wait_on_main(|delegate| delegate.request_user_attention(request_type));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn set_theme(&self, theme: Option<Theme>) {
|
|
|
|
|
self.maybe_wait_on_main(|delegate| delegate.set_theme(theme));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn theme(&self) -> Option<Theme> {
|
|
|
|
|
self.maybe_wait_on_main(|delegate| delegate.theme())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn set_content_protected(&self, protected: bool) {
|
|
|
|
|
self.maybe_wait_on_main(|delegate| delegate.set_content_protected(protected));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn title(&self) -> String {
|
|
|
|
|
self.maybe_wait_on_main(|delegate| delegate.title())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn set_cursor(&self, cursor: Cursor) {
|
|
|
|
|
self.maybe_wait_on_main(|delegate| delegate.set_cursor(cursor));
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-06 17:20:11 +03:00
|
|
|
fn set_cursor_position(&self, position: Position) -> Result<(), RequestError> {
|
|
|
|
|
Ok(self.maybe_wait_on_main(|delegate| delegate.set_cursor_position(position))?)
|
2024-08-23 23:40:27 +03:00
|
|
|
}
|
|
|
|
|
|
2024-09-06 17:20:11 +03:00
|
|
|
fn set_cursor_grab(&self, mode: crate::window::CursorGrabMode) -> Result<(), RequestError> {
|
|
|
|
|
Ok(self.maybe_wait_on_main(|delegate| delegate.set_cursor_grab(mode))?)
|
2024-08-23 23:40:27 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn set_cursor_visible(&self, visible: bool) {
|
|
|
|
|
self.maybe_wait_on_main(|delegate| delegate.set_cursor_visible(visible))
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-06 17:20:11 +03:00
|
|
|
fn drag_window(&self) -> Result<(), RequestError> {
|
|
|
|
|
Ok(self.maybe_wait_on_main(|delegate| delegate.drag_window())?)
|
2024-08-23 23:40:27 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn drag_resize_window(
|
|
|
|
|
&self,
|
|
|
|
|
direction: crate::window::ResizeDirection,
|
2024-09-06 17:20:11 +03:00
|
|
|
) -> Result<(), RequestError> {
|
|
|
|
|
Ok(self.maybe_wait_on_main(|delegate| delegate.drag_resize_window(direction))?)
|
2024-08-23 23:40:27 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn show_window_menu(&self, position: Position) {
|
|
|
|
|
self.maybe_wait_on_main(|delegate| delegate.show_window_menu(position))
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-06 17:20:11 +03:00
|
|
|
fn set_cursor_hittest(&self, hittest: bool) -> Result<(), RequestError> {
|
|
|
|
|
Ok(self.maybe_wait_on_main(|delegate| delegate.set_cursor_hittest(hittest))?)
|
2024-08-23 23:40:27 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn current_monitor(&self) -> Option<CoreMonitorHandle> {
|
|
|
|
|
self.maybe_wait_on_main(|delegate| {
|
|
|
|
|
delegate.current_monitor().map(|inner| CoreMonitorHandle { inner })
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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 }),
|
|
|
|
|
)
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn primary_monitor(&self) -> Option<CoreMonitorHandle> {
|
|
|
|
|
self.maybe_wait_on_main(|delegate| {
|
|
|
|
|
delegate.primary_monitor().map(|inner| CoreMonitorHandle { inner })
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(feature = "rwh_06")]
|
|
|
|
|
fn rwh_06_display_handle(&self) -> &dyn rwh_06::HasDisplayHandle {
|
|
|
|
|
self
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(feature = "rwh_06")]
|
|
|
|
|
fn rwh_06_window_handle(&self) -> &dyn rwh_06::HasWindowHandle {
|
|
|
|
|
self
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-25 18:10:41 -07:00
|
|
|
// WindowExtIOS
|
|
|
|
|
impl Inner {
|
2020-01-03 14:52:27 -05:00
|
|
|
pub fn set_scale_factor(&self, scale_factor: f64) {
|
2022-12-28 18:36:32 +01:00
|
|
|
assert!(
|
|
|
|
|
dpi::validate_scale_factor(scale_factor),
|
|
|
|
|
"`WindowExtIOS::set_scale_factor` received an invalid hidpi factor"
|
|
|
|
|
);
|
|
|
|
|
let scale_factor = scale_factor as CGFloat;
|
|
|
|
|
self.view.setContentScaleFactor(scale_factor);
|
2019-05-25 18:10:41 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn set_valid_orientations(&self, valid_orientations: ValidOrientations) {
|
2022-12-28 18:36:32 +01:00
|
|
|
self.view_controller.set_supported_interface_orientations(
|
|
|
|
|
MainThreadMarker::new().unwrap(),
|
|
|
|
|
valid_orientations,
|
|
|
|
|
);
|
2019-05-25 18:10:41 -07:00
|
|
|
}
|
2019-07-30 23:57:31 -07:00
|
|
|
|
|
|
|
|
pub fn set_prefers_home_indicator_hidden(&self, hidden: bool) {
|
2023-07-08 22:36:42 +03:00
|
|
|
self.view_controller.set_prefers_home_indicator_auto_hidden(hidden);
|
2019-07-30 23:57:31 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn set_preferred_screen_edges_deferring_system_gestures(&self, edges: ScreenEdge) {
|
2024-02-27 21:07:52 +01:00
|
|
|
self.view_controller.set_preferred_screen_edges_deferring_system_gestures(edges);
|
2019-07-30 23:57:31 -07:00
|
|
|
}
|
2019-08-09 02:10:54 +03:00
|
|
|
|
|
|
|
|
pub fn set_prefers_status_bar_hidden(&self, hidden: bool) {
|
2023-07-08 22:36:42 +03:00
|
|
|
self.view_controller.set_prefers_status_bar_hidden(hidden);
|
2019-08-09 02:10:54 +03:00
|
|
|
}
|
2023-10-20 12:26:10 +02:00
|
|
|
|
|
|
|
|
pub fn set_preferred_status_bar_style(&self, status_bar_style: StatusBarStyle) {
|
2024-02-27 21:07:52 +01:00
|
|
|
self.view_controller.set_preferred_status_bar_style(status_bar_style);
|
2023-10-20 12:26:10 +02:00
|
|
|
}
|
2024-01-16 21:31:18 +01:00
|
|
|
|
|
|
|
|
pub fn recognize_pinch_gesture(&self, should_recognize: bool) {
|
|
|
|
|
self.view.recognize_pinch_gesture(should_recognize);
|
|
|
|
|
}
|
|
|
|
|
|
2024-04-27 09:55:04 -04:00
|
|
|
pub fn recognize_pan_gesture(
|
|
|
|
|
&self,
|
|
|
|
|
should_recognize: bool,
|
|
|
|
|
minimum_number_of_touches: u8,
|
|
|
|
|
maximum_number_of_touches: u8,
|
|
|
|
|
) {
|
|
|
|
|
self.view.recognize_pan_gesture(
|
|
|
|
|
should_recognize,
|
|
|
|
|
minimum_number_of_touches,
|
|
|
|
|
maximum_number_of_touches,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2024-01-16 21:31:18 +01:00
|
|
|
pub fn recognize_doubletap_gesture(&self, should_recognize: bool) {
|
|
|
|
|
self.view.recognize_doubletap_gesture(should_recognize);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn recognize_rotation_gesture(&self, should_recognize: bool) {
|
|
|
|
|
self.view.recognize_rotation_gesture(should_recognize);
|
|
|
|
|
}
|
2019-05-25 18:10:41 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Inner {
|
2023-08-14 21:19:57 +02:00
|
|
|
fn screen_frame(&self) -> CGRect {
|
2022-12-28 18:36:32 +01:00
|
|
|
self.rect_to_screen_space(self.window.bounds())
|
2019-05-25 18:10:41 -07:00
|
|
|
}
|
|
|
|
|
|
2023-08-14 21:19:57 +02:00
|
|
|
fn rect_to_screen_space(&self, rect: CGRect) -> CGRect {
|
2022-12-28 18:36:32 +01:00
|
|
|
let screen_space = self.window.screen().coordinateSpace();
|
|
|
|
|
self.window.convertRect_toCoordinateSpace(rect, &screen_space)
|
2019-05-25 18:10:41 -07:00
|
|
|
}
|
|
|
|
|
|
2023-08-14 21:19:57 +02:00
|
|
|
fn rect_from_screen_space(&self, rect: CGRect) -> CGRect {
|
2022-12-28 18:36:32 +01:00
|
|
|
let screen_space = self.window.screen().coordinateSpace();
|
|
|
|
|
self.window.convertRect_fromCoordinateSpace(rect, &screen_space)
|
2019-05-25 18:10:41 -07:00
|
|
|
}
|
|
|
|
|
|
2023-08-14 21:19:57 +02:00
|
|
|
fn safe_area_screen_space(&self) -> CGRect {
|
2022-12-28 18:36:32 +01:00
|
|
|
let bounds = self.window.bounds();
|
2019-08-26 15:47:23 -07:00
|
|
|
if app_state::os_capabilities().safe_area {
|
2022-12-28 18:36:32 +01:00
|
|
|
let safe_area = self.window.safeAreaInsets();
|
2019-05-25 18:10:41 -07:00
|
|
|
let safe_bounds = CGRect {
|
|
|
|
|
origin: CGPoint {
|
|
|
|
|
x: bounds.origin.x + safe_area.left,
|
|
|
|
|
y: bounds.origin.y + safe_area.top,
|
|
|
|
|
},
|
|
|
|
|
size: CGSize {
|
|
|
|
|
width: bounds.size.width - safe_area.left - safe_area.right,
|
|
|
|
|
height: bounds.size.height - safe_area.top - safe_area.bottom,
|
|
|
|
|
},
|
|
|
|
|
};
|
2022-06-10 13:43:33 +03:00
|
|
|
self.rect_to_screen_space(safe_bounds)
|
2019-05-25 18:10:41 -07:00
|
|
|
} else {
|
2022-06-10 13:43:33 +03:00
|
|
|
let screen_frame = self.rect_to_screen_space(bounds);
|
2022-12-28 18:36:32 +01:00
|
|
|
let status_bar_frame = {
|
2024-05-27 14:49:22 +02:00
|
|
|
let app = UIApplication::sharedApplication(MainThreadMarker::new().unwrap());
|
|
|
|
|
#[allow(deprecated)]
|
2022-12-28 18:36:32 +01:00
|
|
|
app.statusBarFrame()
|
2019-05-25 18:10:41 -07:00
|
|
|
};
|
|
|
|
|
let (y, height) = if screen_frame.origin.y > status_bar_frame.size.height {
|
|
|
|
|
(screen_frame.origin.y, screen_frame.size.height)
|
|
|
|
|
} else {
|
|
|
|
|
let y = status_bar_frame.size.height;
|
2019-06-21 11:33:15 -04:00
|
|
|
let height = screen_frame.size.height
|
|
|
|
|
- (status_bar_frame.size.height - screen_frame.origin.y);
|
2019-05-25 18:10:41 -07:00
|
|
|
(y, height)
|
|
|
|
|
};
|
|
|
|
|
CGRect {
|
|
|
|
|
origin: CGPoint { x: screen_frame.origin.x, y },
|
|
|
|
|
size: CGSize { width: screen_frame.size.width, height },
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
2024-09-27 22:12:50 +02:00
|
|
|
pub struct WindowId(usize);
|
2019-05-25 18:10:41 -07:00
|
|
|
|
|
|
|
|
impl WindowId {
|
2024-09-27 22:12:50 +02:00
|
|
|
pub const fn into_raw(self) -> u64 {
|
|
|
|
|
self.0 as _
|
2022-07-02 14:27:19 +03:00
|
|
|
}
|
|
|
|
|
|
2024-09-27 22:12:50 +02:00
|
|
|
pub const fn from_raw(id: u64) -> Self {
|
|
|
|
|
Self(id as _)
|
2022-07-02 14:27:19 +03:00
|
|
|
}
|
2019-05-25 18:10:41 -07:00
|
|
|
|
2024-09-27 22:12:50 +02:00
|
|
|
fn from_window(window: &UIWindow) -> Self {
|
|
|
|
|
Self(window as *const UIWindow as usize)
|
2019-05-25 18:10:41 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-08 00:46:28 +02:00
|
|
|
#[derive(Clone, Debug, Default, PartialEq)]
|
2024-01-31 17:29:59 +04:00
|
|
|
pub struct PlatformSpecificWindowAttributes {
|
2020-01-03 14:52:27 -05:00
|
|
|
pub scale_factor: Option<f64>,
|
2019-05-25 18:10:41 -07:00
|
|
|
pub valid_orientations: ValidOrientations,
|
2019-07-30 23:57:31 -07:00
|
|
|
pub prefers_home_indicator_hidden: bool,
|
2019-08-09 02:10:54 +03:00
|
|
|
pub prefers_status_bar_hidden: bool,
|
2023-10-20 12:26:10 +02:00
|
|
|
pub preferred_status_bar_style: StatusBarStyle,
|
2019-07-30 23:57:31 -07:00
|
|
|
pub preferred_screen_edges_deferring_system_gestures: ScreenEdge,
|
2019-05-25 18:10:41 -07:00
|
|
|
}
|