diff --git a/Cargo.toml b/Cargo.toml index 99590cdb98..515a4bf60b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,8 +39,8 @@ simple_logger = "2.1.0" [target.'cfg(target_os = "android")'.dependencies] ndk = "0.6" -ndk-sys = "0.3" ndk-glue = "0.6" +parking_lot = "0.12" [target.'cfg(any(target_os = "ios", target_os = "macos"))'.dependencies] objc = "0.2.7" @@ -137,5 +137,6 @@ members = [ ] [patch.crates-io] -ndk = { git = "https://github.com/rust-windowing/android-ndk-rs", rev = "6b901cd30a8ce04294c4b0383618cb5fd7a3e8b0" } -ndk-glue = { git = "https://github.com/rust-windowing/android-ndk-rs", rev = "6b901cd30a8ce04294c4b0383618cb5fd7a3e8b0" } +# https://github.com/rust-windowing/android-ndk-rs/pull/282 +ndk = { git = "https://github.com/MarijnS95/android-ndk-rs", branch = "ndk-glue-parking-lot" } +ndk-glue = { git = "https://github.com/MarijnS95/android-ndk-rs", branch = "ndk-glue-parking-lot" } diff --git a/src/platform_impl/android/mod.rs b/src/platform_impl/android/mod.rs index 331f964edb..6191376813 100644 --- a/src/platform_impl/android/mod.rs +++ b/src/platform_impl/android/mod.rs @@ -11,6 +11,7 @@ use ndk::{ configuration::Configuration, event::{InputEvent, KeyAction, Keycode, MotionAction}, looper::{ForeignLooper, Poll, ThreadLooper}, + native_window::NativeWindow, }; use ndk_glue::{Event, Rect}; use raw_window_handle::{HasRawWindowHandle, RawWindowHandle}; @@ -235,6 +236,7 @@ pub struct EventLoop { start_cause: event::StartCause, looper: ThreadLooper, running: bool, + window_lock: Option>, } #[derive(Default, Debug, Copy, Clone, PartialEq, Hash)] @@ -264,6 +266,7 @@ impl EventLoop { start_cause: event::StartCause::Init, looper: ThreadLooper::for_thread().unwrap(), running: false, + window_lock: None, } } @@ -296,6 +299,11 @@ impl EventLoop { match self.first_event.take() { Some(EventSource::Callback) => match ndk_glue::poll_events().unwrap() { Event::WindowCreated => { + // Acquire a lock on the window to prevent Android from destroying + // it until we've notified and waited for the user in Event::Suspended. + // XXX: Don't send this event if Android already removed the window + // before we managed to handle this event? + self.window_lock.replace(ndk_glue::native_window().unwrap()); call_event_handler!( event_handler, self.window_target(), @@ -312,6 +320,8 @@ impl EventLoop { control_flow, event::Event::Suspended ); + // Release the lock, allowing Android to clean up this surface + self.window_lock.take(); } Event::Pause => self.running = false, Event::Resume => self.running = true, @@ -783,7 +793,7 @@ impl Window { } pub fn raw_window_handle(&self) -> RawWindowHandle { - if let Some(native_window) = ndk_glue::native_window().as_ref() { + if let Some(native_window) = ndk_glue::native_window() { native_window.raw_window_handle() } else { panic!("Cannot get the native window, it's null and will always be null before Event::Resumed and after Event::Suspended. Make sure you only call this function between those events."); diff --git a/src/window.rs b/src/window.rs index 96189872f8..0d68cc8beb 100644 --- a/src/window.rs +++ b/src/window.rs @@ -1048,12 +1048,21 @@ impl Window { } unsafe impl raw_window_handle::HasRawWindowHandle for Window { - /// Returns a `raw_window_handle::RawWindowHandle` for the Window + /// Returns a [`raw_window_handle::RawWindowHandle`] for the Window /// /// ## Platform-specific /// - /// - **Android:** Only available after receiving the Resumed event and before Suspended. *If you* - /// *try to get the handle outside of that period, this function will panic*! + /// ### Android + /// + /// Only available after receiving [`Event::Resumed`] and before [`Event::Suspended`]. *If you + /// try to get the handle outside of that period, this function will panic*! + /// + /// Make sure to release or destroy any resources created from this `RawWindowHandle` (ie. Vulkan + /// or OpenGL surfaces) before returning from [`Event::Suspended`], at which point Android will + /// release the underlying window/surface: any subsequent interaction is undefined behavior. + /// + /// [`Event::Resumed`]: crate::event::Event::Resumed + /// [`Event::Suspended`]: crate::event::Event::Suspended fn raw_window_handle(&self) -> raw_window_handle::RawWindowHandle { self.window.raw_window_handle() }