2015-06-05 23:38:21 +10:00
|
|
|
use libc;
|
|
|
|
use std::mem;
|
|
|
|
use super::DelegateState;
|
|
|
|
use Event;
|
|
|
|
use events::{ Touch, TouchPhase };
|
|
|
|
|
|
|
|
use objc::runtime::{ Class, Object, Sel, BOOL, YES };
|
|
|
|
use objc::declare::{ ClassDecl };
|
|
|
|
|
|
|
|
use super::ffi::{
|
|
|
|
longjmp,
|
|
|
|
id,
|
|
|
|
nil,
|
|
|
|
CGRect,
|
|
|
|
CGPoint,
|
2015-06-08 19:26:42 +10:00
|
|
|
CGFloat,
|
2015-06-05 23:38:21 +10:00
|
|
|
UIViewAutoresizingFlexibleWidth,
|
|
|
|
UIViewAutoresizingFlexibleHeight
|
|
|
|
};
|
|
|
|
|
|
|
|
use super::jmpbuf;
|
|
|
|
|
|
|
|
|
|
|
|
pub 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];
|
2015-06-08 19:26:42 +10:00
|
|
|
let scale: CGFloat = msg_send![main_screen, nativeScale];
|
|
|
|
|
2015-06-05 23:38:21 +10:00
|
|
|
let window: id = msg_send![Class::get("UIWindow").unwrap(), alloc];
|
|
|
|
let window: id = msg_send![window, initWithFrame:bounds.clone()];
|
|
|
|
|
|
|
|
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 class = Class::get("MainView").unwrap();
|
|
|
|
let view:id = msg_send![class, alloc];
|
|
|
|
let view:id = msg_send![view, initForGl:&bounds];
|
|
|
|
|
|
|
|
|
|
|
|
let _: () = msg_send![view_controller, setView:view];
|
|
|
|
|
|
|
|
|
|
|
|
let _: () = msg_send![window, setRootViewController:view_controller];
|
|
|
|
|
|
|
|
let _: () = msg_send![window, addSubview:view];
|
|
|
|
let _: () = msg_send![window, makeKeyAndVisible];
|
|
|
|
|
2015-06-08 19:26:42 +10:00
|
|
|
let state = Box::new(DelegateState::new(window, view_controller, view, size, scale as f32));
|
2015-06-05 23:38:21 +10:00
|
|
|
let state_ptr: *mut DelegateState = mem::transmute(state);
|
|
|
|
this.set_ivar("glutinState", state_ptr as *mut libc::c_void);
|
|
|
|
|
|
|
|
|
|
|
|
let _: () = msg_send![this, performSelector:sel!(postLaunch:) withObject:nil afterDelay:0.0];
|
|
|
|
}
|
|
|
|
YES
|
|
|
|
}
|
|
|
|
|
|
|
|
extern fn post_launch(_: &Object, _: Sel, _: id) {
|
|
|
|
unsafe { longjmp(mem::transmute(&mut jmpbuf),1); }
|
|
|
|
}
|
|
|
|
|
|
|
|
extern fn did_become_active(this: &Object, _: Sel, _: id) {
|
|
|
|
unsafe {
|
|
|
|
let state: *mut libc::c_void = *this.get_ivar("glutinState");
|
|
|
|
let state = &mut *(state as *mut DelegateState);
|
|
|
|
state.events_queue.push_back(Event::Focused(true));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
extern fn will_resign_active(this: &Object, _: Sel, _: id) {
|
|
|
|
unsafe {
|
|
|
|
let state: *mut libc::c_void = *this.get_ivar("glutinState");
|
|
|
|
let state = &mut *(state as *mut DelegateState);
|
|
|
|
state.events_queue.push_back(Event::Focused(false));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
extern fn will_enter_foreground(this: &Object, _: Sel, _: id) {
|
|
|
|
unsafe {
|
|
|
|
let state: *mut libc::c_void = *this.get_ivar("glutinState");
|
|
|
|
let state = &mut *(state as *mut DelegateState);
|
|
|
|
state.events_queue.push_back(Event::Suspended(false));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
extern fn did_enter_background(this: &Object, _: Sel, _: id) {
|
|
|
|
unsafe {
|
|
|
|
let state: *mut libc::c_void = *this.get_ivar("glutinState");
|
|
|
|
let state = &mut *(state as *mut DelegateState);
|
|
|
|
state.events_queue.push_back(Event::Suspended(true));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
extern fn will_terminate(this: &Object, _: Sel, _: id) {
|
|
|
|
unsafe {
|
|
|
|
let state: *mut libc::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
|
|
|
|
state.events_queue.push_front(Event::Closed);
|
|
|
|
longjmp(mem::transmute(&mut jmpbuf),1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
extern fn handle_touches(this: &Object, _: Sel, touches: id, _:id) {
|
|
|
|
unsafe {
|
|
|
|
let state: *mut libc::c_void = *this.get_ivar("glutinState");
|
|
|
|
let state = &mut *(state as *mut DelegateState);
|
|
|
|
|
|
|
|
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];
|
|
|
|
|
|
|
|
state.events_queue.push_back(Event::Touch(Touch {
|
|
|
|
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)
|
|
|
|
}
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let superclass = Class::get("UIResponder").unwrap();
|
|
|
|
let mut decl = ClassDecl::new(superclass, "AppDelegate").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 libc::c_void>("glutinState");
|
|
|
|
|
|
|
|
decl.register();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pub fn create_view_class() {
|
|
|
|
let superclass = Class::get("UIViewController").unwrap();
|
|
|
|
let decl = ClassDecl::new(superclass, "MainViewController").unwrap();
|
|
|
|
|
|
|
|
decl.register();
|
|
|
|
|
|
|
|
extern fn init_for_gl(this: &Object, _: Sel, frame: *const libc::c_void) -> id {
|
|
|
|
unsafe {
|
|
|
|
let bounds: *const CGRect = mem::transmute(frame);
|
|
|
|
let view: id = msg_send![this, initWithFrame:(*bounds).clone()];
|
|
|
|
|
|
|
|
let _: () = msg_send![view, setAutoresizingMask: UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight];
|
|
|
|
let _: () = msg_send![view, setAutoresizesSubviews:YES];
|
|
|
|
|
|
|
|
let layer: id = msg_send![view, layer];
|
|
|
|
let _ : () = msg_send![layer, setOpaque:YES];
|
|
|
|
|
|
|
|
view
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
extern fn layer_class(_: &Class, _: Sel) -> *const Class {
|
|
|
|
unsafe { mem::transmute(Class::get("CAEAGLLayer").unwrap()) }
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
let superclass = Class::get("UIView").unwrap();
|
|
|
|
let mut decl = ClassDecl::new(superclass, "MainView").unwrap();
|
|
|
|
|
|
|
|
unsafe {
|
|
|
|
decl.add_method(sel!(initForGl:),
|
|
|
|
init_for_gl as extern fn(&Object, Sel, *const libc::c_void) -> id);
|
|
|
|
|
|
|
|
decl.add_class_method(sel!(layerClass),
|
|
|
|
layer_class as extern fn(&Class, Sel) -> *const Class);
|
|
|
|
decl.register();
|
|
|
|
}
|
|
|
|
}
|