diff --git a/Cargo.toml b/Cargo.toml index 8e5a107f66..be6cbb2e1e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,9 +35,9 @@ image = "0.22.4" simple_logger = "1.4.0" [target.'cfg(target_os = "android")'.dependencies] -android_glue = { git = "https://github.com/rust-windowing/android-rs-glue" } -android-ndk = { git = "https://github.com/rust-windowing/android-ndk-rs" } -android-ndk-sys = { git = "https://github.com/rust-windowing/android-ndk-rs" } +android-glue = { path = "../../android-ndk-rs/android-glue" } +android-ndk = { path = "../../android-ndk-rs/android-ndk", default-features = false } +android-ndk-sys = { path = "../../android-ndk-rs/android-ndk-sys", default-features = false } [target.'cfg(target_os = "ios")'.dependencies] objc = "0.2.7" diff --git a/src/platform/android.rs b/src/platform/android.rs index 73ef7971fa..fc79d19349 100644 --- a/src/platform/android.rs +++ b/src/platform/android.rs @@ -6,7 +6,7 @@ use glutin_interface::{ AndroidWindowParts, NativeDisplay, NativeWindow, NativeWindowSource, RawDisplay, RawWindow, Seal, }; -use std::os::raw; +use raw_window_handle::{HasRawWindowHandle, RawWindowHandle}; use winit_types::dpi::PhysicalSize; use winit_types::error::Error; @@ -19,15 +19,9 @@ impl EventLoopExtAndroid for EventLoop {} pub trait EventLoopWindowTargetExtAndroid {} /// Additional methods on `Window` that are specific to Android. -pub trait WindowExtAndroid { - fn a_native_window(&self) -> *const *mut raw::c_void; -} +pub trait WindowExtAndroid {} -impl WindowExtAndroid for Window { - fn a_native_window(&self) -> *const *mut raw::c_void { - self.window.a_native_window() - } -} +impl WindowExtAndroid for Window {} /// Additional methods on `WindowBuilder` that are specific to Android. pub trait WindowBuilderExtAndroid {} @@ -36,9 +30,13 @@ impl WindowBuilderExtAndroid for WindowBuilder {} impl NativeWindow for Window { fn raw_window(&self) -> RawWindow { - RawWindow::Android { - a_native_window: self.a_native_window(), - _non_exhaustive_do_not_use: Seal, + if let RawWindowHandle::Android(handle) = self.raw_window_handle() { + RawWindow::Android { + a_native_window: handle.a_native_window, + _non_exhaustive_do_not_use: Seal, + } + } else { + unreachable!() } } diff --git a/src/platform_impl/android/mod.rs b/src/platform_impl/android/mod.rs index 7d5159374c..ae2761b186 100644 --- a/src/platform_impl/android/mod.rs +++ b/src/platform_impl/android/mod.rs @@ -4,37 +4,31 @@ use crate::event; use crate::event_loop::{self, ControlFlow}; use crate::monitor; use crate::window; -use android_ndk::android_app::{AndroidApp, Cmd}; +use android_glue::Event; use android_ndk::event::{InputEvent, MotionAction}; use android_ndk::looper::{ForeignLooper, Poll, ThreadLooper}; -use android_ndk_sys::native_app_glue; use std::collections::VecDeque; use std::fmt::{Display, Formatter}; -use std::os::raw; use std::sync::{Arc, Mutex}; use std::time::{Duration, Instant}; use winit_types::dpi::{PhysicalPosition, PhysicalSize, Position, Size}; use winit_types::error::{Error, ErrorType}; -pub enum Event { - Cmd, - Input, +enum EventSource { + Callback, + InputQueue, User, } -fn convert(poll: Poll) -> Option { +fn poll(poll: Poll) -> Option { match poll { - Poll::Event { data, .. } => { - assert!(!data.is_null()); - let source = unsafe { &*(data as *const native_app_glue::android_poll_source) }; - Some(match source.id { - native_app_glue::LOOPER_ID_MAIN => Event::Cmd, - native_app_glue::LOOPER_ID_INPUT => Event::Input, - _ => unreachable!(), - }) - } + Poll::Event { data, .. } => match data as usize { + 0 => Some(EventSource::Callback), + 1 => Some(EventSource::InputQueue), + _ => unreachable!(), + }, Poll::Timeout => None, - Poll::Wake => Some(Event::User), + Poll::Wake => Some(EventSource::User), Poll::Callback => unreachable!(), } } @@ -63,17 +57,10 @@ impl EventLoop { + FnMut(event::Event<'_, T>, &event_loop::EventLoopWindowTarget, &mut ControlFlow), { let mut cf = ControlFlow::default(); - - let mut start_cause = event::StartCause::Init; let mut first_event = None; - - let mut android_app = unsafe { AndroidApp::from_ptr(android_glue::get_android_app()) }; + let mut start_cause = event::StartCause::Init; let looper = ThreadLooper::for_thread().unwrap(); - let mut running = false; - let mut prev_size = MonitorHandle.size(); - let mut frame = 0u64; - let mut redraw_queue = VecDeque::with_capacity(5); loop { event_handler( @@ -83,105 +70,94 @@ impl EventLoop { ); let mut redraw = false; + let mut resized = false; + match first_event.take() { - Some(Event::Cmd) => { - android_app.handle_cmd(|_, cmd| match cmd { - // NOTE: Commands WindowResized and WindowRedrawNeeded - // are not used in the android ndk glue. ConfigChanged - // is unreliable way of detecting orientation changes - // because the event is fired before ANativeWindow - // updates it's width and height. It also fires when - // the phone is rotated 180 degrees even though no - // redraw is required. - Cmd::InitWindow => { - redraw = true; - event_handler(event::Event::Resumed, self.window_target(), &mut cf); - } - Cmd::TermWindow => { - event_handler(event::Event::Suspended, self.window_target(), &mut cf); - } - Cmd::ConfigChanged => { - let size = MonitorHandle.size(); - if prev_size != size { - prev_size = size; - redraw_queue.push_back((frame + 5, size)); - } - } - Cmd::Pause => { - running = false; - } - Cmd::Resume => { - running = true; - } - _ => {} - }); - } - Some(Event::Input) => { - let input_queue = android_app - .input_queue() - .expect("native_app_glue set the input_queue field"); - while let Some(event) = input_queue.get_event() { - if let Some(event) = input_queue.pre_dispatch(event) { - let window_id = window::WindowId(WindowId); - let device_id = event::DeviceId(DeviceId); - match &event { - InputEvent::MotionEvent(motion_event) => { - let phase = match motion_event.action() { - MotionAction::Down => Some(event::TouchPhase::Started), - MotionAction::Up => Some(event::TouchPhase::Ended), - MotionAction::Move => Some(event::TouchPhase::Moved), - MotionAction::Cancel => Some(event::TouchPhase::Cancelled), - _ => None, // TODO mouse events - }; - let pointer = motion_event.pointer_at_index(0); - let location = PhysicalPosition { - x: pointer.x() as _, - y: pointer.y() as _, - }; - - if let Some(phase) = phase { - let event = event::Event::WindowEvent { - window_id, - event: event::WindowEvent::Touch(event::Touch { - device_id, - phase, - location, - id: 0, - force: None, - }), + Some(EventSource::Callback) => match android_glue::poll_events().unwrap() { + Event::WindowCreated => { + event_handler(event::Event::Resumed, self.window_target(), &mut cf); + } + Event::WindowResized => resized = true, + Event::WindowRedrawNeeded => redraw = true, + Event::WindowDestroyed => { + event_handler(event::Event::Suspended, self.window_target(), &mut cf); + } + Event::Pause => running = false, + Event::Resume => running = true, + Event::InputQueueCreated => { + android_glue::input_queue() + .lock() + .unwrap() + .as_ref() + .unwrap() + .attach_looper(looper.as_foreign(), 1); + } + Event::InputQueueDestroyed => { + android_glue::input_queue() + .lock() + .unwrap() + .as_ref() + .unwrap() + .detach_looper(); + } + _ => {} + }, + Some(EventSource::InputQueue) => { + if let Some(input_queue) = android_glue::input_queue().lock().unwrap().as_ref() + { + while let Some(event) = input_queue.get_event() { + if let Some(event) = input_queue.pre_dispatch(event) { + let window_id = window::WindowId(WindowId); + let device_id = event::DeviceId(DeviceId); + match &event { + InputEvent::MotionEvent(motion_event) => { + let phase = match motion_event.action() { + MotionAction::Down => Some(event::TouchPhase::Started), + MotionAction::Up => Some(event::TouchPhase::Ended), + MotionAction::Move => Some(event::TouchPhase::Moved), + MotionAction::Cancel => { + Some(event::TouchPhase::Cancelled) + } + _ => None, // TODO mouse events + }; + let pointer = motion_event.pointer_at_index(0); + let location = PhysicalPosition { + x: pointer.x() as _, + y: pointer.y() as _, }; - event_handler(event, self.window_target(), &mut cf); + + if let Some(phase) = phase { + let event = event::Event::WindowEvent { + window_id, + event: event::WindowEvent::Touch(event::Touch { + device_id, + phase, + location, + id: 0, + force: None, + }), + }; + event_handler(event, self.window_target(), &mut cf); + } } - } - InputEvent::KeyEvent(_) => {} // TODO - }; - input_queue.finish_event(event, true); + InputEvent::KeyEvent(_) => {} // TODO + }; + input_queue.finish_event(event, true); + } } } } - _ => {} - } - - let mut user_queue = self.user_queue.lock().unwrap(); - while let Some(event) = user_queue.pop_front() { - event_handler( - event::Event::UserEvent(event), - self.window_target(), - &mut cf, - ); - } - - if let Some((rframe, size)) = redraw_queue.pop_front() { - redraw = true; - if frame >= rframe { - let event = event::Event::WindowEvent { - window_id: window::WindowId(WindowId), - event: event::WindowEvent::Resized(size), - }; - event_handler(event, self.window_target(), &mut cf); - } else { - redraw_queue.push_front((rframe, size)); + Some(EventSource::User) => { + let mut user_queue = self.user_queue.lock().unwrap(); + while let Some(event) = user_queue.pop_front() { + event_handler( + event::Event::UserEvent(event), + self.window_target(), + &mut cf, + ); + } } + None => {} } event_handler( @@ -190,11 +166,19 @@ impl EventLoop { &mut cf, ); - if running && redraw { + if resized && running { + let size = MonitorHandle.size(); + let event = event::Event::WindowEvent { + window_id: window::WindowId(WindowId), + event: event::WindowEvent::Resized(size), + }; + event_handler(event, self.window_target(), &mut cf); + } + + if redraw && running { let event = event::Event::RedrawRequested(window::WindowId(WindowId)); event_handler(event, self.window_target(), &mut cf); } - frame += 1; event_handler( event::Event::RedrawEventsCleared, @@ -202,20 +186,13 @@ impl EventLoop { &mut cf, ); - if redraw_queue.len() > 0 { - if cf == ControlFlow::Wait { - let until = Instant::now() + Duration::from_millis(10); - cf = ControlFlow::WaitUntil(until); - } - } - match cf { ControlFlow::Exit => panic!(), ControlFlow::Poll => { start_cause = event::StartCause::Poll; } ControlFlow::Wait => { - first_event = convert(looper.poll_all().unwrap()); + first_event = poll(looper.poll_all().unwrap()); start_cause = event::StartCause::WaitCancelled { start: Instant::now(), requested_resume: None, @@ -228,7 +205,7 @@ impl EventLoop { } else { instant - start }; - first_event = convert(looper.poll_all_timeout(duration).unwrap()); + first_event = poll(looper.poll_all_timeout(duration).unwrap()); start_cause = if first_event.is_some() { event::StartCause::WaitCancelled { start, @@ -320,8 +297,7 @@ impl MonitorHandle { } pub fn size(&self) -> PhysicalSize { - let android_app = unsafe { AndroidApp::from_ptr(android_glue::get_android_app()) }; - if let Some(native_window) = android_app.native_window() { + if let Some(native_window) = android_glue::native_window().lock().unwrap().as_ref() { let width = native_window.width() as _; let height = native_window.height() as _; PhysicalSize::new(width, height) @@ -335,12 +311,14 @@ impl MonitorHandle { } pub fn scale_factor(&self) -> f64 { - let android_app = unsafe { AndroidApp::from_ptr(android_glue::get_android_app()) }; + // TODO + 1.0 + /*let android_app = android_glue::get_android_app(); android_app .config() .density() .map(|dpi| dpi as f64 / 160.0) - .unwrap_or(1.0) + .unwrap_or(1.0)*/ } pub fn video_modes(&self) -> impl Iterator { @@ -417,7 +395,6 @@ impl Window { } pub fn inner_size(&self) -> PhysicalSize { - // TODO need to subtract system bar self.outer_size() } @@ -429,35 +406,19 @@ impl Window { MonitorHandle.size() } - pub fn set_min_inner_size(&self, _: Option) { - // no effect - } + pub fn set_min_inner_size(&self, _: Option) {} - pub fn set_max_inner_size(&self, _: Option) { - // no effect - } + pub fn set_max_inner_size(&self, _: Option) {} - pub fn set_title(&self, _title: &str) { - // TODO there's probably a way to do this - // no effect - } + pub fn set_title(&self, _title: &str) {} - pub fn set_visible(&self, _visibility: bool) { - // no effect - } + pub fn set_visible(&self, _visibility: bool) {} - pub fn set_resizable(&self, _resizeable: bool) { - // no effect - // Should probably have an effect with multi-windows though - } + pub fn set_resizable(&self, _resizeable: bool) {} - pub fn set_minimized(&self, _minimized: bool) { - // no effect - } + pub fn set_minimized(&self, _minimized: bool) {} - pub fn set_maximized(&self, _maximized: bool) { - // no effect - } + pub fn set_maximized(&self, _maximized: bool) {} pub fn set_fullscreen(&self, _monitor: Option) -> Result<(), Error> { Err(make_error!(ErrorType::NotSupported( @@ -466,30 +427,18 @@ impl Window { } pub fn fullscreen(&self) -> Option { - // no efffect None } - pub fn set_decorations(&self, _decorations: bool) { - // TODO - } + pub fn set_decorations(&self, _decorations: bool) {} - pub fn set_always_on_top(&self, _always_on_top: bool) { - // no effect - } + pub fn set_always_on_top(&self, _always_on_top: bool) {} - pub fn set_window_icon(&self, _window_icon: Option) { - // no effect - } + pub fn set_window_icon(&self, _window_icon: Option) {} - pub fn set_ime_position(&self, _position: Position) { - // no effect - // What is an IME candidate box? - } + pub fn set_ime_position(&self, _position: Position) {} - pub fn set_cursor_icon(&self, _: window::CursorIcon) { - // no effect - } + pub fn set_cursor_icon(&self, _: window::CursorIcon) {} pub fn set_cursor_position(&self, _: Position) -> Result<(), Error> { Err(make_error!(ErrorType::NotSupported( @@ -503,18 +452,17 @@ impl Window { ))) } - pub fn set_cursor_visible(&self, _: bool) { - // no effect - } - - pub fn a_native_window(&self) -> *const *mut raw::c_void { - unsafe { &android_glue::get_android_app().as_ref().window as *const _ as *const _ } - } + pub fn set_cursor_visible(&self, _: bool) {} pub fn raw_window_handle(&self) -> raw_window_handle::RawWindowHandle { + let a_native_window = + if let Some(native_window) = android_glue::native_window().lock().unwrap().as_ref() { + unsafe { native_window.ptr().as_mut() as *mut _ as *mut _ } + } else { + panic!("native window null"); + }; let mut handle = raw_window_handle::android::AndroidHandle::empty(); - handle.a_native_window = - unsafe { android_glue::get_android_app().as_ref() }.window as *mut _; + handle.a_native_window = a_native_window; raw_window_handle::RawWindowHandle::Android(handle) } }