From 8c13a53b500f4545055d6c21ba26ba018056cca2 Mon Sep 17 00:00:00 2001 From: Lucas Nogueira Date: Thu, 30 Apr 2026 11:29:43 -0300 Subject: [PATCH 1/2] refactor(mobile): move Resumed and Suspended to WindowEvent --- .changes/window-lifecycle-events.md | 5 ++ src/event.rs | 46 ++++++++--------- src/platform_impl/android/mod.rs | 18 ++++--- src/platform_impl/android/ndk_glue.rs | 48 ++++++++++-------- src/platform_impl/ios/mod.rs | 6 ++- src/platform_impl/ios/scene.rs | 27 ++++++---- src/platform_impl/ios/view.rs | 72 ++++++++++++++------------- 7 files changed, 124 insertions(+), 98 deletions(-) create mode 100644 .changes/window-lifecycle-events.md diff --git a/.changes/window-lifecycle-events.md b/.changes/window-lifecycle-events.md new file mode 100644 index 000000000..9d2141f9f --- /dev/null +++ b/.changes/window-lifecycle-events.md @@ -0,0 +1,5 @@ +--- +"tao": minor +--- + +Moved `Suspended` and `Resumed` from `Event` to `WindowEvent` so Android and iOS lifecycle events are emitted for the specific window that was suspended or resumed. diff --git a/src/event.rs b/src/event.rs index d72af30ba..ac05804c9 100644 --- a/src/event.rs +++ b/src/event.rs @@ -77,24 +77,6 @@ pub enum Event<'a, T: 'static> { /// Emitted when an event is sent from [`EventLoopProxy::send_event`](crate::event_loop::EventLoopProxy::send_event) UserEvent(T), - /// Emitted when the application has been suspended. - /// - /// ## Platform-specific - /// - /// - **Android**: This is triggered by `onPause` method of the Activity. - /// - **iOS**: This is triggered by `applicationWillResignActive` method of the UIApplicationDelegate. - /// - **Linux / macOS / Windows**: Unsupported. - Suspended, - - /// Emitted when the application has been resumed. - /// - /// ## Platform-specific - /// - /// - **Android**: This is triggered by `onResume` method of the Activity. The first onResume() is ignored to match the iOS implementation, since that is called on activity creation. - /// - **iOS**: This is triggered by `applicationWillEnterForeground` method of the UIApplicationDelegate. - /// - **Linux / macOS / Windows**: Unsupported. - Resumed, - /// Emitted when all of the event loop's input events have been processed and redraw processing /// is about to begin. /// @@ -189,8 +171,6 @@ impl Clone for Event<'static, T> { RedrawRequested(wid) => RedrawRequested(*wid), RedrawEventsCleared => RedrawEventsCleared, LoopDestroyed => LoopDestroyed, - Suspended => Suspended, - Resumed => Resumed, Opened { urls } => Opened { urls: urls.clone() }, Reopen { has_visible_windows, @@ -218,8 +198,6 @@ impl<'a, T> Event<'a, T> { RedrawRequested(wid) => Ok(RedrawRequested(wid)), RedrawEventsCleared => Ok(RedrawEventsCleared), LoopDestroyed => Ok(LoopDestroyed), - Suspended => Ok(Suspended), - Resumed => Ok(Resumed), Opened { urls } => Ok(Opened { urls }), Reopen { has_visible_windows, @@ -246,8 +224,6 @@ impl<'a, T> Event<'a, T> { RedrawRequested(wid) => Some(RedrawRequested(wid)), RedrawEventsCleared => Some(RedrawEventsCleared), LoopDestroyed => Some(LoopDestroyed), - Suspended => Some(Suspended), - Resumed => Some(Resumed), Opened { urls } => Some(Opened { urls }), Reopen { has_visible_windows, @@ -314,6 +290,24 @@ pub enum WindowEvent<'a> { /// - **macOS:** Fired if the [`crate::window::Window`] is dropped or the dock `Quit` item is clicked. Destroyed, + /// The window has been suspended. + /// + /// ## Platform-specific + /// + /// - **Android**: This is triggered by `onPause` method of the Activity. + /// - **iOS**: This is triggered by `applicationWillResignActive` method of the UIApplicationDelegate. + /// - **Linux / macOS / Windows**: Unsupported. + Suspended, + + /// The window has been resumed. + /// + /// ## Platform-specific + /// + /// - **Android**: This is triggered by `onResume` method of the Activity. The first onResume() is ignored to match the iOS implementation, since that is called on activity creation. + /// - **iOS**: This is triggered by `applicationWillEnterForeground` method of the UIApplicationDelegate. + /// - **Linux / macOS / Windows**: Unsupported. + Resumed, + /// A file has been dropped into the window. /// /// When the user drops multiple files at once, this event will be emitted for each file @@ -467,6 +461,8 @@ impl Clone for WindowEvent<'static> { Moved(pos) => Moved(*pos), CloseRequested => CloseRequested, Destroyed => Destroyed, + Suspended => Suspended, + Resumed => Resumed, DroppedFile(file) => DroppedFile(file.clone()), HoveredFile(file) => HoveredFile(file.clone()), HoveredFileCancelled => HoveredFileCancelled, @@ -559,6 +555,8 @@ impl<'a> WindowEvent<'a> { Moved(position) => Some(Moved(position)), CloseRequested => Some(CloseRequested), Destroyed => Some(Destroyed), + Suspended => Some(Suspended), + Resumed => Some(Resumed), DroppedFile(file) => Some(DroppedFile(file)), HoveredFile(file) => Some(HoveredFile(file)), HoveredFileCancelled => Some(HoveredFileCancelled), diff --git a/src/platform_impl/android/mod.rs b/src/platform_impl/android/mod.rs index e53808c09..07c4ece84 100644 --- a/src/platform_impl/android/mod.rs +++ b/src/platform_impl/android/mod.rs @@ -136,12 +136,15 @@ impl EventLoop { match self.first_event.take() { Some(EventSource::Callback) => match ndk_glue::poll_events().unwrap() { - Event::Resume => { + Event::Resume { id: window_id } => { call_event_handler!( event_handler, self.window_target(), control_flow, - event::Event::Resumed + event::Event::WindowEvent { + window_id, + event: event::WindowEvent::Resumed + } ); } Event::WindowEvent { @@ -174,12 +177,15 @@ impl EventLoop { } _ => {} }, - Event::Pause => { + Event::Pause { id: window_id } => { call_event_handler!( event_handler, self.window_target(), control_flow, - event::Event::Suspended + event::Event::WindowEvent { + window_id, + event: event::WindowEvent::Suspended + } ); } Event::Stop => self.running = false, @@ -785,7 +791,7 @@ impl Window { if let Some(w) = ndk_glue::activity_window_manager(self.activity_id).as_ref() { handle.a_native_window = w.as_obj().as_raw() as *mut _; } 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."); + panic!("Cannot get the native window, it's null and will always be null before WindowEvent::Resumed and after WindowEvent::Suspended. Make sure you only call this function between those events."); }; rwh_04::RawWindowHandle::AndroidNdk(handle) } @@ -797,7 +803,7 @@ impl Window { if let Some(w) = ndk_glue::activity_window_manager(self.activity_id).as_ref() { handle.a_native_window = w.as_obj().as_raw() as *mut _; } 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."); + panic!("Cannot get the native window, it's null and will always be null before WindowEvent::Resumed and after WindowEvent::Suspended. Make sure you only call this function between those events."); }; rwh_05::RawWindowHandle::AndroidNdk(handle) } diff --git a/src/platform_impl/android/ndk_glue.rs b/src/platform_impl/android/ndk_glue.rs index 628c7ee1e..ca4f6a0bc 100644 --- a/src/platform_impl/android/ndk_glue.rs +++ b/src/platform_impl/android/ndk_glue.rs @@ -25,10 +25,7 @@ use std::{ fs::File, io::{BufRead, BufReader}, os::unix::prelude::*, - sync::{ - atomic::{AtomicBool, Ordering}, - Arc, Condvar, Mutex, RwLock, RwLockReadGuard, - }, + sync::{Arc, Condvar, Mutex, RwLock, RwLockReadGuard}, thread, time::Duration, }; @@ -218,7 +215,7 @@ static INTENT_URLS: Lazy>> = Lazy::new(Default::default); static INPUT_QUEUE: Lazy>> = Lazy::new(Default::default); static CONTENT_RECT: Lazy> = Lazy::new(Default::default); static LOOPER: Lazy>> = Lazy::new(Default::default); -static DID_RESUME: AtomicBool = AtomicBool::new(false); +static RESUMED_ACTIVITIES: Lazy>> = Lazy::new(Default::default); pub fn main_window_manager() -> Option { WINDOW_MANAGER.lock().unwrap().values().next().cloned() @@ -240,6 +237,14 @@ pub fn content_rect() -> Rect { CONTENT_RECT.read().unwrap().clone() } +fn activity_id(env: &mut JNIEnv<'_>, activity: &JObject<'_>) -> ActivityId { + env + .call_method(activity, "getId", "()I", &[]) + .unwrap() + .i() + .unwrap() +} + pub fn main_android_context() -> Option { CONTEXTS.lock().unwrap().values().next().cloned() } @@ -298,8 +303,8 @@ pub struct Rect { #[repr(u8)] pub enum Event { Start, - Resume, - Pause, + Resume { id: WindowId }, + Pause { id: WindowId }, Stop, LowMemory, WindowEvent { id: WindowId, event: WindowEvent }, @@ -449,17 +454,23 @@ pub unsafe fn onActivityCreate( handle_intent(env, intent); } -pub unsafe fn resume(_: JNIEnv, _: JClass, _: JObject) { - let did_resume = DID_RESUME.swap(true, Ordering::Relaxed); +pub unsafe fn resume(mut env: JNIEnv, _: JClass, activity: JObject) { + let activity_id = activity_id(&mut env, &activity); + let did_resume = !RESUMED_ACTIVITIES.lock().unwrap().insert(activity_id); // first Activity onResume() is called even after onCreate() // to match the iOS implementation, we ignore the first resume event if did_resume { - wake(Event::Resume); + wake(Event::Resume { + id: WindowId(super::WindowId(activity_id)), + }); } } -pub unsafe fn pause(_: JNIEnv, _: JClass, _: JObject) { - wake(Event::Pause); +pub unsafe fn pause(mut env: JNIEnv, _: JClass, activity: JObject) { + let activity_id = activity_id(&mut env, &activity); + wake(Event::Pause { + id: WindowId(super::WindowId(activity_id)), + }); } #[allow(non_snake_case)] @@ -469,11 +480,7 @@ pub unsafe fn onWindowFocusChanged( activity: JObject, has_focus: libc::c_int, ) { - let activity_id = env - .call_method(&activity, "getId", "()I", &[]) - .unwrap() - .i() - .unwrap(); + let activity_id = activity_id(&mut env, &activity); let event = Event::WindowEvent { id: WindowId(super::WindowId(activity_id)), event: WindowEvent::Focused(has_focus != 0), @@ -691,11 +698,7 @@ pub unsafe fn stop(_: JNIEnv, _: JClass, _: JObject) { #[allow(non_snake_case)] pub unsafe fn onActivityDestroy(mut env: JNIEnv, _: JClass, activity: JObject) { - let activity_id = env - .call_method(&activity, "getId", "()I", &[]) - .unwrap() - .i() - .unwrap(); + let activity_id = activity_id(&mut env, &activity); let is_changing_configurations = env .call_method(&activity, "isChangingConfigurations", "()Z", &[]) @@ -712,6 +715,7 @@ pub unsafe fn onActivityDestroy(mut env: JNIEnv, _: JClass, activity: JObject) { }); CONTEXTS.lock().unwrap().remove(&activity_id); WINDOW_MANAGER.lock().unwrap().remove(&activity_id); + RESUMED_ACTIVITIES.lock().unwrap().remove(&activity_id); } } diff --git a/src/platform_impl/ios/mod.rs b/src/platform_impl/ios/mod.rs index ba183d445..08a994426 100644 --- a/src/platform_impl/ios/mod.rs +++ b/src/platform_impl/ios/mod.rs @@ -50,8 +50,10 @@ //! //! This is how those event are represented in tao: //! -//! - applicationWillEnterForeground is Resumed -//! - applicationWillResignActive is Suspended +//! - sceneWillEnterForeground is WindowEvent::Resumed for each window in the scene +//! - sceneWillResignActive is WindowEvent::Suspended for each window in the scene +//! - applicationWillEnterForeground is WindowEvent::Resumed for each window in non-scene apps +//! - applicationWillResignActive is WindowEvent::Suspended for each window in non-scene apps //! - applicationWillTerminate is LoopDestroyed //! //! Keep in mind that after LoopDestroyed event is received every attempt to draw with diff --git a/src/platform_impl/ios/scene.rs b/src/platform_impl/ios/scene.rs index 23414f06b..2cc980983 100644 --- a/src/platform_impl/ios/scene.rs +++ b/src/platform_impl/ios/scene.rs @@ -47,6 +47,17 @@ pub unsafe fn multiple_scenes_enabled() -> bool { (*num).as_bool() } +unsafe fn handle_scene_window_events(scene: &UIScene, event: impl Fn() -> WindowEvent<'static>) { + if let Some(window_scene) = scene.downcast_ref::() { + for window in window_scene.windows() { + app_state::handle_nonuser_event(EventWrapper::StaticEvent(Event::WindowEvent { + window_id: RootWindowId(window.into()), + event: event(), + })); + } + } +} + define_class!( #[unsafe(super(NSObject))] #[name = "TaoSceneDelegate"] @@ -89,19 +100,17 @@ define_class!( #[unsafe(method(sceneWillResignActive:))] fn sceneWillResignActive(&self, scene: &UIScene) { unsafe { - if let Some(window_scene) = scene.downcast_ref::() { - for window in window_scene.windows() { - app_state::handle_nonuser_event(EventWrapper::StaticEvent(Event::WindowEvent { - window_id: RootWindowId(window.into()), - event: WindowEvent::Focused(false), - })); - } - } + handle_scene_window_events(scene, || WindowEvent::Focused(false)); + handle_scene_window_events(scene, || WindowEvent::Suspended); } } #[unsafe(method(sceneWillEnterForeground:))] - fn sceneWillEnterForeground(&self, _scene: &UIScene) {} + fn sceneWillEnterForeground(&self, scene: &UIScene) { + unsafe { + handle_scene_window_events(scene, || WindowEvent::Resumed); + } + } #[unsafe(method(sceneDidEnterBackground:))] fn sceneDidEnterBackground(&self, _scene: &UIScene) {} diff --git a/src/platform_impl/ios/view.rs b/src/platform_impl/ios/view.rs index 7f37832fc..10c894f8d 100644 --- a/src/platform_impl/ios/view.rs +++ b/src/platform_impl/ios/view.rs @@ -665,6 +665,27 @@ pub fn create_delegate_class() { } } + unsafe fn handle_tao_window_events(event: impl Fn() -> WindowEvent<'static>) { + let app: id = msg_send![class!(UIApplication), sharedApplication]; + let windows: id = msg_send![app, windows]; + let windows_enum: id = msg_send![windows, objectEnumerator]; + let mut events = Vec::new(); + loop { + let window: id = msg_send![windows_enum, nextObject]; + if window == nil { + break; + } + let is_tao_window: bool = msg_send![window, isKindOfClass: class!(TaoUIWindow)]; + if is_tao_window { + events.push(EventWrapper::StaticEvent(Event::WindowEvent { + window_id: RootWindowId(window.into()), + event: event(), + })); + } + } + app_state::handle_nonuser_events(events); + } + // custom URL schemes // https://developer.apple.com/documentation/xcode/defining-a-custom-url-scheme-for-your-app extern "C" fn application_open_url( @@ -701,35 +722,16 @@ pub fn create_delegate_class() { } extern "C" fn will_resign_active(_: &Object, _: Sel, _: id) { - unsafe { app_state::handle_nonuser_event(EventWrapper::StaticEvent(Event::Suspended)) } + unsafe { handle_tao_window_events(|| WindowEvent::Suspended) } } extern "C" fn will_enter_foreground(_: &Object, _: Sel, _: id) { - unsafe { app_state::handle_nonuser_event(EventWrapper::StaticEvent(Event::Resumed)) } + unsafe { handle_tao_window_events(|| WindowEvent::Resumed) } } - extern "C" fn did_enter_background(_: &Object, _: Sel, _: id) {} - extern "C" fn will_terminate(_: &Object, _: Sel, _: id) { unsafe { - let app: id = msg_send![class!(UIApplication), sharedApplication]; - let windows: id = msg_send![app, windows]; - let windows_enum: id = msg_send![windows, objectEnumerator]; - let mut events = Vec::new(); - loop { - let window: id = msg_send![windows_enum, nextObject]; - if window == nil { - break; - } - let is_tao_window: bool = msg_send![window, isKindOfClass: class!(TaoUIWindow)]; - if is_tao_window { - events.push(EventWrapper::StaticEvent(Event::WindowEvent { - window_id: RootWindowId(window.into()), - event: WindowEvent::Destroyed, - })); - } - } - app_state::handle_nonuser_events(events); + handle_tao_window_events(|| WindowEvent::Destroyed); app_state::terminated(); } } @@ -742,12 +744,14 @@ pub fn create_delegate_class() { .expect("Failed to declare class `AppDelegate`"); unsafe { + let uses_scenes = multiple_scenes_enabled(); + decl.add_method( sel!(application:didFinishLaunchingWithOptions:), did_finish_launching as extern "C" fn(_, _, _, _) -> _, ); - if multiple_scenes_enabled() { + if uses_scenes { decl.add_method( sel!(application:configurationForConnectingSceneSession:options:), configuration_for_connecting_scene_session as extern "C" fn(_, _, _, _, _) -> _, @@ -764,18 +768,16 @@ pub fn create_delegate_class() { application_continue as extern "C" fn(_, _, _, _, _) -> _, ); - decl.add_method( - sel!(applicationWillResignActive:), - will_resign_active as extern "C" fn(_, _, _), - ); - decl.add_method( - sel!(applicationWillEnterForeground:), - will_enter_foreground as extern "C" fn(_, _, _), - ); - decl.add_method( - sel!(applicationDidEnterBackground:), - did_enter_background as extern "C" fn(_, _, _), - ); + if !uses_scenes { + decl.add_method( + sel!(applicationWillResignActive:), + will_resign_active as extern "C" fn(_, _, _), + ); + decl.add_method( + sel!(applicationWillEnterForeground:), + will_enter_foreground as extern "C" fn(_, _, _), + ); + } decl.add_method( sel!(applicationWillTerminate:), From f20bd58bb9ab71558acb05a82d3d4aed27c73ff9 Mon Sep 17 00:00:00 2001 From: Lucas Nogueira Date: Thu, 30 Apr 2026 11:41:49 -0300 Subject: [PATCH 2/2] move events --- .changes/window-lifecycle-events.md | 2 +- src/event.rs | 20 +++++++++++++++ src/platform_impl/android/mod.rs | 37 ++++++++++++++++++++++----- src/platform_impl/android/ndk_glue.rs | 30 ++++++++++++++-------- 4 files changed, 70 insertions(+), 19 deletions(-) diff --git a/.changes/window-lifecycle-events.md b/.changes/window-lifecycle-events.md index 9d2141f9f..2ac492337 100644 --- a/.changes/window-lifecycle-events.md +++ b/.changes/window-lifecycle-events.md @@ -2,4 +2,4 @@ "tao": minor --- -Moved `Suspended` and `Resumed` from `Event` to `WindowEvent` so Android and iOS lifecycle events are emitted for the specific window that was suspended or resumed. +Moved Android and iOS lifecycle events to `WindowEvent`, including `Started`, `Stopped`, `Suspended`, and `Resumed`, so they are emitted for the specific window whose activity or scene changed lifecycle state. diff --git a/src/event.rs b/src/event.rs index ac05804c9..0328bbfad 100644 --- a/src/event.rs +++ b/src/event.rs @@ -290,6 +290,14 @@ pub enum WindowEvent<'a> { /// - **macOS:** Fired if the [`crate::window::Window`] is dropped or the dock `Quit` item is clicked. Destroyed, + /// The window has been started. + /// + /// ## Platform-specific + /// + /// - **Android**: This is triggered by `onStart` method of the Activity. + /// - **Linux / macOS / iOS / Windows**: Unsupported. + Started, + /// The window has been suspended. /// /// ## Platform-specific @@ -308,6 +316,14 @@ pub enum WindowEvent<'a> { /// - **Linux / macOS / Windows**: Unsupported. Resumed, + /// The window has been stopped. + /// + /// ## Platform-specific + /// + /// - **Android**: This is triggered by `onStop` method of the Activity. + /// - **Linux / macOS / iOS / Windows**: Unsupported. + Stopped, + /// A file has been dropped into the window. /// /// When the user drops multiple files at once, this event will be emitted for each file @@ -461,8 +477,10 @@ impl Clone for WindowEvent<'static> { Moved(pos) => Moved(*pos), CloseRequested => CloseRequested, Destroyed => Destroyed, + Started => Started, Suspended => Suspended, Resumed => Resumed, + Stopped => Stopped, DroppedFile(file) => DroppedFile(file.clone()), HoveredFile(file) => HoveredFile(file.clone()), HoveredFileCancelled => HoveredFileCancelled, @@ -555,8 +573,10 @@ impl<'a> WindowEvent<'a> { Moved(position) => Some(Moved(position)), CloseRequested => Some(CloseRequested), Destroyed => Some(Destroyed), + Started => Some(Started), Suspended => Some(Suspended), Resumed => Some(Resumed), + Stopped => Some(Stopped), DroppedFile(file) => Some(DroppedFile(file)), HoveredFile(file) => Some(HoveredFile(file)), HoveredFileCancelled => Some(HoveredFileCancelled), diff --git a/src/platform_impl/android/mod.rs b/src/platform_impl/android/mod.rs index 07c4ece84..e3e17953c 100644 --- a/src/platform_impl/android/mod.rs +++ b/src/platform_impl/android/mod.rs @@ -17,7 +17,7 @@ use ndk::{ }; use once_cell::sync::Lazy; use std::{ - collections::VecDeque, + collections::{HashSet, VecDeque}, sync::RwLock, time::{Duration, Instant}, }; @@ -72,7 +72,7 @@ pub struct EventLoop { first_event: Option, start_cause: event::StartCause, looper: ThreadLooper, - running: bool, + running: HashSet, } #[derive(Default, Debug, Copy, Clone, PartialEq, Eq, Hash)] @@ -104,7 +104,7 @@ impl EventLoop { first_event: None, start_cause: event::StartCause::Init, looper: ThreadLooper::for_thread().unwrap(), - running: false, + running: HashSet::new(), } } @@ -153,6 +153,18 @@ impl EventLoop { } => match event { WindowEvent::Resized => resized_window_id = Some(window_id), WindowEvent::RedrawNeeded => redraw_window_id = Some(window_id), + WindowEvent::Started => { + self.running.insert(window_id); + call_event_handler!( + event_handler, + self.window_target(), + control_flow, + event::Event::WindowEvent { + window_id, + event: event::WindowEvent::Started, + } + ); + } WindowEvent::Focused(focused) => { call_event_handler!( event_handler, @@ -164,7 +176,20 @@ impl EventLoop { } ); } + WindowEvent::Stopped => { + self.running.remove(&window_id); + call_event_handler!( + event_handler, + self.window_target(), + control_flow, + event::Event::WindowEvent { + window_id, + event: event::WindowEvent::Stopped, + } + ); + } WindowEvent::Destroyed => { + self.running.remove(&window_id); call_event_handler!( event_handler, self.window_target(), @@ -188,8 +213,6 @@ impl EventLoop { } ); } - Event::Stop => self.running = false, - Event::Start => self.running = true, Event::Opened => { let urls = ndk_glue::take_intent_urls(); if !urls.is_empty() { @@ -342,7 +365,7 @@ impl EventLoop { ); if let Some(window_id) = resized_window_id { - if self.running { + if self.running.contains(&window_id) { let size = MonitorHandle.size(); let event = event::Event::WindowEvent { window_id, @@ -353,7 +376,7 @@ impl EventLoop { } if let Some(window_id) = redraw_window_id { - if self.running { + if self.running.contains(&window_id) { let event = event::Event::RedrawRequested(window_id); call_event_handler!(event_handler, self.window_target(), control_flow, event); } diff --git a/src/platform_impl/android/ndk_glue.rs b/src/platform_impl/android/ndk_glue.rs index ca4f6a0bc..aea7bea63 100644 --- a/src/platform_impl/android/ndk_glue.rs +++ b/src/platform_impl/android/ndk_glue.rs @@ -62,10 +62,10 @@ const DATA_URL_ENCODING_SET: &AsciiSet = &CONTROLS /// 2. android package anme (for ex: wryapp) /// 3. the android activity that has external linking for the following functions and calls them: /// - `private external fun onActivityCreate(activity: WryActivity)`` -/// - `private external fun start()` -/// - `private external fun resume()` -/// - `private external fun pause()` -/// - `private external fun stop()` +/// - `private external fun start(activity: WryActivity)` +/// - `private external fun resume(activity: WryActivity)` +/// - `private external fun pause(activity: WryActivity)` +/// - `private external fun stop(activity: WryActivity)` /// - `private external fun onActivitySaveInstanceState()` /// - `private external fun onActivityDestroy(activity: WryActivity)` /// - `private external fun onActivityLowMemory()` @@ -268,7 +268,7 @@ pub static PIPE: Lazy<[OwnedFd; 2]> = Lazy::new(|| { pub fn poll_events() -> Option { unsafe { let size = std::mem::size_of::(); - let mut event = Event::Start; + let mut event = Event::LowMemory; if libc::read(PIPE[0].as_raw_fd(), &mut event as *mut _ as *mut _, size) == size as libc::ssize_t { @@ -302,10 +302,8 @@ pub struct Rect { #[derive(Clone, Debug, Eq, PartialEq, Copy)] #[repr(u8)] pub enum Event { - Start, Resume { id: WindowId }, Pause { id: WindowId }, - Stop, LowMemory, WindowEvent { id: WindowId, event: WindowEvent }, ContentRectChanged, @@ -317,8 +315,10 @@ pub enum Event { pub enum WindowEvent { Focused(bool), Created, + Started, Resized, RedrawNeeded, + Stopped, Destroyed, } @@ -688,12 +688,20 @@ pub unsafe fn handle_intent(mut env: JNIEnv, intent: JObject) { } } -pub unsafe fn start(_: JNIEnv, _: JClass, _: JObject) { - wake(Event::Start); +pub unsafe fn start(mut env: JNIEnv, _: JClass, activity: JObject) { + let activity_id = activity_id(&mut env, &activity); + wake(Event::WindowEvent { + id: WindowId(super::WindowId(activity_id)), + event: WindowEvent::Started, + }); } -pub unsafe fn stop(_: JNIEnv, _: JClass, _: JObject) { - wake(Event::Stop); +pub unsafe fn stop(mut env: JNIEnv, _: JClass, activity: JObject) { + let activity_id = activity_id(&mut env, &activity); + wake(Event::WindowEvent { + id: WindowId(super::WindowId(activity_id)), + event: WindowEvent::Stopped, + }); } #[allow(non_snake_case)]