mirror of
https://github.com/rust-mobile/android-activity.git
synced 2026-07-04 05:47:26 +00:00
Expose native_window() via AndroidApp instead of static
To be able to support multiple activities per-process we can't have any static/global state.
This commit is contained in:
+46
-24
@@ -5,7 +5,7 @@ use ndk::asset::AssetManager;
|
||||
use ndk::configuration::Configuration;
|
||||
use ndk::looper::{FdEvent};
|
||||
use ndk::native_window::NativeWindow;
|
||||
use ndk_sys::ALooper_wake;
|
||||
use ndk_sys::{ALooper_wake};
|
||||
use ndk_sys::{ALooper, ALooper_pollAll};
|
||||
use std::ffi::{CStr, CString};
|
||||
use std::fs::File;
|
||||
@@ -16,11 +16,9 @@ use std::os::raw;
|
||||
use std::ptr::NonNull;
|
||||
use std::sync::Arc;
|
||||
use std::sync::RwLock;
|
||||
use std::sync::RwLockReadGuard;
|
||||
use std::time::Duration;
|
||||
use std::{thread, ptr};
|
||||
use std::os::unix::prelude::*;
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
use crate::input::{MotionEvent, KeyEvent};
|
||||
|
||||
@@ -51,16 +49,6 @@ pub mod input;
|
||||
// getter also helps keep simple winit usage portable.
|
||||
static mut ANDROID_APP: Option<AndroidApp> = None;
|
||||
|
||||
// This is mainly just for convenience for implementing a winit backend
|
||||
// although ideally it shouldn't be necessary to have a static global.
|
||||
//
|
||||
// Removing this would just require moving the `native_window()` getter
|
||||
// to be an AndroidApp method and require winit to pass around the
|
||||
// app wherever it needs to query the window.
|
||||
lazy_static! {
|
||||
static ref NATIVE_WINDOW: RwLock<Option<NativeWindow>> = Default::default();
|
||||
}
|
||||
|
||||
// Note: unlike in ndk-glue this has signed components (consistent
|
||||
// with Android's ARect) which generally allows for representing
|
||||
// rectangles with a negative/off-screen origin. Even though this
|
||||
@@ -76,6 +64,33 @@ pub struct Rect {
|
||||
pub bottom: i32,
|
||||
}
|
||||
|
||||
// XXX: NativeWindow is a ref-counted object but the NativeWindow rust API
|
||||
// doesn't currently implement Clone() in terms of acquiring a reference
|
||||
// and Drop() in terms of releasing a reference.
|
||||
|
||||
/// A reference to a `NativeWindow`, used for rendering
|
||||
pub struct NativeWindowRef {
|
||||
inner: NativeWindow
|
||||
}
|
||||
impl NativeWindowRef {
|
||||
pub fn new(native_window: &NativeWindow) -> Self {
|
||||
unsafe { ndk_sys::ANativeWindow_acquire(native_window.ptr().as_ptr()); }
|
||||
Self { inner: native_window.clone() }
|
||||
}
|
||||
}
|
||||
impl Drop for NativeWindowRef {
|
||||
fn drop(&mut self) {
|
||||
unsafe { ndk_sys::ANativeWindow_release(self.inner.ptr().as_ptr()) }
|
||||
}
|
||||
}
|
||||
impl Deref for NativeWindowRef {
|
||||
type Target = NativeWindow;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.inner
|
||||
}
|
||||
}
|
||||
|
||||
// The only time it's safe to update the android_app->savedState pointer is
|
||||
// while handling a SaveState event, so this API is only exposed for those
|
||||
// events...
|
||||
@@ -272,6 +287,7 @@ impl Deref for AndroidApp {
|
||||
pub struct AndroidAppInner {
|
||||
ptr: NonNull<ffi::android_app>,
|
||||
config: RwLock<Configuration>,
|
||||
native_window: RwLock<Option<NativeWindow>>,
|
||||
}
|
||||
|
||||
impl AndroidApp {
|
||||
@@ -290,10 +306,25 @@ impl AndroidApp {
|
||||
inner: Arc::new(AndroidAppInner {
|
||||
ptr,
|
||||
config: RwLock::new(config),
|
||||
native_window: Default::default(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Queries the current [`NativeWindow`] for the application.
|
||||
///
|
||||
/// This will only return `Some(window)` between
|
||||
/// [`AndroidAppMainEvent::InitWindow`] and [`AndroidAppMainEvent::TerminateWindow`]
|
||||
/// events.
|
||||
pub fn native_window<'a>(&self) -> Option<NativeWindowRef> {
|
||||
let guard = self.native_window.read().unwrap();
|
||||
if let Some(ref window) = *guard {
|
||||
Some(NativeWindowRef::new(window))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Calls [`ALooper_pollAll`] on the looper associated with this AndroidApp as well
|
||||
/// as processing any events (such as lifecycle events) via the given `callback`.
|
||||
///
|
||||
@@ -387,11 +418,11 @@ impl AndroidApp {
|
||||
}
|
||||
MainEvent::InitWindow { .. } => {
|
||||
let win_ptr = (*app_ptr.as_ptr()).window;
|
||||
*NATIVE_WINDOW.write().unwrap() =
|
||||
*self.native_window.write().unwrap() =
|
||||
Some(NativeWindow::from_ptr(NonNull::new(win_ptr).unwrap()));
|
||||
}
|
||||
MainEvent::TerminateWindow { .. } => {
|
||||
*NATIVE_WINDOW.write().unwrap() = None;
|
||||
*self.native_window.write().unwrap() = None;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
@@ -681,15 +712,6 @@ pub fn android_app() -> AndroidApp {
|
||||
}
|
||||
}
|
||||
|
||||
/// Queries the current [`NativeWindow`] for the application.
|
||||
///
|
||||
/// This will only return `Some(window)` between
|
||||
/// [`AndroidAppMainEvent::InitWindow`] and [`AndroidAppMainEvent::TerminateWindow`]
|
||||
/// events.
|
||||
pub fn native_window() -> RwLockReadGuard<'static, Option<NativeWindow>> {
|
||||
NATIVE_WINDOW.read().unwrap()
|
||||
}
|
||||
|
||||
// Rust doesn't give us a clean way to directly export symbols from C/C++
|
||||
// so we rename the C/C++ symbols and re-export these JNI entrypoints from
|
||||
// Rust...
|
||||
|
||||
+45
-21
@@ -55,16 +55,6 @@ pub mod input {
|
||||
// getter also helps keep simple winit usage portable.
|
||||
static mut ANDROID_APP: Option<AndroidApp> = None;
|
||||
|
||||
// This is mainly just for convenience for implementing a winit backend
|
||||
// although ideally it shouldn't be necessary to have a static global.
|
||||
//
|
||||
// Removing this would just require moving the `native_window()` getter
|
||||
// to be an AndroidApp method and require winit to pass around the
|
||||
// app wherever it needs to query the window.
|
||||
lazy_static! {
|
||||
static ref NATIVE_WINDOW: RwLock<Option<NativeWindow>> = Default::default();
|
||||
}
|
||||
|
||||
pub type InputEvent = ndk::event::InputEvent;
|
||||
|
||||
// Note: unlike in ndk-glue this has signed components (consistent
|
||||
@@ -82,6 +72,33 @@ pub struct Rect {
|
||||
pub bottom: i32,
|
||||
}
|
||||
|
||||
// XXX: NativeWindow is a ref-counted object but the NativeWindow rust API
|
||||
// doesn't currently implement Clone() in terms of acquiring a reference
|
||||
// and Drop() in terms of releasing a reference.
|
||||
|
||||
/// A reference to a `NativeWindow`, used for rendering
|
||||
pub struct NativeWindowRef {
|
||||
inner: NativeWindow
|
||||
}
|
||||
impl NativeWindowRef {
|
||||
pub fn new(native_window: &NativeWindow) -> Self {
|
||||
unsafe { ndk_sys::ANativeWindow_acquire(native_window.ptr().as_ptr()); }
|
||||
Self { inner: native_window.clone() }
|
||||
}
|
||||
}
|
||||
impl Drop for NativeWindowRef {
|
||||
fn drop(&mut self) {
|
||||
unsafe { ndk_sys::ANativeWindow_release(self.inner.ptr().as_ptr()) }
|
||||
}
|
||||
}
|
||||
impl Deref for NativeWindowRef {
|
||||
type Target = NativeWindow;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.inner
|
||||
}
|
||||
}
|
||||
|
||||
// The only time it's safe to update the android_app->savedState pointer is
|
||||
// while handling a SaveState event, so this API is only exposed for those
|
||||
// events...
|
||||
@@ -279,6 +296,7 @@ impl Deref for AndroidApp {
|
||||
pub struct AndroidAppInner {
|
||||
ptr: NonNull<ffi::android_app>,
|
||||
config: RwLock<Configuration>,
|
||||
native_window: RwLock<Option<NativeWindow>>,
|
||||
}
|
||||
|
||||
impl AndroidApp {
|
||||
@@ -297,6 +315,7 @@ impl AndroidApp {
|
||||
inner: Arc::new(AndroidAppInner {
|
||||
ptr,
|
||||
config: RwLock::new(config),
|
||||
native_window: Default::default()
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -308,6 +327,20 @@ impl AndroidApp {
|
||||
}
|
||||
}
|
||||
|
||||
/// Queries the current [`NativeWindow`] for the application.
|
||||
///
|
||||
/// This will only return `Some(window)` between
|
||||
/// [`AndroidAppMainEvent::InitWindow`] and [`AndroidAppMainEvent::TerminateWindow`]
|
||||
/// events.
|
||||
pub fn native_window<'a>(&self) -> Option<NativeWindowRef> {
|
||||
let guard = self.native_window.read().unwrap();
|
||||
if let Some(ref window) = *guard {
|
||||
Some(NativeWindowRef::new(window))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Calls [`ALooper_pollAll`] on the looper associated with this AndroidApp as well
|
||||
/// as processing any events (such as lifecycle events) via the given `callback`.
|
||||
///
|
||||
@@ -408,11 +441,11 @@ impl AndroidApp {
|
||||
}
|
||||
MainEvent::InitWindow { .. } => {
|
||||
let win_ptr = (*app_ptr.as_ptr()).window;
|
||||
*NATIVE_WINDOW.write().unwrap() =
|
||||
*self.native_window.write().unwrap() =
|
||||
Some(NativeWindow::from_ptr(NonNull::new(win_ptr).unwrap()));
|
||||
}
|
||||
MainEvent::TerminateWindow { .. } => {
|
||||
*NATIVE_WINDOW.write().unwrap() = None;
|
||||
*self.native_window.write().unwrap() = None;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
@@ -593,15 +626,6 @@ pub fn android_app() -> AndroidApp {
|
||||
}
|
||||
}
|
||||
|
||||
/// Queries the current [`NativeWindow`] for the application.
|
||||
///
|
||||
/// This will only return `Some(window)` between
|
||||
/// [`AndroidAppMainEvent::InitWindow`] and [`AndroidAppMainEvent::TerminateWindow`]
|
||||
/// events.
|
||||
pub fn native_window() -> RwLockReadGuard<'static, Option<NativeWindow>> {
|
||||
NATIVE_WINDOW.read().unwrap()
|
||||
}
|
||||
|
||||
// Rust doesn't give us a clean way to directly export symbols from C/C++
|
||||
// so we rename the C/C++ symbols and re-export this entrypoint from
|
||||
// Rust...
|
||||
|
||||
Reference in New Issue
Block a user