Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions winit-uikit/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ objc2-ui-kit = { workspace = true, features = [
"UIView",
"UIViewController",
"UIWindow",
"UIScene",
"UIWindowScene"
] }
winit-common = { workspace = true, features = ["core-foundation", "event-handler"] }

Expand Down
12 changes: 8 additions & 4 deletions winit-uikit/src/app_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -451,10 +451,14 @@ fn handle_hidpi_proxy(mtm: MainThreadMarker, event: ScaleFactorChanged) {
let ScaleFactorChanged { suggested_size, scale_factor, window } = event;
let new_surface_size = Arc::new(Mutex::new(suggested_size));
get_handler(mtm).handle(|app| {
app.window_event(&ActiveEventLoop { mtm }, window.id(), WindowEvent::ScaleFactorChanged {
scale_factor,
surface_size_writer: SurfaceSizeWriter::new(Arc::downgrade(&new_surface_size)),
});
app.window_event(
&ActiveEventLoop { mtm },
window.id(),
WindowEvent::ScaleFactorChanged {
scale_factor,
surface_size_writer: SurfaceSizeWriter::new(Arc::downgrade(&new_surface_size)),
},
);
});
let (view, screen_frame) = get_view_and_screen_frame(&window);
let physical_size = *new_surface_size.lock().unwrap();
Expand Down
42 changes: 30 additions & 12 deletions winit-uikit/src/event_loop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,13 +139,12 @@ pub struct EventLoop {
}

#[derive(Default, Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct PlatformSpecificEventLoopAttributes {}
pub struct PlatformSpecificEventLoopAttributes {
pub mtm: Option<MainThreadMarker>,
}

impl EventLoop {
pub fn new(_: &PlatformSpecificEventLoopAttributes) -> Result<EventLoop, EventLoopError> {
let mtm = MainThreadMarker::new()
.expect("On iOS, `EventLoop` must be created on the main thread");

pub fn new_with_mtm(mtm: MainThreadMarker) -> Result<EventLoop, EventLoopError> {
if !AppState::setup_global(mtm) {
// Required, AppState is global state, and event loop can only be run once.
return Err(EventLoopError::RecreationAttempt);
Expand Down Expand Up @@ -238,17 +237,36 @@ impl EventLoop {
})
}

pub fn new(
attributes: &PlatformSpecificEventLoopAttributes,
) -> Result<EventLoop, EventLoopError> {
// if the user provided a MainThreadMarker, use it; otherwise, create one
let mtm = match attributes.mtm {
Some(mtm) => mtm,
None => MainThreadMarker::new()
.expect("On iOS, `EventLoop` must be created on the main thread"),
};

EventLoop::new_with_mtm(mtm)
}

// Require `'static` for correctness, we won't be able to `Drop` the user's state otherwise.
pub fn run_app_never_return<A: ApplicationHandler + 'static>(self, app: A) -> ! {
let application: Option<Retained<UIApplication>> =
unsafe { msg_send![UIApplication::class(), sharedApplication] };
assert!(
application.is_none(),
"\
`EventLoop` cannot be `run` after a call to `UIApplicationMain` on iOS\nNote: \
`EventLoop::run_app` calls `UIApplicationMain` on iOS",
);

if let Some(_) = application {
// launch without calling `UIApplicationMain`, then park the thread forever
// it would probably be better to turn this into a `register_app`-style function
// and just return immediately
app_state::launch(self.mtm, app, || {
loop {
std::thread::park();
}
});

// manually call did_finish_launching(mtm);
app_state::did_finish_launching(self.mtm);
}
// We intentionally override neither the application nor the delegate,
// to allow the user to do so themselves!
//
Expand Down
8 changes: 8 additions & 0 deletions winit-uikit/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ mod window;

use std::os::raw::c_void;

pub use objc2;

#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use winit_core::monitor::{MonitorHandle, VideoMode};
Expand Down Expand Up @@ -294,6 +296,12 @@ impl WindowExtIOS for dyn Window + '_ {
}
}

pub trait EventLoopBuilderExtIOS {
/// Sets the main thread marker to be used by the event loop.
fn with_main_thread_marker(&mut self, main_thread_marker: objc2::MainThreadMarker)
-> &mut Self;
}

/// Ios specific window attributes.
#[derive(Clone, Debug, Default, PartialEq)]
pub struct WindowAttributesIos {
Expand Down
36 changes: 28 additions & 8 deletions winit-uikit/src/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,20 +47,20 @@ define_class!(
#[unsafe(method(becomeKeyWindow))]
fn become_key_window(&self) {
let mtm = MainThreadMarker::new().unwrap();
app_state::handle_nonuser_event(mtm, EventWrapper::Window {
window_id: self.id(),
event: WindowEvent::Focused(true),
});
app_state::handle_nonuser_event(
mtm,
EventWrapper::Window { window_id: self.id(), event: WindowEvent::Focused(true) },
);
let _: () = unsafe { msg_send![super(self), becomeKeyWindow] };
}

#[unsafe(method(resignKeyWindow))]
fn resign_key_window(&self) {
let mtm = MainThreadMarker::new().unwrap();
app_state::handle_nonuser_event(mtm, EventWrapper::Window {
window_id: self.id(),
event: WindowEvent::Focused(false),
});
app_state::handle_nonuser_event(
mtm,
EventWrapper::Window { window_id: self.id(), event: WindowEvent::Focused(false) },
);
let _: () = unsafe { msg_send![super(self), resignKeyWindow] };
}
}
Expand Down Expand Up @@ -490,6 +490,22 @@ impl Window {
) -> Result<Window, RequestError> {
let mtm = event_loop.mtm;

// check if there is already one or more scenes using .connectedScenes
let mut window_scene: Option<Retained<objc2_ui_kit::UIWindowScene>> = None;

unsafe {
let app = UIApplication::sharedApplication(mtm);
let connected_scenes = app.connectedScenes();
for scene in connected_scenes.iter() {
// check if UIWindowScene
if scene.isKindOfClass(class!(UIWindowScene)) {
window_scene = Some(Retained::cast_unchecked::<objc2_ui_kit::UIWindowScene>(
scene.clone(),
));
}
}
};

if window_attributes.min_surface_size.is_some() {
warn!("`WindowAttributes::min_surface_size` is ignored on iOS");
}
Expand Down Expand Up @@ -539,6 +555,10 @@ impl Window {
let view_controller = WinitViewController::new(mtm, &ios_attributes, &view);
let window = WinitUIWindow::new(mtm, &window_attributes, frame, &view_controller);
window.makeKeyAndVisible();
unsafe {
window.setWindowLevel(10000.0);
window.setWindowScene(window_scene.as_deref());
}

let inner = Inner {
window,
Expand Down
8 changes: 8 additions & 0 deletions winit/src/event_loop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,14 @@ impl winit_android::EventLoopBuilderExtAndroid for EventLoopBuilder {
}
}

#[cfg(ios_platform)]
impl winit_uikit::EventLoopBuilderExtIOS for EventLoopBuilder {
fn with_main_thread_marker(&mut self, mtm: winit_uikit::objc2::MainThreadMarker) -> &mut Self {
self.platform_specific.mtm = Some(mtm);
self
}
}

#[cfg(macos_platform)]
impl winit_appkit::EventLoopBuilderExtMacOS for EventLoopBuilder {
#[inline]
Expand Down
Loading