2016-12-14 00:28:30 +11:00
|
|
|
//! iOS support
|
|
|
|
//!
|
|
|
|
//! # Building app
|
|
|
|
//! To build ios app you will need rustc built for this targets:
|
|
|
|
//!
|
|
|
|
//! - armv7-apple-ios
|
|
|
|
//! - armv7s-apple-ios
|
|
|
|
//! - i386-apple-ios
|
|
|
|
//! - aarch64-apple-ios
|
|
|
|
//! - x86_64-apple-ios
|
|
|
|
//!
|
|
|
|
//! Then
|
|
|
|
//!
|
|
|
|
//! ```
|
|
|
|
//! cargo build --target=...
|
|
|
|
//! ```
|
|
|
|
//! The simplest way to integrate your app into xcode environment is to build it
|
|
|
|
//! as a static library. Wrap your main function and export it.
|
|
|
|
//!
|
|
|
|
//! ```rust, ignore
|
|
|
|
//! #[no_mangle]
|
|
|
|
//! pub extern fn start_glutin_app() {
|
|
|
|
//! start_inner()
|
|
|
|
//! }
|
|
|
|
//!
|
|
|
|
//! fn start_inner() {
|
|
|
|
//! ...
|
|
|
|
//! }
|
|
|
|
//!
|
|
|
|
//! ```
|
|
|
|
//!
|
|
|
|
//! Compile project and then drag resulting .a into Xcode project. Add glutin.h to xcode.
|
|
|
|
//!
|
2016-12-14 00:37:13 +11:00
|
|
|
//! ```ignore
|
2016-12-14 00:28:30 +11:00
|
|
|
//! void start_glutin_app();
|
|
|
|
//! ```
|
|
|
|
//!
|
|
|
|
//! Use start_glutin_app inside your xcode's main function.
|
|
|
|
//!
|
|
|
|
//!
|
|
|
|
//! # App lifecycle and events
|
|
|
|
//!
|
|
|
|
//! iOS environment is very different from other platforms and you must be very
|
|
|
|
//! careful with it's events. Familiarize yourself with
|
|
|
|
//! [app lifecycle](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIApplicationDelegate_Protocol/).
|
|
|
|
//!
|
|
|
|
//!
|
|
|
|
//! This is how those event are represented in glutin:
|
|
|
|
//!
|
|
|
|
//! - applicationDidBecomeActive is Focused(true)
|
|
|
|
//! - applicationWillResignActive is Focused(false)
|
|
|
|
//! - applicationDidEnterBackground is Suspended(true)
|
|
|
|
//! - applicationWillEnterForeground is Suspended(false)
|
|
|
|
//! - applicationWillTerminate is Closed
|
|
|
|
//!
|
|
|
|
//! Keep in mind that after Closed event is received every attempt to draw with
|
|
|
|
//! opengl will result in segfault.
|
|
|
|
//!
|
|
|
|
//! Also note that app will not receive Closed event if suspended, it will be SIGKILL'ed
|
|
|
|
|
2015-06-05 23:38:21 +10:00
|
|
|
#![cfg(target_os = "ios")]
|
|
|
|
|
2016-12-14 00:28:30 +11:00
|
|
|
use std::collections::VecDeque;
|
|
|
|
use std::ptr;
|
|
|
|
use std::mem;
|
|
|
|
use std::os::raw::c_void;
|
|
|
|
|
|
|
|
use libc;
|
|
|
|
use libc::c_int;
|
|
|
|
use objc::runtime::{Class, Object, Sel, BOOL, YES };
|
|
|
|
use objc::declare::{ ClassDecl };
|
|
|
|
|
2017-09-07 18:33:46 +10:00
|
|
|
use { CreationError, CursorState, MouseCursor, WindowAttributes };
|
2017-09-04 20:41:10 +10:00
|
|
|
use WindowId as RootEventId;
|
|
|
|
use WindowEvent;
|
|
|
|
use Event;
|
2016-12-14 00:28:30 +11:00
|
|
|
use events::{ Touch, TouchPhase };
|
2017-09-07 18:33:46 +10:00
|
|
|
use window::MonitorId as RootMonitorId;
|
2016-12-14 00:28:30 +11:00
|
|
|
|
|
|
|
mod ffi;
|
|
|
|
use self::ffi::{
|
|
|
|
setjmp,
|
|
|
|
UIApplicationMain,
|
|
|
|
CFTimeInterval,
|
|
|
|
CFRunLoopRunInMode,
|
|
|
|
kCFRunLoopDefaultMode,
|
|
|
|
kCFRunLoopRunHandledSource,
|
|
|
|
id,
|
|
|
|
nil,
|
|
|
|
NSString,
|
|
|
|
CGFloat,
|
|
|
|
longjmp,
|
|
|
|
CGRect,
|
|
|
|
CGPoint
|
|
|
|
};
|
|
|
|
|
|
|
|
static mut jmpbuf: [c_int;27] = [0;27];
|
|
|
|
|
2017-08-29 10:46:03 +10:00
|
|
|
#[derive(Clone)]
|
2016-12-14 00:28:30 +11:00
|
|
|
pub struct MonitorId;
|
|
|
|
|
2017-09-07 01:32:24 +10:00
|
|
|
pub struct Window {
|
2016-12-14 00:28:30 +11:00
|
|
|
delegate_state: *mut DelegateState
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone)]
|
|
|
|
pub struct WindowProxy;
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
struct DelegateState {
|
2017-09-16 00:24:09 +10:00
|
|
|
events_queue: VecDeque<Event>,
|
2016-12-14 00:28:30 +11:00
|
|
|
window: id,
|
|
|
|
controller: id,
|
|
|
|
size: (u32,u32),
|
|
|
|
scale: f32
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl DelegateState {
|
|
|
|
#[inline]
|
|
|
|
fn new(window: id, controller:id, size: (u32,u32), scale: f32) -> DelegateState {
|
|
|
|
DelegateState {
|
|
|
|
events_queue: VecDeque::new(),
|
|
|
|
window: window,
|
|
|
|
controller: controller,
|
|
|
|
size: size,
|
|
|
|
scale: scale
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl MonitorId {
|
|
|
|
#[inline]
|
|
|
|
pub fn get_name(&self) -> Option<String> {
|
|
|
|
Some("Primary".to_string())
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
pub fn get_dimensions(&self) -> (u32, u32) {
|
|
|
|
unimplemented!()
|
|
|
|
}
|
2017-09-07 18:33:46 +10:00
|
|
|
|
|
|
|
#[inline]
|
2017-10-20 04:08:05 +11:00
|
|
|
pub fn get_position(&self) -> (i32, i32) {
|
2017-09-07 18:33:46 +10:00
|
|
|
// iOS assumes single screen
|
|
|
|
(0, 0)
|
|
|
|
}
|
2017-10-17 22:56:38 +11:00
|
|
|
|
|
|
|
#[inline]
|
|
|
|
pub fn get_hidpi_factor(&self) -> f32 {
|
|
|
|
1.0
|
|
|
|
}
|
2016-12-14 00:28:30 +11:00
|
|
|
}
|
2015-06-05 23:38:21 +10:00
|
|
|
|
2017-09-04 20:41:10 +10:00
|
|
|
pub struct EventsLoop {
|
|
|
|
delegate_state: *mut DelegateState
|
|
|
|
}
|
2016-01-08 02:01:18 +11:00
|
|
|
|
2017-10-26 05:03:57 +11:00
|
|
|
#[derive(Clone)]
|
2017-09-04 20:41:10 +10:00
|
|
|
pub struct EventsLoopProxy;
|
2015-06-05 23:38:21 +10:00
|
|
|
|
2017-09-04 20:41:10 +10:00
|
|
|
impl EventsLoop {
|
|
|
|
pub fn new() -> EventsLoop {
|
2016-12-14 00:28:30 +11:00
|
|
|
unsafe {
|
|
|
|
if setjmp(mem::transmute(&mut jmpbuf)) != 0 {
|
|
|
|
let app: id = msg_send![Class::get("UIApplication").unwrap(), sharedApplication];
|
|
|
|
let delegate: id = msg_send![app, delegate];
|
|
|
|
let state: *mut c_void = *(&*delegate).get_ivar("glutinState");
|
|
|
|
let state = state as *mut DelegateState;
|
|
|
|
|
2017-09-04 20:41:10 +10:00
|
|
|
let events_loop = EventsLoop {
|
2016-12-14 00:28:30 +11:00
|
|
|
delegate_state: state
|
|
|
|
};
|
|
|
|
|
2017-09-04 20:41:10 +10:00
|
|
|
return events_loop;
|
2016-12-14 00:28:30 +11:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-04 20:41:10 +10:00
|
|
|
create_delegate_class();
|
|
|
|
create_view_class();
|
|
|
|
start_app();
|
2016-12-14 00:28:30 +11:00
|
|
|
|
2017-09-04 20:41:10 +10:00
|
|
|
panic!("Couldn't create UIApplication")
|
2015-06-05 23:38:21 +10:00
|
|
|
}
|
|
|
|
|
2017-09-04 20:41:10 +10:00
|
|
|
#[inline]
|
|
|
|
pub fn get_available_monitors(&self) -> VecDeque<MonitorId> {
|
|
|
|
let mut rb = VecDeque::new();
|
|
|
|
rb.push_back(MonitorId);
|
|
|
|
rb
|
|
|
|
}
|
2016-12-14 00:28:30 +11:00
|
|
|
|
2017-09-04 20:41:10 +10:00
|
|
|
#[inline]
|
|
|
|
pub fn get_primary_monitor(&self) -> MonitorId {
|
|
|
|
MonitorId
|
|
|
|
}
|
2016-12-14 00:28:30 +11:00
|
|
|
|
2017-09-04 20:41:10 +10:00
|
|
|
pub fn poll_events<F>(&mut self, mut callback: F)
|
|
|
|
where F: FnMut(::Event)
|
|
|
|
{
|
|
|
|
unsafe {
|
|
|
|
let state = &mut *self.delegate_state;
|
2016-12-14 00:28:30 +11:00
|
|
|
|
2017-09-04 20:41:10 +10:00
|
|
|
if let Some(event) = state.events_queue.pop_front() {
|
2017-09-16 00:24:09 +10:00
|
|
|
callback(event);
|
2017-09-04 20:41:10 +10:00
|
|
|
return;
|
2016-12-14 00:28:30 +11:00
|
|
|
}
|
|
|
|
|
2017-09-04 20:41:10 +10:00
|
|
|
// jump hack, so we won't quit on willTerminate event before processing it
|
|
|
|
if setjmp(mem::transmute(&mut jmpbuf)) != 0 {
|
|
|
|
if let Some(event) = state.events_queue.pop_front() {
|
2017-09-16 00:24:09 +10:00
|
|
|
callback(event);
|
2017-09-04 20:41:10 +10:00
|
|
|
return;
|
|
|
|
}
|
2016-12-14 00:28:30 +11:00
|
|
|
}
|
|
|
|
|
2017-09-04 20:41:10 +10:00
|
|
|
// run runloop
|
|
|
|
let seconds: CFTimeInterval = 0.000002;
|
|
|
|
while CFRunLoopRunInMode(kCFRunLoopDefaultMode, seconds, 1) == kCFRunLoopRunHandledSource {}
|
2016-12-14 00:28:30 +11:00
|
|
|
|
2017-09-04 20:41:10 +10:00
|
|
|
if let Some(event) = state.events_queue.pop_front() {
|
2017-09-16 00:24:09 +10:00
|
|
|
callback(event)
|
2016-12-14 00:28:30 +11:00
|
|
|
}
|
|
|
|
}
|
2017-09-04 20:41:10 +10:00
|
|
|
}
|
2016-12-14 00:28:30 +11:00
|
|
|
|
2017-09-04 20:41:10 +10:00
|
|
|
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;
|
2016-12-14 00:28:30 +11:00
|
|
|
}
|
2017-09-04 20:41:10 +10:00
|
|
|
});
|
|
|
|
if let ::ControlFlow::Break = control_flow {
|
|
|
|
break;
|
2016-12-14 00:28:30 +11:00
|
|
|
}
|
2017-09-04 20:41:10 +10:00
|
|
|
::std::thread::sleep(::std::time::Duration::from_millis(5));
|
2016-12-14 00:28:30 +11:00
|
|
|
}
|
2017-09-04 20:41:10 +10:00
|
|
|
}
|
2016-12-14 00:28:30 +11:00
|
|
|
|
2017-09-04 20:41:10 +10:00
|
|
|
pub fn create_proxy(&self) -> EventsLoopProxy {
|
|
|
|
EventsLoopProxy
|
|
|
|
}
|
|
|
|
}
|
2016-12-14 00:28:30 +11:00
|
|
|
|
2017-09-04 20:41:10 +10:00
|
|
|
impl EventsLoopProxy {
|
|
|
|
pub fn wakeup(&self) -> Result<(), ::EventsLoopClosed> {
|
|
|
|
unimplemented!()
|
2015-06-05 23:38:21 +10:00
|
|
|
}
|
2017-09-04 20:41:10 +10:00
|
|
|
}
|
2015-06-05 23:38:21 +10:00
|
|
|
|
2017-09-04 20:41:10 +10:00
|
|
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
|
|
|
pub struct WindowId;
|
2016-12-14 00:28:30 +11:00
|
|
|
|
2017-09-04 20:41:10 +10:00
|
|
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
|
|
|
pub struct DeviceId;
|
2015-06-05 23:38:21 +10:00
|
|
|
|
2017-09-04 20:41:10 +10:00
|
|
|
#[derive(Clone, Default)]
|
|
|
|
pub struct PlatformSpecificWindowBuilderAttributes;
|
|
|
|
|
2017-09-07 01:32:24 +10:00
|
|
|
impl Window {
|
2017-09-04 20:41:10 +10:00
|
|
|
pub fn new(ev: &EventsLoop, _: &WindowAttributes, _: &PlatformSpecificWindowBuilderAttributes)
|
2017-09-07 01:32:24 +10:00
|
|
|
-> Result<Window, CreationError>
|
2017-09-04 20:41:10 +10:00
|
|
|
{
|
2017-09-07 01:32:24 +10:00
|
|
|
Ok(Window {
|
2017-09-04 20:41:10 +10:00
|
|
|
delegate_state: ev.delegate_state,
|
|
|
|
})
|
2016-12-14 00:28:30 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
pub fn set_title(&self, _: &str) {
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
pub fn show(&self) {
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
pub fn hide(&self) {
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
pub fn get_position(&self) -> Option<(i32, i32)> {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
pub fn set_position(&self, _x: i32, _y: i32) {
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
pub fn get_inner_size(&self) -> Option<(u32, u32)> {
|
|
|
|
unsafe { Some((&*self.delegate_state).size) }
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
pub fn get_outer_size(&self) -> Option<(u32, u32)> {
|
|
|
|
self.get_inner_size()
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
pub fn set_inner_size(&self, _x: u32, _y: u32) {
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
pub fn platform_display(&self) -> *mut libc::c_void {
|
|
|
|
unimplemented!();
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
pub fn platform_window(&self) -> *mut libc::c_void {
|
2015-06-05 23:38:21 +10:00
|
|
|
unimplemented!()
|
|
|
|
}
|
|
|
|
|
2016-12-14 00:28:30 +11:00
|
|
|
#[inline]
|
|
|
|
pub fn set_window_resize_callback(&mut self, _: Option<fn(u32, u32)>) {
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
pub fn set_cursor(&self, _: MouseCursor) {
|
2015-06-05 23:38:21 +10:00
|
|
|
}
|
|
|
|
|
2016-12-14 00:28:30 +11:00
|
|
|
#[inline]
|
|
|
|
pub fn set_cursor_state(&self, _: CursorState) -> Result<(), String> {
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
pub fn hidpi_factor(&self) -> f32 {
|
|
|
|
unsafe { (&*self.delegate_state) }.scale
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
pub fn set_cursor_position(&self, _x: i32, _y: i32) -> Result<(), ()> {
|
2015-06-05 23:38:21 +10:00
|
|
|
unimplemented!();
|
|
|
|
}
|
2016-12-14 00:28:30 +11:00
|
|
|
|
|
|
|
#[inline]
|
|
|
|
pub fn create_window_proxy(&self) -> WindowProxy {
|
|
|
|
WindowProxy
|
|
|
|
}
|
|
|
|
|
2017-08-28 10:43:34 +10:00
|
|
|
#[inline]
|
2017-09-07 18:33:46 +10:00
|
|
|
pub fn set_maximized(&self, _maximized: bool) {
|
|
|
|
// iOS has single screen maximized apps so nothing to do
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
pub fn set_fullscreen(&self, _monitor: Option<RootMonitorId>) {
|
|
|
|
// iOS has single screen maximized apps so nothing to do
|
2017-08-28 10:43:34 +10:00
|
|
|
}
|
|
|
|
|
2017-12-22 23:50:46 +11:00
|
|
|
#[inline]
|
|
|
|
pub fn set_decorations(&self, _decorations: bool) {
|
|
|
|
// N/A
|
|
|
|
}
|
|
|
|
|
2017-08-28 10:43:34 +10:00
|
|
|
#[inline]
|
2017-09-07 18:33:46 +10:00
|
|
|
pub fn get_current_monitor(&self) -> RootMonitorId {
|
|
|
|
RootMonitorId{inner: MonitorId}
|
2017-08-28 10:43:34 +10:00
|
|
|
}
|
2016-12-14 00:28:30 +11:00
|
|
|
|
|
|
|
#[inline]
|
2017-09-04 20:41:10 +10:00
|
|
|
pub fn id(&self) -> WindowId {
|
|
|
|
WindowId
|
2016-12-14 00:28:30 +11:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-04 20:41:10 +10:00
|
|
|
fn create_delegate_class() {
|
|
|
|
extern fn did_finish_launching(this: &mut Object, _: Sel, _: id, _: id) -> BOOL {
|
|
|
|
unsafe {
|
|
|
|
let main_screen: id = msg_send![Class::get("UIScreen").unwrap(), mainScreen];
|
|
|
|
let bounds: CGRect = msg_send![main_screen, bounds];
|
|
|
|
let scale: CGFloat = msg_send![main_screen, nativeScale];
|
2016-12-14 00:28:30 +11:00
|
|
|
|
2017-09-04 20:41:10 +10:00
|
|
|
let window: id = msg_send![Class::get("UIWindow").unwrap(), alloc];
|
|
|
|
let window: id = msg_send![window, initWithFrame:bounds.clone()];
|
2016-12-14 00:28:30 +11:00
|
|
|
|
2017-09-04 20:41:10 +10:00
|
|
|
let size = (bounds.size.width as u32, bounds.size.height as u32);
|
|
|
|
|
|
|
|
let view_controller: id = msg_send![Class::get("MainViewController").unwrap(), alloc];
|
|
|
|
let view_controller: id = msg_send![view_controller, init];
|
|
|
|
|
|
|
|
let _: () = msg_send![window, setRootViewController:view_controller];
|
|
|
|
let _: () = msg_send![window, makeKeyAndVisible];
|
|
|
|
|
|
|
|
let state = Box::new(DelegateState::new(window, view_controller, size, scale as f32));
|
|
|
|
let state_ptr: *mut DelegateState = mem::transmute(state);
|
|
|
|
this.set_ivar("glutinState", state_ptr as *mut c_void);
|
|
|
|
|
|
|
|
|
|
|
|
let _: () = msg_send![this, performSelector:sel!(postLaunch:) withObject:nil afterDelay:0.0];
|
2016-12-14 00:28:30 +11:00
|
|
|
}
|
2017-09-04 20:41:10 +10:00
|
|
|
YES
|
2016-12-14 00:28:30 +11:00
|
|
|
}
|
2015-06-05 23:38:21 +10:00
|
|
|
|
2017-09-04 20:41:10 +10:00
|
|
|
extern fn post_launch(_: &Object, _: Sel, _: id) {
|
|
|
|
unsafe { longjmp(mem::transmute(&mut jmpbuf),1); }
|
|
|
|
}
|
2016-12-14 00:28:30 +11:00
|
|
|
|
2017-09-04 20:41:10 +10:00
|
|
|
extern fn did_become_active(this: &Object, _: Sel, _: id) {
|
2016-12-14 00:28:30 +11:00
|
|
|
unsafe {
|
2017-09-04 20:41:10 +10:00
|
|
|
let state: *mut c_void = *this.get_ivar("glutinState");
|
|
|
|
let state = &mut *(state as *mut DelegateState);
|
2017-09-16 00:24:09 +10:00
|
|
|
state.events_queue.push_back(Event::WindowEvent {
|
|
|
|
window_id: RootEventId(WindowId),
|
|
|
|
event: WindowEvent::Focused(true),
|
|
|
|
});
|
2017-09-04 20:41:10 +10:00
|
|
|
}
|
|
|
|
}
|
2016-12-14 00:28:30 +11:00
|
|
|
|
2017-09-04 20:41:10 +10:00
|
|
|
extern fn will_resign_active(this: &Object, _: Sel, _: id) {
|
|
|
|
unsafe {
|
|
|
|
let state: *mut c_void = *this.get_ivar("glutinState");
|
|
|
|
let state = &mut *(state as *mut DelegateState);
|
2017-09-16 00:24:09 +10:00
|
|
|
state.events_queue.push_back(Event::WindowEvent {
|
|
|
|
window_id: RootEventId(WindowId),
|
|
|
|
event: WindowEvent::Focused(false),
|
|
|
|
});
|
2017-09-04 20:41:10 +10:00
|
|
|
}
|
|
|
|
}
|
2016-12-14 00:28:30 +11:00
|
|
|
|
2017-09-04 20:41:10 +10:00
|
|
|
extern fn will_enter_foreground(this: &Object, _: Sel, _: id) {
|
|
|
|
unsafe {
|
|
|
|
let state: *mut c_void = *this.get_ivar("glutinState");
|
|
|
|
let state = &mut *(state as *mut DelegateState);
|
2017-09-16 00:24:09 +10:00
|
|
|
state.events_queue.push_back(Event::Suspended(false));
|
2017-09-04 20:41:10 +10:00
|
|
|
}
|
|
|
|
}
|
2016-12-14 00:28:30 +11:00
|
|
|
|
2017-09-04 20:41:10 +10:00
|
|
|
extern fn did_enter_background(this: &Object, _: Sel, _: id) {
|
|
|
|
unsafe {
|
|
|
|
let state: *mut c_void = *this.get_ivar("glutinState");
|
|
|
|
let state = &mut *(state as *mut DelegateState);
|
2017-09-16 00:24:09 +10:00
|
|
|
state.events_queue.push_back(Event::Suspended(true));
|
2017-09-04 20:41:10 +10:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
extern fn will_terminate(this: &Object, _: Sel, _: id) {
|
|
|
|
unsafe {
|
|
|
|
let state: *mut c_void = *this.get_ivar("glutinState");
|
|
|
|
let state = &mut *(state as *mut DelegateState);
|
|
|
|
// push event to the front to garantee that we'll process it
|
|
|
|
// immidiatly after jump
|
2017-09-16 00:24:09 +10:00
|
|
|
state.events_queue.push_front(Event::WindowEvent {
|
|
|
|
window_id: RootEventId(WindowId),
|
|
|
|
event: WindowEvent::Closed,
|
|
|
|
});
|
2017-09-04 20:41:10 +10:00
|
|
|
longjmp(mem::transmute(&mut jmpbuf),1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
extern fn handle_touches(this: &Object, _: Sel, touches: id, _:id) {
|
|
|
|
unsafe {
|
|
|
|
let state: *mut c_void = *this.get_ivar("glutinState");
|
|
|
|
let state = &mut *(state as *mut DelegateState);
|
2016-12-14 00:28:30 +11:00
|
|
|
|
2017-09-04 20:41:10 +10:00
|
|
|
let touches_enum: id = msg_send![touches, objectEnumerator];
|
|
|
|
|
|
|
|
loop {
|
|
|
|
let touch: id = msg_send![touches_enum, nextObject];
|
|
|
|
if touch == nil {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
let location: CGPoint = msg_send![touch, locationInView:nil];
|
|
|
|
let touch_id = touch as u64;
|
|
|
|
let phase: i32 = msg_send![touch, phase];
|
|
|
|
|
2017-09-16 00:24:09 +10:00
|
|
|
state.events_queue.push_back(Event::WindowEvent {
|
|
|
|
window_id: RootEventId(WindowId),
|
|
|
|
event: WindowEvent::Touch(Touch {
|
|
|
|
device_id: DEVICE_ID,
|
|
|
|
id: touch_id,
|
|
|
|
location: (location.x as f64, location.y as f64),
|
|
|
|
phase: match phase {
|
|
|
|
0 => TouchPhase::Started,
|
|
|
|
1 => TouchPhase::Moved,
|
|
|
|
// 2 is UITouchPhaseStationary and is not expected here
|
|
|
|
3 => TouchPhase::Ended,
|
|
|
|
4 => TouchPhase::Cancelled,
|
|
|
|
_ => panic!("unexpected touch phase: {:?}", phase)
|
|
|
|
}
|
|
|
|
}),
|
|
|
|
});
|
2017-09-04 20:41:10 +10:00
|
|
|
}
|
2016-12-14 00:28:30 +11:00
|
|
|
}
|
|
|
|
}
|
2017-09-04 20:41:10 +10:00
|
|
|
|
|
|
|
let ui_responder = Class::get("UIResponder").unwrap();
|
|
|
|
let mut decl = ClassDecl::new("AppDelegate", ui_responder).unwrap();
|
|
|
|
|
|
|
|
unsafe {
|
|
|
|
decl.add_method(sel!(application:didFinishLaunchingWithOptions:),
|
|
|
|
did_finish_launching as extern fn(&mut Object, Sel, id, id) -> BOOL);
|
|
|
|
|
|
|
|
decl.add_method(sel!(applicationDidBecomeActive:),
|
|
|
|
did_become_active as extern fn(&Object, Sel, id));
|
|
|
|
|
|
|
|
decl.add_method(sel!(applicationWillResignActive:),
|
|
|
|
will_resign_active as extern fn(&Object, Sel, id));
|
|
|
|
|
|
|
|
decl.add_method(sel!(applicationWillEnterForeground:),
|
|
|
|
will_enter_foreground as extern fn(&Object, Sel, id));
|
|
|
|
|
|
|
|
decl.add_method(sel!(applicationDidEnterBackground:),
|
|
|
|
did_enter_background as extern fn(&Object, Sel, id));
|
|
|
|
|
|
|
|
decl.add_method(sel!(applicationWillTerminate:),
|
|
|
|
will_terminate as extern fn(&Object, Sel, id));
|
|
|
|
|
|
|
|
|
|
|
|
decl.add_method(sel!(touchesBegan:withEvent:),
|
|
|
|
handle_touches as extern fn(this: &Object, _: Sel, _: id, _:id));
|
|
|
|
|
|
|
|
decl.add_method(sel!(touchesMoved:withEvent:),
|
|
|
|
handle_touches as extern fn(this: &Object, _: Sel, _: id, _:id));
|
|
|
|
|
|
|
|
decl.add_method(sel!(touchesEnded:withEvent:),
|
|
|
|
handle_touches as extern fn(this: &Object, _: Sel, _: id, _:id));
|
|
|
|
|
|
|
|
decl.add_method(sel!(touchesCancelled:withEvent:),
|
|
|
|
handle_touches as extern fn(this: &Object, _: Sel, _: id, _:id));
|
|
|
|
|
|
|
|
|
|
|
|
decl.add_method(sel!(postLaunch:),
|
|
|
|
post_launch as extern fn(&Object, Sel, id));
|
|
|
|
|
|
|
|
decl.add_ivar::<*mut c_void>("glutinState");
|
|
|
|
|
|
|
|
decl.register();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn create_view_class() {
|
|
|
|
let ui_view_controller = Class::get("UIViewController").unwrap();
|
|
|
|
let decl = ClassDecl::new("MainViewController", ui_view_controller).unwrap();
|
|
|
|
|
|
|
|
decl.register();
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn start_app() {
|
|
|
|
unsafe {
|
|
|
|
UIApplicationMain(0, ptr::null(), nil, NSString::alloc(nil).init_str("AppDelegate"));
|
|
|
|
}
|
2016-12-14 00:28:30 +11:00
|
|
|
}
|
2017-04-23 06:52:35 +10:00
|
|
|
|
|
|
|
// Constant device ID, to be removed when this backend is updated to report real device IDs.
|
|
|
|
const DEVICE_ID: ::DeviceId = ::DeviceId(DeviceId);
|