Update Android code with EventsLoop (#272)

* Update Android code with EventsLoop

* Fix run_forever
This commit is contained in:
tomaka 2017-09-04 12:41:02 +02:00 committed by GitHub
parent 5b57b73fe8
commit fe1deb83ae

View file

@ -3,12 +3,11 @@
extern crate android_glue;
use libc;
use std::ffi::{CString};
use std::sync::mpsc::{Receiver, channel};
use std::os::raw::c_void;
use {CreationError, WindowEvent as Event, MouseCursor};
use {CreationError, Event, WindowEvent, MouseCursor};
use CreationError::OsError;
use events::ElementState::{Pressed, Released};
use WindowId as RootWindowId;
use events::{Touch, TouchPhase};
use std::collections::VecDeque;
@ -17,30 +16,132 @@ use CursorState;
use WindowAttributes;
use FullScreenState;
gen_api_transition!();
pub struct Window {
native_window: *const c_void,
pub struct EventsLoop {
event_rx: Receiver<android_glue::Event>,
}
pub struct EventsLoopProxy;
impl EventsLoop {
pub fn new() -> EventsLoop {
let (tx, rx) = channel();
android_glue::add_sender(tx);
EventsLoop {
event_rx: rx,
}
}
#[inline]
pub fn get_available_monitors(&self) -> VecDeque<MonitorId> {
let mut rb = VecDeque::new();
rb.push_back(MonitorId);
rb
}
#[inline]
pub fn get_primary_monitor(&self) -> MonitorId {
MonitorId
}
pub fn poll_events<F>(&mut self, mut callback: F)
where F: FnMut(::Event)
{
let event = match self.event_rx.try_recv() {
Ok(android_glue::Event::EventMotion(motion)) => {
Some(WindowEvent::Touch(Touch {
phase: match motion.action {
android_glue::MotionAction::Down => TouchPhase::Started,
android_glue::MotionAction::Move => TouchPhase::Moved,
android_glue::MotionAction::Up => TouchPhase::Ended,
android_glue::MotionAction::Cancel => TouchPhase::Cancelled,
},
location: (motion.x as f64, motion.y as f64),
id: motion.pointer_id as u64,
device_id: DEVICE_ID,
}))
},
Ok(android_glue::Event::InitWindow) => {
// The activity went to foreground.
Some(WindowEvent::Suspended(false))
},
Ok(android_glue::Event::TermWindow) => {
// The activity went to background.
Some(WindowEvent::Suspended(true))
},
Ok(android_glue::Event::WindowResized) |
Ok(android_glue::Event::ConfigChanged) => {
// Activity Orientation changed or resized.
let native_window = unsafe { android_glue::get_native_window() };
if native_window.is_null() {
None
} else {
let w = unsafe { ffi::ANativeWindow_getWidth(native_window as *const _) } as u32;
let h = unsafe { ffi::ANativeWindow_getHeight(native_window as *const _) } as u32;
Some(WindowEvent::Resized(w, h))
}
},
Ok(android_glue::Event::WindowRedrawNeeded) => {
// The activity needs to be redrawn.
Some(WindowEvent::Refresh)
}
_ => {
None
}
};
if let Some(event) = event {
callback(Event::WindowEvent {
window_id: RootWindowId(WindowId),
event: event
});
}
}
pub fn run_forever<F>(&mut self, mut callback: F)
where F: FnMut(::Event) -> ::ControlFlow,
{
// Yeah that's a very bad implementation.
loop {
let mut control_flow = ::ControlFlow::Continue;
self.poll_events(|e| {
if let ::ControlFlow::Break = callback(e) {
control_flow = ::ControlFlow::Break;
}
});
if let ::ControlFlow::Break = control_flow {
break;
}
::std::thread::sleep(::std::time::Duration::from_millis(5));
}
}
pub fn create_proxy(&self) -> EventsLoopProxy {
EventsLoopProxy
}
}
impl EventsLoopProxy {
pub fn wakeup(&self) -> Result<(), ::EventsLoopClosed> {
android_glue::wake_event_loop();
Ok(())
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct WindowId;
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct DeviceId;
pub struct Window2 {
native_window: *const c_void,
}
#[derive(Clone)]
pub struct MonitorId;
mod ffi;
#[inline]
pub fn get_available_monitors() -> VecDeque<MonitorId> {
let mut rb = VecDeque::new();
rb.push_back(MonitorId);
rb
}
#[inline]
pub fn get_primary_monitor() -> MonitorId {
MonitorId
}
impl MonitorId {
#[inline]
pub fn get_name(&self) -> Option<String> {
@ -58,79 +159,11 @@ pub struct PlatformSpecificWindowBuilderAttributes;
#[derive(Clone, Default)]
pub struct PlatformSpecificHeadlessBuilderAttributes;
pub struct PollEventsIterator<'a> {
window: &'a Window,
}
impl<'a> Iterator for PollEventsIterator<'a> {
type Item = Event;
fn next(&mut self) -> Option<Event> {
match self.window.event_rx.try_recv() {
Ok(android_glue::Event::EventMotion(motion)) => {
Some(Event::Touch(Touch {
phase: match motion.action {
android_glue::MotionAction::Down => TouchPhase::Started,
android_glue::MotionAction::Move => TouchPhase::Moved,
android_glue::MotionAction::Up => TouchPhase::Ended,
android_glue::MotionAction::Cancel => TouchPhase::Cancelled,
},
location: (motion.x as f64, motion.y as f64),
id: motion.pointer_id as u64,
device_id: DEVICE_ID,
}))
},
Ok(android_glue::Event::InitWindow) => {
// The activity went to foreground.
Some(Event::Suspended(false))
},
Ok(android_glue::Event::TermWindow) => {
// The activity went to background.
Some(Event::Suspended(true))
},
Ok(android_glue::Event::WindowResized) |
Ok(android_glue::Event::ConfigChanged) => {
// Activity Orientation changed or resized.
self.window.get_inner_size().map(|s| Event::Resized(s.0, s.1))
},
Ok(android_glue::Event::WindowRedrawNeeded) => {
// The activity needs to be redrawn.
Some(Event::Refresh)
}
_ => {
None
}
}
}
}
pub struct WaitEventsIterator<'a> {
window: &'a Window,
}
impl<'a> Iterator for WaitEventsIterator<'a> {
type Item = Event;
#[inline]
fn next(&mut self) -> Option<Event> {
loop {
// calling poll_events()
if let Some(ev) = self.window.poll_events().next() {
return Some(ev);
}
// TODO: Implement a proper way of sleeping on the event queue
// timer::sleep(Duration::milliseconds(16));
}
}
}
impl Window {
pub fn new(win_attribs: &WindowAttributes, _: &PlatformSpecificWindowBuilderAttributes)
-> Result<Window, CreationError>
impl Window2 {
pub fn new(_: &EventsLoop, win_attribs: &WindowAttributes,
_: &PlatformSpecificWindowBuilderAttributes)
-> Result<Window2, CreationError>
{
use std::{mem, ptr};
// not implemented
assert!(win_attribs.min_dimensions.is_none());
assert!(win_attribs.max_dimensions.is_none());
@ -140,13 +173,10 @@ impl Window {
return Err(OsError(format!("Android's native window is null")));
}
let (tx, rx) = channel();
android_glue::add_sender(tx);
android_glue::set_multitouch(win_attribs.multitouch);
Ok(Window {
Ok(Window2 {
native_window: native_window as *const _,
event_rx: rx,
})
}
@ -155,11 +185,6 @@ impl Window {
self.native_window
}
#[inline]
pub fn is_closed(&self) -> bool {
false
}
#[inline]
pub fn set_title(&self, _: &str) {
}
@ -183,14 +208,12 @@ impl Window {
#[inline]
pub fn get_inner_size(&self) -> Option<(u32, u32)> {
let native_window = unsafe { android_glue::get_native_window() };
if native_window.is_null() {
if self.native_window.is_null() {
None
} else {
Some((
unsafe { ffi::ANativeWindow_getWidth(native_window as *const _) } as u32,
unsafe { ffi::ANativeWindow_getHeight(native_window as *const _) } as u32
unsafe { ffi::ANativeWindow_getWidth(self.native_window as *const _) } as u32,
unsafe { ffi::ANativeWindow_getHeight(self.native_window as *const _) } as u32
))
}
}
@ -204,25 +227,6 @@ impl Window {
pub fn set_inner_size(&self, _x: u32, _y: u32) {
}
#[inline]
pub fn create_window_proxy(&self) -> WindowProxy {
WindowProxy
}
#[inline]
pub fn poll_events(&self) -> PollEventsIterator {
PollEventsIterator {
window: self
}
}
#[inline]
pub fn wait_events(&self) -> WaitEventsIterator {
WaitEventsIterator {
window: self
}
}
#[inline]
pub fn platform_display(&self) -> *mut libc::c_void {
unimplemented!();
@ -233,16 +237,12 @@ impl Window {
unimplemented!()
}
#[inline]
pub fn set_window_resize_callback(&mut self, _: Option<fn(u32, u32)>) {
}
#[inline]
pub fn set_cursor(&self, _: MouseCursor) {
}
#[inline]
pub fn set_cursor_state(&self, state: CursorState) -> Result<(), String> {
pub fn set_cursor_state(&self, _state: CursorState) -> Result<(), String> {
Ok(())
}
@ -252,31 +252,25 @@ impl Window {
}
#[inline]
pub fn set_cursor_position(&self, x: i32, y: i32) -> Result<(), ()> {
unimplemented!();
pub fn set_cursor_position(&self, _x: i32, _y: i32) -> Result<(), ()> {
Ok(())
}
#[inline]
pub fn set_maximized(&self, maximized: bool) {
pub fn set_maximized(&self, _maximized: bool) {
}
#[inline]
pub fn set_fullscreen(&self, state: FullScreenState) {
pub fn set_fullscreen(&self, _state: FullScreenState) {
}
pub fn id(&self) -> WindowId {
WindowId
}
}
unsafe impl Send for Window {}
unsafe impl Sync for Window {}
#[derive(Clone)]
pub struct WindowProxy;
impl WindowProxy {
#[inline]
pub fn wakeup_event_loop(&self) {
android_glue::wake_event_loop();
}
}
unsafe impl Send for Window2 {}
unsafe impl Sync for Window2 {}
// Constant device ID, to be removed when this backend is updated to report real device IDs.
const DEVICE_ID: ::DeviceId = ::DeviceId(DeviceId);