mirror of
https://github.com/italicsjenga/winit-sonoma-fix.git
synced 2024-12-25 06:41:31 +11:00
commit
ae53bb0f14
|
@ -11,8 +11,16 @@ addons:
|
||||||
packages:
|
packages:
|
||||||
- libxxf86vm-dev
|
- libxxf86vm-dev
|
||||||
|
|
||||||
|
install:
|
||||||
|
- |
|
||||||
|
if [ $TRAVIS_OS_NAME = osx ]; then
|
||||||
|
sh ~/rust-installer/rustup.sh -y --disable-sudo --prefix=/Users/travis/rust \
|
||||||
|
--add-target=x86_64-apple-ios
|
||||||
|
fi
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- cargo build --verbose
|
- cargo build --verbose
|
||||||
|
- if [ $TRAVIS_OS_NAME = osx ]; then cargo build --target x86_64-apple-ios --verbose; fi
|
||||||
- cargo test --verbose
|
- cargo test --verbose
|
||||||
|
|
||||||
os:
|
os:
|
||||||
|
|
|
@ -1,226 +0,0 @@
|
||||||
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,
|
|
||||||
CGFloat,
|
|
||||||
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];
|
|
||||||
let scale: CGFloat = msg_send![main_screen, nativeScale];
|
|
||||||
|
|
||||||
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];
|
|
||||||
|
|
||||||
let state = Box::new(DelegateState::new(window, view_controller, view, size, scale as f32));
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,467 +0,0 @@
|
||||||
//! 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.
|
|
||||||
//!
|
|
||||||
//! ```c
|
|
||||||
//! 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
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#![cfg(target_os = "ios")]
|
|
||||||
#![deny(warnings)]
|
|
||||||
|
|
||||||
use std::collections::VecDeque;
|
|
||||||
use std::ptr;
|
|
||||||
use std::io;
|
|
||||||
use std::mem;
|
|
||||||
use std::ffi::CString;
|
|
||||||
|
|
||||||
use libc;
|
|
||||||
use objc::runtime::{Class, BOOL, YES, NO };
|
|
||||||
|
|
||||||
use native_monitor::NativeMonitorId;
|
|
||||||
use { Api, PixelFormat, CreationError, GlContext, CursorState, MouseCursor, Event };
|
|
||||||
use { PixelFormatRequirements, GlAttributes, WindowAttributes, ContextError };
|
|
||||||
use CreationError::OsError;
|
|
||||||
|
|
||||||
mod delegate;
|
|
||||||
use self::delegate::{ create_delegate_class, create_view_class };
|
|
||||||
|
|
||||||
mod ffi;
|
|
||||||
use self::ffi::{
|
|
||||||
gles,
|
|
||||||
setjmp,
|
|
||||||
dlopen,
|
|
||||||
dlsym,
|
|
||||||
UIApplicationMain,
|
|
||||||
kEAGLColorFormatRGB565,
|
|
||||||
CFTimeInterval,
|
|
||||||
CFRunLoopRunInMode,
|
|
||||||
kCFRunLoopDefaultMode,
|
|
||||||
kCFRunLoopRunHandledSource,
|
|
||||||
kEAGLDrawablePropertyRetainedBacking,
|
|
||||||
kEAGLDrawablePropertyColorFormat,
|
|
||||||
RTLD_LAZY,
|
|
||||||
RTLD_GLOBAL,
|
|
||||||
id,
|
|
||||||
nil,
|
|
||||||
NSString,
|
|
||||||
CGFloat
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
static mut jmpbuf: [libc::c_int;27] = [0;27];
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct MonitorId;
|
|
||||||
|
|
||||||
pub struct Window {
|
|
||||||
eagl_context: id,
|
|
||||||
delegate_state: *mut DelegateState
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct WindowProxy;
|
|
||||||
|
|
||||||
pub struct PollEventsIterator<'a> {
|
|
||||||
window: &'a Window,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct WaitEventsIterator<'a> {
|
|
||||||
window: &'a Window,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct DelegateState {
|
|
||||||
events_queue: VecDeque<Event>,
|
|
||||||
window: id,
|
|
||||||
controller: id,
|
|
||||||
view: id,
|
|
||||||
size: (u32,u32),
|
|
||||||
scale: f32
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
impl DelegateState {
|
|
||||||
#[inline]
|
|
||||||
fn new(window: id, controller:id, view: id, size: (u32,u32), scale: f32) -> DelegateState {
|
|
||||||
DelegateState {
|
|
||||||
events_queue: VecDeque::new(),
|
|
||||||
window: window,
|
|
||||||
controller: controller,
|
|
||||||
view: view,
|
|
||||||
size: size,
|
|
||||||
scale: scale
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[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> {
|
|
||||||
Some("Primary".to_string())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn get_native_identifier(&self) -> NativeMonitorId {
|
|
||||||
NativeMonitorId::Unavailable
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn get_dimensions(&self) -> (u32, u32) {
|
|
||||||
unimplemented!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Default)]
|
|
||||||
pub struct PlatformSpecificWindowBuilderAttributes;
|
|
||||||
|
|
||||||
impl Window {
|
|
||||||
|
|
||||||
pub fn new(builder: &WindowAttributes, _: &PixelFormatRequirements, _: &GlAttributes<&Window>,
|
|
||||||
_: &PlatformSpecificWindowBuilderAttributes) -> Result<Window, CreationError>
|
|
||||||
{
|
|
||||||
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 libc::c_void = *(&*delegate).get_ivar("glutinState");
|
|
||||||
let state = state as *mut DelegateState;
|
|
||||||
|
|
||||||
let context = Window::create_context();
|
|
||||||
|
|
||||||
let mut window = Window {
|
|
||||||
eagl_context: context,
|
|
||||||
delegate_state: state
|
|
||||||
};
|
|
||||||
|
|
||||||
window.init_context(builder);
|
|
||||||
|
|
||||||
return Ok(window)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
create_delegate_class();
|
|
||||||
create_view_class();
|
|
||||||
Window::start_app();
|
|
||||||
|
|
||||||
Err(CreationError::OsError(format!("Couldn't create UIApplication")))
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn init_context(&mut self, builder: &WindowAttributes) {
|
|
||||||
let draw_props: id = msg_send![Class::get("NSDictionary").unwrap(), alloc];
|
|
||||||
let draw_props: id = msg_send![draw_props,
|
|
||||||
initWithObjects:
|
|
||||||
vec![
|
|
||||||
msg_send![Class::get("NSNumber").unwrap(), numberWithBool: NO],
|
|
||||||
kEAGLColorFormatRGB565
|
|
||||||
].as_ptr()
|
|
||||||
forKeys:
|
|
||||||
vec![
|
|
||||||
kEAGLDrawablePropertyRetainedBacking,
|
|
||||||
kEAGLDrawablePropertyColorFormat
|
|
||||||
].as_ptr()
|
|
||||||
count: 2
|
|
||||||
];
|
|
||||||
let _ = self.make_current();
|
|
||||||
|
|
||||||
let state = &mut *self.delegate_state;
|
|
||||||
|
|
||||||
if builder.multitouch {
|
|
||||||
let _: () = msg_send![state.view, setMultipleTouchEnabled:YES];
|
|
||||||
}
|
|
||||||
|
|
||||||
let _: () = msg_send![state.view, setContentScaleFactor:state.scale as CGFloat];
|
|
||||||
|
|
||||||
let layer: id = msg_send![state.view, layer];
|
|
||||||
let _: () = msg_send![layer, setContentsScale:state.scale as CGFloat];
|
|
||||||
let _: () = msg_send![layer, setDrawableProperties: draw_props];
|
|
||||||
|
|
||||||
let gl = gles::Gles2::load_with(|symbol| self.get_proc_address(symbol));
|
|
||||||
let mut color_render_buf: gles::types::GLuint = 0;
|
|
||||||
let mut frame_buf: gles::types::GLuint = 0;
|
|
||||||
gl.GenRenderbuffers(1, &mut color_render_buf);
|
|
||||||
gl.BindRenderbuffer(gles::RENDERBUFFER, color_render_buf);
|
|
||||||
|
|
||||||
let ok: BOOL = msg_send![self.eagl_context, renderbufferStorage:gles::RENDERBUFFER fromDrawable:layer];
|
|
||||||
if ok != YES {
|
|
||||||
panic!("EAGL: could not set renderbufferStorage");
|
|
||||||
}
|
|
||||||
|
|
||||||
gl.GenFramebuffers(1, &mut frame_buf);
|
|
||||||
gl.BindFramebuffer(gles::FRAMEBUFFER, frame_buf);
|
|
||||||
|
|
||||||
gl.FramebufferRenderbuffer(gles::FRAMEBUFFER, gles::COLOR_ATTACHMENT0, gles::RENDERBUFFER, color_render_buf);
|
|
||||||
|
|
||||||
let status = gl.CheckFramebufferStatus(gles::FRAMEBUFFER);
|
|
||||||
if gl.CheckFramebufferStatus(gles::FRAMEBUFFER) != gles::FRAMEBUFFER_COMPLETE {
|
|
||||||
panic!("framebuffer status: {:?}", status);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create_context() -> id {
|
|
||||||
unsafe {
|
|
||||||
let eagl_context: id = msg_send![Class::get("EAGLContext").unwrap(), alloc];
|
|
||||||
let eagl_context: id = msg_send![eagl_context, initWithAPI:2]; // es2
|
|
||||||
eagl_context
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn start_app() {
|
|
||||||
unsafe {
|
|
||||||
UIApplicationMain(0, ptr::null(), nil, NSString::alloc(nil).init_str("AppDelegate"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[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 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!();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn platform_window(&self) -> *mut libc::c_void {
|
|
||||||
unimplemented!()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn get_pixel_format(&self) -> PixelFormat {
|
|
||||||
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, _: 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<(), ()> {
|
|
||||||
unimplemented!();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn create_window_proxy(&self) -> WindowProxy {
|
|
||||||
WindowProxy
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
impl GlContext for Window {
|
|
||||||
#[inline]
|
|
||||||
unsafe fn make_current(&self) -> Result<(), ContextError> {
|
|
||||||
let res: BOOL = msg_send![Class::get("EAGLContext").unwrap(), setCurrentContext: self.eagl_context];
|
|
||||||
if res == YES {
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(ContextError::IoError(io::Error::new(io::ErrorKind::Other, "EAGLContext::setCurrentContext unsuccessful")))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn is_current(&self) -> bool {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_proc_address(&self, addr: &str) -> *const () {
|
|
||||||
let addr_c = CString::new(addr).unwrap();
|
|
||||||
let path = CString::new("/System/Library/Frameworks/OpenGLES.framework/OpenGLES").unwrap();
|
|
||||||
unsafe {
|
|
||||||
let lib = dlopen(path.as_ptr(), RTLD_LAZY | RTLD_GLOBAL);
|
|
||||||
dlsym(lib, addr_c.as_ptr()) as *const _
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn swap_buffers(&self) -> Result<(), ContextError> {
|
|
||||||
unsafe {
|
|
||||||
let res: BOOL = msg_send![self.eagl_context, presentRenderbuffer: gles::RENDERBUFFER];
|
|
||||||
if res == YES {
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(ContextError::IoError(io::Error::new(io::ErrorKind::Other, "EAGLContext.presentRenderbuffer unsuccessful")))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn get_api(&self) -> Api {
|
|
||||||
unimplemented!()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn get_pixel_format(&self) -> PixelFormat {
|
|
||||||
unimplemented!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WindowProxy {
|
|
||||||
#[inline]
|
|
||||||
pub fn wakeup_event_loop(&self) {
|
|
||||||
unimplemented!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
impl<'a> Iterator for WaitEventsIterator<'a> {
|
|
||||||
type Item = Event;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn next(&mut self) -> Option<Event> {
|
|
||||||
loop {
|
|
||||||
if let Some(ev) = self.window.poll_events().next() {
|
|
||||||
return Some(ev);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Iterator for PollEventsIterator<'a> {
|
|
||||||
type Item = Event;
|
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Event> {
|
|
||||||
unsafe {
|
|
||||||
let state = &mut *self.window.delegate_state;
|
|
||||||
|
|
||||||
if let Some(event) = state.events_queue.pop_front() {
|
|
||||||
return Some(event)
|
|
||||||
}
|
|
||||||
|
|
||||||
// jump hack, so we won't quit on willTerminate event before processing it
|
|
||||||
if setjmp(mem::transmute(&mut jmpbuf)) != 0 {
|
|
||||||
return state.events_queue.pop_front()
|
|
||||||
}
|
|
||||||
|
|
||||||
// run runloop
|
|
||||||
let seconds: CFTimeInterval = 0.000002;
|
|
||||||
while CFRunLoopRunInMode(kCFRunLoopDefaultMode, seconds, 1) == kCFRunLoopRunHandledSource {}
|
|
||||||
|
|
||||||
state.events_queue.pop_front()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -3,4 +3,3 @@
|
||||||
pub mod dlopen;
|
pub mod dlopen;
|
||||||
pub mod wayland;
|
pub mod wayland;
|
||||||
pub mod x11;
|
pub mod x11;
|
||||||
pub mod ios;
|
|
||||||
|
|
|
@ -27,12 +27,6 @@ pub type NSUInteger = u32;
|
||||||
#[cfg(target_pointer_width = "64")]
|
#[cfg(target_pointer_width = "64")]
|
||||||
pub type NSUInteger = u64;
|
pub type NSUInteger = u64;
|
||||||
|
|
||||||
#[allow(non_upper_case_globals)]
|
|
||||||
pub const UIViewAutoresizingFlexibleWidth: NSUInteger = 1 << 1;
|
|
||||||
#[allow(non_upper_case_globals)]
|
|
||||||
pub const UIViewAutoresizingFlexibleHeight: NSUInteger = 1 << 4;
|
|
||||||
|
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct CGPoint {
|
pub struct CGPoint {
|
||||||
|
@ -54,21 +48,12 @@ pub struct CGSize {
|
||||||
pub height: CGFloat
|
pub height: CGFloat
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod gles {
|
|
||||||
include!(concat!(env!("OUT_DIR"), "/gles2_bindings.rs"));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[link(name = "UIKit", kind = "framework")]
|
#[link(name = "UIKit", kind = "framework")]
|
||||||
#[link(name = "CoreFoundation", kind = "framework")]
|
#[link(name = "CoreFoundation", kind = "framework")]
|
||||||
#[link(name = "GlKit", kind = "framework")]
|
#[link(name = "GlKit", kind = "framework")]
|
||||||
extern {
|
extern {
|
||||||
pub static kCFRunLoopDefaultMode: CFStringRef;
|
pub static kCFRunLoopDefaultMode: CFStringRef;
|
||||||
|
|
||||||
pub static kEAGLColorFormatRGB565: id;
|
|
||||||
// pub static kEAGLColorFormatRGBA8: id;
|
|
||||||
pub static kEAGLDrawablePropertyColorFormat: id;
|
|
||||||
pub static kEAGLDrawablePropertyRetainedBacking: id;
|
|
||||||
|
|
||||||
// int UIApplicationMain ( int argc, char *argv[], NSString *principalClassName, NSString *delegateClassName );
|
// int UIApplicationMain ( int argc, char *argv[], NSString *principalClassName, NSString *delegateClassName );
|
||||||
pub fn UIApplicationMain(argc: libc::c_int, argv: *const libc::c_char, principalClassName: id, delegateClassName: id) -> libc::c_int;
|
pub fn UIApplicationMain(argc: libc::c_int, argv: *const libc::c_char, principalClassName: id, delegateClassName: id) -> libc::c_int;
|
||||||
|
|
||||||
|
@ -81,14 +66,6 @@ extern {
|
||||||
pub fn longjmp(env: *mut libc::c_void, val: libc::c_int);
|
pub fn longjmp(env: *mut libc::c_void, val: libc::c_int);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const RTLD_LAZY: libc::c_int = 0x001;
|
|
||||||
pub const RTLD_GLOBAL: libc::c_int = 0x100;
|
|
||||||
|
|
||||||
extern {
|
|
||||||
pub fn dlopen(filename: *const libc::c_char, flag: libc::c_int) -> *mut libc::c_void;
|
|
||||||
pub fn dlsym(handle: *mut libc::c_void, symbol: *const libc::c_char) -> *mut libc::c_void;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait NSString {
|
pub trait NSString {
|
||||||
unsafe fn alloc(_: Self) -> id {
|
unsafe fn alloc(_: Self) -> id {
|
||||||
msg_send![class("NSString"), alloc]
|
msg_send![class("NSString"), alloc]
|
|
@ -1,54 +1,494 @@
|
||||||
|
//! 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.
|
||||||
|
//!
|
||||||
|
//! ```ignore
|
||||||
|
//! 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
|
||||||
|
|
||||||
#![cfg(target_os = "ios")]
|
#![cfg(target_os = "ios")]
|
||||||
|
|
||||||
use GlAttributes;
|
use std::collections::VecDeque;
|
||||||
use CreationError;
|
use std::ptr;
|
||||||
use PixelFormat;
|
use std::mem;
|
||||||
use PixelFormatRequirements;
|
use std::os::raw::c_void;
|
||||||
use ContextError;
|
|
||||||
|
|
||||||
pub use api::ios::*;
|
use libc;
|
||||||
|
use libc::c_int;
|
||||||
|
use objc::runtime::{Class, Object, Sel, BOOL, YES };
|
||||||
|
use objc::declare::{ ClassDecl };
|
||||||
|
|
||||||
#[derive(Clone, Default)]
|
use native_monitor::NativeMonitorId;
|
||||||
pub struct PlatformSpecificHeadlessBuilderAttributes;
|
use { CreationError, CursorState, MouseCursor, Event, WindowAttributes };
|
||||||
|
use events::{ Touch, TouchPhase };
|
||||||
|
|
||||||
pub struct HeadlessContext(i32);
|
mod ffi;
|
||||||
|
use self::ffi::{
|
||||||
|
setjmp,
|
||||||
|
UIApplicationMain,
|
||||||
|
CFTimeInterval,
|
||||||
|
CFRunLoopRunInMode,
|
||||||
|
kCFRunLoopDefaultMode,
|
||||||
|
kCFRunLoopRunHandledSource,
|
||||||
|
id,
|
||||||
|
nil,
|
||||||
|
NSString,
|
||||||
|
CGFloat,
|
||||||
|
longjmp,
|
||||||
|
CGRect,
|
||||||
|
CGPoint
|
||||||
|
};
|
||||||
|
|
||||||
impl HeadlessContext {
|
static mut jmpbuf: [c_int;27] = [0;27];
|
||||||
/// See the docs in the crate root file.
|
|
||||||
pub fn new(_: (u32, u32), _: &PixelFormatRequirements, _: &GlAttributes<&HeadlessContext>,
|
#[derive(Clone)]
|
||||||
_: &PlatformSpecificHeadlessBuilderAttributes)
|
pub struct MonitorId;
|
||||||
-> Result<HeadlessContext, CreationError>
|
|
||||||
{
|
pub struct Window {
|
||||||
unimplemented!()
|
delegate_state: *mut DelegateState
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct WindowProxy;
|
||||||
|
|
||||||
|
pub struct PollEventsIterator<'a> {
|
||||||
|
window: &'a Window,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct WaitEventsIterator<'a> {
|
||||||
|
window: &'a Window,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct DelegateState {
|
||||||
|
events_queue: VecDeque<Event>,
|
||||||
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
/// See the docs in the crate root file.
|
|
||||||
pub unsafe fn make_current(&self) -> Result<(), ContextError> {
|
|
||||||
unimplemented!()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn swap_buffers(&self) -> Result<(), ContextError> {
|
|
||||||
unimplemented!()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// See the docs in the crate root file.
|
|
||||||
pub fn is_current(&self) -> bool {
|
|
||||||
unimplemented!()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// See the docs in the crate root file.
|
|
||||||
pub fn get_proc_address(&self, _addr: &str) -> *const () {
|
|
||||||
unimplemented!()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_api(&self) -> ::Api {
|
|
||||||
::Api::OpenGlEs
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_pixel_format(&self) -> PixelFormat {
|
|
||||||
unimplemented!();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl Send for HeadlessContext {}
|
#[inline]
|
||||||
unsafe impl Sync for HeadlessContext {}
|
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> {
|
||||||
|
Some("Primary".to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn get_native_identifier(&self) -> NativeMonitorId {
|
||||||
|
NativeMonitorId::Unavailable
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn get_dimensions(&self) -> (u32, u32) {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Default)]
|
||||||
|
pub struct PlatformSpecificWindowBuilderAttributes;
|
||||||
|
|
||||||
|
impl Window {
|
||||||
|
|
||||||
|
pub fn new(_: &WindowAttributes, _: &PlatformSpecificWindowBuilderAttributes) -> Result<Window, CreationError>
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
|
||||||
|
let window = Window {
|
||||||
|
delegate_state: state
|
||||||
|
};
|
||||||
|
|
||||||
|
return Ok(window)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Window::create_delegate_class();
|
||||||
|
Window::create_view_class();
|
||||||
|
Window::start_app();
|
||||||
|
|
||||||
|
Err(CreationError::OsError(format!("Couldn't create UIApplication")))
|
||||||
|
}
|
||||||
|
|
||||||
|
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];
|
||||||
|
|
||||||
|
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 _: () = 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];
|
||||||
|
}
|
||||||
|
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 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 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 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 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 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 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 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"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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 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!();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn platform_window(&self) -> *mut libc::c_void {
|
||||||
|
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, _: 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<(), ()> {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn create_window_proxy(&self) -> WindowProxy {
|
||||||
|
WindowProxy
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WindowProxy {
|
||||||
|
#[inline]
|
||||||
|
pub fn wakeup_event_loop(&self) {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl<'a> Iterator for WaitEventsIterator<'a> {
|
||||||
|
type Item = Event;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn next(&mut self) -> Option<Event> {
|
||||||
|
loop {
|
||||||
|
if let Some(ev) = self.window.poll_events().next() {
|
||||||
|
return Some(ev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Iterator for PollEventsIterator<'a> {
|
||||||
|
type Item = Event;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Event> {
|
||||||
|
unsafe {
|
||||||
|
let state = &mut *self.window.delegate_state;
|
||||||
|
|
||||||
|
if let Some(event) = state.events_queue.pop_front() {
|
||||||
|
return Some(event)
|
||||||
|
}
|
||||||
|
|
||||||
|
// jump hack, so we won't quit on willTerminate event before processing it
|
||||||
|
if setjmp(mem::transmute(&mut jmpbuf)) != 0 {
|
||||||
|
return state.events_queue.pop_front()
|
||||||
|
}
|
||||||
|
|
||||||
|
// run runloop
|
||||||
|
let seconds: CFTimeInterval = 0.000002;
|
||||||
|
while CFRunLoopRunInMode(kCFRunLoopDefaultMode, seconds, 1) == kCFRunLoopRunHandledSource {}
|
||||||
|
|
||||||
|
state.events_queue.pop_front()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -11,9 +11,7 @@ pub fn get_available_monitors() -> VecDeque<MonitorId> {
|
||||||
let max_displays = 10u32;
|
let max_displays = 10u32;
|
||||||
let mut active_displays = [0u32; 10];
|
let mut active_displays = [0u32; 10];
|
||||||
let mut display_count = 0;
|
let mut display_count = 0;
|
||||||
display::CGGetActiveDisplayList(max_displays,
|
display::CGGetActiveDisplayList(max_displays, &mut active_displays[0], &mut display_count);
|
||||||
&mut active_displays[0],
|
|
||||||
&mut display_count);
|
|
||||||
for i in 0..display_count as usize {
|
for i in 0..display_count as usize {
|
||||||
monitors.push_back(MonitorId(active_displays[i]));
|
monitors.push_back(MonitorId(active_displays[i]));
|
||||||
}
|
}
|
||||||
|
@ -23,18 +21,14 @@ pub fn get_available_monitors() -> VecDeque<MonitorId> {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_primary_monitor() -> MonitorId {
|
pub fn get_primary_monitor() -> MonitorId {
|
||||||
let id = unsafe {
|
let id = unsafe { MonitorId(display::CGMainDisplayID()) };
|
||||||
MonitorId(display::CGMainDisplayID())
|
|
||||||
};
|
|
||||||
id
|
id
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MonitorId {
|
impl MonitorId {
|
||||||
pub fn get_name(&self) -> Option<String> {
|
pub fn get_name(&self) -> Option<String> {
|
||||||
let MonitorId(display_id) = *self;
|
let MonitorId(display_id) = *self;
|
||||||
let screen_num = unsafe {
|
let screen_num = unsafe { display::CGDisplayModelNumber(display_id) };
|
||||||
display::CGDisplayModelNumber(display_id)
|
|
||||||
};
|
|
||||||
Some(format!("Monitor #{}", screen_num))
|
Some(format!("Monitor #{}", screen_num))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue