diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/android/mod.rs | 72 | ||||
-rw-r--r-- | src/events.rs | 14 | ||||
-rw-r--r-- | src/lib.rs | 256 | ||||
-rw-r--r-- | src/osx/headless.rs | 25 | ||||
-rw-r--r-- | src/osx/mod.rs | 109 | ||||
-rw-r--r-- | src/osx/mod.rs.BACKUP.6164.rs | 524 | ||||
-rw-r--r-- | src/osx/mod.rs.BASE.6164.rs | 485 | ||||
-rw-r--r-- | src/osx/mod.rs.LOCAL.6164.rs | 498 | ||||
-rw-r--r-- | src/osx/mod.rs.REMOTE.6164.rs | 492 | ||||
-rw-r--r-- | src/osx/monitor.rs | 15 | ||||
-rw-r--r-- | src/win32/init.rs | 64 | ||||
-rw-r--r-- | src/win32/mod.rs | 104 | ||||
-rw-r--r-- | src/win32/monitor.rs | 28 | ||||
-rw-r--r-- | src/x11/ffi.rs | 10 | ||||
-rw-r--r-- | src/x11/headless.rs | 32 | ||||
-rw-r--r-- | src/x11/mod.rs | 5 | ||||
-rw-r--r-- | src/x11/window/mod.rs | 161 | ||||
-rw-r--r-- | src/x11/window/monitor.rs | 19 |
18 files changed, 2588 insertions, 325 deletions
diff --git a/src/android/mod.rs b/src/android/mod.rs index 7279f99..6987f52 100644 --- a/src/android/mod.rs +++ b/src/android/mod.rs @@ -1,14 +1,17 @@ extern crate android_glue; use libc; -use {CreationError, Event, WindowBuilder}; +use std::ffi::{CString}; +use std::sync::mpsc::{Receiver, channel}; +use {CreationError, Event, MouseCursor}; use CreationError::OsError; use events::ElementState::{Pressed, Released}; use events::Event::{MouseInput, MouseMoved}; use events::MouseButton::LeftMouseButton; -#[cfg(feature = "headless")] -use HeadlessRendererBuilder; +use std::collections::RingBuf; + +use BuilderAttribs; pub struct Window { display: ffi::egl::types::EGLDisplay, @@ -21,8 +24,10 @@ pub struct MonitorID; mod ffi; -pub fn get_available_monitors() -> Vec<MonitorID> { - vec![ MonitorID ] +pub fn get_available_monitors() -> RingBuf <MonitorID> { + let mut rb = RingBuf::new(); + rb.push_back(MonitorID); + rb } pub fn get_primary_monitor() -> MonitorID { @@ -34,18 +39,18 @@ impl MonitorID { Some("Primary".to_string()) } - pub fn get_dimensions(&self) -> (uint, uint) { + pub fn get_dimensions(&self) -> (u32, u32) { unimplemented!() } } #[cfg(feature = "headless")] -pub struct HeadlessContext(int); +pub struct HeadlessContext(i32); #[cfg(feature = "headless")] impl HeadlessContext { /// See the docs in the crate root file. - pub fn new(_builder: HeadlessRendererBuilder) -> Result<HeadlessContext, CreationError> { + pub fn new(_builder: BuilderAttribs) -> Result<HeadlessContext, CreationError> { unimplemented!() } @@ -60,8 +65,13 @@ impl HeadlessContext { } } +#[cfg(feature = "headless")] +unsafe impl Send for HeadlessContext {} +#[cfg(feature = "headless")] +unsafe impl Sync for HeadlessContext {} + impl Window { - pub fn new(builder: WindowBuilder) -> Result<Window, CreationError> { + pub fn new(builder: BuilderAttribs) -> Result<Window, CreationError> { use std::{mem, ptr}; if builder.sharing.is_some() { @@ -110,6 +120,7 @@ impl Window { attribute_list.push_all(&[ffi::egl::RED_SIZE as i32, 1]); attribute_list.push_all(&[ffi::egl::GREEN_SIZE as i32, 1]); attribute_list.push_all(&[ffi::egl::BLUE_SIZE as i32, 1]); + attribute_list.push_all(&[ffi::egl::DEPTH_SIZE as i32, 1]); attribute_list.push(ffi::egl::NONE as i32); let mut num_config: ffi::egl::types::EGLint = mem::uninitialized(); @@ -180,50 +191,50 @@ impl Window { pub fn hide(&self) { } - pub fn get_position(&self) -> Option<(int, int)> { + pub fn get_position(&self) -> Option<(i32, i32)> { None } - pub fn set_position(&self, _x: int, _y: int) { + pub fn set_position(&self, _x: i32, _y: i32) { } - pub fn get_inner_size(&self) -> Option<(uint, uint)> { + pub fn get_inner_size(&self) -> Option<(u32, u32)> { let native_window = unsafe { android_glue::get_native_window() }; if native_window.is_null() { None } else { Some(( - unsafe { ffi::ANativeWindow_getWidth(native_window) } as uint, - unsafe { ffi::ANativeWindow_getHeight(native_window) } as uint + unsafe { ffi::ANativeWindow_getWidth(native_window) } as u32, + unsafe { ffi::ANativeWindow_getHeight(native_window) } as u32 )) } } - pub fn get_outer_size(&self) -> Option<(uint, uint)> { + pub fn get_outer_size(&self) -> Option<(u32, u32)> { self.get_inner_size() } - pub fn set_inner_size(&self, _x: uint, _y: uint) { + pub fn set_inner_size(&self, _x: u32, _y: u32) { } pub fn create_window_proxy(&self) -> WindowProxy { WindowProxy } - pub fn poll_events(&self) -> Vec<Event> { - let mut events = Vec::new(); + pub fn poll_events(&self) -> RingBuf<Event> { + let mut events = RingBuf::new(); loop { match self.event_rx.try_recv() { Ok(event) => match event { android_glue::Event::EventDown => { - events.push(MouseInput(Pressed, LeftMouseButton)); + events.push_back(MouseInput(Pressed, LeftMouseButton)); }, android_glue::Event::EventUp => { - events.push(MouseInput(Released, LeftMouseButton)); + events.push_back(MouseInput(Released, LeftMouseButton)); }, android_glue::Event::EventMove(x, y) => { - events.push(MouseMoved((x as int, y as int))); + events.push_back(MouseMoved((x as i32, y as i32))); }, }, Err(_) => { @@ -234,7 +245,7 @@ impl Window { events } - pub fn wait_events(&self) -> Vec<Event> { + pub fn wait_events(&self) -> RingBuf<Event> { use std::time::Duration; use std::io::timer; timer::sleep(Duration::milliseconds(16)); @@ -248,12 +259,9 @@ impl Window { } pub fn get_proc_address(&self, addr: &str) -> *const () { - use std::c_str::ToCStr; - + let addr = CString::from_slice(addr.as_bytes()).as_slice_with_nul().as_ptr(); unsafe { - addr.with_c_str(|s| { - ffi::egl::GetProcAddress(s) as *const () - }) + ffi::egl::GetProcAddress(addr) as *const () } } @@ -271,12 +279,18 @@ impl Window { ::Api::OpenGlEs } - pub fn set_window_resize_callback(&mut self, _: Option<fn(uint, uint)>) { + pub fn set_window_resize_callback(&mut self, _: Option<fn(u32, u32)>) { + } + + pub fn set_cursor(&self, _: MouseCursor) { } } +unsafe impl Send for Window {} +unsafe impl Sync for Window {} + #[cfg(feature = "window")] -#[deriving(Clone)] +#[derive(Clone)] pub struct WindowProxy; impl WindowProxy { diff --git a/src/events.rs b/src/events.rs index beafbec..34234b2 100644 --- a/src/events.rs +++ b/src/events.rs @@ -1,10 +1,10 @@ -#[deriving(Clone, Show, Copy)] +#[derive(Clone, Show, Copy)] pub enum Event { /// The size of the window has changed. - Resized(uint, uint), + Resized(u32, u32), /// The position of the window has changed. - Moved(int, int), + Moved(i32, i32), /// The window has been closed. Closed, @@ -23,7 +23,7 @@ pub enum Event { /// The cursor has moved on the window. /// /// The parameter are the (x,y) coords in pixels relative to the top-left corner of the window. - MouseMoved((int, int)), + MouseMoved((i32, i32)), /// A positive value indicates that the wheel was rotated forward, away from the user; /// a negative value indicates that the wheel was rotated backward, toward the user. @@ -38,13 +38,13 @@ pub enum Event { pub type ScanCode = u8; -#[deriving(Show, Hash, PartialEq, Eq, Clone, Copy)] +#[derive(Show, Hash, PartialEq, Eq, Clone, Copy)] pub enum ElementState { Pressed, Released, } -#[deriving(Show, Hash, PartialEq, Eq, Clone, Copy)] +#[derive(Show, Hash, PartialEq, Eq, Clone, Copy)] pub enum MouseButton { LeftMouseButton, RightMouseButton, @@ -52,7 +52,7 @@ pub enum MouseButton { OtherMouseButton(u8), } -#[deriving(Show, Hash, PartialEq, Eq, Clone, Copy)] +#[derive(Show, Hash, PartialEq, Eq, Clone, Copy)] pub enum VirtualKeyCode { /// The '1' key over the letters. Key1, @@ -1,6 +1,4 @@ #![feature(unsafe_destructor)] -#![feature(globs)] -#![feature(phase)] #![unstable] //! The purpose of this library is to provide an OpenGL context on as many @@ -43,6 +41,7 @@ extern crate core_graphics; pub use events::*; use std::default::Default; +use std::collections::ring_buf::IntoIter as RingBufIter; #[cfg(all(not(target_os = "windows"), not(target_os = "linux"), not(target_os = "macos"), not(target_os = "android")))] use this_platform_is_not_supported; @@ -67,21 +66,23 @@ mod events; pub struct MonitorID(winimpl::MonitorID); /// Error that can happen while creating a window or a headless renderer. -#[deriving(Clone, Show, PartialEq, Eq)] +#[derive(Clone, Show, PartialEq, Eq)] pub enum CreationError { OsError(String), + NotSupported, } impl std::error::Error for CreationError { fn description(&self) -> &str { match self { &CreationError::OsError(ref text) => text.as_slice(), + &CreationError::NotSupported => "Some of the requested attributes are not supported", } } } /// All APIs related to OpenGL that you can possibly get while using glutin. -#[deriving(Show, Clone, Copy, PartialEq, Eq)] +#[derive(Show, Clone, Copy, PartialEq, Eq)] pub enum Api { /// The classical OpenGL. Available on Windows, Linux, OS/X. OpenGl, @@ -89,25 +90,93 @@ pub enum Api { OpenGlEs, } +#[derive(Show, Copy)] +pub enum MouseCursor { + /// The platform-dependent default cursor. + Default, + /// A simple crosshair. + Crosshair, + /// A hand (often used to indicate links in web browsers). + Hand, + /// Self explanatory. + Arrow, + /// Indicates something is to be moved. + Move, + /// Indicates text that may be selected or edited. + Text, + /// Program busy indicator. + Wait, + /// Help indicator (often rendered as a "?") + Help, + /// Progress indicator. Shows that processing is being done. But in contrast + /// with "Wait" the user may still interact with the program. Often rendered + /// as a spinning beach ball, or an arrow with a watch or hourglass. + Progress, + + /// Cursor showing that something cannot be done. + NotAllowed, + ContextMenu, + NoneCursor, + Cell, + VerticalText, + Alias, + Copy, + NoDrop, + Grab, + Grabbing, + AllScroll, + ZoomIn, + ZoomOut, + + /// Indicate that some edge is to be moved. For example, the 'SeResize' cursor + /// is used when the movement starts from the south-east corner of the box. + EResize, + NResize, + NeResize, + NwResize, + SResize, + SeResize, + SwResize, + WResize, + EwResize, + NsResize, + NeswResize, + NwseResize, + ColResize, + RowResize, +} + /// Object that allows you to build windows. #[cfg(feature = "window")] pub struct WindowBuilder<'a> { - sharing: Option<&'a Window>, - dimensions: Option<(uint, uint)>, + attribs: BuilderAttribs<'a> +} + +/// Attributes +struct BuilderAttribs<'a> { + headless: bool, + strict: bool, + sharing: Option<&'a winimpl::Window>, + dimensions: Option<(u32, u32)>, title: String, monitor: Option<winimpl::MonitorID>, - gl_version: Option<(uint, uint)>, + gl_version: Option<(u32, u32)>, gl_debug: bool, vsync: bool, visible: bool, multisampling: Option<u16>, + depth_bits: Option<u8>, + stencil_bits: Option<u8>, + color_bits: Option<u8>, + alpha_bits: Option<u8>, + stereoscopy: bool, } -#[cfg(feature = "window")] -impl<'a> WindowBuilder<'a> { - /// Initializes a new `WindowBuilder` with default values. - pub fn new() -> WindowBuilder<'a> { - WindowBuilder { +impl BuilderAttribs<'static> { + fn new() -> BuilderAttribs<'static> { + BuilderAttribs { + headless: false, + strict: false, sharing: None, dimensions: None, title: "glutin window".to_string(), @@ -117,20 +186,35 @@ impl<'a> WindowBuilder<'a> { vsync: false, visible: true, multisampling: None, + depth_bits: None, + stencil_bits: None, + color_bits: None, + alpha_bits: None, + stereoscopy: false, + } + } +} + +#[cfg(feature = "window")] +impl<'a> WindowBuilder<'a> { + /// Initializes a new `WindowBuilder` with default values. + pub fn new() -> WindowBuilder<'a> { + WindowBuilder { + attribs: BuilderAttribs::new(), } } /// Requests the window to be of specific dimensions. /// /// Width and height are in pixels. - pub fn with_dimensions(mut self, width: uint, height: uint) -> WindowBuilder<'a> { - self.dimensions = Some((width, height)); + pub fn with_dimensions(mut self, width: u32, height: u32) -> WindowBuilder<'a> { + self.attribs.dimensions = Some((width, height)); self } /// Requests a specific title for the window. pub fn with_title(mut self, title: String) -> WindowBuilder<'a> { - self.title = title; + self.attribs.title = title; self } @@ -139,7 +223,7 @@ impl<'a> WindowBuilder<'a> { /// If you don't specify dimensions for the window, it will match the monitor's. pub fn with_fullscreen(mut self, monitor: MonitorID) -> WindowBuilder<'a> { let MonitorID(monitor) = monitor; - self.monitor = Some(monitor); + self.attribs.monitor = Some(monitor); self } @@ -147,7 +231,7 @@ impl<'a> WindowBuilder<'a> { /// /// There are some exceptions, like FBOs or VAOs. See the OpenGL documentation. pub fn with_shared_lists(mut self, other: &'a Window) -> WindowBuilder<'a> { - self.sharing = Some(other); + self.attribs.sharing = Some(&other.window); self } @@ -155,8 +239,8 @@ impl<'a> WindowBuilder<'a> { /// /// Version is a (major, minor) pair. For example to request OpenGL 3.3 /// you would pass `(3, 3)`. - pub fn with_gl_version(mut self, version: (uint, uint)) -> WindowBuilder<'a> { - self.gl_version = Some(version); + pub fn with_gl_version(mut self, version: (u32, u32)) -> WindowBuilder<'a> { + self.attribs.gl_version = Some(version); self } @@ -165,19 +249,19 @@ impl<'a> WindowBuilder<'a> { /// The default value for this flag is `cfg!(ndebug)`, which means that it's enabled /// when you run `cargo build` and disabled when you run `cargo build --release`. pub fn with_gl_debug_flag(mut self, flag: bool) -> WindowBuilder<'a> { - self.gl_debug = flag; + self.attribs.gl_debug = flag; self } /// Requests that the window has vsync enabled. pub fn with_vsync(mut self) -> WindowBuilder<'a> { - self.vsync = true; + self.attribs.vsync = true; self } /// Sets whether the window will be initially hidden or visible. pub fn with_visibility(mut self, visible: bool) -> WindowBuilder<'a> { - self.visible = visible; + self.attribs.visible = visible; self } @@ -189,7 +273,32 @@ impl<'a> WindowBuilder<'a> { pub fn with_multisampling(mut self, samples: u16) -> WindowBuilder<'a> { use std::num::UnsignedInt; assert!(samples.is_power_of_two()); - self.multisampling = Some(samples); + self.attribs.multisampling = Some(samples); + self + } + + /// Sets the number of bits in the depth buffer. + pub fn with_depth_buffer(mut self, bits: u8) -> WindowBuilder<'a> { + self.attribs.depth_bits = Some(bits); + self + } + + /// Sets the number of bits in the stencil buffer. + pub fn with_stencil_buffer(mut self, bits: u8) -> WindowBuilder<'a> { + self.attribs.stencil_bits = Some(bits); + self + } + + /// Sets the number of bits in the color buffer. + pub fn with_pixel_format(mut self, color_bits: u8, alpha_bits: u8) -> WindowBuilder<'a> { + self.attribs.color_bits = Some(color_bits); + self.attribs.alpha_bits = Some(alpha_bits); + self + } + + /// Request the backend to be stereoscopic. + pub fn with_stereoscopy(mut self) -> WindowBuilder<'a> { + self.attribs.stereoscopy = true; self } @@ -199,36 +308,45 @@ impl<'a> WindowBuilder<'a> { /// out of memory, etc. pub fn build(mut self) -> Result<Window, CreationError> { // resizing the window to the dimensions of the monitor when fullscreen - if self.dimensions.is_none() && self.monitor.is_some() { - self.dimensions = Some(self.monitor.as_ref().unwrap().get_dimensions()) + if self.attribs.dimensions.is_none() && self.attribs.monitor.is_some() { + self.attribs.dimensions = Some(self.attribs.monitor.as_ref().unwrap().get_dimensions()) } // default dimensions - if self.dimensions.is_none() { - self.dimensions = Some((1024, 768)); + if self.attribs.dimensions.is_none() { + self.attribs.dimensions = Some((1024, 768)); } // building - winimpl::Window::new(self).map(|w| Window { window: w }) + winimpl::Window::new(self.attribs).map(|w| Window { window: w }) + } + + /// Builds the window. + /// + /// The context is build in a *strict* way. That means that if the backend couldn't give + /// you what you requested, an `Err` will be returned. + pub fn build_strict(mut self) -> Result<Window, CreationError> { + self.attribs.strict = true; + self.build() } } /// Object that allows you to build headless contexts. #[cfg(feature = "headless")] pub struct HeadlessRendererBuilder { - dimensions: (uint, uint), - gl_version: Option<(uint, uint)>, - gl_debug: bool, + attribs: BuilderAttribs<'static>, } #[cfg(feature = "headless")] impl HeadlessRendererBuilder { /// Initializes a new `HeadlessRendererBuilder` with default values. - pub fn new(width: uint, height: uint) -> HeadlessRendererBuilder { + pub fn new(width: u32, height: u32) -> HeadlessRendererBuilder { HeadlessRendererBuilder { - dimensions: (width, height), - gl_version: None, - gl_debug: cfg!(ndebug), + attribs: BuilderAttribs { + headless: true, + dimensions: Some((width, height)), + .. BuilderAttribs::new() + }, } } @@ -236,8 +354,8 @@ impl HeadlessRendererBuilder { /// /// Version is a (major, minor) pair. For example to request OpenGL 3.3 /// you would pass `(3, 3)`. - pub fn with_gl_version(mut self, version: (uint, uint)) -> HeadlessRendererBuilder { - self.gl_version = Some(version); + pub fn with_gl_version(mut self, version: (u32, u32)) -> HeadlessRendererBuilder { + self.attribs.gl_version = Some(version); self } @@ -246,7 +364,7 @@ impl HeadlessRendererBuilder { /// The default value for this flag is `cfg!(ndebug)`, which means that it's enabled /// when you run `cargo build` and disabled when you run `cargo build --release`. pub fn with_gl_debug_flag(mut self, flag: bool) -> HeadlessRendererBuilder { - self.gl_debug = flag; + self.attribs.gl_debug = flag; self } @@ -255,7 +373,16 @@ impl HeadlessRendererBuilder { /// Error should be very rare and only occur in case of permission denied, incompatible system, /// out of memory, etc. pub fn build(self) -> Result<HeadlessContext, CreationError> { - winimpl::HeadlessContext::new(self).map(|w| HeadlessContext { context: w }) + winimpl::HeadlessContext::new(self.attribs).map(|w| HeadlessContext { context: w }) + } + + /// Builds the headless context. + /// + /// The context is build in a *strict* way. That means that if the backend couldn't give + /// you what you requested, an `Err` will be returned. + pub fn build_strict(mut self) -> Result<HeadlessContext, CreationError> { + self.attribs.strict = true; + self.build() } } @@ -363,7 +490,7 @@ impl Window { /// /// Returns `None` if the window no longer exists. #[inline] - pub fn get_position(&self) -> Option<(int, int)> { + pub fn get_position(&self) -> Option<(i32, i32)> { self.window.get_position() } @@ -373,7 +500,7 @@ impl Window { /// /// This is a no-op if the window has already been closed. #[inline] - pub fn set_position(&self, x: int, y: int) { + pub fn set_position(&self, x: i32, y: i32) { self.window.set_position(x, y) } @@ -385,7 +512,7 @@ impl Window { /// /// Returns `None` if the window no longer exists. #[inline] - pub fn get_inner_size(&self) -> Option<(uint, uint)> { + pub fn get_inner_size(&self) -> Option<(u32, u32)> { self.window.get_inner_size() } @@ -396,7 +523,7 @@ impl Window { /// /// Returns `None` if the window no longer exists. #[inline] - pub fn get_outer_size(&self) -> Option<(uint, uint)> { + pub fn get_outer_size(&self) -> Option<(u32, u32)> { self.window.get_outer_size() } @@ -406,7 +533,7 @@ impl Window { /// /// This is a no-op if the window has already been closed. #[inline] - pub fn set_inner_size(&self, x: uint, y: uint) { + pub fn set_inner_size(&self, x: u32, y: u32) { self.window.set_inner_size(x, y) } @@ -415,7 +542,7 @@ impl Window { /// Contrary to `wait_events`, this function never blocks. #[inline] pub fn poll_events(&self) -> PollEventsIterator { - PollEventsIterator { data: self.window.poll_events() } + PollEventsIterator { data: self.window.poll_events().into_iter() } } /// Waits for an event, then returns an iterator to all the events that are currently @@ -425,7 +552,7 @@ impl Window { /// this function will block until there is one. #[inline] pub fn wait_events(&self) -> WaitEventsIterator { - WaitEventsIterator { data: self.window.wait_events() } + WaitEventsIterator { data: self.window.wait_events().into_iter() } } /// Sets the context as the current context. @@ -485,9 +612,15 @@ impl Window { /// operating systems) during resize operations. This can be used to repaint /// during window resizing. #[experimental] - pub fn set_window_resize_callback(&mut self, callback: Option<fn(uint, uint)>) { + pub fn set_window_resize_callback(&mut self, callback: Option<fn(u32, u32)>) { self.window.set_window_resize_callback(callback); } + + /// Modifies the mouse cursor of the window. + /// Has no effect on Android. + pub fn set_cursor(&self, cursor: MouseCursor) { + self.window.set_cursor(cursor); + } } #[cfg(feature = "window")] @@ -502,7 +635,7 @@ impl gl_common::GlFunctionsSource for Window { /// threads. /// #[cfg(feature = "window")] -#[deriving(Clone)] +#[derive(Clone)] pub struct WindowProxy { proxy: winimpl::WindowProxy, } @@ -550,7 +683,7 @@ impl HeadlessContext { } #[experimental] - pub fn set_window_resize_callback(&mut self, _: Option<fn(uint, uint)>) { + pub fn set_window_resize_callback(&mut self, _: Option<fn(u32, u32)>) { } } @@ -565,12 +698,13 @@ impl gl_common::GlFunctionsSource for HeadlessContext { // Implementation note: we retreive the list once, then serve each element by one by one. // This may change in the future. pub struct PollEventsIterator<'a> { - data: Vec<Event>, + data: RingBufIter<Event>, } -impl<'a> Iterator<Event> for PollEventsIterator<'a> { +impl<'a> Iterator for PollEventsIterator<'a> { + type Item = Event; fn next(&mut self) -> Option<Event> { - self.data.remove(0) + self.data.next() } } @@ -578,12 +712,13 @@ impl<'a> Iterator<Event> for PollEventsIterator<'a> { // Implementation note: we retreive the list once, then serve each element by one by one. // This may change in the future. pub struct WaitEventsIterator<'a> { - data: Vec<Event>, + data: RingBufIter<Event>, } -impl<'a> Iterator<Event> for WaitEventsIterator<'a> { +impl<'a> Iterator for WaitEventsIterator<'a> { + type Item = Event; fn next(&mut self) -> Option<Event> { - self.data.remove(0) + self.data.next() } } @@ -592,13 +727,14 @@ impl<'a> Iterator<Event> for WaitEventsIterator<'a> { // This may change in the future. #[cfg(feature = "window")] pub struct AvailableMonitorsIter { - data: Vec<winimpl::MonitorID>, + data: RingBufIter<winimpl::MonitorID>, } #[cfg(feature = "window")] -impl Iterator<MonitorID> for AvailableMonitorsIter { +impl Iterator for AvailableMonitorsIter { + type Item = MonitorID; fn next(&mut self) -> Option<MonitorID> { - self.data.remove(0).map(|id| MonitorID(id)) + self.data.next().map(|id| MonitorID(id)) } } @@ -606,7 +742,7 @@ impl Iterator<MonitorID> for AvailableMonitorsIter { #[cfg(feature = "window")] pub fn get_available_monitors() -> AvailableMonitorsIter { let data = winimpl::get_available_monitors(); - AvailableMonitorsIter{ data: data } + AvailableMonitorsIter{ data: data.into_iter() } } /// Returns the primary monitor of the system. @@ -624,7 +760,7 @@ impl MonitorID { } /// Returns the number of pixels currently displayed on the monitor. - pub fn get_dimensions(&self) -> (uint, uint) { + pub fn get_dimensions(&self) -> (u32, u32) { let &MonitorID(ref id) = self; id.get_dimensions() } diff --git a/src/osx/headless.rs b/src/osx/headless.rs index bbe3d9f..ab3c341 100644 --- a/src/osx/headless.rs +++ b/src/osx/headless.rs @@ -1,6 +1,6 @@ use CreationError; use CreationError::OsError; -use HeadlessRendererBuilder; +use BuilderAttribs; use libc; use std::ptr; @@ -24,23 +24,23 @@ static mut framebuffer: u32 = 0; static mut texture: u32 = 0; pub struct HeadlessContext { - width: uint, - height: uint, + width: usize, + height: usize, context: id, } impl HeadlessContext { - pub fn new(builder: HeadlessRendererBuilder) -> Result<HeadlessContext, CreationError> { + pub fn new(builder: BuilderAttribs) -> Result<HeadlessContext, CreationError> { let (width, height) = builder.dimensions; let context = unsafe { let attributes = [ - NSOpenGLPFADoubleBuffer as uint, - NSOpenGLPFAClosestPolicy as uint, - NSOpenGLPFAColorSize as uint, 24, - NSOpenGLPFAAlphaSize as uint, 8, - NSOpenGLPFADepthSize as uint, 24, - NSOpenGLPFAStencilSize as uint, 8, - NSOpenGLPFAOffScreen as uint, + NSOpenGLPFADoubleBuffer as usize, + NSOpenGLPFAClosestPolicy as usize, + NSOpenGLPFAColorSize as usize, 24, + NSOpenGLPFAAlphaSize as usize, 8, + NSOpenGLPFADepthSize as usize, 24, + NSOpenGLPFAStencilSize as usize, 8, + NSOpenGLPFAOffScreen as usize, 0 ]; @@ -99,6 +99,9 @@ impl HeadlessContext { } } +unsafe impl Send for HeadlessContext {} +unsafe impl Sync for HeadlessContext {} + impl Drop for HeadlessContext { fn drop(&mut self) { unsafe { diff --git a/src/osx/mod.rs b/src/osx/mod.rs index 83c51a3..4b111bf 100644 --- a/src/osx/mod.rs +++ b/src/osx/mod.rs @@ -1,13 +1,12 @@ #[cfg(feature = "headless")] pub use self::headless::HeadlessContext; -use {CreationError, Event}; +use {CreationError, Event, MouseCursor}; use CreationError::OsError; use libc; use std::ascii::AsciiExt; -#[cfg(feature = "window")] -use WindowBuilder; +use BuilderAttribs; use cocoa::base::{id, NSUInteger, nil, objc_allocateClassPair, class, objc_registerClassPair}; use cocoa::base::{selector, msg_send, class_addMethod, class_addIvar}; @@ -20,9 +19,13 @@ use core_foundation::string::CFString; use core_foundation::bundle::{CFBundleGetBundleWithIdentifier, CFBundleGetFunctionPointerForName}; use std::cell::Cell; -use std::c_str::CString; +use std::ffi::{CString, c_str_to_bytes}; use std::mem; use std::ptr; +use std::collections::RingBuf; +use std::str::FromStr; +use std::str::from_utf8; +use std::ascii::AsciiExt; use events::Event::{MouseInput, MouseMoved, ReceivedCharacter, KeyboardInput, MouseWheel}; use events::ElementState::{Pressed, Released}; @@ -49,7 +52,7 @@ struct DelegateState<'a> { is_closed: bool, context: id, view: id, - handler: Option<fn(uint, uint)>, + handler: Option<fn(u32, u32)>, } pub struct Window { @@ -57,14 +60,14 @@ pub struct Window { window: id, context: id, delegate: id, - resize: Option<fn(uint, uint)>, + resize: Option<fn(u32, u32)>, is_closed: Cell<bool>, } #[cfg(feature = "window")] impl Window { - pub fn new(builder: WindowBuilder) -> Result<Window, CreationError> { + pub fn new(builder: BuilderAttribs) -> Result<Window, CreationError> { if builder.sharing.is_some() { unimplemented!() } @@ -74,7 +77,12 @@ impl Window { } #[cfg(feature = "window")] -#[deriving(Clone)] +unsafe impl Send for Window {} +#[cfg(feature = "window")] +unsafe impl Sync for Window {} + +#[cfg(feature = "window")] +#[derive(Clone)] pub struct WindowProxy; impl WindowProxy { @@ -121,7 +129,7 @@ extern fn window_did_resize(this: id, _: id) -> id { match state.handler { Some(handler) => { let rect = NSView::frame(state.view); - (handler)(rect.size.width as uint, rect.size.height as uint); + (handler)(rect.size.width as u32, rect.size.height as u32); } None => {} } @@ -130,7 +138,7 @@ extern fn window_did_resize(this: id, _: id) -> id { } impl Window { - fn new_impl(dimensions: Option<(uint, uint)>, title: &str, monitor: Option<MonitorID>, + fn new_impl(dimensions: Option<(u32, u32)>, title: &str, monitor: Option<MonitorID>, vsync: bool, visible: bool, gl_version: Option<(uint, uint)>) -> Result<Window, CreationError> { let app = match Window::create_app() { Some(app) => app, @@ -166,9 +174,9 @@ impl Window { let delegate = unsafe { // Create a delegate class, add callback methods and store InternalState as user data. let delegate = objc_allocateClassPair(ns_object, DELEGATE_NAME.as_ptr() as *const i8, 0); - class_addMethod(delegate, selector("windowShouldClose:"), window_should_close, "B@:@".to_c_str().as_ptr()); - class_addMethod(delegate, selector("windowDidResize:"), window_did_resize, "V@:@".to_c_str().as_ptr()); - class_addIvar(delegate, DELEGATE_STATE_IVAR.as_ptr() as *const i8, ptr_size, 3, "?".to_c_str().as_ptr()); + class_addMethod(delegate, selector("windowShouldClose:"), window_should_close, CString::from_slice("B@:@".as_bytes()).as_ptr()); + class_addMethod(delegate, selector("windowDidResize:"), window_did_resize, CString::from_slice("V@:@".as_bytes()).as_ptr()); + class_addIvar(delegate, DELEGATE_STATE_IVAR.as_ptr() as *const i8, ptr_size, 3, CString::from_slice("?".as_bytes()).as_ptr()); objc_registerClassPair(delegate); let del_obj = msg_send()(delegate, selector("alloc")); @@ -203,7 +211,7 @@ impl Window { } } - fn create_window(dimensions: (uint, uint), title: &str, monitor: Option<MonitorID>) -> Option<id> { + fn create_window(dimensions: (u32, u32), title: &str, monitor: Option<MonitorID>) -> Option<id> { unsafe { let scr_frame = match monitor { Some(_) => { @@ -269,13 +277,13 @@ impl Window { }; unsafe { let attributes = [ - NSOpenGLPFADoubleBuffer as uint, - NSOpenGLPFAClosestPolicy as uint, - NSOpenGLPFAColorSize as uint, 24, - NSOpenGLPFAAlphaSize as uint, 8, - NSOpenGLPFADepthSize as uint, 24, - NSOpenGLPFAStencilSize as uint, 8, - NSOpenGLPFAOpenGLProfile as uint, profile, + NSOpenGLPFADoubleBuffer as u32, + NSOpenGLPFAClosestPolicy as u32, + NSOpenGLPFAColorSize as u32, 24, + NSOpenGLPFAAlphaSize as u32, 8, + NSOpenGLPFADepthSize as u32, 24, + NSOpenGLPFAStencilSize as u32, 8, + NSOpenGLPFAOpenGLProfile as u32, profile, 0 ]; @@ -315,24 +323,24 @@ impl Window { pub fn hide(&self) { } - pub fn get_position(&self) -> Option<(int, int)> { + pub fn get_position(&self) -> Option<(i32, i32)> { unimplemented!() } - pub fn set_position(&self, _x: int, _y: int) { + pub fn set_position(&self, _x: i32, _y: i32) { unimplemented!() } - pub fn get_inner_size(&self) -> Option<(uint, uint)> { + pub fn get_inner_size(&self) -> Option<(u32, u32)> { let rect = unsafe { NSView::frame(self.view) }; - Some((rect.size.width as uint, rect.size.height as uint)) + Some((rect.size.width as u32, rect.size.height as u32)) } - pub fn get_outer_size(&self) -> Option<(uint, uint)> { + pub fn get_outer_size(&self) -> Option<(u32, u32)> { unimplemented!() } - pub fn set_inner_size(&self, _x: uint, _y: uint) { + pub fn set_inner_size(&self, _x: u32, _y: u32) { unimplemented!() } @@ -340,8 +348,8 @@ impl Window { WindowProxy } - pub fn poll_events(&self) -> Vec<Event> { - let mut events = Vec::new(); + pub fn poll_events(&self) -> RingBuf<Event> { + let mut events = RingBuf::new(); loop { unsafe { @@ -373,53 +381,54 @@ impl Window { } match event.get_type() { - NSLeftMouseDown => { events.push(MouseInput(Pressed, LeftMouseButton)); }, - NSLeftMouseUp => { events.push(MouseInput(Released, LeftMouseButton)); }, - NSRightMouseDown => { events.push(MouseInput(Pressed, RightMouseButton)); }, - NSRightMouseUp => { events.push(MouseInput(Released, RightMouseButton)); }, + NSLeftMouseDown => { events.push_back(MouseInput(Pressed, LeftMouseButton)); }, + NSLeftMouseUp => { events.push_back(MouseInput(Released, LeftMouseButton)); }, + NSRightMouseDown => { events.push_back(MouseInput(Pressed, RightMouseButton)); }, + NSRightMouseUp => { events.push_back(MouseInput(Released, RightMouseButton)); }, NSMouseMoved => { let window_point = event.locationInWindow(); let view_point = self.view.convertPoint_fromView_(window_point, nil); - events.push(MouseMoved((view_point.x as int, view_point.y as int))); + events.push_back(MouseMoved((view_point.x as i32, view_point.y as i32))); }, NSKeyDown => { - let received_str = CString::new(event.characters().UTF8String(), false); - for received_char in received_str.as_str().unwrap().chars() { + let received_c_str = event.characters().UTF8String(); + let received_str = CString::from_slice(c_str_to_bytes(&received_c_str)); + for received_char in from_utf8(received_str.as_bytes()).unwrap().chars() { if received_char.is_ascii() { - events.push(ReceivedCharacter(received_char)); + events.push_back(ReceivedCharacter(received_char)); } } let vkey = event::vkeycode_to_element(event.keycode()); - events.push(KeyboardInput(Pressed, event.keycode() as u8, vkey)); + events.push_back(KeyboardInput(Pressed, event.keycode() as u8, vkey)); }, NSKeyUp => { let vkey = event::vkeycode_to_element(event.keycode()); - events.push(KeyboardInput(Released, event.keycode() as u8, vkey)); + events.push_back(KeyboardInput(Released, event.keycode() as u8, vkey)); }, NSFlagsChanged => { let shift_modifier = Window::modifier_event(event, appkit::NSShiftKeyMask as u64, events::VirtualKeyCode::LShift, shift_pressed); if shift_modifier.is_some() { shift_pressed = !shift_pressed; - events.push(shift_modifier.unwrap()); + events.push_back(shift_modifier.unwrap()); } let ctrl_modifier = Window::modifier_event(event, appkit::NSControlKeyMask as u64, events::VirtualKeyCode::LControl, ctrl_pressed); if ctrl_modifier.is_some() { ctrl_pressed = !ctrl_pressed; - events.push(ctrl_modifier.unwrap()); + events.push_back(ctrl_modifier.unwrap()); } let win_modifier = Window::modifier_event(event, appkit::NSCommandKeyMask as u64, events::VirtualKeyCode::LWin, win_pressed); if win_modifier.is_some() { win_pressed = !win_pressed; - events.push(win_modifier.unwrap()); + events.push_back(win_modifier.unwrap()); } let alt_modifier = Window::modifier_event(event, appkit::NSAlternateKeyMask as u64, events::VirtualKeyCode::LAlt, alt_pressed); if alt_modifier.is_some() { alt_pressed = !alt_pressed; - events.push(alt_modifier.unwrap()); + events.push_back(alt_modifier.unwrap()); } }, - NSScrollWheel => { events.push(MouseWheel(-event.scrollingDeltaY() as i32)); }, + NSScrollWheel => { events.push_back(MouseWheel(-event.scrollingDeltaY() as i32)); }, NSOtherMouseDown => { }, NSOtherMouseUp => { }, NSOtherMouseDragged => { }, @@ -445,7 +454,7 @@ impl Window { event.modifierFlags() & modifier != 0 } - pub fn wait_events(&self) -> Vec<Event> { + pub fn wait_events(&self) -> RingBuf<Event> { unsafe { let event = NSApp().nextEventMatchingMask_untilDate_inMode_dequeue_( NSAnyEventMask as u64, @@ -463,8 +472,8 @@ impl Window { } pub fn get_proc_address(&self, _addr: &str) -> *const () { - let symbol_name = _addr.parse::<CFString>().unwrap(); - let framework_name = "com.apple.opengl".parse::<CFString>().unwrap(); + let symbol_name: CFString = FromStr::from_str(_addr).unwrap(); + let framework_name: CFString = FromStr::from_str("com.apple.opengl").unwrap(); let framework = unsafe { CFBundleGetBundleWithIdentifier(framework_name.as_concrete_TypeRef()) }; @@ -486,7 +495,11 @@ impl Window { ::Api::OpenGl } - pub fn set_window_resize_callback(&mut self, callback: Option<fn(uint, uint)>) { + pub fn set_window_resize_callback(&mut self, callback: Option<fn(u32, u32)>) { self.resize = callback; } + + pub fn set_cursor(&self, cursor: MouseCursor) { + unimplemented!() + } } diff --git a/src/osx/mod.rs.BACKUP.6164.rs b/src/osx/mod.rs.BACKUP.6164.rs new file mode 100644 index 0000000..7521b5d --- /dev/null +++ b/src/osx/mod.rs.BACKUP.6164.rs @@ -0,0 +1,524 @@ +#[cfg(feature = "headless")] +pub use self::headless::HeadlessContext; + +use {CreationError, Event, MouseCursor}; +use CreationError::OsError; +use libc; +use std::ascii::AsciiExt; + +use BuilderAttribs; + +use cocoa::base::{id, NSUInteger, nil, objc_allocateClassPair, class, objc_registerClassPair}; +use cocoa::base::{selector, msg_send, class_addMethod, class_addIvar}; +use cocoa::base::{object_setInstanceVariable, object_getInstanceVariable}; +use cocoa::appkit; +use cocoa::appkit::*; + +use core_foundation::base::TCFType; +use core_foundation::string::CFString; +use core_foundation::bundle::{CFBundleGetBundleWithIdentifier, CFBundleGetFunctionPointerForName}; + +use std::cell::Cell; +use std::ffi::{CString, c_str_to_bytes}; +use std::mem; +use std::ptr; +use std::collections::RingBuf; +use std::str::FromStr; +use std::str::from_utf8; +use std::ascii::AsciiExt; + +use events::Event::{MouseInput, MouseMoved, ReceivedCharacter, KeyboardInput, MouseWheel}; +use events::ElementState::{Pressed, Released}; +use events::MouseButton::{LeftMouseButton, RightMouseButton}; +use events; + +pub use self::monitor::{MonitorID, get_available_monitors, get_primary_monitor}; + +mod monitor; +mod event; + +#[cfg(feature = "headless")] +mod headless; + +static mut shift_pressed: bool = false; +static mut ctrl_pressed: bool = false; +static mut win_pressed: bool = false; +static mut alt_pressed: bool = false; + +static DELEGATE_NAME: &'static [u8] = b"glutin_window_delegate\0"; +static DELEGATE_STATE_IVAR: &'static [u8] = b"glutin_state"; + +struct DelegateState<'a> { + is_closed: bool, + context: id, + view: id, + handler: Option<fn(u32, u32)>, +} + +pub struct Window { + view: id, + window: id, + context: id, + delegate: id, + resize: Option<fn(u32, u32)>, + + is_closed: Cell<bool>, +} + +#[cfg(feature = "window")] +impl Window { + pub fn new(builder: BuilderAttribs) -> Result<Window, CreationError> { + if builder.sharing.is_some() { + unimplemented!() + } + + Window::new_impl(builder.dimensions, builder.title.as_slice(), builder.monitor, builder.vsync, builder.visible, builder.gl_version) + } +} + +#[cfg(feature = "window")] +unsafe impl Send for Window {} +#[cfg(feature = "window")] +unsafe impl Sync for Window {} + +#[cfg(feature = "window")] +#[derive(Clone)] +pub struct WindowProxy; + +impl WindowProxy { + pub fn wakeup_event_loop(&self) { + unsafe { + let pool = NSAutoreleasePool::new(nil); + let event = + NSEvent::otherEventWithType_location_modifierFlags_timestamp_windowNumber_context_subtype_data1_data2( + nil, + NSApplicationDefined, + NSPoint::new(0.0, 0.0), + 0, + 0.0, + 0, + ptr::null_mut(), + 0, + 0, + 0); + NSApp().postEvent_atStart_(event, true); + pool.drain(); + } + } +} + +extern fn window_should_close(this: id, _: id) -> id { + unsafe { + let mut stored_value = ptr::null_mut(); + object_getInstanceVariable(this, DELEGATE_STATE_IVAR.as_ptr() as *const i8, &mut stored_value); + let state = stored_value as *mut DelegateState; + + (*state).is_closed = true; + } + 0 +} + +extern fn window_did_resize(this: id, _: id) -> id { + unsafe { + let mut stored_value = ptr::null_mut(); + object_getInstanceVariable(this, DELEGATE_STATE_IVAR.as_ptr() as *const i8, &mut stored_value); + let state = &mut *(stored_value as *mut DelegateState); + + let _: id = msg_send()(state.context, selector("update")); + + match state.handler { + Some(handler) => { + let rect = NSView::frame(state.view); + (handler)(rect.size.width as u32, rect.size.height as u32); + } + None => {} + } + } + 0 +} + +impl Window { +<<<<<<< HEAD + fn new_impl(dimensions: Option<(u32, u32)>, title: &str, monitor: Option<MonitorID>, + vsync: bool, visible: bool) -> Result<Window, CreationError> { +======= + fn new_impl(dimensions: Option<(uint, uint)>, title: &str, monitor: Option<MonitorID>, + vsync: bool, visible: bool, gl_version: Option<(uint, uint)>) -> Result<Window, CreationError> { +>>>>>>> pixelpirate/master + let app = match Window::create_app() { + Some(app) => app, + None => { return Err(OsError(format!("Couldn't create NSApplication"))); }, + }; + let window = match Window::create_window(dimensions.unwrap_or((800, 600)), title, monitor) { + Some(window) => window, + None => { return Err(OsError(format!("Couldn't create NSWindow"))); }, + }; + let view = match Window::create_view(window) { + Some(view) => view, + None => { return Err(OsError(format!("Couldn't create NSView"))); }, + }; + + let context = match Window::create_context(view, vsync, gl_version) { + Some(context) => context, + None => { return Err(OsError(format!("Couldn't create OpenGL context"))); }, + }; + + unsafe { + app.activateIgnoringOtherApps_(true); + if visible { + window.makeKeyAndOrderFront_(nil); + } else { + window.makeKeyWindow(); + } + } + + // Set up the window delegate to receive events + let ptr_size = mem::size_of::<libc::intptr_t>() as u64; + let ns_object = class("NSObject"); + + let delegate = unsafe { + // Create a delegate class, add callback methods and store InternalState as user data. + let delegate = objc_allocateClassPair(ns_object, DELEGATE_NAME.as_ptr() as *const i8, 0); + class_addMethod(delegate, selector("windowShouldClose:"), window_should_close, CString::from_slice("B@:@".as_bytes()).as_ptr()); + class_addMethod(delegate, selector("windowDidResize:"), window_did_resize, CString::from_slice("V@:@".as_bytes()).as_ptr()); + class_addIvar(delegate, DELEGATE_STATE_IVAR.as_ptr() as *const i8, ptr_size, 3, CString::from_slice("?".as_bytes()).as_ptr()); + objc_registerClassPair(delegate); + + let del_obj = msg_send()(delegate, selector("alloc")); + let del_obj: id = msg_send()(del_obj, selector("init")); + let _: id = msg_send()(window, selector("setDelegate:"), del_obj); + del_obj + }; + + let window = Window { + view: view, + window: window, + context: context, + delegate: delegate, + resize: None, + + is_closed: Cell::new(false), + }; + + Ok(window) + } + + fn create_app() -> Option<id> { + unsafe { + let app = NSApp(); + if app == nil { + None + } else { + app.setActivationPolicy_(NSApplicationActivationPolicyRegular); + app.finishLaunching(); + Some(app) + } + } + } + + fn create_window(dimensions: (u32, u32), title: &str, monitor: Option<MonitorID>) -> Option<id> { + unsafe { + let scr_frame = match monitor { + Some(_) => { + let screen = NSScreen::mainScreen(nil); + NSScreen::frame(screen) + } + None => { + let (width, height) = dimensions; + NSRect::new(NSPoint::new(0., 0.), NSSize::new(width as f64, height as f64)) + } + }; + + let masks = match monitor { + Some(_) => NSBorderlessWindowMask as NSUInteger, + None => NSTitledWindowMask as NSUInteger | + NSClosableWindowMask as NSUInteger | + NSMiniaturizableWindowMask as NSUInteger | + NSResizableWindowMask as NSUInteger, + }; + + let window = NSWindow::alloc(nil).initWithContentRect_styleMask_backing_defer_( + scr_frame, + masks, + NSBackingStoreBuffered, + false, + ); + + if window == nil { + None + } else { + let title = NSString::alloc(nil).init_str(title); + window.setTitle_(title); + window.setAcceptsMouseMovedEvents_(true); + if monitor.is_some() { + window.setLevel_(NSMainMenuWindowLevel as i64 + 1); + } + else { + window.center(); + } + Some(window) + } + } + } + + fn create_view(window: id) -> Option<id> { + unsafe { + let view = NSView::alloc(nil).init(); + if view == nil { + None + } else { + view.setWantsBestResolutionOpenGLSurface_(true); + window.setContentView_(view); + Some(view) + } + } + } + + fn create_context(view: id, vsync: bool, gl_version: Option<(uint, uint)>) -> Option<id> { + let profile = match gl_version { + None | Some((0...2, _)) | Some((3, 0)) => NSOpenGLProfileVersionLegacy as uint, + Some((3, 1...2)) => NSOpenGLProfileVersion3_2Core as uint, + Some((_, _)) => NSOpenGLProfileVersion4_1Core as uint, + }; + unsafe { + let attributes = [ +<<<<<<< HEAD + NSOpenGLPFADoubleBuffer as u32, + NSOpenGLPFAClosestPolicy as u32, + NSOpenGLPFAColorSize as u32, 24, + NSOpenGLPFAAlphaSize as u32, 8, + NSOpenGLPFADepthSize as u32, 24, + NSOpenGLPFAStencilSize as u32, 8, +======= + NSOpenGLPFADoubleBuffer as uint, + NSOpenGLPFAClosestPolicy as uint, + NSOpenGLPFAColorSize as uint, 24, + NSOpenGLPFAAlphaSize as uint, 8, + NSOpenGLPFADepthSize as uint, 24, + NSOpenGLPFAStencilSize as uint, 8, + NSOpenGLPFAOpenGLProfile as uint, profile, +>>>>>>> pixelpirate/master + 0 + ]; + + let pixelformat = NSOpenGLPixelFormat::alloc(nil).initWithAttributes_(&attributes); + if pixelformat == nil { + return None; + } + + let context = NSOpenGLContext::alloc(nil).initWithFormat_shareContext_(pixelformat, nil); + if context == nil { + None + } else { + context.setView_(view); + if vsync { + let value = 1; + context.setValues_forParameter_(&value, NSOpenGLContextParameter::NSOpenGLCPSwapInterval); + } + Some(context) + } + } + } + + pub fn is_closed(&self) -> bool { + self.is_closed.get() + } + + pub fn set_title(&self, title: &str) { + unsafe { + let title = NSString::alloc(nil).init_str(title); + self.window.setTitle_(title); + } + } + + pub fn show(&self) { + } + + pub fn hide(&self) { + } + + pub fn get_position(&self) -> Option<(i32, i32)> { + unimplemented!() + } + + pub fn set_position(&self, _x: i32, _y: i32) { + unimplemented!() + } + + pub fn get_inner_size(&self) -> Option<(u32, u32)> { + let rect = unsafe { NSView::frame(self.view) }; + Some((rect.size.width as u32, rect.size.height as u32)) + } + + pub fn get_outer_size(&self) -> Option<(u32, u32)> { + unimplemented!() + } + + pub fn set_inner_size(&self, _x: u32, _y: u32) { + unimplemented!() + } + + pub fn create_window_proxy(&self) -> WindowProxy { + WindowProxy + } + + pub fn poll_events(&self) -> RingBuf<Event> { + let mut events = RingBuf::new(); + + loop { + unsafe { + let event = NSApp().nextEventMatchingMask_untilDate_inMode_dequeue_( + NSAnyEventMask as u64, + NSDate::distantPast(nil), + NSDefaultRunLoopMode, + true); + if event == nil { break; } + { + // Create a temporary structure with state that delegates called internally + // by sendEvent can read and modify. When that returns, update window state. + // This allows the synchronous resize loop to continue issuing callbacks + // to the user application, by passing handler through to the delegate state. + let mut ds = DelegateState { + is_closed: self.is_closed.get(), + context: self.context, + view: self.view, + handler: self.resize, + }; + object_setInstanceVariable(self.delegate, + DELEGATE_STATE_IVAR.as_ptr() as *const i8, + &mut ds as *mut DelegateState as *mut libc::c_void); + NSApp().sendEvent_(event); + object_setInstanceVariable(self.delegate, + DELEGATE_STATE_IVAR.as_ptr() as *const i8, + ptr::null_mut()); + self.is_closed.set(ds.is_closed); +} + + match event.get_type() { + NSLeftMouseDown => { events.push_back(MouseInput(Pressed, LeftMouseButton)); }, + NSLeftMouseUp => { events.push_back(MouseInput(Released, LeftMouseButton)); }, + NSRightMouseDown => { events.push_back(MouseInput(Pressed, RightMouseButton)); }, + NSRightMouseUp => { events.push_back(MouseInput(Released, RightMouseButton)); }, + NSMouseMoved => { + let window_point = event.locationInWindow(); + let view_point = self.view.convertPoint_fromView_(window_point, nil); + events.push_back(MouseMoved((view_point.x as i32, view_point.y as i32))); + }, + NSKeyDown => { + let received_c_str = event.characters().UTF8String(); + let received_str = CString::from_slice(c_str_to_bytes(&received_c_str)); + for received_char in from_utf8(received_str.as_bytes()).unwrap().chars() { + if received_char.is_ascii() { + events.push_back(ReceivedCharacter(received_char)); + } + } + + let vkey = event::vkeycode_to_element(event.keycode()); + events.push_back(KeyboardInput(Pressed, event.keycode() as u8, vkey)); + }, + NSKeyUp => { + let vkey = event::vkeycode_to_element(event.keycode()); + events.push_back(KeyboardInput(Released, event.keycode() as u8, vkey)); + }, + NSFlagsChanged => { + let shift_modifier = Window::modifier_event(event, appkit::NSShiftKeyMask as u64, events::VirtualKeyCode::LShift, shift_pressed); + if shift_modifier.is_some() { + shift_pressed = !shift_pressed; + events.push_back(shift_modifier.unwrap()); + } + let ctrl_modifier = Window::modifier_event(event, appkit::NSControlKeyMask as u64, events::VirtualKeyCode::LControl, ctrl_pressed); + if ctrl_modifier.is_some() { + ctrl_pressed = !ctrl_pressed; + events.push_back(ctrl_modifier.unwrap()); + } + let win_modifier = Window::modifier_event(event, appkit::NSCommandKeyMask as u64, events::VirtualKeyCode::LWin, win_pressed); + if win_modifier.is_some() { + win_pressed = !win_pressed; + events.push_back(win_modifier.unwrap()); + } + let alt_modifier = Window::modifier_event(event, appkit::NSAlternateKeyMask as u64, events::VirtualKeyCode::LAlt, alt_pressed); + if alt_modifier.is_some() { + alt_pressed = !alt_pressed; + events.push_back(alt_modifier.unwrap()); + } + }, + NSScrollWheel => { events.push_back(MouseWheel(-event.scrollingDeltaY() as i32)); }, + NSOtherMouseDown => { }, + NSOtherMouseUp => { }, + NSOtherMouseDragged => { }, + _ => { }, + } + } + } + events + } + + unsafe fn modifier_event(event: id, keymask: u64, key: events::VirtualKeyCode, key_pressed: bool) -> Option<Event> { + if !key_pressed && Window::modifier_key_pressed(event, keymask) { + return Some(KeyboardInput(Pressed, event.keycode() as u8, Some(key))); + } + else if key_pressed && !Window::modifier_key_pressed(event, keymask) { + return Some(KeyboardInput(Released, event.keycode() as u8, Some(key))); + } + + return None; + } + + unsafe fn modifier_key_pressed(event: id, modifier: u64) -> bool { + event.modifierFlags() & modifier != 0 + } + + pub fn wait_events(&self) -> RingBuf<Event> { + unsafe { + let event = NSApp().nextEventMatchingMask_untilDate_inMode_dequeue_( + NSAnyEventMask as u64, + NSDate::distantFuture(nil), + NSDefaultRunLoopMode, + false); + NSApp().sendEvent_(event); + + self.poll_events() + } + } + + pub unsafe fn make_current(&self) { + self.context.makeCurrentContext(); + } + + pub fn get_proc_address(&self, _addr: &str) -> *const () { +<<<<<<< HEAD + let symbol_name: CFString = FromStr::from_str(_addr).unwrap(); + let framework_name: CFString = FromStr::from_str("com.apple.opengl").unwrap(); +======= + let symbol_name = _addr.parse::<CFString>().unwrap(); + let framework_name = "com.apple.opengl".parse::<CFString>().unwrap(); +>>>>>>> pixelpirate/master + let framework = unsafe { + CFBundleGetBundleWithIdentifier(framework_name.as_concrete_TypeRef()) + }; + let symbol = unsafe { + CFBundleGetFunctionPointerForName(framework, symbol_name.as_concrete_TypeRef()) + }; + symbol as *const () + } + + pub fn swap_buffers(&self) { + unsafe { self.context.flushBuffer(); } + } + + pub fn platform_display(&self) -> *mut libc::c_void { + unimplemented!() + } + + pub fn get_api(&self) -> ::Api { + ::Api::OpenGl + } + + pub fn set_window_resize_callback(&mut self, callback: Option<fn(u32, u32)>) { + self.resize = callback; + } + + pub fn set_cursor(&self, cursor: MouseCursor) { + unimplemented!() + } +} diff --git a/src/osx/mod.rs.BASE.6164.rs b/src/osx/mod.rs.BASE.6164.rs new file mode 100644 index 0000000..7df6603 --- /dev/null +++ b/src/osx/mod.rs.BASE.6164.rs @@ -0,0 +1,485 @@ +#[cfg(feature = "headless")] +pub use self::headless::HeadlessContext; + +use {CreationError, Event}; +use CreationError::OsError; +use libc; + +#[cfg(feature = "window")] +use WindowBuilder; + +use cocoa::base::{id, NSUInteger, nil, objc_allocateClassPair, class, objc_registerClassPair}; +use cocoa::base::{selector, msg_send, class_addMethod, class_addIvar}; +use cocoa::base::{object_setInstanceVariable, object_getInstanceVariable}; +use cocoa::appkit; +use cocoa::appkit::*; + +use core_foundation::base::TCFType; +use core_foundation::string::CFString; +use core_foundation::bundle::{CFBundleGetBundleWithIdentifier, CFBundleGetFunctionPointerForName}; + +use std::cell::Cell; +use std::c_str::CString; +use std::mem; +use std::ptr; + +use events::Event::{MouseInput, MouseMoved, ReceivedCharacter, KeyboardInput, MouseWheel}; +use events::ElementState::{Pressed, Released}; +use events::MouseButton::{LeftMouseButton, RightMouseButton}; +use events; + +pub use self::monitor::{MonitorID, get_available_monitors, get_primary_monitor}; + +mod monitor; +mod event; + +#[cfg(feature = "headless")] +mod headless; + +static mut shift_pressed: bool = false; +static mut ctrl_pressed: bool = false; +static mut win_pressed: bool = false; +static mut alt_pressed: bool = false; + +static DELEGATE_NAME: &'static [u8] = b"glutin_window_delegate\0"; +static DELEGATE_STATE_IVAR: &'static [u8] = b"glutin_state"; + +struct DelegateState<'a> { + is_closed: bool, + context: id, + view: id, + handler: Option<fn(uint, uint)>, +} + +pub struct Window { + view: id, + window: id, + context: id, + delegate: id, + resize: Option<fn(uint, uint)>, + + is_closed: Cell<bool>, +} + +#[cfg(feature = "window")] +impl Window { + pub fn new(builder: WindowBuilder) -> Result<Window, CreationError> { + if builder.sharing.is_some() { + unimplemented!() + } + + Window::new_impl(builder.dimensions, builder.title.as_slice(), builder.monitor, builder.vsync, builder.visible) + } +} + +#[cfg(feature = "window")] +#[deriving(Clone)] +pub struct WindowProxy; + +impl WindowProxy { + pub fn wakeup_event_loop(&self) { + unsafe { + let pool = NSAutoreleasePool::new(nil); + let event = + NSEvent::otherEventWithType_location_modifierFlags_timestamp_windowNumber_context_subtype_data1_data2( + nil, + NSApplicationDefined, + NSPoint::new(0.0, 0.0), + 0, + 0.0, + 0, + ptr::null_mut(), + 0, + 0, + 0); + NSApp().postEvent_atStart_(event, true); + pool.drain(); + } + } +} + +extern fn window_should_close(this: id, _: id) -> id { + unsafe { + let mut stored_value = ptr::null_mut(); + object_getInstanceVariable(this, DELEGATE_STATE_IVAR.as_ptr() as *const i8, &mut stored_value); + let state = stored_value as *mut DelegateState; + + (*state).is_closed = true; + } + 0 +} + +extern fn window_did_resize(this: id, _: id) -> id { + unsafe { + let mut stored_value = ptr::null_mut(); + object_getInstanceVariable(this, DELEGATE_STATE_IVAR.as_ptr() as *const i8, &mut stored_value); + let state = &mut *(stored_value as *mut DelegateState); + + let _: id = msg_send()(state.context, selector("update")); + + match state.handler { + Some(handler) => { + let rect = NSView::frame(state.view); + (handler)(rect.size.width as uint, rect.size.height as uint); + } + None => {} + } + } + 0 +} + +impl Window { + fn new_impl(dimensions: Option<(uint, uint)>, title: &str, monitor: Option<MonitorID>, + vsync: bool, visible: bool) -> Result<Window, CreationError> { + let app = match Window::create_app() { + Some(app) => app, + None => { return Err(OsError(format!("Couldn't create NSApplication"))); }, + }; + let window = match Window::create_window(dimensions.unwrap_or((800, 600)), title, monitor) { + Some(window) => window, + None => { return Err(OsError(format!("Couldn't create NSWindow"))); }, + }; + let view = match Window::create_view(window) { + Some(view) => view, + None => { return Err(OsError(format!("Couldn't create NSView"))); }, + }; + + let context = match Window::create_context(view, vsync) { + Some(context) => context, + None => { return Err(OsError(format!("Couldn't create OpenGL context"))); }, + }; + + unsafe { + app.activateIgnoringOtherApps_(true); + if visible { + window.makeKeyAndOrderFront_(nil); + } else { + window.makeKeyWindow(); + } + } + + // Set up the window delegate to receive events + let ptr_size = mem::size_of::<libc::intptr_t>() as u64; + let ns_object = class("NSObject"); + + let delegate = unsafe { + // Create a delegate class, add callback methods and store InternalState as user data. + let delegate = objc_allocateClassPair(ns_object, DELEGATE_NAME.as_ptr() as *const i8, 0); + class_addMethod(delegate, selector("windowShouldClose:"), window_should_close, "B@:@".to_c_str().as_ptr()); + class_addMethod(delegate, selector("windowDidResize:"), window_did_resize, "V@:@".to_c_str().as_ptr()); + class_addIvar(delegate, DELEGATE_STATE_IVAR.as_ptr() as *const i8, ptr_size, 3, "?".to_c_str().as_ptr()); + objc_registerClassPair(delegate); + + let del_obj = msg_send()(delegate, selector("alloc")); + let del_obj: id = msg_send()(del_obj, selector("init")); + let _: id = msg_send()(window, selector("setDelegate:"), del_obj); + del_obj + }; + + let window = Window { + view: view, + window: window, + context: context, + delegate: delegate, + resize: None, + + is_closed: Cell::new(false), + }; + + Ok(window) + } + + fn create_app() -> Option<id> { + unsafe { + let app = NSApp(); + if app == nil { + None + } else { + app.setActivationPolicy_(NSApplicationActivationPolicyRegular); + app.finishLaunching(); + Some(app) + } + } + } + + fn create_window(dimensions: (uint, uint), title: &str, monitor: Option<MonitorID>) -> Option<id> { + unsafe { + let scr_frame = match monitor { + Some(_) => { + let screen = NSScreen::mainScreen(nil); + NSScreen::frame(screen) + } + None => { + let (width, height) = dimensions; + NSRect::new(NSPoint::new(0., 0.), NSSize::new(width as f64, height as f64)) + } + }; + + let masks = match monitor { + Some(_) => NSBorderlessWindowMask as NSUInteger, + None => NSTitledWindowMask as NSUInteger | + NSClosableWindowMask as NSUInteger | + NSMiniaturizableWindowMask as NSUInteger | + NSResizableWindowMask as NSUInteger, + }; + + let window = NSWindow::alloc(nil).initWithContentRect_styleMask_backing_defer_( + scr_frame, + masks, + NSBackingStoreBuffered, + false, + ); + + if window == nil { + None + } else { + let title = NSString::alloc(nil).init_str(title); + window.setTitle_(title); + window.setAcceptsMouseMovedEvents_(true); + if monitor.is_some() { + window.setLevel_(NSMainMenuWindowLevel as i64 + 1); + } + else { + window.center(); + } + Some(window) + } + } + } + + fn create_view(window: id) -> Option<id> { + unsafe { + let view = NSView::alloc(nil).init(); + if view == nil { + None + } else { + view.setWantsBestResolutionOpenGLSurface_(true); + window.setContentView_(view); + Some(view) + } + } + } + + fn create_context(view: id, vsync: bool) -> Option<id> { + unsafe { + let attributes = [ + NSOpenGLPFADoubleBuffer as uint, + NSOpenGLPFAClosestPolicy as uint, + NSOpenGLPFAColorSize as uint, 24, + NSOpenGLPFAAlphaSize as uint, 8, + NSOpenGLPFADepthSize as uint, 24, + NSOpenGLPFAStencilSize as uint, 8, + 0 + ]; + + let pixelformat = NSOpenGLPixelFormat::alloc(nil).initWithAttributes_(&attributes); + if pixelformat == nil { + return None; + } + + let context = NSOpenGLContext::alloc(nil).initWithFormat_shareContext_(pixelformat, nil); + if context == nil { + None + } else { + context.setView_(view); + if vsync { + let value = 1; + context.setValues_forParameter_(&value, NSOpenGLContextParameter::NSOpenGLCPSwapInterval); + } + Some(context) + } + } + } + + pub fn is_closed(&self) -> bool { + self.is_closed.get() + } + + pub fn set_title(&self, title: &str) { + unsafe { + let title = NSString::alloc(nil).init_str(title); + self.window.setTitle_(title); + } + } + + pub fn show(&self) { + } + + pub fn hide(&self) { + } + + pub fn get_position(&self) -> Option<(int, int)> { + unimplemented!() + } + + pub fn set_position(&self, _x: int, _y: int) { + unimplemented!() + } + + pub fn get_inner_size(&self) -> Option<(uint, uint)> { + let rect = unsafe { NSView::frame(self.view) }; + Some((rect.size.width as uint, rect.size.height as uint)) + } + + pub fn get_outer_size(&self) -> Option<(uint, uint)> { + unimplemented!() + } + + pub fn set_inner_size(&self, _x: uint, _y: uint) { + unimplemented!() + } + + pub fn create_window_proxy(&self) -> WindowProxy { + WindowProxy + } + + pub fn poll_events(&self) -> Vec<Event> { + let mut events = Vec::new(); + + loop { + unsafe { + let event = NSApp().nextEventMatchingMask_untilDate_inMode_dequeue_( + NSAnyEventMask as u64, + NSDate::distantPast(nil), + NSDefaultRunLoopMode, + true); + if event == nil { break; } + { + // Create a temporary structure with state that delegates called internally + // by sendEvent can read and modify. When that returns, update window state. + // This allows the synchronous resize loop to continue issuing callbacks + // to the user application, by passing handler through to the delegate state. + let mut ds = DelegateState { + is_closed: self.is_closed.get(), + context: self.context, + view: self.view, + handler: self.resize, + }; + object_setInstanceVariable(self.delegate, + DELEGATE_STATE_IVAR.as_ptr() as *const i8, + &mut ds as *mut DelegateState as *mut libc::c_void); + NSApp().sendEvent_(event); + object_setInstanceVariable(self.delegate, + DELEGATE_STATE_IVAR.as_ptr() as *const i8, + ptr::null_mut()); + self.is_closed.set(ds.is_closed); +} + + match event.get_type() { + NSLeftMouseDown => { events.push(MouseInput(Pressed, LeftMouseButton)); }, + NSLeftMouseUp => { events.push(MouseInput(Released, LeftMouseButton)); }, + NSRightMouseDown => { events.push(MouseInput(Pressed, RightMouseButton)); }, + NSRightMouseUp => { events.push(MouseInput(Released, RightMouseButton)); }, + NSMouseMoved => { + let window_point = event.locationInWindow(); + let view_point = self.view.convertPoint_fromView_(window_point, nil); + events.push(MouseMoved((view_point.x as int, view_point.y as int))); + }, + NSKeyDown => { + let received_str = CString::new(event.characters().UTF8String(), false); + for received_char in received_str.as_str().unwrap().chars() { + if received_char.is_ascii() { + events.push(ReceivedCharacter(received_char)); + } + } + + let vkey = event::vkeycode_to_element(event.keycode()); + events.push(KeyboardInput(Pressed, event.keycode() as u8, vkey)); + }, + NSKeyUp => { + let vkey = event::vkeycode_to_element(event.keycode()); + events.push(KeyboardInput(Released, event.keycode() as u8, vkey)); + }, + NSFlagsChanged => { + let shift_modifier = Window::modifier_event(event, appkit::NSShiftKeyMask as u64, events::VirtualKeyCode::LShift, shift_pressed); + if shift_modifier.is_some() { + shift_pressed = !shift_pressed; + events.push(shift_modifier.unwrap()); + } + let ctrl_modifier = Window::modifier_event(event, appkit::NSControlKeyMask as u64, events::VirtualKeyCode::LControl, ctrl_pressed); + if ctrl_modifier.is_some() { + ctrl_pressed = !ctrl_pressed; + events.push(ctrl_modifier.unwrap()); + } + let win_modifier = Window::modifier_event(event, appkit::NSCommandKeyMask as u64, events::VirtualKeyCode::LWin, win_pressed); + if win_modifier.is_some() { + win_pressed = !win_pressed; + events.push(win_modifier.unwrap()); + } + let alt_modifier = Window::modifier_event(event, appkit::NSAlternateKeyMask as u64, events::VirtualKeyCode::LAlt, alt_pressed); + if alt_modifier.is_some() { + alt_pressed = !alt_pressed; + events.push(alt_modifier.unwrap()); + } + }, + NSScrollWheel => { events.push(MouseWheel(-event.scrollingDeltaY() as i32)); }, + NSOtherMouseDown => { }, + NSOtherMouseUp => { }, + NSOtherMouseDragged => { }, + _ => { }, + } + } + } + events + } + + unsafe fn modifier_event(event: id, keymask: u64, key: events::VirtualKeyCode, key_pressed: bool) -> Option<Event> { + if !key_pressed && Window::modifier_key_pressed(event, keymask) { + return Some(KeyboardInput(Pressed, event.keycode() as u8, Some(key))); + } + else if key_pressed && !Window::modifier_key_pressed(event, keymask) { + return Some(KeyboardInput(Released, event.keycode() as u8, Some(key))); + } + + return None; + } + + unsafe fn modifier_key_pressed(event: id, modifier: u64) -> bool { + event.modifierFlags() & modifier != 0 + } + + pub fn wait_events(&self) -> Vec<Event> { + unsafe { + let event = NSApp().nextEventMatchingMask_untilDate_inMode_dequeue_( + NSAnyEventMask as u64, + NSDate::distantFuture(nil), + NSDefaultRunLoopMode, + false); + NSApp().sendEvent_(event); + + self.poll_events() + } + } + + pub unsafe fn make_current(&self) { + self.context.makeCurrentContext(); + } + + pub fn get_proc_address(&self, _addr: &str) -> *const () { + let symbol_name: CFString = from_str(_addr).unwrap(); + let framework_name: CFString = from_str("com.apple.opengl").unwrap(); + let framework = unsafe { + CFBundleGetBundleWithIdentifier(framework_name.as_concrete_TypeRef()) + }; + let symbol = unsafe { + CFBundleGetFunctionPointerForName(framework, symbol_name.as_concrete_TypeRef()) + }; + symbol as *const () + } + + pub fn swap_buffers(&self) { + unsafe { self.context.flushBuffer(); } + } + + pub fn platform_display(&self) -> *mut libc::c_void { + unimplemented!() + } + + pub fn get_api(&self) -> ::Api { + ::Api::OpenGl + } + + pub fn set_window_resize_callback(&mut self, callback: Option<fn(uint, uint)>) { + self.resize = callback; + } +} diff --git a/src/osx/mod.rs.LOCAL.6164.rs b/src/osx/mod.rs.LOCAL.6164.rs new file mode 100644 index 0000000..59d979a --- /dev/null +++ b/src/osx/mod.rs.LOCAL.6164.rs @@ -0,0 +1,498 @@ +#[cfg(feature = "headless")] +pub use self::headless::HeadlessContext; + +use {CreationError, Event, MouseCursor}; +use CreationError::OsError; +use libc; + +use BuilderAttribs; + +use cocoa::base::{id, NSUInteger, nil, objc_allocateClassPair, class, objc_registerClassPair}; +use cocoa::base::{selector, msg_send, class_addMethod, class_addIvar}; +use cocoa::base::{object_setInstanceVariable, object_getInstanceVariable}; +use cocoa::appkit; +use cocoa::appkit::*; + +use core_foundation::base::TCFType; +use core_foundation::string::CFString; +use core_foundation::bundle::{CFBundleGetBundleWithIdentifier, CFBundleGetFunctionPointerForName}; + +use std::cell::Cell; +use std::ffi::{CString, c_str_to_bytes}; +use std::mem; +use std::ptr; +use std::collections::RingBuf; +use std::str::FromStr; +use std::str::from_utf8; +use std::ascii::AsciiExt; + +use events::Event::{MouseInput, MouseMoved, ReceivedCharacter, KeyboardInput, MouseWheel}; +use events::ElementState::{Pressed, Released}; +use events::MouseButton::{LeftMouseButton, RightMouseButton}; +use events; + +pub use self::monitor::{MonitorID, get_available_monitors, get_primary_monitor}; + +mod monitor; +mod event; + +#[cfg(feature = "headless")] +mod headless; + +static mut shift_pressed: bool = false; +static mut ctrl_pressed: bool = false; +static mut win_pressed: bool = false; +static mut alt_pressed: bool = false; + +static DELEGATE_NAME: &'static [u8] = b"glutin_window_delegate\0"; +static DELEGATE_STATE_IVAR: &'static [u8] = b"glutin_state"; + +struct DelegateState<'a> { + is_closed: bool, + context: id, + view: id, + handler: Option<fn(u32, u32)>, +} + +pub struct Window { + view: id, + window: id, + context: id, + delegate: id, + resize: Option<fn(u32, u32)>, + + is_closed: Cell<bool>, +} + +#[cfg(feature = "window")] +impl Window { + pub fn new(builder: BuilderAttribs) -> Result<Window, CreationError> { + if builder.sharing.is_some() { + unimplemented!() + } + + Window::new_impl(builder.dimensions, builder.title.as_slice(), builder.monitor, builder.vsync, builder.visible) + } +} + +#[cfg(feature = "window")] +unsafe impl Send for Window {} +#[cfg(feature = "window")] +unsafe impl Sync for Window {} + +#[cfg(feature = "window")] +#[derive(Clone)] +pub struct WindowProxy; + +impl WindowProxy { + pub fn wakeup_event_loop(&self) { + unsafe { + let pool = NSAutoreleasePool::new(nil); + let event = + NSEvent::otherEventWithType_location_modifierFlags_timestamp_windowNumber_context_subtype_data1_data2( + nil, + NSApplicationDefined, + NSPoint::new(0.0, 0.0), + 0, + 0.0, + 0, + ptr::null_mut(), + 0, + 0, + 0); + NSApp().postEvent_atStart_(event, true); + pool.drain(); + } + } +} + +extern fn window_should_close(this: id, _: id) -> id { + unsafe { + let mut stored_value = ptr::null_mut(); + object_getInstanceVariable(this, DELEGATE_STATE_IVAR.as_ptr() as *const i8, &mut stored_value); + let state = stored_value as *mut DelegateState; + + (*state).is_closed = true; + } + 0 +} + +extern fn window_did_resize(this: id, _: id) -> id { + unsafe { + let mut stored_value = ptr::null_mut(); + object_getInstanceVariable(this, DELEGATE_STATE_IVAR.as_ptr() as *const i8, &mut stored_value); + let state = &mut *(stored_value as *mut DelegateState); + + let _: id = msg_send()(state.context, selector("update")); + + match state.handler { + Some(handler) => { + let rect = NSView::frame(state.view); + (handler)(rect.size.width as u32, rect.size.height as u32); + } + None => {} + } + } + 0 +} + +impl Window { + fn new_impl(dimensions: Option<(u32, u32)>, title: &str, monitor: Option<MonitorID>, + vsync: bool, visible: bool) -> Result<Window, CreationError> { + let app = match Window::create_app() { + Some(app) => app, + None => { return Err(OsError(format!("Couldn't create NSApplication"))); }, + }; + let window = match Window::create_window(dimensions.unwrap_or((800, 600)), title, monitor) { + Some(window) => window, + None => { return Err(OsError(format!("Couldn't create NSWindow"))); }, + }; + let view = match Window::create_view(window) { + Some(view) => view, + None => { return Err(OsError(format!("Couldn't create NSView"))); }, + }; + + let context = match Window::create_context(view, vsync) { + Some(context) => context, + None => { return Err(OsError(format!("Couldn't create OpenGL context"))); }, + }; + + unsafe { + app.activateIgnoringOtherApps_(true); + if visible { + window.makeKeyAndOrderFront_(nil); + } else { + window.makeKeyWindow(); + } + } + + // Set up the window delegate to receive events + let ptr_size = mem::size_of::<libc::intptr_t>() as u64; + let ns_object = class("NSObject"); + + let delegate = unsafe { + // Create a delegate class, add callback methods and store InternalState as user data. + let delegate = objc_allocateClassPair(ns_object, DELEGATE_NAME.as_ptr() as *const i8, 0); + class_addMethod(delegate, selector("windowShouldClose:"), window_should_close, CString::from_slice("B@:@".as_bytes()).as_ptr()); + class_addMethod(delegate, selector("windowDidResize:"), window_did_resize, CString::from_slice("V@:@".as_bytes()).as_ptr()); + class_addIvar(delegate, DELEGATE_STATE_IVAR.as_ptr() as *const i8, ptr_size, 3, CString::from_slice("?".as_bytes()).as_ptr()); + objc_registerClassPair(delegate); + + let del_obj = msg_send()(delegate, selector("alloc")); + let del_obj: id = msg_send()(del_obj, selector("init")); + let _: id = msg_send()(window, selector("setDelegate:"), del_obj); + del_obj + }; + + let window = Window { + view: view, + window: window, + context: context, + delegate: delegate, + resize: None, + + is_closed: Cell::new(false), + }; + + Ok(window) + } + + fn create_app() -> Option<id> { + unsafe { + let app = NSApp(); + if app == nil { + None + } else { + app.setActivationPolicy_(NSApplicationActivationPolicyRegular); + app.finishLaunching(); + Some(app) + } + } + } + + fn create_window(dimensions: (u32, u32), title: &str, monitor: Option<MonitorID>) -> Option<id> { + unsafe { + let scr_frame = match monitor { + Some(_) => { + let screen = NSScreen::mainScreen(nil); + NSScreen::frame(screen) + } + None => { + let (width, height) = dimensions; + NSRect::new(NSPoint::new(0., 0.), NSSize::new(width as f64, height as f64)) + } + }; + + let masks = match monitor { + Some(_) => NSBorderlessWindowMask as NSUInteger, + None => NSTitledWindowMask as NSUInteger | + NSClosableWindowMask as NSUInteger | + NSMiniaturizableWindowMask as NSUInteger | + NSResizableWindowMask as NSUInteger, + }; + + let window = NSWindow::alloc(nil).initWithContentRect_styleMask_backing_defer_( + scr_frame, + masks, + NSBackingStoreBuffered, + false, + ); + + if window == nil { + None + } else { + let title = NSString::alloc(nil).init_str(title); + window.setTitle_(title); + window.setAcceptsMouseMovedEvents_(true); + if monitor.is_some() { + window.setLevel_(NSMainMenuWindowLevel as i64 + 1); + } + else { + window.center(); + } + Some(window) + } + } + } + + fn create_view(window: id) -> Option<id> { + unsafe { + let view = NSView::alloc(nil).init(); + if view == nil { + None + } else { + view.setWantsBestResolutionOpenGLSurface_(true); + window.setContentView_(view); + Some(view) + } + } + } + + fn create_context(view: id, vsync: bool) -> Option<id> { + unsafe { + let attributes = [ + NSOpenGLPFADoubleBuffer as u32, + NSOpenGLPFAClosestPolicy as u32, + NSOpenGLPFAColorSize as u32, 24, + NSOpenGLPFAAlphaSize as u32, 8, + NSOpenGLPFADepthSize as u32, 24, + NSOpenGLPFAStencilSize as u32, 8, + 0 + ]; + + let pixelformat = NSOpenGLPixelFormat::alloc(nil).initWithAttributes_(&attributes); + if pixelformat == nil { + return None; + } + + let context = NSOpenGLContext::alloc(nil).initWithFormat_shareContext_(pixelformat, nil); + if context == nil { + None + } else { + context.setView_(view); + if vsync { + let value = 1; + context.setValues_forParameter_(&value, NSOpenGLContextParameter::NSOpenGLCPSwapInterval); + } + Some(context) + } + } + } + + pub fn is_closed(&self) -> bool { + self.is_closed.get() + } + + pub fn set_title(&self, title: &str) { + unsafe { + let title = NSString::alloc(nil).init_str(title); + self.window.setTitle_(title); + } + } + + pub fn show(&self) { + } + + pub fn hide(&self) { + } + + pub fn get_position(&self) -> Option<(i32, i32)> { + unimplemented!() + } + + pub fn set_position(&self, _x: i32, _y: i32) { + unimplemented!() + } + + pub fn get_inner_size(&self) -> Option<(u32, u32)> { + let rect = unsafe { NSView::frame(self.view) }; + Some((rect.size.width as u32, rect.size.height as u32)) + } + + pub fn get_outer_size(&self) -> Option<(u32, u32)> { + unimplemented!() + } + + pub fn set_inner_size(&self, _x: u32, _y: u32) { + unimplemented!() + } + + pub fn create_window_proxy(&self) -> WindowProxy { + WindowProxy + } + + pub fn poll_events(&self) -> RingBuf<Event> { + let mut events = RingBuf::new(); + + loop { + unsafe { + let event = NSApp().nextEventMatchingMask_untilDate_inMode_dequeue_( + NSAnyEventMask as u64, + NSDate::distantPast(nil), + NSDefaultRunLoopMode, + true); + if event == nil { break; } + { + // Create a temporary structure with state that delegates called internally + // by sendEvent can read and modify. When that returns, update window state. + // This allows the synchronous resize loop to continue issuing callbacks + // to the user application, by passing handler through to the delegate state. + let mut ds = DelegateState { + is_closed: self.is_closed.get(), + context: self.context, + view: self.view, + handler: self.resize, + }; + object_setInstanceVariable(self.delegate, + DELEGATE_STATE_IVAR.as_ptr() as *const i8, + &mut ds as *mut DelegateState as *mut libc::c_void); + NSApp().sendEvent_(event); + object_setInstanceVariable(self.delegate, + DELEGATE_STATE_IVAR.as_ptr() as *const i8, + ptr::null_mut()); + self.is_closed.set(ds.is_closed); +} + + match event.get_type() { + NSLeftMouseDown => { events.push_back(MouseInput(Pressed, LeftMouseButton)); }, + NSLeftMouseUp => { events.push_back(MouseInput(Released, LeftMouseButton)); }, + NSRightMouseDown => { events.push_back(MouseInput(Pressed, RightMouseButton)); }, + NSRightMouseUp => { events.push_back(MouseInput(Released, RightMouseButton)); }, + NSMouseMoved => { + let window_point = event.locationInWindow(); + let view_point = self.view.convertPoint_fromView_(window_point, nil); + events.push_back(MouseMoved((view_point.x as i32, view_point.y as i32))); + }, + NSKeyDown => { + let received_c_str = event.characters().UTF8String(); + let received_str = CString::from_slice(c_str_to_bytes(&received_c_str)); + for received_char in from_utf8(received_str.as_bytes()).unwrap().chars() { + if received_char.is_ascii() { + events.push_back(ReceivedCharacter(received_char)); + } + } + + let vkey = event::vkeycode_to_element(event.keycode()); + events.push_back(KeyboardInput(Pressed, event.keycode() as u8, vkey)); + }, + NSKeyUp => { + let vkey = event::vkeycode_to_element(event.keycode()); + events.push_back(KeyboardInput(Released, event.keycode() as u8, vkey)); + }, + NSFlagsChanged => { + let shift_modifier = Window::modifier_event(event, appkit::NSShiftKeyMask as u64, events::VirtualKeyCode::LShift, shift_pressed); + if shift_modifier.is_some() { + shift_pressed = !shift_pressed; + events.push_back(shift_modifier.unwrap()); + } + let ctrl_modifier = Window::modifier_event(event, appkit::NSControlKeyMask as u64, events::VirtualKeyCode::LControl, ctrl_pressed); + if ctrl_modifier.is_some() { + ctrl_pressed = !ctrl_pressed; + events.push_back(ctrl_modifier.unwrap()); + } + let win_modifier = Window::modifier_event(event, appkit::NSCommandKeyMask as u64, events::VirtualKeyCode::LWin, win_pressed); + if win_modifier.is_some() { + win_pressed = !win_pressed; + events.push_back(win_modifier.unwrap()); + } + let alt_modifier = Window::modifier_event(event, appkit::NSAlternateKeyMask as u64, events::VirtualKeyCode::LAlt, alt_pressed); + if alt_modifier.is_some() { + alt_pressed = !alt_pressed; + events.push_back(alt_modifier.unwrap()); + } + }, + NSScrollWheel => { events.push_back(MouseWheel(-event.scrollingDeltaY() as i32)); }, + NSOtherMouseDown => { }, + NSOtherMouseUp => { }, + NSOtherMouseDragged => { }, + _ => { }, + } + } + } + events + } + + unsafe fn modifier_event(event: id, keymask: u64, key: events::VirtualKeyCode, key_pressed: bool) -> Option<Event> { + if !key_pressed && Window::modifier_key_pressed(event, keymask) { + return Some(KeyboardInput(Pressed, event.keycode() as u8, Some(key))); + } + else if key_pressed && !Window::modifier_key_pressed(event, keymask) { + return Some(KeyboardInput(Released, event.keycode() as u8, Some(key))); + } + + return None; + } + + unsafe fn modifier_key_pressed(event: id, modifier: u64) -> bool { + event.modifierFlags() & modifier != 0 + } + + pub fn wait_events(&self) -> RingBuf<Event> { + unsafe { + let event = NSApp().nextEventMatchingMask_untilDate_inMode_dequeue_( + NSAnyEventMask as u64, + NSDate::distantFuture(nil), + NSDefaultRunLoopMode, + false); + NSApp().sendEvent_(event); + + self.poll_events() + } + } + + pub unsafe fn make_current(&self) { + self.context.makeCurrentContext(); + } + + pub fn get_proc_address(&self, _addr: &str) -> *const () { + let symbol_name: CFString = FromStr::from_str(_addr).unwrap(); + let framework_name: CFString = FromStr::from_str("com.apple.opengl").unwrap(); + let framework = unsafe { + CFBundleGetBundleWithIdentifier(framework_name.as_concrete_TypeRef()) + }; + let symbol = unsafe { + CFBundleGetFunctionPointerForName(framework, symbol_name.as_concrete_TypeRef()) + }; + symbol as *const () + } + + pub fn swap_buffers(&self) { + unsafe { self.context.flushBuffer(); } + } + + pub fn platform_display(&self) -> *mut libc::c_void { + unimplemented!() + } + + pub fn get_api(&self) -> ::Api { + ::Api::OpenGl + } + + pub fn set_window_resize_callback(&mut self, callback: Option<fn(u32, u32)>) { + self.resize = callback; + } + + pub fn set_cursor(&self, cursor: MouseCursor) { + unimplemented!() + } +} diff --git a/src/osx/mod.rs.REMOTE.6164.rs b/src/osx/mod.rs.REMOTE.6164.rs new file mode 100644 index 0000000..83c51a3 --- /dev/null +++ b/src/osx/mod.rs.REMOTE.6164.rs @@ -0,0 +1,492 @@ +#[cfg(feature = "headless")] +pub use self::headless::HeadlessContext; + +use {CreationError, Event}; +use CreationError::OsError; +use libc; +use std::ascii::AsciiExt; + +#[cfg(feature = "window")] +use WindowBuilder; + +use cocoa::base::{id, NSUInteger, nil, objc_allocateClassPair, class, objc_registerClassPair}; +use cocoa::base::{selector, msg_send, class_addMethod, class_addIvar}; +use cocoa::base::{object_setInstanceVariable, object_getInstanceVariable}; +use cocoa::appkit; +use cocoa::appkit::*; + +use core_foundation::base::TCFType; +use core_foundation::string::CFString; +use core_foundation::bundle::{CFBundleGetBundleWithIdentifier, CFBundleGetFunctionPointerForName}; + +use std::cell::Cell; +use std::c_str::CString; +use std::mem; +use std::ptr; + +use events::Event::{MouseInput, MouseMoved, ReceivedCharacter, KeyboardInput, MouseWheel}; +use events::ElementState::{Pressed, Released}; +use events::MouseButton::{LeftMouseButton, RightMouseButton}; +use events; + +pub use self::monitor::{MonitorID, get_available_monitors, get_primary_monitor}; + +mod monitor; +mod event; + +#[cfg(feature = "headless")] +mod headless; + +static mut shift_pressed: bool = false; +static mut ctrl_pressed: bool = false; +static mut win_pressed: bool = false; +static mut alt_pressed: bool = false; + +static DELEGATE_NAME: &'static [u8] = b"glutin_window_delegate\0"; +static DELEGATE_STATE_IVAR: &'static [u8] = b"glutin_state"; + +struct DelegateState<'a> { + is_closed: bool, + context: id, + view: id, + handler: Option<fn(uint, uint)>, +} + +pub struct Window { + view: id, + window: id, + context: id, + delegate: id, + resize: Option<fn(uint, uint)>, + + is_closed: Cell<bool>, +} + +#[cfg(feature = "window")] +impl Window { + pub fn new(builder: WindowBuilder) -> Result<Window, CreationError> { + if builder.sharing.is_some() { + unimplemented!() + } + + Window::new_impl(builder.dimensions, builder.title.as_slice(), builder.monitor, builder.vsync, builder.visible, builder.gl_version) + } +} + +#[cfg(feature = "window")] +#[deriving(Clone)] +pub struct WindowProxy; + +impl WindowProxy { + pub fn wakeup_event_loop(&self) { + unsafe { + let pool = NSAutoreleasePool::new(nil); + let event = + NSEvent::otherEventWithType_location_modifierFlags_timestamp_windowNumber_context_subtype_data1_data2( + nil, + NSApplicationDefined, + NSPoint::new(0.0, 0.0), + 0, + 0.0, + 0, + ptr::null_mut(), + 0, + 0, + 0); + NSApp().postEvent_atStart_(event, true); + pool.drain(); + } + } +} + +extern fn window_should_close(this: id, _: id) -> id { + unsafe { + let mut stored_value = ptr::null_mut(); + object_getInstanceVariable(this, DELEGATE_STATE_IVAR.as_ptr() as *const i8, &mut stored_value); + let state = stored_value as *mut DelegateState; + + (*state).is_closed = true; + } + 0 +} + +extern fn window_did_resize(this: id, _: id) -> id { + unsafe { + let mut stored_value = ptr::null_mut(); + object_getInstanceVariable(this, DELEGATE_STATE_IVAR.as_ptr() as *const i8, &mut stored_value); + let state = &mut *(stored_value as *mut DelegateState); + + let _: id = msg_send()(state.context, selector("update")); + + match state.handler { + Some(handler) => { + let rect = NSView::frame(state.view); + (handler)(rect.size.width as uint, rect.size.height as uint); + } + None => {} + } + } + 0 +} + +impl Window { + fn new_impl(dimensions: Option<(uint, uint)>, title: &str, monitor: Option<MonitorID>, + vsync: bool, visible: bool, gl_version: Option<(uint, uint)>) -> Result<Window, CreationError> { + let app = match Window::create_app() { + Some(app) => app, + None => { return Err(OsError(format!("Couldn't create NSApplication"))); }, + }; + let window = match Window::create_window(dimensions.unwrap_or((800, 600)), title, monitor) { + Some(window) => window, + None => { return Err(OsError(format!("Couldn't create NSWindow"))); }, + }; + let view = match Window::create_view(window) { + Some(view) => view, + None => { return Err(OsError(format!("Couldn't create NSView"))); }, + }; + + let context = match Window::create_context(view, vsync, gl_version) { + Some(context) => context, + None => { return Err(OsError(format!("Couldn't create OpenGL context"))); }, + }; + + unsafe { + app.activateIgnoringOtherApps_(true); + if visible { + window.makeKeyAndOrderFront_(nil); + } else { + window.makeKeyWindow(); + } + } + + // Set up the window delegate to receive events + let ptr_size = mem::size_of::<libc::intptr_t>() as u64; + let ns_object = class("NSObject"); + + let delegate = unsafe { + // Create a delegate class, add callback methods and store InternalState as user data. + let delegate = objc_allocateClassPair(ns_object, DELEGATE_NAME.as_ptr() as *const i8, 0); + class_addMethod(delegate, selector("windowShouldClose:"), window_should_close, "B@:@".to_c_str().as_ptr()); + class_addMethod(delegate, selector("windowDidResize:"), window_did_resize, "V@:@".to_c_str().as_ptr()); + class_addIvar(delegate, DELEGATE_STATE_IVAR.as_ptr() as *const i8, ptr_size, 3, "?".to_c_str().as_ptr()); + objc_registerClassPair(delegate); + + let del_obj = msg_send()(delegate, selector("alloc")); + let del_obj: id = msg_send()(del_obj, selector("init")); + let _: id = msg_send()(window, selector("setDelegate:"), del_obj); + del_obj + }; + + let window = Window { + view: view, + window: window, + context: context, + delegate: delegate, + resize: None, + + is_closed: Cell::new(false), + }; + + Ok(window) + } + + fn create_app() -> Option<id> { + unsafe { + let app = NSApp(); + if app == nil { + None + } else { + app.setActivationPolicy_(NSApplicationActivationPolicyRegular); + app.finishLaunching(); + Some(app) + } + } + } + + fn create_window(dimensions: (uint, uint), title: &str, monitor: Option<MonitorID>) -> Option<id> { + unsafe { + let scr_frame = match monitor { + Some(_) => { + let screen = NSScreen::mainScreen(nil); + NSScreen::frame(screen) + } + None => { + let (width, height) = dimensions; + NSRect::new(NSPoint::new(0., 0.), NSSize::new(width as f64, height as f64)) + } + }; + + let masks = match monitor { + Some(_) => NSBorderlessWindowMask as NSUInteger, + None => NSTitledWindowMask as NSUInteger | + NSClosableWindowMask as NSUInteger | + NSMiniaturizableWindowMask as NSUInteger | + NSResizableWindowMask as NSUInteger, + }; + + let window = NSWindow::alloc(nil).initWithContentRect_styleMask_backing_defer_( + scr_frame, + masks, + NSBackingStoreBuffered, + false, + ); + + if window == nil { + None + } else { + let title = NSString::alloc(nil).init_str(title); + window.setTitle_(title); + window.setAcceptsMouseMovedEvents_(true); + if monitor.is_some() { + window.setLevel_(NSMainMenuWindowLevel as i64 + 1); + } + else { + window.center(); + } + Some(window) + } + } + } + + fn create_view(window: id) -> Option<id> { + unsafe { + let view = NSView::alloc(nil).init(); + if view == nil { + None + } else { + view.setWantsBestResolutionOpenGLSurface_(true); + window.setContentView_(view); + Some(view) + } + } + } + + fn create_context(view: id, vsync: bool, gl_version: Option<(uint, uint)>) -> Option<id> { + let profile = match gl_version { + None | Some((0...2, _)) | Some((3, 0)) => NSOpenGLProfileVersionLegacy as uint, + Some((3, 1...2)) => NSOpenGLProfileVersion3_2Core as uint, + Some((_, _)) => NSOpenGLProfileVersion4_1Core as uint, + }; + unsafe { + let attributes = [ + NSOpenGLPFADoubleBuffer as uint, + NSOpenGLPFAClosestPolicy as uint, + NSOpenGLPFAColorSize as uint, 24, + NSOpenGLPFAAlphaSize as uint, 8, + NSOpenGLPFADepthSize as uint, 24, + NSOpenGLPFAStencilSize as uint, 8, + NSOpenGLPFAOpenGLProfile as uint, profile, + 0 + ]; + + let pixelformat = NSOpenGLPixelFormat::alloc(nil).initWithAttributes_(&attributes); + if pixelformat == nil { + return None; + } + + let context = NSOpenGLContext::alloc(nil).initWithFormat_shareContext_(pixelformat, nil); + if context == nil { + None + } else { + context.setView_(view); + if vsync { + let value = 1; + context.setValues_forParameter_(&value, NSOpenGLContextParameter::NSOpenGLCPSwapInterval); + } + Some(context) + } + } + } + + pub fn is_closed(&self) -> bool { + self.is_closed.get() + } + + pub fn set_title(&self, title: &str) { + unsafe { + let title = NSString::alloc(nil).init_str(title); + self.window.setTitle_(title); + } + } + + pub fn show(&self) { + } + + pub fn hide(&self) { + } + + pub fn get_position(&self) -> Option<(int, int)> { + unimplemented!() + } + + pub fn set_position(&self, _x: int, _y: int) { + unimplemented!() + } + + pub fn get_inner_size(&self) -> Option<(uint, uint)> { + let rect = unsafe { NSView::frame(self.view) }; + Some((rect.size.width as uint, rect.size.height as uint)) + } + + pub fn get_outer_size(&self) -> Option<(uint, uint)> { + unimplemented!() + } + + pub fn set_inner_size(&self, _x: uint, _y: uint) { + unimplemented!() + } + + pub fn create_window_proxy(&self) -> WindowProxy { + WindowProxy + } + + pub fn poll_events(&self) -> Vec<Event> { + let mut events = Vec::new(); + + loop { + unsafe { + let event = NSApp().nextEventMatchingMask_untilDate_inMode_dequeue_( + NSAnyEventMask as u64, + NSDate::distantPast(nil), + NSDefaultRunLoopMode, + true); + if event == nil { break; } + { + // Create a temporary structure with state that delegates called internally + // by sendEvent can read and modify. When that returns, update window state. + // This allows the synchronous resize loop to continue issuing callbacks + // to the user application, by passing handler through to the delegate state. + let mut ds = DelegateState { + is_closed: self.is_closed.get(), + context: self.context, + view: self.view, + handler: self.resize, + }; + object_setInstanceVariable(self.delegate, + DELEGATE_STATE_IVAR.as_ptr() as *const i8, + &mut ds as *mut DelegateState as *mut libc::c_void); + NSApp().sendEvent_(event); + object_setInstanceVariable(self.delegate, + DELEGATE_STATE_IVAR.as_ptr() as *const i8, + ptr::null_mut()); + self.is_closed.set(ds.is_closed); +} + + match event.get_type() { + NSLeftMouseDown => { events.push(MouseInput(Pressed, LeftMouseButton)); }, + NSLeftMouseUp => { events.push(MouseInput(Released, LeftMouseButton)); }, + NSRightMouseDown => { events.push(MouseInput(Pressed, RightMouseButton)); }, + NSRightMouseUp => { events.push(MouseInput(Released, RightMouseButton)); }, + NSMouseMoved => { + let window_point = event.locationInWindow(); + let view_point = self.view.convertPoint_fromView_(window_point, nil); + events.push(MouseMoved((view_point.x as int, view_point.y as int))); + }, + NSKeyDown => { + let received_str = CString::new(event.characters().UTF8String(), false); + for received_char in received_str.as_str().unwrap().chars() { + if received_char.is_ascii() { + events.push(ReceivedCharacter(received_char)); + } + } + + let vkey = event::vkeycode_to_element(event.keycode()); + events.push(KeyboardInput(Pressed, event.keycode() as u8, vkey)); + }, + NSKeyUp => { + let vkey = event::vkeycode_to_element(event.keycode()); + events.push(KeyboardInput(Released, event.keycode() as u8, vkey)); + }, + NSFlagsChanged => { + let shift_modifier = Window::modifier_event(event, appkit::NSShiftKeyMask as u64, events::VirtualKeyCode::LShift, shift_pressed); + if shift_modifier.is_some() { + shift_pressed = !shift_pressed; + events.push(shift_modifier.unwrap()); + } + let ctrl_modifier = Window::modifier_event(event, appkit::NSControlKeyMask as u64, events::VirtualKeyCode::LControl, ctrl_pressed); + if ctrl_modifier.is_some() { + ctrl_pressed = !ctrl_pressed; + events.push(ctrl_modifier.unwrap()); + } + let win_modifier = Window::modifier_event(event, appkit::NSCommandKeyMask as u64, events::VirtualKeyCode::LWin, win_pressed); + if win_modifier.is_some() { + win_pressed = !win_pressed; + events.push(win_modifier.unwrap()); + } + let alt_modifier = Window::modifier_event(event, appkit::NSAlternateKeyMask as u64, events::VirtualKeyCode::LAlt, alt_pressed); + if alt_modifier.is_some() { + alt_pressed = !alt_pressed; + events.push(alt_modifier.unwrap()); + } + }, + NSScrollWheel => { events.push(MouseWheel(-event.scrollingDeltaY() as i32)); }, + NSOtherMouseDown => { }, + NSOtherMouseUp => { }, + NSOtherMouseDragged => { }, + _ => { }, + } + } + } + events + } + + unsafe fn modifier_event(event: id, keymask: u64, key: events::VirtualKeyCode, key_pressed: bool) -> Option<Event> { + if !key_pressed && Window::modifier_key_pressed(event, keymask) { + return Some(KeyboardInput(Pressed, event.keycode() as u8, Some(key))); + } + else if key_pressed && !Window::modifier_key_pressed(event, keymask) { + return Some(KeyboardInput(Released, event.keycode() as u8, Some(key))); + } + + return None; + } + + unsafe fn modifier_key_pressed(event: id, modifier: u64) -> bool { + event.modifierFlags() & modifier != 0 + } + + pub fn wait_events(&self) -> Vec<Event> { + unsafe { + let event = NSApp().nextEventMatchingMask_untilDate_inMode_dequeue_( + NSAnyEventMask as u64, + NSDate::distantFuture(nil), + NSDefaultRunLoopMode, + false); + NSApp().sendEvent_(event); + + self.poll_events() + } + } + + pub unsafe fn make_current(&self) { + self.context.makeCurrentContext(); + } + + pub fn get_proc_address(&self, _addr: &str) -> *const () { + let symbol_name = _addr.parse::<CFString>().unwrap(); + let framework_name = "com.apple.opengl".parse::<CFString>().unwrap(); + let framework = unsafe { + CFBundleGetBundleWithIdentifier(framework_name.as_concrete_TypeRef()) + }; + let symbol = unsafe { + CFBundleGetFunctionPointerForName(framework, symbol_name.as_concrete_TypeRef()) + }; + symbol as *const () + } + + pub fn swap_buffers(&self) { + unsafe { self.context.flushBuffer(); } + } + + pub fn platform_display(&self) -> *mut libc::c_void { + unimplemented!() + } + + pub fn get_api(&self) -> ::Api { + ::Api::OpenGl + } + + pub fn set_window_resize_callback(&mut self, callback: Option<fn(uint, uint)>) { + self.resize = callback; + } +} diff --git a/src/osx/monitor.rs b/src/osx/monitor.rs index 383fd32..912c02d 100644 --- a/src/osx/monitor.rs +++ b/src/osx/monitor.rs @@ -1,18 +1,19 @@ use core_graphics::display; +use std::collections::RingBuf; pub struct MonitorID(u32); -pub fn get_available_monitors() -> Vec<MonitorID> { - let mut monitors = Vec::new(); +pub fn get_available_monitors() -> RingBuf<MonitorID> { + let mut monitors = RingBuf::new(); unsafe { let max_displays = 10u32; - let mut active_displays = [0u32, ..10]; + let mut active_displays = [0u32; 10]; let mut display_count = 0; display::CGGetActiveDisplayList(max_displays, &mut active_displays[0], &mut display_count); - for i in range(0u, display_count as uint) { - monitors.push(MonitorID(active_displays[i])); + for i in range(0us, display_count as usize) { + monitors.push_back(MonitorID(active_displays[i])); } } monitors @@ -34,12 +35,12 @@ impl MonitorID { Some(format!("Monitor #{}", screen_num)) } - pub fn get_dimensions(&self) -> (uint, uint) { + pub fn get_dimensions(&self) -> (u32, u32) { let MonitorID(display_id) = *self; let dimension = unsafe { let height = display::CGDisplayPixelsHigh(display_id); let width = display::CGDisplayPixelsWide(display_id); - (width as uint, height as uint) + (width as u32, height as u32) }; dimension } diff --git a/src/win32/init.rs b/src/win32/init.rs index 3cdf8d5..7317c42 100644 --- a/src/win32/init.rs +++ b/src/win32/init.rs @@ -6,7 +6,9 @@ use {CreationError, Event}; use CreationError::OsError; use std::cell::RefCell; +use std::ffi::CString; use std::rc::Rc; +use std::sync::mpsc::{Sender, Receiver, channel}; use libc; use super::gl; @@ -18,11 +20,15 @@ use winapi; /// receive an event for another window. thread_local!(static WINDOW: Rc<RefCell<Option<(winapi::HWND, Sender<Event>)>>> = Rc::new(RefCell::new(None))); -pub fn new_window(builder_dimensions: Option<(uint, uint)>, builder_title: String, +/// Work-around the fact that HGLRC doesn't implement Send +pub struct ContextHack(pub winapi::HGLRC); +unsafe impl Send for ContextHack {} + +pub fn new_window(builder_dimensions: Option<(u32, u32)>, builder_title: String, builder_monitor: Option<super::MonitorID>, - builder_gl_version: Option<(uint, uint)>, builder_debug: bool, + builder_gl_version: Option<(u32, u32)>, builder_debug: bool, builder_vsync: bool, builder_hidden: bool, - builder_sharelists: Option<winapi::HGLRC>, builder_multisampling: Option<u16>) + builder_sharelists: Option<ContextHack>, builder_multisampling: Option<u16>) -> Result<Window, CreationError> { use std::mem; @@ -38,6 +44,8 @@ pub fn new_window(builder_dimensions: Option<(uint, uint)>, builder_title: Strin // so we create a new thread dedicated to this window. // This is the only safe method. Using `nosend` wouldn't work for non-native runtime. ::std::thread::Thread::spawn(move || { + let builder_sharelists = builder_sharelists.map(|s| s.0); + // registering the window class let class_name = { let class_name: Vec<u16> = "Window Class".utf16_units().chain(Some(0).into_iter()) @@ -132,7 +140,7 @@ pub fn new_window(builder_dimensions: Option<(uint, uint)>, builder_title: Strin if handle.is_null() { use std::os; tx.send(Err(OsError(format!("CreateWindowEx function failed: {}", - os::error_string(os::errno() as uint))))); + os::error_string(os::errno() as usize))))); return; } @@ -144,7 +152,7 @@ pub fn new_window(builder_dimensions: Option<(uint, uint)>, builder_title: Strin let hdc = unsafe { winapi::GetDC(dummy_window) }; if hdc.is_null() { tx.send(Err(OsError(format!("GetDC function failed: {}", - os::error_string(os::errno() as uint))))); + os::error_string(os::errno() as usize))))); unsafe { winapi::DestroyWindow(dummy_window); } return; } @@ -172,7 +180,7 @@ pub fn new_window(builder_dimensions: Option<(uint, uint)>, builder_title: Strin if pf_index == 0 { tx.send(Err(OsError(format!("ChoosePixelFormat function failed: {}", - os::error_string(os::errno() as uint))))); + os::error_string(os::errno() as usize))))); unsafe { winapi::DestroyWindow(dummy_window); } return; } @@ -181,7 +189,7 @@ pub fn new_window(builder_dimensions: Option<(uint, uint)>, builder_title: Strin mem::size_of::<winapi::PIXELFORMATDESCRIPTOR>() as winapi::UINT, &mut output) } == 0 { tx.send(Err(OsError(format!("DescribePixelFormat function failed: {}", - os::error_string(os::errno() as uint))))); + os::error_string(os::errno() as usize))))); unsafe { winapi::DestroyWindow(dummy_window); } return; } @@ -193,7 +201,7 @@ pub fn new_window(builder_dimensions: Option<(uint, uint)>, builder_title: Strin unsafe { if winapi::SetPixelFormat(dummy_hdc, 1, &pixel_format) == 0 { tx.send(Err(OsError(format!("SetPixelFormat function failed: {}", - os::error_string(os::errno() as uint))))); + os::error_string(os::errno() as usize))))); winapi::DestroyWindow(dummy_window); return; } @@ -204,7 +212,7 @@ pub fn new_window(builder_dimensions: Option<(uint, uint)>, builder_title: Strin let ctxt = unsafe { gl::wgl::CreateContext(dummy_hdc as *const libc::c_void) }; if ctxt.is_null() { tx.send(Err(OsError(format!("wglCreateContext function failed: {}", - os::error_string(os::errno() as uint))))); + os::error_string(os::errno() as usize))))); unsafe { winapi::DestroyWindow(dummy_window); } return; } @@ -216,11 +224,13 @@ pub fn new_window(builder_dimensions: Option<(uint, uint)>, builder_title: Strin // loading the extra WGL functions let extra_functions = gl::wgl_extra::Wgl::load_with(|addr| { + use libc; + + let addr = CString::from_slice(addr.as_bytes()); + let addr = addr.as_slice_with_nul().as_ptr(); + unsafe { - addr.with_c_str(|s| { - use libc; - gl::wgl::GetProcAddress(s) as *const libc::c_void - }) + gl::wgl::GetProcAddress(addr) as *const libc::c_void } }); @@ -261,7 +271,7 @@ pub fn new_window(builder_dimensions: Option<(uint, uint)>, builder_title: Strin if handle.is_null() { use std::os; tx.send(Err(OsError(format!("CreateWindowEx function failed: {}", - os::error_string(os::errno() as uint))))); + os::error_string(os::errno() as usize))))); return; } @@ -273,7 +283,7 @@ pub fn new_window(builder_dimensions: Option<(uint, uint)>, builder_title: Strin let hdc = unsafe { winapi::GetDC(real_window) }; if hdc.is_null() { tx.send(Err(OsError(format!("GetDC function failed: {}", - os::error_string(os::errno() as uint))))); + os::error_string(os::errno() as usize))))); unsafe { winapi::DestroyWindow(real_window); } return; } @@ -284,7 +294,7 @@ pub fn new_window(builder_dimensions: Option<(uint, uint)>, builder_title: Strin unsafe { if winapi::SetPixelFormat(hdc, 1, &pixel_format) == 0 { tx.send(Err(OsError(format!("SetPixelFormat function failed: {}", - os::error_string(os::errno() as uint))))); + os::error_string(os::errno() as usize))))); winapi::DestroyWindow(real_window); return; } @@ -329,7 +339,7 @@ pub fn new_window(builder_dimensions: Option<(uint, uint)>, builder_title: Strin if ctxt.is_null() { tx.send(Err(OsError(format!("OpenGL context creation failed: {}", - os::error_string(os::errno() as uint))))); + os::error_string(os::errno() as usize))))); unsafe { winapi::DestroyWindow(real_window); } return; } @@ -359,7 +369,7 @@ pub fn new_window(builder_dimensions: Option<(uint, uint)>, builder_title: Strin let lib = unsafe { winapi::LoadLibraryW(name) }; if lib.is_null() { tx.send(Err(OsError(format!("LoadLibrary function failed: {}", - os::error_string(os::errno() as uint))))); + os::error_string(os::errno() as usize))))); unsafe { gl::wgl::DeleteContext(context); } unsafe { winapi::DestroyWindow(real_window); } return; @@ -409,9 +419,9 @@ pub fn new_window(builder_dimensions: Option<(uint, uint)>, builder_title: Strin unsafe { winapi::TranslateMessage(&msg) }; unsafe { winapi::DispatchMessageW(&msg) }; // calls `callback` (see below) } - }).detach(); + }); - rx.recv() + rx.recv().unwrap() } /// Checks that the window is the good one, and if so send the event to it. @@ -429,7 +439,7 @@ fn send_event(input_window: winapi::HWND, event: Event) { return; } - sender.send_opt(event).ok(); // ignoring if closed + sender.send(event).ok(); // ignoring if closed }); } @@ -465,16 +475,16 @@ extern "system" fn callback(window: winapi::HWND, msg: winapi::UINT, winapi::WM_SIZE => { use events::Event::Resized; - let w = winapi::LOWORD(lparam as winapi::DWORD) as uint; - let h = winapi::HIWORD(lparam as winapi::DWORD) as uint; + let w = winapi::LOWORD(lparam as winapi::DWORD) as u32; + let h = winapi::HIWORD(lparam as winapi::DWORD) as u32; send_event(window, Resized(w, h)); 0 }, winapi::WM_MOVE => { use events::Event::Moved; - let x = winapi::LOWORD(lparam as winapi::DWORD) as i16 as int; - let y = winapi::HIWORD(lparam as winapi::DWORD) as i16 as int; + let x = winapi::LOWORD(lparam as winapi::DWORD) as i32; + let y = winapi::HIWORD(lparam as winapi::DWORD) as i32; send_event(window, Moved(x, y)); 0 }, @@ -490,8 +500,8 @@ extern "system" fn callback(window: winapi::HWND, msg: winapi::UINT, winapi::WM_MOUSEMOVE => { use events::Event::MouseMoved; - let x = winapi::GET_X_LPARAM(lparam) as int; - let y = winapi::GET_Y_LPARAM(lparam) as int; + let x = winapi::GET_X_LPARAM(lparam) as i32; + let y = winapi::GET_Y_LPARAM(lparam) as i32; send_event(window, MouseMoved((x, y))); diff --git a/src/win32/mod.rs b/src/win32/mod.rs index dba08e5..e6964b4 100644 --- a/src/win32/mod.rs +++ b/src/win32/mod.rs @@ -1,13 +1,12 @@ use std::sync::atomic::AtomicBool; use std::ptr; +use std::ffi::CString; +use std::collections::RingBuf; +use std::sync::mpsc::Receiver; use libc; -use {CreationError, Event}; +use {CreationError, Event, MouseCursor}; -#[cfg(feature = "window")] -use WindowBuilder; - -#[cfg(feature = "headless")] -use HeadlessRendererBuilder; +use BuilderAttribs; pub use self::monitor::{MonitorID, get_available_monitors, get_primary_monitor}; @@ -18,16 +17,14 @@ mod gl; mod init; mod monitor; -/// -#[cfg(feature = "headless")] +/// pub struct HeadlessContext(Window); -#[cfg(feature = "headless")] impl HeadlessContext { /// See the docs in the crate root file. - pub fn new(builder: HeadlessRendererBuilder) -> Result<HeadlessContext, CreationError> { - let HeadlessRendererBuilder { dimensions, gl_version, gl_debug } = builder; - init::new_window(Some(dimensions), "".to_string(), None, gl_version, gl_debug, false, true, + pub fn new(builder: BuilderAttribs) -> Result<HeadlessContext, CreationError> { + let BuilderAttribs { dimensions, gl_version, gl_debug, .. } = builder; + init::new_window(dimensions, "".to_string(), None, gl_version, gl_debug, false, true, None, None) .map(|w| HeadlessContext(w)) } @@ -47,10 +44,15 @@ impl HeadlessContext { ::Api::OpenGl } - pub fn set_window_resize_callback(&mut self, _: Option<fn(uint, uint)>) { + pub fn set_window_resize_callback(&mut self, _: Option<fn(u32, u32)>) { } } +#[cfg(feature = "headless")] +unsafe impl Send for HeadlessContext {} +#[cfg(feature = "headless")] +unsafe impl Sync for HeadlessContext {} + /// The Win32 implementation of the main `Window` object. pub struct Window { /// Main handle for the window. @@ -75,18 +77,21 @@ pub struct Window { is_closed: AtomicBool, } -#[cfg(feature = "window")] +unsafe impl Send for Window {} +unsafe impl Sync for Window {} + impl Window { /// See the docs in the crate root file. - pub fn new(builder: WindowBuilder) -> Result<Window, CreationError> { - let WindowBuilder { dimensions, title, monitor, gl_version, - gl_debug, vsync, visible, sharing, multisampling } = builder; + pub fn new(builder: BuilderAttribs) -> Result<Window, CreationError> { + let BuilderAttribs { dimensions, title, monitor, gl_version, + gl_debug, vsync, visible, sharing, multisampling, .. } = builder; init::new_window(dimensions, title, monitor, gl_version, gl_debug, vsync, - !visible, sharing.map(|w| w.window.context), multisampling) + !visible, sharing.map(|w| init::ContextHack(w.context)), + multisampling) } } -#[deriving(Clone)] +#[derive(Clone)] pub struct WindowProxy; impl WindowProxy { @@ -98,12 +103,12 @@ impl WindowProxy { impl Window { /// See the docs in the crate root file. pub fn is_closed(&self) -> bool { - use std::sync::atomic::Relaxed; + use std::sync::atomic::Ordering::Relaxed; self.is_closed.load(Relaxed) } /// See the docs in the crate root file. - /// + /// /// Calls SetWindowText on the HWND. pub fn set_title(&self, text: &str) { unsafe { @@ -126,7 +131,7 @@ impl Window { } /// See the docs in the crate root file. - pub fn get_position(&self) -> Option<(int, int)> { + pub fn get_position(&self) -> Option<(i32, i32)> { use std::mem; let mut placement: winapi::WINDOWPLACEMENT = unsafe { mem::zeroed() }; @@ -137,11 +142,11 @@ impl Window { } let ref rect = placement.rcNormalPosition; - Some((rect.left as int, rect.top as int)) + Some((rect.left as i32, rect.top as i32)) } /// See the docs in the crate root file. - pub fn set_position(&self, x: int, y: int) { + pub fn set_position(&self, x: i32, y: i32) { use libc; unsafe { @@ -152,7 +157,7 @@ impl Window { } /// See the docs in the crate root file. - pub fn get_inner_size(&self) -> Option<(uint, uint)> { + pub fn get_inner_size(&self) -> Option<(u32, u32)> { use std::mem; let mut rect: winapi::RECT = unsafe { mem::uninitialized() }; @@ -161,13 +166,13 @@ impl Window { } Some(( - (rect.right - rect.left) as uint, - (rect.bottom - rect.top) as uint + (rect.right - rect.left) as u32, + (rect.bottom - rect.top) as u32 )) } /// See the docs in the crate root file. - pub fn get_outer_size(&self) -> Option<(uint, uint)> { + pub fn get_outer_size(&self) -> Option<(u32, u32)> { use std::mem; let mut rect: winapi::RECT = unsafe { mem::uninitialized() }; @@ -176,13 +181,13 @@ impl Window { } Some(( - (rect.right - rect.left) as uint, - (rect.bottom - rect.top) as uint + (rect.right - rect.left) as u32, + (rect.bottom - rect.top) as u32 )) } /// See the docs in the crate root file. - pub fn set_inner_size(&self, x: uint, y: uint) { + pub fn set_inner_size(&self, x: u32, y: u32) { use libc; unsafe { @@ -198,33 +203,33 @@ impl Window { /// See the docs in the crate root file. // TODO: return iterator - pub fn poll_events(&self) -> Vec<Event> { - let mut events = Vec::new(); + pub fn poll_events(&self) -> RingBuf<Event> { + let mut events = RingBuf::new(); loop { match self.events_receiver.try_recv() { - Ok(ev) => events.push(ev), + Ok(ev) => events.push_back(ev), Err(_) => break } } // if one of the received events is `Closed`, setting `is_closed` to true if events.iter().any(|e| match e { &::events::Event::Closed => true, _ => false }) { - use std::sync::atomic::Relaxed; + use std::sync::atomic::Ordering::Relaxed; self.is_closed.store(true, Relaxed); } - + events } /// See the docs in the crate root file. // TODO: return iterator - pub fn wait_events(&self) -> Vec<Event> { - match self.events_receiver.recv_opt() { + pub fn wait_events(&self) -> RingBuf<Event> { + match self.events_receiver.recv() { Ok(ev) => { // if the received event is `Closed`, setting `is_closed` to true match ev { ::events::Event::Closed => { - use std::sync::atomic::Relaxed; + use std::sync::atomic::Ordering::Relaxed; self.is_closed.store(true, Relaxed); }, _ => () @@ -237,9 +242,9 @@ impl Window { }, Err(_) => { - use std::sync::atomic::Relaxed; + use std::sync::atomic::Ordering::Relaxed; self.is_closed.store(true, Relaxed); - vec![] + RingBuf::new() } } } @@ -252,14 +257,13 @@ impl Window { /// See the docs in the crate root file. pub fn get_proc_address(&self, addr: &str) -> *const () { - use std::c_str::ToCStr; + let addr = CString::from_slice(addr.as_bytes()); + let addr = addr.as_slice_with_nul().as_ptr(); unsafe { - addr.with_c_str(|s| { - let p = gl::wgl::GetProcAddress(s) as *const (); - if !p.is_null() { return p; } - winapi::GetProcAddress(self.gl_library, s) as *const () - }) + let p = gl::wgl::GetProcAddress(addr) as *const (); + if !p.is_null() { return p; } + winapi::GetProcAddress(self.gl_library, addr) as *const () } } @@ -279,7 +283,11 @@ impl Window { ::Api::OpenGl } - pub fn set_window_resize_callback(&mut self, _: Option<fn(uint, uint)>) { + pub fn set_window_resize_callback(&mut self, _: Option<fn(u32, u32)>) { + } + + pub fn set_cursor(&self, cursor: MouseCursor) { + unimplemented!() } } diff --git a/src/win32/monitor.rs b/src/win32/monitor.rs index f841f1e..2078a52 100644 --- a/src/win32/monitor.rs +++ b/src/win32/monitor.rs @@ -1,9 +1,11 @@ use winapi; +use std::collections::RingBuf; + /// Win32 implementation of the main `MonitorID` object. pub struct MonitorID { /// The system name of the monitor. - name: [winapi::WCHAR, ..32], + name: [winapi::WCHAR; 32], /// Name to give to the user. readable_name: String, @@ -15,22 +17,22 @@ pub struct MonitorID { /// The position of the monitor in pixels on the desktop. /// /// A window that is positionned at these coordinates will overlap the monitor. - position: (uint, uint), + position: (u32, u32), /// The current resolution in pixels on the monitor. - dimensions: (uint, uint), + dimensions: (u32, u32), } /// Win32 implementation of the main `get_available_monitors` function. -pub fn get_available_monitors() -> Vec<MonitorID> { +pub fn get_available_monitors() -> RingBuf<MonitorID> { use std::{iter, mem, ptr}; // return value - let mut result = Vec::new(); + let mut result = RingBuf::new(); // enumerating the devices is done by querying device 0, then device 1, then device 2, etc. // until the query function returns null - for id in iter::count(0u, 1) { + for id in iter::count(0u32, 1) { // getting the DISPLAY_DEVICEW object of the current device let output = { let mut output: winapi::DISPLAY_DEVICEW = unsafe { mem::zeroed() }; @@ -56,7 +58,7 @@ pub fn get_available_monitors() -> Vec<MonitorID> { // computing the human-friendly name let readable_name = String::from_utf16_lossy(output.DeviceString.as_slice()); - let readable_name = readable_name.as_slice().trim_right_chars(0 as char).to_string(); + let readable_name = readable_name.as_slice().trim_right_matches(0 as char).to_string(); // getting the position let (position, dimensions) = unsafe { @@ -70,15 +72,15 @@ pub fn get_available_monitors() -> Vec<MonitorID> { } let point: &winapi::POINTL = mem::transmute(&dev.union1); - let position = (point.x as uint, point.y as uint); + let position = (point.x as u32, point.y as u32); - let dimensions = (dev.dmPelsWidth as uint, dev.dmPelsHeight as uint); + let dimensions = (dev.dmPelsWidth as u32, dev.dmPelsHeight as u32); (position, dimensions) }; // adding to the resulting list - result.push(MonitorID { + result.push_back(MonitorID { name: output.DeviceName, readable_name: readable_name, flags: output.StateFlags, @@ -111,7 +113,7 @@ impl MonitorID { } /// See the docs if the crate root file. - pub fn get_dimensions(&self) -> (uint, uint) { + pub fn get_dimensions(&self) -> (u32, u32) { // TODO: retreive the dimensions every time this is called self.dimensions } @@ -123,9 +125,9 @@ impl MonitorID { } /// This is a Win32-only function for `MonitorID` that returns the position of the - /// monitor on the desktop. + /// monitor on the desktop. /// A window that is positionned at these coordinates will overlap the monitor. - pub fn get_position(&self) -> (uint, uint) { + pub fn get_position(&self) -> (u32, u32) { self.position } } diff --git a/src/x11/ffi.rs b/src/x11/ffi.rs index 5610eee..5e7b5a1 100644 --- a/src/x11/ffi.rs +++ b/src/x11/ffi.rs @@ -1241,7 +1241,7 @@ pub struct XSetWindowAttributes { #[repr(C)] pub struct XEvent { pub type_: libc::c_int, - pad: [libc::c_long, ..24], + pad: [libc::c_long; 24], } #[repr(C)] @@ -1253,7 +1253,7 @@ pub struct XClientMessageEvent { pub window: Window, pub message_type: Atom, pub format: libc::c_int, - pub l: [libc::c_long, ..5], + pub l: [libc::c_long; 5], } #[repr(C)] @@ -1384,6 +1384,7 @@ extern "C" { #[link(name = "GL")] #[link(name = "X11")] #[link(name = "Xxf86vm")] +#[link(name = "Xcursor")] extern "C" { pub fn XCloseDisplay(display: *mut Display); pub fn XCheckMaskEvent(display: *mut Display, event_mask: libc::c_long, @@ -1435,7 +1436,7 @@ extern "C" { res_class: *mut libc::c_char) -> XIM; // TODO: this is a vararg function - //pub fn XCreateIC(im: XIM, ...) -> XIC; + //pub fn XCreateIC(im: XIM; .) -> XIC; pub fn XCreateIC(im: XIM, a: *const libc::c_char, b: libc::c_long, c: *const libc::c_char, d: Window, e: *const ()) -> XIC; pub fn XDestroyIC(ic: XIC); @@ -1454,6 +1455,9 @@ extern "C" { x: libc::c_int, y: libc::c_int) -> Bool; pub fn XF86VidModeGetAllModeLines(dpy: *mut Display, screen: libc::c_int, modecount_return: *mut libc::c_int, modesinfo: *mut *mut *mut XF86VidModeModeInfo) -> Bool; + + pub fn XcursorLibraryLoadCursor(dpy: *mut Display, name: *const libc::c_char) -> Cursor; + pub fn XDefineCursor(dby: *mut Display, w: Window, cursor: Cursor); } /* diff --git a/src/x11/headless.rs b/src/x11/headless.rs index 95f5233..7692832 100644 --- a/src/x11/headless.rs +++ b/src/x11/headless.rs @@ -1,23 +1,32 @@ -use HeadlessRendererBuilder; +use BuilderAttribs; use CreationError; use CreationError::OsError; use libc; use std::{mem, ptr}; use super::ffi; +fn with_c_str<F, T>(s: &str, f: F) -> T where F: FnOnce(*const i8) -> T { + use std::ffi::CString; + let c_str = CString::from_slice(s.as_bytes()); + f(c_str.as_slice_with_nul().as_ptr()) +} + pub struct HeadlessContext { context: ffi::OSMesaContext, buffer: Vec<u32>, - width: uint, - height: uint, + width: u32, + height: u32, } impl HeadlessContext { - pub fn new(builder: HeadlessRendererBuilder) -> Result<HeadlessContext, CreationError> { + pub fn new(builder: BuilderAttribs) -> Result<HeadlessContext, CreationError> { + let dimensions = builder.dimensions.unwrap(); + Ok(HeadlessContext { - width: builder.dimensions.0, - height: builder.dimensions.1, - buffer: Vec::from_elem(builder.dimensions.0 * builder.dimensions.1, unsafe { mem::uninitialized() }), + width: dimensions.0, + height: dimensions.1, + buffer: ::std::iter::repeat(unsafe { mem::uninitialized() }) + .take((dimensions.0 * dimensions.1) as usize).collect(), context: unsafe { let ctxt = ffi::OSMesaCreateContext(0x1908, ptr::null()); if ctxt.is_null() { @@ -39,10 +48,8 @@ impl HeadlessContext { } pub fn get_proc_address(&self, addr: &str) -> *const () { - use std::c_str::ToCStr; - unsafe { - addr.with_c_str(|s| { + with_c_str(addr, |s| { ffi::OSMesaGetProcAddress(mem::transmute(s)) as *const () }) } @@ -53,7 +60,7 @@ impl HeadlessContext { ::Api::OpenGl } - pub fn set_window_resize_callback(&mut self, _: Option<fn(uint, uint)>) { + pub fn set_window_resize_callback(&mut self, _: Option<fn(u32, u32)>) { } } @@ -62,3 +69,6 @@ impl Drop for HeadlessContext { unsafe { ffi::OSMesaDestroyContext(self.context) } } } + +unsafe impl Send for HeadlessContext {} +unsafe impl Sync for HeadlessContext {} diff --git a/src/x11/mod.rs b/src/x11/mod.rs index 9ce789f..22184a9 100644 --- a/src/x11/mod.rs +++ b/src/x11/mod.rs @@ -11,3 +11,8 @@ mod headless; #[cfg(feature = "window")] mod window; + +#[cfg(not(feature = "window"))] +pub type Window = (); // TODO: hack to make things work +#[cfg(not(feature = "window"))] +pub type MonitorID = (); // TODO: hack to make things work diff --git a/src/x11/window/mod.rs b/src/x11/window/mod.rs index 422b5b6..5b70a19 100644 --- a/src/x11/window/mod.rs +++ b/src/x11/window/mod.rs @@ -1,10 +1,11 @@ -use {Event, WindowBuilder}; +use {Event, BuilderAttribs, MouseCursor}; use CreationError; use CreationError::OsError; use libc; use std::{mem, ptr}; use std::cell::Cell; use std::sync::atomic::AtomicBool; +use std::collections::RingBuf; use super::ffi; use std::sync::{Arc, Once, ONCE_INIT}; @@ -16,13 +17,19 @@ mod monitor; static THREAD_INIT: Once = ONCE_INIT; fn ensure_thread_init() { - THREAD_INIT.doit(|| { + THREAD_INIT.call_once(|| { unsafe { ffi::XInitThreads(); } }); } +fn with_c_str<F, T>(s: &str, f: F) -> T where F: FnOnce(*const i8) -> T { + use std::ffi::CString; + let c_str = CString::from_slice(s.as_bytes()); + f(c_str.as_slice_with_nul().as_ptr()) +} + struct XWindow { display: *mut ffi::Display, window: ffi::Window, @@ -34,6 +41,9 @@ struct XWindow { im: ffi::XIM, } +unsafe impl Send for Window {} +unsafe impl Sync for Window {} + impl Drop for XWindow { fn drop(&mut self) { unsafe { @@ -53,7 +63,7 @@ impl Drop for XWindow { } } -#[deriving(Clone)] +#[derive(Clone)] pub struct WindowProxy { x: Arc<XWindow>, } @@ -86,7 +96,7 @@ pub struct Window { } impl Window { - pub fn new(builder: WindowBuilder) -> Result<Window, CreationError> { + pub fn new(builder: BuilderAttribs) -> Result<Window, CreationError> { ensure_thread_init(); let dimensions = builder.dimensions.unwrap_or((800, 600)); @@ -150,7 +160,7 @@ impl Window { } for i in range(0, mode_num) { - let mode: ffi::XF86VidModeModeInfo = ptr::read(*modes.offset(i as int) as *const _); + let mode: ffi::XF86VidModeModeInfo = ptr::read(*modes.offset(i as isize) as *const _); if mode.hdisplay == dimensions.0 as u16 && mode.vdisplay == dimensions.1 as u16 { best_mode = i; } @@ -159,7 +169,7 @@ impl Window { return Err(OsError(format!("Could not find a suitable graphics mode"))); } - modes + modes }; let xf86_desk_mode = unsafe { @@ -205,7 +215,7 @@ impl Window { if builder.monitor.is_some() { window_attributes |= ffi::CWOverrideRedirect; unsafe { - ffi::XF86VidModeSwitchToMode(display, screen_id, *modes.offset(best_mode as int)); + ffi::XF86VidModeSwitchToMode(display, screen_id, *modes.offset(best_mode as isize)); ffi::XF86VidModeSetViewPort(display, screen_id, 0, 0); set_win_attr.override_redirect = 1; } @@ -230,13 +240,13 @@ impl Window { // creating window, step 2 let wm_delete_window = unsafe { - use std::c_str::ToCStr; - - let delete_window = "WM_DELETE_WINDOW".to_c_str(); - let mut wm_delete_window = ffi::XInternAtom(display, delete_window.as_ptr(), 0); + let mut wm_delete_window = with_c_str("WM_DELETE_WINDOW", |delete_window| + ffi::XInternAtom(display, delete_window, 0) + ); ffi::XSetWMProtocols(display, window, &mut wm_delete_window, 1); - let c_title = builder.title.to_c_str(); - ffi::XStoreName(display, window, c_title.as_ptr()); + with_c_str(&*builder.title, |title| {; + ffi::XStoreName(display, window, title); + }); ffi::XFlush(display); wm_delete_window @@ -253,13 +263,15 @@ impl Window { // creating input context let ic = unsafe { - use std::c_str::ToCStr; - - let input_style = "inputStyle".to_c_str(); - let client_window = "clientWindow".to_c_str(); - let ic = ffi::XCreateIC(im, input_style.as_ptr(), - ffi::XIMPreeditNothing | ffi::XIMStatusNothing, client_window.as_ptr(), - window, ptr::null()); + let ic = with_c_str("inputStyle", |input_style| + with_c_str("clientWindow", |client_window| + ffi::XCreateIC( + im, input_style, + ffi::XIMPreeditNothing | ffi::XIMStatusNothing, client_window, + window, ptr::null() + ) + ) + ); if ic.is_null() { return Err(OsError(format!("XCreateIC failed"))); } @@ -298,14 +310,14 @@ impl Window { // loading the extra GLX functions let extra_functions = ffi::glx_extra::Glx::load_with(|addr| { - addr.with_c_str(|s| { + with_c_str(addr, |s| { use libc; ffi::glx::GetProcAddress(s as *const u8) as *const libc::c_void }) }); let share = if let Some(win) = builder.sharing { - win.window.x.context + win.x.context } else { ptr::null() }; @@ -346,16 +358,15 @@ impl Window { } pub fn is_closed(&self) -> bool { - use std::sync::atomic::Relaxed; + use std::sync::atomic::Ordering::Relaxed; self.is_closed.load(Relaxed) } pub fn set_title(&self, title: &str) { - let c_title = title.to_c_str(); - unsafe { - ffi::XStoreName(self.x.display, self.x.window, c_title.as_ptr()); + with_c_str(title, |title| unsafe { + ffi::XStoreName(self.x.display, self.x.window, title); ffi::XFlush(self.x.display); - } + }) } pub fn show(&self) { @@ -372,7 +383,7 @@ impl Window { } } - fn get_geometry(&self) -> Option<(int, int, uint, uint)> { + fn get_geometry(&self) -> Option<(i32, i32, u32, u32)> { unsafe { use std::mem; @@ -391,27 +402,27 @@ impl Window { return None; } - Some((x as int, y as int, width as uint, height as uint)) + Some((x as i32, y as i32, width as u32, height as u32)) } } - pub fn get_position(&self) -> Option<(int, int)> { + pub fn get_position(&self) -> Option<(i32, i32)> { self.get_geometry().map(|(x, y, _, _)| (x, y)) } - pub fn set_position(&self, x: int, y: int) { + pub fn set_position(&self, x: i32, y: i32) { unsafe { ffi::XMoveWindow(self.x.display, self.x.window, x as libc::c_int, y as libc::c_int) } } - pub fn get_inner_size(&self) -> Option<(uint, uint)> { + pub fn get_inner_size(&self) -> Option<(u32, u32)> { self.get_geometry().map(|(_, _, w, h)| (w, h)) } - pub fn get_outer_size(&self) -> Option<(uint, uint)> { + pub fn get_outer_size(&self) -> Option<(u32, u32)> { unimplemented!() } - pub fn set_inner_size(&self, _x: uint, _y: uint) { + pub fn set_inner_size(&self, _x: u32, _y: u32) { unimplemented!() } @@ -421,10 +432,10 @@ impl Window { } } - pub fn poll_events(&self) -> Vec<Event> { + pub fn poll_events(&self) -> RingBuf<Event> { use std::mem; - let mut events = Vec::new(); + let mut events = RingBuf::new(); loop { use std::num::Int; @@ -447,15 +458,15 @@ impl Window { ffi::ClientMessage => { use events::Event::{Closed, Awakened}; - use std::sync::atomic::Relaxed; + use std::sync::atomic::Ordering::Relaxed; let client_msg: &ffi::XClientMessageEvent = unsafe { mem::transmute(&xev) }; if client_msg.l[0] == self.wm_delete_window as libc::c_long { self.is_closed.store(true, Relaxed); - events.push(Closed); + events.push_back(Closed); } else { - events.push(Awakened); + events.push_back(Awakened); } }, @@ -465,14 +476,14 @@ impl Window { let (current_width, current_height) = self.current_size.get(); if current_width != cfg_event.width || current_height != cfg_event.height { self.current_size.set((cfg_event.width, cfg_event.height)); - events.push(Resized(cfg_event.width as uint, cfg_event.height as uint)); + events.push_back(Resized(cfg_event.width as u32, cfg_event.height as u32)); } }, ffi::MotionNotify => { use events::Event::MouseMoved; let event: &ffi::XMotionEvent = unsafe { mem::transmute(&xev) }; - events.push(MouseMoved((event.x as int, event.y as int))); + events.push_back(MouseMoved((event.x as i32, event.y as i32))); }, ffi::KeyPress | ffi::KeyRelease => { @@ -490,18 +501,18 @@ impl Window { let written = unsafe { use std::str; - let mut buffer: [u8, ..16] = [mem::uninitialized(), ..16]; + let mut buffer: [u8; 16] = [mem::uninitialized(); 16]; let raw_ev: *mut ffi::XKeyEvent = event; let count = ffi::Xutf8LookupString(self.x.ic, mem::transmute(raw_ev), mem::transmute(buffer.as_mut_ptr()), buffer.len() as libc::c_int, ptr::null_mut(), ptr::null_mut()); - str::from_utf8(buffer.as_slice().slice_to(count as uint)) + str::from_utf8(buffer.as_slice().slice_to(count as usize)) .unwrap_or("").to_string() }; for chr in written.as_slice().chars() { - events.push(ReceivedCharacter(chr)); + events.push_back(ReceivedCharacter(chr)); } let keysym = unsafe { @@ -510,7 +521,7 @@ impl Window { let vkey = events::keycode_to_element(keysym as libc::c_uint); - events.push(KeyboardInput(state, event.keycode as u8, vkey)); + events.push_back(KeyboardInput(state, event.keycode as u8, vkey)); }, ffi::ButtonPress | ffi::ButtonRelease => { @@ -527,11 +538,11 @@ impl Window { ffi::Button2 => Some(MiddleMouseButton), ffi::Button3 => Some(RightMouseButton), ffi::Button4 => { - events.push(MouseWheel(1)); + events.push_back(MouseWheel(1)); None } ffi::Button5 => { - events.push(MouseWheel(-1)); + events.push_back(MouseWheel(-1)); None } _ => None @@ -539,7 +550,7 @@ impl Window { match button { Some(button) => - events.push(MouseInput(state, button)), + events.push_back(MouseInput(state, button)), None => () }; }, @@ -551,7 +562,7 @@ impl Window { events } - pub fn wait_events(&self) -> Vec<Event> { + pub fn wait_events(&self) -> RingBuf<Event> { use std::mem; loop { @@ -576,11 +587,10 @@ impl Window { } pub fn get_proc_address(&self, addr: &str) -> *const () { - use std::c_str::ToCStr; use std::mem; unsafe { - addr.with_c_str(|s| { + with_c_str(addr, |s| { ffi::glx::GetProcAddress(mem::transmute(s)) as *const () }) } @@ -599,6 +609,53 @@ impl Window { ::Api::OpenGl } - pub fn set_window_resize_callback(&mut self, _: Option<fn(uint, uint)>) { + pub fn set_window_resize_callback(&mut self, _: Option<fn(u32, u32)>) { + } + + pub fn set_cursor(&self, cursor: MouseCursor) { + unsafe { + use std::ffi::CString; + let cursor_name = match cursor { + MouseCursor::Alias => "link", + MouseCursor::Arrow => "arrow", + MouseCursor::Cell => "plus", + MouseCursor::Copy => "copy", + MouseCursor::Crosshair => "crosshair", + MouseCursor::Default => "left_ptr", + MouseCursor::Grabbing => "grabbing", + MouseCursor::Hand | MouseCursor::Grab => "hand", + MouseCursor::Help => "question_arrow", + MouseCursor::Move => "move", + MouseCursor::NoDrop => "circle", + MouseCursor::NotAllowed => "crossed_circle", + MouseCursor::Progress => "left_ptr_watch", + + /// Resize cursors + MouseCursor::EResize => "right_side", + MouseCursor::NResize => "top_side", + MouseCursor::NeResize => "top_right_corner", + MouseCursor::NwResize => "top_left_corner", + MouseCursor::SResize => "bottom_side", + MouseCursor::SeResize => "bottom_right_corner", + MouseCursor::SwResize => "bottom_left_corner", + MouseCursor::WResize => "left_side", + MouseCursor::EwResize | MouseCursor::ColResize => "h_double_arrow", + MouseCursor::NsResize | MouseCursor::RowResize => "v_double_arrow", + MouseCursor::NwseResize => "bd_double_arrow", + MouseCursor::NeswResize => "fd_double_arrow", + + MouseCursor::Text | MouseCursor::VerticalText => "xterm", + MouseCursor::Wait => "watch", + + /// TODO: Find matching X11 cursors + MouseCursor::ContextMenu | MouseCursor::NoneCursor | + MouseCursor::AllScroll | MouseCursor::ZoomIn | + MouseCursor::ZoomOut => "left_ptr", + }; + let c_string = CString::from_slice(cursor_name.as_bytes()); + let xcursor = ffi::XcursorLibraryLoadCursor(self.x.display, c_string.as_ptr()); + ffi::XDefineCursor (self.x.display, self.x.window, xcursor); + ffi::XFlush(self.x.display); + } } } diff --git a/src/x11/window/monitor.rs b/src/x11/window/monitor.rs index f62a8ef..3c188b6 100644 --- a/src/x11/window/monitor.rs +++ b/src/x11/window/monitor.rs @@ -1,10 +1,11 @@ -use std::{ptr}; +use std::ptr; +use std::collections::RingBuf; use super::super::ffi; use super::ensure_thread_init; -pub struct MonitorID(pub uint); +pub struct MonitorID(pub u32); -pub fn get_available_monitors() -> Vec<MonitorID> { +pub fn get_available_monitors() -> RingBuf<MonitorID> { ensure_thread_init(); let nb_monitors = unsafe { let display = ffi::XOpenDisplay(ptr::null()); @@ -16,9 +17,9 @@ pub fn get_available_monitors() -> Vec<MonitorID> { nb_monitors }; - let mut vec = Vec::new(); - vec.grow_fn(nb_monitors as uint, |i| MonitorID(i)); - vec + let mut monitors = RingBuf::new(); + monitors.extend(range(0, nb_monitors).map(|i| MonitorID(i as u32))); + monitors } pub fn get_primary_monitor() -> MonitorID { @@ -33,7 +34,7 @@ pub fn get_primary_monitor() -> MonitorID { primary_monitor }; - MonitorID(primary_monitor as uint) + MonitorID(primary_monitor as u32) } impl MonitorID { @@ -42,7 +43,7 @@ impl MonitorID { Some(format!("Monitor #{}", screen_num)) } - pub fn get_dimensions(&self) -> (uint, uint) { + pub fn get_dimensions(&self) -> (u32, u32) { let dimensions = unsafe { let display = ffi::XOpenDisplay(ptr::null()); let MonitorID(screen_num) = *self; @@ -50,7 +51,7 @@ impl MonitorID { let width = ffi::XWidthOfScreen(screen); let height = ffi::XHeightOfScreen(screen); ffi::XCloseDisplay(display); - (width as uint, height as uint) + (width as u32, height as u32) }; dimensions |