#![cfg(target_os = "emscripten")] use std::ffi::CString; use libc; use Api; use Event; use CreationError; use ContextError; use CursorState; use GlAttributes; use GlContext; use MouseCursor; use PixelFormat; use PixelFormatRequirements; use WindowAttributes; use std::collections::VecDeque; mod ffi; pub struct Window { context: ffi::EMSCRIPTEN_WEBGL_CONTEXT_HANDLE, } pub struct PollEventsIterator<'a> { window: &'a Window, } impl<'a> Iterator for PollEventsIterator<'a> { type Item = Event; #[inline] fn next(&mut self) -> Option { None } } pub struct WaitEventsIterator<'a> { window: &'a Window, } impl<'a> Iterator for WaitEventsIterator<'a> { type Item = Event; #[inline] fn next(&mut self) -> Option { None } } #[derive(Clone)] pub struct WindowProxy; impl WindowProxy { #[inline] pub fn wakeup_event_loop(&self) { unimplemented!() } } #[derive(Clone)] pub struct MonitorId; #[inline] pub fn get_available_monitors() -> VecDeque { let mut list = VecDeque::new(); list.push_back(MonitorId); list } #[inline] pub fn get_primary_monitor() -> MonitorId { MonitorId } impl MonitorId { #[inline] pub fn get_name(&self) -> Option { Some("Canvas".to_owned()) } #[inline] pub fn get_native_identifier(&self) -> ::native_monitor::NativeMonitorId { ::native_monitor::NativeMonitorId::Unavailable } #[inline] pub fn get_dimensions(&self) -> (u32, u32) { unimplemented!() } } impl Window { pub fn new(window: &WindowAttributes, pf_reqs: &PixelFormatRequirements, opengl: &GlAttributes<&Window>) -> Result { // getting the default values of attributes let mut attributes = unsafe { use std::mem; let mut attributes: ffi::EmscriptenWebGLContextAttributes = mem::uninitialized(); ffi::emscripten_webgl_init_context_attributes(&mut attributes); attributes }; // setting the attributes // FIXME: /*match builder.opengl.version { Some((major, minor)) => { attributes.majorVersion = major as libc::c_int; attributes.minorVersion = minor as libc::c_int; }, None => () };*/ // creating the context let context = unsafe { use std::{mem, ptr}; let context = ffi::emscripten_webgl_create_context(ptr::null(), &attributes); if context <= 0 { return Err(CreationError::OsError(format!("Error while calling emscripten_webgl_create_context: {}", error_to_str(mem::transmute(context))))); } context }; // TODO: emscripten_set_webglcontextrestored_callback Ok(Window { context: context }) } #[inline] pub fn set_title(&self, _title: &str) { } #[inline] pub fn get_position(&self) -> Option<(i32, i32)> { Some((0, 0)) } #[inline] pub fn set_position(&self, _: i32, _: i32) { } pub fn get_inner_size(&self) -> Option<(u32, u32)> { unsafe { use std::{mem, ptr}; let mut width = mem::uninitialized(); let mut height = mem::uninitialized(); if ffi::emscripten_get_element_css_size(ptr::null(), &mut width, &mut height) != ffi::EMSCRIPTEN_RESULT_SUCCESS { None } else { Some((width as u32, height as u32)) } } } #[inline] pub fn get_outer_size(&self) -> Option<(u32, u32)> { self.get_inner_size() } #[inline] pub fn set_inner_size(&self, width: u32, height: u32) { unsafe { use std::ptr; ffi::emscripten_set_element_css_size(ptr::null(), width as libc::c_double, height as libc::c_double); } } #[inline] pub fn poll_events(&self) -> PollEventsIterator { PollEventsIterator { window: self, } } #[inline] pub fn wait_events(&self) -> WaitEventsIterator { WaitEventsIterator { window: self, } } #[inline] pub fn create_window_proxy(&self) -> WindowProxy { WindowProxy } #[inline] pub fn show(&self) {} #[inline] pub fn hide(&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) { } #[inline] pub fn set_cursor(&self, cursor: MouseCursor) { } #[inline] pub fn set_cursor_state(&self, state: CursorState) -> Result<(), String> { Ok(()) } #[inline] pub fn hidpi_factor(&self) -> f32 { 1.0 } #[inline] pub fn set_cursor_position(&self, x: i32, y: i32) -> Result<(), ()> { Ok(()) } } impl GlContext for Window { #[inline] unsafe fn make_current(&self) -> Result<(), ContextError> { // TOOD: check if == EMSCRIPTEN_RESULT ffi::emscripten_webgl_make_context_current(self.context); Ok(()) } #[inline] fn is_current(&self) -> bool { true // FIXME: } fn get_proc_address(&self, addr: &str) -> *const () { let addr = CString::new(addr).unwrap(); unsafe { // FIXME: if `as_ptr()` is used, then wrong data is passed to emscripten ffi::emscripten_GetProcAddress(addr.into_raw() as *const _) as *const _ } } #[inline] fn swap_buffers(&self) -> Result<(), ContextError> { unsafe { ffi::emscripten_sleep(1); } // FIXME: Ok(()) } #[inline] fn get_api(&self) -> Api { Api::WebGl } #[inline] fn get_pixel_format(&self) -> PixelFormat { unimplemented!(); } } impl Drop for Window { fn drop(&mut self) { unsafe { ffi::emscripten_exit_fullscreen(); ffi::emscripten_webgl_destroy_context(self.context); } } } fn error_to_str(code: ffi::EMSCRIPTEN_RESULT) -> &'static str { match code { ffi::EMSCRIPTEN_RESULT_SUCCESS | ffi::EMSCRIPTEN_RESULT_DEFERRED => "Internal error in the library (success detected as failure)", ffi::EMSCRIPTEN_RESULT_NOT_SUPPORTED => "Not supported", ffi::EMSCRIPTEN_RESULT_FAILED_NOT_DEFERRED => "Failed not deferred", ffi::EMSCRIPTEN_RESULT_INVALID_TARGET => "Invalid target", ffi::EMSCRIPTEN_RESULT_UNKNOWN_TARGET => "Unknown target", ffi::EMSCRIPTEN_RESULT_INVALID_PARAM => "Invalid parameter", ffi::EMSCRIPTEN_RESULT_FAILED => "Failed", ffi::EMSCRIPTEN_RESULT_NO_DATA => "No data", _ => "Undocumented error" } }