aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--README.md13
-rw-r--r--appveyor.yml16
-rw-r--r--etc/32bits/libgdi32.abin0 -> 257548 bytes
-rw-r--r--etc/32bits/libopengl32.abin0 -> 269090 bytes
-rw-r--r--etc/64bits/libgdi32.abin0 -> 449524 bytes
-rw-r--r--etc/64bits/libopengl32.abin0 -> 269008 bytes
-rw-r--r--examples/support/mod.rs14
-rw-r--r--src/android/ffi.rs7
-rw-r--r--src/android/mod.rs5
-rw-r--r--src/events.rs4
-rw-r--r--src/lib.rs24
-rw-r--r--src/osx/event.rs156
-rw-r--r--src/osx/mod.rs99
-rw-r--r--src/win32/ffi.rs18
-rw-r--r--src/win32/init.rs21
-rw-r--r--src/win32/mod.rs21
-rw-r--r--src/win32/monitor.rs2
-rw-r--r--src/x11/ffi.rs35
-rw-r--r--src/x11/window/events.rs12
-rw-r--r--src/x11/window/mod.rs109
-rw-r--r--src/x11/window/monitor.rs8
-rw-r--r--tests/headless.rs10
22 files changed, 506 insertions, 68 deletions
diff --git a/README.md b/README.md
index 1a085c4..d0c0c3a 100644
--- a/README.md
+++ b/README.md
@@ -10,8 +10,7 @@ Alternative to GLFW in pure Rust.
```bash
git clone https://github.com/tomaka/glutin
cd glutin
-cargo test
-./target/test/window # or target\test\window.exe
+cargo run --example window
```
## Usage
@@ -44,8 +43,8 @@ fn main() {
### Android
- - To compile the examples for android, initialize the submodules, go to `deps/apk-builder/apk-builder` and run `cargo build`, then go back to `gl-init` and call `ANDROID_HOME=/path/to/sdk NDK_HOME=/path/to/ndk NDK_STANDALONE=/path/to/standalone cargo test --no-run --target=arm-linux-androideabi`
- - Events are not implemented
+ - To compile the examples for android, initialize the submodules, go to `deps/apk-builder/apk-builder` and run `cargo build`, then go back to `glutin` and call `ANDROID_HOME=/path/to/sdk NDK_HOME=/path/to/ndk NDK_STANDALONE=/path/to/standalone cargo test --no-run --target=arm-linux-androideabi`
+ - Events and vsync are not implemented
- Headless rendering doesn't work
### Emscripten
@@ -54,7 +53,9 @@ fn main() {
### OS/X
- - Events are not implemented
+ - Some events are not implemented
+ - Implementation is still work-in-progress
+ - Vsync not implemented
### Win32
@@ -66,4 +67,4 @@ fn main() {
- Some input events are not implemented
- Pixel formats not implemented
- - The implementation probably needs a cleanup
+ - Vsync not implemented
diff --git a/appveyor.yml b/appveyor.yml
new file mode 100644
index 0000000..ed0256b
--- /dev/null
+++ b/appveyor.yml
@@ -0,0 +1,16 @@
+install:
+ - ps: Start-FileDownload 'https://static.rust-lang.org/dist/rust-nightly-i686-w64-mingw32.exe'
+ - ps: Start-FileDownload 'https://static.rust-lang.org/cargo-dist/cargo-nightly-i686-w64-mingw32.tar.gz'
+ - rust-nightly-i686-w64-mingw32.exe /VERYSILENT /NORESTART
+ - 7z e cargo-nightly-i686-w64-mingw32.tar.gz
+ - 7z x cargo-nightly-i686-w64-mingw32.tar
+ - SET PATH=%PATH%;C:\Program Files (x86)\Rust\bin
+ - SET PATH=%PATH%;%CD%\cargo-nightly-i686-w64-mingw32\bin
+ - mkdir %HOMEDRIVE%%HOMEPATH%\.rust
+ - cp etc/32bits/* %HOMEDRIVE%%HOMEPATH%\.rust
+
+build: false
+
+test_script:
+ - cargo test --verbose --no-default-features --features "window"
+ - cargo test --verbose --no-default-features --features "headless"
diff --git a/etc/32bits/libgdi32.a b/etc/32bits/libgdi32.a
new file mode 100644
index 0000000..013890d
--- /dev/null
+++ b/etc/32bits/libgdi32.a
Binary files differ
diff --git a/etc/32bits/libopengl32.a b/etc/32bits/libopengl32.a
new file mode 100644
index 0000000..f0ec114
--- /dev/null
+++ b/etc/32bits/libopengl32.a
Binary files differ
diff --git a/etc/64bits/libgdi32.a b/etc/64bits/libgdi32.a
new file mode 100644
index 0000000..1ea92d2
--- /dev/null
+++ b/etc/64bits/libgdi32.a
Binary files differ
diff --git a/etc/64bits/libopengl32.a b/etc/64bits/libopengl32.a
new file mode 100644
index 0000000..7394b96
--- /dev/null
+++ b/etc/64bits/libopengl32.a
Binary files differ
diff --git a/examples/support/mod.rs b/examples/support/mod.rs
index f27c4e7..12aa68c 100644
--- a/examples/support/mod.rs
+++ b/examples/support/mod.rs
@@ -7,13 +7,23 @@ use glutin;
#[cfg(not(target_os = "android"))]
mod gl {
- generate_gl_bindings!("gl", "core", "1.1", "struct")
+ generate_gl_bindings! {
+ api: "gl",
+ profile: "core",
+ version: "1.1",
+ generator: "struct"
+ }
}
#[cfg(target_os = "android")]
mod gl {
pub use self::Gles1 as Gl;
- generate_gl_bindings!("gles1", "core", "1.1", "struct")
+ generate_gl_bindings! {
+ api: "gles1",
+ profile: "core",
+ version: "1.1",
+ generator: "struct"
+ }
}
pub struct Context {
diff --git a/src/android/ffi.rs b/src/android/ffi.rs
index a7482e3..b65f44d 100644
--- a/src/android/ffi.rs
+++ b/src/android/ffi.rs
@@ -17,7 +17,12 @@ pub mod egl {
pub type NativePixmapType = super::EGLNativePixmapType;
pub type NativeWindowType = super::EGLNativeWindowType;
- generate_gl_bindings!("egl", "core", "1.5", "static")
+ generate_gl_bindings! {
+ api: "egl",
+ profile: "core",
+ version: "1.5",
+ generator: "static"
+ }
}
pub type khronos_utime_nanoseconds_t = khronos_uint64_t;
diff --git a/src/android/mod.rs b/src/android/mod.rs
index d900abe..db3dd19 100644
--- a/src/android/mod.rs
+++ b/src/android/mod.rs
@@ -1,6 +1,7 @@
extern crate android_glue;
extern crate native;
+use libc;
use {Event, WindowBuilder};
pub struct Window {
@@ -186,6 +187,10 @@ impl Window {
ffi::egl::SwapBuffers(self.display, self.surface);
}
}
+
+ pub fn platform_display(&self) -> *mut libc::c_void {
+ self.display as *mut libc::c_void
+ }
}
#[unsafe_destructor]
diff --git a/src/events.rs b/src/events.rs
index f28fb59..0c11a75 100644
--- a/src/events.rs
+++ b/src/events.rs
@@ -128,7 +128,8 @@ pub enum VirtualKeyCode {
Kana,
Kanji,
L,
- LCracket,
+ LAlt,
+ LBracket,
LControl,
Left,
LMenu,
@@ -171,6 +172,7 @@ pub enum VirtualKeyCode {
Prevtrack,
Q,
R,
+ RAlt,
RBracket,
RControl,
Return,
diff --git a/src/lib.rs b/src/lib.rs
index 041ebeb..096bae4 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -37,6 +37,8 @@ extern crate libc;
extern crate cocoa;
#[cfg(target_os = "macos")]
extern crate core_foundation;
+#[cfg(target_os = "linux")]
+extern crate sync;
pub use events::*;
@@ -71,6 +73,7 @@ pub struct WindowBuilder {
title: String,
monitor: Option<winimpl::MonitorID>,
gl_version: Option<(uint, uint)>,
+ vsync: bool,
}
#[cfg(feature = "window")]
@@ -79,9 +82,10 @@ impl WindowBuilder {
pub fn new() -> WindowBuilder {
WindowBuilder {
dimensions: None,
- title: "gl-init-rs window".to_string(),
+ title: "glutin window".to_string(),
monitor: None,
gl_version: None,
+ vsync: false,
}
}
@@ -117,6 +121,12 @@ impl WindowBuilder {
self
}
+ /// Requests that the window has vsync enabled.
+ pub fn with_vsync(mut self) -> WindowBuilder {
+ self.vsync = true;
+ self
+ }
+
/// Builds the window.
///
/// Error should be very rare and only occur in case of permission denied, incompatible system,
@@ -337,10 +347,22 @@ impl Window {
///
/// You should call this function every time you have finished rendering, or the image
/// may not be displayed on the screen.
+ ///
+ /// **Warning**: if you enabled vsync, this function will block until the next time the screen
+ /// is refreshed. However drivers can choose to override your vsync settings, which means that
+ /// you can't know in advance whether `swap_buffers` will block or not.
#[inline]
pub fn swap_buffers(&self) {
self.window.swap_buffers()
}
+
+ /// Gets the native platform specific display for this window.
+ /// This is typically only required when integrating with
+ /// other libraries that need this information.
+ #[inline]
+ pub unsafe fn platform_display(&self) -> *mut libc::c_void {
+ self.window.platform_display()
+ }
}
/// Represents a headless OpenGL context.
diff --git a/src/osx/event.rs b/src/osx/event.rs
new file mode 100644
index 0000000..a4128a4
--- /dev/null
+++ b/src/osx/event.rs
@@ -0,0 +1,156 @@
+use events;
+use events::KeyModifiers;
+use cocoa::base::NSUInteger;
+use cocoa::appkit;
+
+pub fn modifierflag_to_element(flag: NSUInteger) -> KeyModifiers {
+ let mut modifiers = KeyModifiers::empty();
+ if flag & appkit::NSShiftKeyMask as u64 == appkit::NSShiftKeyMask as u64 {
+ modifiers = modifiers | events::LEFT_SHIFT_MODIFIER;
+ }
+ if flag & appkit::NSControlKeyMask as u64 == appkit::NSControlKeyMask as u64 {
+ modifiers = modifiers | events::LEFT_CONTROL_MODIFIER;
+ }
+ if flag & appkit::NSAlternateKeyMask as u64 == appkit::NSAlternateKeyMask as u64 {
+ modifiers = modifiers | events::LEFT_ALT_MODIFIER;
+ }
+ if flag & appkit::NSNumericPadKeyMask as u64 == appkit::NSNumericPadKeyMask as u64 {
+ modifiers = modifiers | events::NUM_LOCK_MODIFIER;
+ }
+ modifiers
+}
+
+pub fn vkeycode_to_element(code: u16) -> Option<events::VirtualKeyCode> {
+ Some(match code {
+ 0x00 => events::A,
+ 0x01 => events::S,
+ 0x02 => events::D,
+ 0x03 => events::F,
+ 0x04 => events::H,
+ 0x05 => events::G,
+ 0x06 => events::Z,
+ 0x07 => events::X,
+ 0x08 => events::C,
+ 0x09 => events::V,
+ //0x0a => World 1,
+ 0x0b => events::B,
+ 0x0c => events::Q,
+ 0x0d => events::W,
+ 0x0e => events::E,
+ 0x0f => events::R,
+ 0x10 => events::Y,
+ 0x11 => events::T,
+ 0x12 => events::Key1,
+ 0x13 => events::Key2,
+ 0x14 => events::Key3,
+ 0x15 => events::Key4,
+ 0x16 => events::Key6,
+ 0x17 => events::Key5,
+ 0x18 => events::Equals,
+ 0x19 => events::Key9,
+ 0x1a => events::Key7,
+ 0x1b => events::Minus,
+ 0x1c => events::Key8,
+ 0x1d => events::Key0,
+ 0x1e => events::RBracket,
+ 0x1f => events::O,
+ 0x20 => events::U,
+ 0x21 => events::LBracket,
+ 0x22 => events::I,
+ 0x23 => events::P,
+ 0x24 => events::Return,
+ 0x25 => events::L,
+ 0x26 => events::J,
+ 0x27 => events::Apostrophe,
+ 0x28 => events::K,
+ 0x29 => events::Semicolon,
+ 0x2a => events::Backslash,
+ 0x2b => events::Comma,
+ 0x2c => events::Slash,
+ 0x2d => events::N,
+ 0x2e => events::M,
+ 0x2f => events::Period,
+ 0x30 => events::Tab,
+ 0x31 => events::Space,
+ 0x32 => events::Grave,
+ 0x33 => events::Back,
+ //0x34 => unkown,
+ 0x35 => events::Escape,
+ 0x36 => events::RWin,
+ 0x37 => events::LWin,
+ 0x38 => events::LShift,
+ //0x39 => Caps lock,
+ //0x3a => Left alt,
+ 0x3b => events::LControl,
+ 0x3c => events::RShift,
+ //0x3d => Right alt,
+ 0x3e => events::RControl,
+ //0x3f => Fn key,
+ //0x40 => F17 Key,
+ 0x41 => events::Decimal,
+ //0x42 -> unkown,
+ 0x43 => events::Multiply,
+ //0x44 => unkown,
+ 0x45 => events::Add,
+ //0x46 => unkown,
+ 0x47 => events::Numlock,
+ //0x48 => KeypadClear,
+ 0x49 => events::VolumeUp,
+ 0x4a => events::VolumeDown,
+ 0x4b => events::Divide,
+ 0x4c => events::NumpadEnter,
+ //0x4d => unkown,
+ 0x4e => events::Subtract,
+ //0x4f => F18 key,
+ //0x50 => F19 Key,
+ 0x51 => events::NumpadEquals,
+ 0x52 => events::Numpad0,
+ 0x53 => events::Numpad1,
+ 0x54 => events::Numpad2,
+ 0x55 => events::Numpad3,
+ 0x56 => events::Numpad4,
+ 0x57 => events::Numpad5,
+ 0x58 => events::Numpad6,
+ 0x59 => events::Numpad7,
+ //0x5a => F20 Key,
+ 0x5b => events::Numpad8,
+ 0x5c => events::Numpad9,
+ //0x5d => unkown,
+ //0x5e => unkown,
+ //0x5f => unkown,
+ 0x60 => events::F5,
+ 0x61 => events::F6,
+ 0x62 => events::F7,
+ 0x63 => events::F3,
+ 0x64 => events::F8,
+ 0x65 => events::F9,
+ //0x66 => unkown,
+ 0x67 => events::F11,
+ //0x68 => unkown,
+ 0x69 => events::F13,
+ //0x6a => F16 Key,
+ 0x6b => events::F14,
+ //0x6c => unkown,
+ 0x6d => events::F10,
+ //0x6e => unkown,
+ 0x6f => events::F12,
+ //0x70 => unkown,
+ 0x71 => events::F15,
+ 0x72 => events::Insert,
+ 0x73 => events::Home,
+ 0x74 => events::PageUp,
+ 0x75 => events::Delete,
+ 0x76 => events::F4,
+ 0x77 => events::End,
+ 0x78 => events::F2,
+ 0x79 => events::PageDown,
+ 0x7a => events::F1,
+ 0x7b => events::Left,
+ 0x7c => events::Right,
+ 0x7d => events::Down,
+ 0x7e => events::Up,
+ //0x7f => unkown,
+
+ _ => return None,
+ })
+}
diff --git a/src/osx/mod.rs b/src/osx/mod.rs
index 78d147f..287dcb4 100644
--- a/src/osx/mod.rs
+++ b/src/osx/mod.rs
@@ -1,4 +1,6 @@
use Event;
+use libc;
+use std::sync::atomic::AtomicBool;
#[cfg(feature = "window")]
use WindowBuilder;
@@ -7,14 +9,30 @@ use WindowBuilder;
use HeadlessRendererBuilder;
use cocoa::base::{id, NSUInteger, nil};
+use cocoa::appkit;
use cocoa::appkit::*;
use core_foundation::base::TCFType;
use core_foundation::string::CFString;
use core_foundation::bundle::{CFBundleGetBundleWithIdentifier, CFBundleGetFunctionPointerForName};
+use std::c_str::CString;
+use {MouseInput, Pressed, Released, LeftMouseButton, RightMouseButton, MouseMoved, ReceivedCharacter,
+ KeyboardInput, KeyModifiers};
+
+use events;
+
+mod event;
+
+static mut shift_pressed: bool = false;
+static mut ctrl_pressed: bool = false;
+static mut win_pressed: bool = false;
+static mut alt_pressed: bool = false;
+
pub struct Window {
+ view: id,
context: id,
+ is_closed: AtomicBool,
}
pub struct HeadlessContext(Window);
@@ -86,7 +104,9 @@ impl Window {
}
let window = Window {
+ view: view,
context: context,
+ is_closed: AtomicBool::new(false),
};
Ok(window)
@@ -123,6 +143,7 @@ impl Window {
let title = NSString::alloc(nil).init_str(title);
window.setTitle_(title);
window.center();
+ window.setAcceptsMouseMovedEvents_(true);
Some(window)
}
}
@@ -135,7 +156,7 @@ impl Window {
None
} else {
view.setWantsBestResolutionOpenGLSurface_(true);
- window.setContentView(view);
+ window.setContentView_(view);
Some(view)
}
}
@@ -169,8 +190,8 @@ impl Window {
}
pub fn is_closed(&self) -> bool {
- // TODO: remove fake implementation
- false
+ use std::sync::atomic::Relaxed;
+ self.is_closed.load(Relaxed)
}
pub fn set_title(&self, _title: &str) {
@@ -202,23 +223,63 @@ impl Window {
loop {
unsafe {
- use {MouseInput, Pressed, Released, LeftMouseButton, RightMouseButton};
let event = NSApp().nextEventMatchingMask_untilDate_inMode_dequeue_(
NSAnyEventMask as u64,
NSDate::distantPast(nil),
NSDefaultRunLoopMode,
true);
if event == nil { break; }
+ NSApp().sendEvent_(event);
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 => { },
- NSKeyDown => { },
- NSKeyUp => { },
- NSFlagsChanged => { },
+ 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());
+ let modifiers = event::modifierflag_to_element(event.modifierFlags());
+ events.push(KeyboardInput(Pressed, event.keycode() as u8, vkey, modifiers));
+ },
+ NSKeyUp => {
+ let vkey = event::vkeycode_to_element(event.keycode());
+ let modifiers = event::modifierflag_to_element(event.modifierFlags());
+ events.push(KeyboardInput(Released, event.keycode() as u8, vkey, modifiers));
+ },
+ NSFlagsChanged => {
+ let shift_modifier = Window::modifier_event(event, appkit::NSShiftKeyMask as u64, events::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::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::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::LAlt, alt_pressed);
+ if alt_modifier.is_some() {
+ alt_pressed = !alt_pressed;
+ events.push(alt_modifier.unwrap());
+ }
+ },
NSScrollWheel => { },
NSOtherMouseDown => { },
NSOtherMouseUp => { },
@@ -230,14 +291,30 @@ impl Window {
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), KeyModifiers::empty()));
+ }
+ else if key_pressed && !Window::modifier_key_pressed(event, keymask) {
+ return Some(KeyboardInput(Released, event.keycode() as u8, Some(key), KeyModifiers::empty()));
+ }
+
+ 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,
- true);
+ false);
NSApp().sendEvent_(event);
+
self.poll_events()
}
}
@@ -261,4 +338,8 @@ impl Window {
pub fn swap_buffers(&self) {
unsafe { self.context.flushBuffer(); }
}
+
+ pub fn platform_display(&self) -> *mut libc::c_void {
+ unimplemented!()
+ }
}
diff --git a/src/win32/ffi.rs b/src/win32/ffi.rs
index 2385954..71f8d55 100644
--- a/src/win32/ffi.rs
+++ b/src/win32/ffi.rs
@@ -7,12 +7,26 @@ use libc;
/// WGL bindings
pub mod wgl {
- generate_gl_bindings!("wgl", "core", "1.0", "static")
+ generate_gl_bindings! {
+ api: "wgl",
+ profile: "core",
+ version: "1.0",
+ generator: "static"
+ }
}
/// Functions that are not necessarly always available
pub mod wgl_extra {
- generate_gl_bindings!("wgl", "core", "1.0", "struct", [ "WGL_ARB_create_context" ])
+ generate_gl_bindings! {
+ api: "wgl",
+ profile: "core",
+ version: "1.0",
+ generator: "struct",
+ extensions: [
+ "WGL_ARB_create_context",
+ "WGL_EXT_swap_control"
+ ]
+ }
}
// http://msdn.microsoft.com/en-us/library/windows/desktop/aa383751(v=vs.85).aspx
diff --git a/src/win32/init.rs b/src/win32/init.rs
index bb3f53b..5168cc6 100644
--- a/src/win32/init.rs
+++ b/src/win32/init.rs
@@ -2,7 +2,7 @@ extern crate native;
use self::native::NativeTaskBuilder;
use std::task::TaskBuilder;
-use std::sync::atomics::AtomicBool;
+use std::sync::atomic::AtomicBool;
use std::ptr;
use super::{event, ffi};
use super::Window;
@@ -16,7 +16,7 @@ local_data_key!(WINDOW: (ffi::HWND, Sender<Event>))
pub fn new_window(builder_dimensions: Option<(uint, uint)>, builder_title: String,
builder_monitor: Option<super::MonitorID>,
- builder_gl_version: Option<(uint, uint)>,
+ builder_gl_version: Option<(uint, uint)>, builder_vsync: bool,
builder_headless: bool) -> Result<Window, String>
{
use std::mem;
@@ -346,6 +346,23 @@ pub fn new_window(builder_dimensions: Option<(uint, uint)>, builder_title: Strin
lib
};
+ // handling vsync
+ if builder_vsync {
+ if extra_functions.SwapIntervalEXT.is_loaded() {
+ unsafe { ffi::wgl::MakeCurrent(hdc, context) };
+ if extra_functions.SwapIntervalEXT(1) == 0 {
+ tx.send(Err(format!("wglSwapIntervalEXT failed")));
+ unsafe { ffi::wgl::DeleteContext(context); }
+ unsafe { ffi::DestroyWindow(real_window); }
+ return;
+ }
+
+ // it is important to remove the current context, otherwise you get very weird
+ // errors
+ unsafe { ffi::wgl::MakeCurrent(ptr::null(), ptr::null()); }
+ }
+ }
+
// building the struct
let window = Window{
window: real_window,
diff --git a/src/win32/mod.rs b/src/win32/mod.rs
index 8be3fdb..3cfdc7e 100644
--- a/src/win32/mod.rs
+++ b/src/win32/mod.rs
@@ -1,5 +1,6 @@
-use std::sync::atomics::AtomicBool;
+use std::sync::atomic::AtomicBool;
use std::ptr;
+use libc;
use Event;
#[cfg(feature = "window")]
@@ -24,7 +25,7 @@ impl HeadlessContext {
/// See the docs in the crate root file.
pub fn new(builder: HeadlessRendererBuilder) -> Result<HeadlessContext, String> {
let HeadlessRendererBuilder { dimensions, gl_version } = builder;
- init::new_window(Some(dimensions), "".to_string(), None, gl_version, true)
+ init::new_window(Some(dimensions), "".to_string(), None, gl_version, false, true)
.map(|w| HeadlessContext(w))
}
@@ -67,15 +68,15 @@ pub struct Window {
impl Window {
/// See the docs in the crate root file.
pub fn new(builder: WindowBuilder) -> Result<Window, String> {
- let WindowBuilder { dimensions, title, monitor, gl_version } = builder;
- init::new_window(dimensions, title, monitor, gl_version, false)
+ let WindowBuilder { dimensions, title, monitor, gl_version, vsync } = builder;
+ init::new_window(dimensions, title, monitor, gl_version, vsync, false)
}
}
impl Window {
/// See the docs in the crate root file.
pub fn is_closed(&self) -> bool {
- use std::sync::atomics::Relaxed;
+ use std::sync::atomic::Relaxed;
self.is_closed.load(Relaxed)
}
@@ -170,7 +171,7 @@ impl Window {
// if one of the received events is `Closed`, setting `is_closed` to true
if events.iter().find(|e| match e { &&::Closed => true, _ => false }).is_some() {
- use std::sync::atomics::Relaxed;
+ use std::sync::atomic::Relaxed;
self.is_closed.store(true, Relaxed);
}
@@ -185,7 +186,7 @@ impl Window {
// if the received event is `Closed`, setting `is_closed` to true
match ev {
::Closed => {
- use std::sync::atomics::Relaxed;
+ use std::sync::atomic::Relaxed;
self.is_closed.store(true, Relaxed);
},
_ => ()
@@ -198,7 +199,7 @@ impl Window {
},
Err(_) => {
- use std::sync::atomics::Relaxed;
+ use std::sync::atomic::Relaxed;
self.is_closed.store(true, Relaxed);
vec![]
}
@@ -233,6 +234,10 @@ impl Window {
ffi::SwapBuffers(self.hdc);
}
}
+
+ pub fn platform_display(&self) -> *mut libc::c_void {
+ unimplemented!()
+ }
}
#[unsafe_destructor]
diff --git a/src/win32/monitor.rs b/src/win32/monitor.rs
index a45c8fb..3e6b79a 100644
--- a/src/win32/monitor.rs
+++ b/src/win32/monitor.rs
@@ -101,7 +101,7 @@ pub fn get_primary_monitor() -> MonitorID {
}
}
- fail!("Failed to find the primary monitor")
+ panic!("Failed to find the primary monitor")
}
impl MonitorID {
diff --git a/src/x11/ffi.rs b/src/x11/ffi.rs
index 39a6ae5..6fbfd81 100644
--- a/src/x11/ffi.rs
+++ b/src/x11/ffi.rs
@@ -8,12 +8,25 @@ use libc;
/// GLX bindings
pub mod glx {
- generate_gl_bindings!("glx", "core", "1.4", "static")
+ generate_gl_bindings! {
+ api: "glx",
+ profile: "core",
+ version: "1.4",
+ generator: "static"
+ }
}
/// Functions that are not necessarly always available
pub mod glx_extra {
- generate_gl_bindings!("glx", "core", "1.4", "struct", [ "GLX_ARB_create_context" ])
+ generate_gl_bindings! {
+ api: "glx",
+ profile: "core",
+ version: "1.4",
+ generator: "struct",
+ extensions: [
+ "GLX_ARB_create_context"
+ ]
+ }
}
pub type Atom = libc::c_ulong;
@@ -1325,6 +1338,23 @@ pub struct XButtonEvent {
}
#[repr(C)]
+pub struct XConfigureEvent {
+ pub type_: libc::c_int,
+ pub serial: libc::c_ulong,
+ pub send_event: Bool,
+ pub display: *mut Display,
+ pub event: Window,
+ pub window: Window,
+ pub x: libc::c_int,
+ pub y: libc::c_int,
+ pub width: libc::c_int,
+ pub height: libc::c_int,
+ pub border_width: libc::c_int,
+ pub above: Window,
+ pub override_redirect: Bool,
+}
+
+#[repr(C)]
pub struct XF86VidModeModeInfo {
pub dotclock: libc::c_uint,
pub hdisplay: libc::c_ushort,
@@ -1397,6 +1427,7 @@ extern "C" {
pub fn XMoveWindow(display: *mut Display, w: Window, x: libc::c_int, y: libc::c_int);
pub fn XMapWindow(display: *mut Display, w: Window);
pub fn XNextEvent(display: *mut Display, event_return: *mut XEvent);
+ pub fn XInitThreads() -> Status;
pub fn XOpenDisplay(display_name: *const libc::c_char) -> *mut Display;
pub fn XPeekEvent(display: *mut Display, event_return: *mut XEvent);
pub fn XRefreshKeyboardMapping(event_map: *const XEvent);
diff --git a/src/x11/window/events.rs b/src/x11/window/events.rs
index 4d74eed..bf91e6a 100644
--- a/src/x11/window/events.rs
+++ b/src/x11/window/events.rs
@@ -4,7 +4,7 @@ use VirtualKeyCode;
pub fn keycode_to_element(scancode: libc::c_uint) -> Option<VirtualKeyCode> {
Some(match scancode {
- //ffi::XK_BackSpace => events::Backspace,
+ ffi::XK_BackSpace => events::Back,
ffi::XK_Tab => events::Tab,
//ffi::XK_Linefeed => events::Linefeed,
//ffi::XK_Clear => events::Clear,
@@ -38,9 +38,9 @@ pub fn keycode_to_element(scancode: libc::c_uint) -> Option<VirtualKeyCode> {
ffi::XK_Right => events::Right,
ffi::XK_Down => events::Down,
//ffi::XK_Prior => events::Prior,
- //ffi::XK_Page_Up => events::Page_up,
+ ffi::XK_Page_Up => events::PageUp,
//ffi::XK_Next => events::Next,
- //ffi::XK_Page_Down => events::Page_down,
+ ffi::XK_Page_Down => events::PageDown,
//ffi::XK_End => events::End,
//ffi::XK_Begin => events::Begin,
//ffi::XK_Win_L => events::Win_l,
@@ -185,7 +185,7 @@ pub fn keycode_to_element(scancode: libc::c_uint) -> Option<VirtualKeyCode> {
//ffi::XK_asterisk => events::Asterisk,
//ffi::XK_plus => events::Plus,
//ffi::XK_comma => events::Comma,
- //ffi::XK_minus => events::Minus,
+ ffi::XK_minus => events::Minus,
//ffi::XK_period => events::Period,
//ffi::XK_slash => events::Slash,
//ffi::XK_0 => events::0,
@@ -201,7 +201,7 @@ pub fn keycode_to_element(scancode: libc::c_uint) -> Option<VirtualKeyCode> {
//ffi::XK_colon => events::Colon,
//ffi::XK_semicolon => events::Semicolon,
//ffi::XK_less => events::Less,
- //ffi::XK_equal => events::Equal,
+ ffi::XK_equal => events::Equals,
//ffi::XK_greater => events::Greater,
//ffi::XK_question => events::Question,
//ffi::XK_at => events::At,
@@ -999,4 +999,4 @@ pub fn keycode_to_element(scancode: libc::c_uint) -> Option<VirtualKeyCode> {
//ffi::XK_Hebrew_switch => events::Hebrew_switch,
_ => return None
})
-} \ No newline at end of file
+}
diff --git a/src/x11/window/mod.rs b/src/x11/window/mod.rs
index ad10e16..26d5497 100644
--- a/src/x11/window/mod.rs
+++ b/src/x11/window/mod.rs
@@ -1,14 +1,26 @@
-use {Event, WindowBuilder};
+use {Event, WindowBuilder, KeyModifiers};
use libc;
use std::{mem, ptr};
-use std::sync::atomics::AtomicBool;
+use std::cell::Cell;
+use std::sync::atomic::AtomicBool;
use super::ffi;
+use sync::one::{Once, ONCE_INIT};
pub use self::monitor::{MonitorID, get_available_monitors, get_primary_monitor};
mod events;
mod monitor;
+static THREAD_INIT: Once = ONCE_INIT;
+
+fn ensure_thread_init() {
+ THREAD_INIT.doit(|| {
+ unsafe {
+ ffi::XInitThreads();
+ }
+ });
+}
+
pub struct Window {
display: *mut ffi::Display,
window: ffi::Window,
@@ -20,10 +32,13 @@ pub struct Window {
xf86_desk_mode: *mut ffi::XF86VidModeModeInfo,
screen_id: libc::c_int,
is_fullscreen: bool,
+ current_modifiers: Cell<KeyModifiers>,
+ current_size: Cell<(libc::c_int, libc::c_int)>,
}
impl Window {
pub fn new(builder: WindowBuilder) -> Result<Window, String> {
+ ensure_thread_init();
let dimensions = builder.dimensions.unwrap_or((800, 600));
// calling XOpenDisplay
@@ -83,7 +98,7 @@ impl Window {
best_mode = i;
}
};
- if best_mode == -1 {
+ if best_mode == -1 && builder.monitor.is_some() {
return Err(format!("Could not find a suitable graphics mode"));
}
@@ -120,7 +135,7 @@ impl Window {
let mut set_win_attr = {
let mut swa: ffi::XSetWindowAttributes = unsafe { mem::zeroed() };
swa.colormap = cmap;
- swa.event_mask = ffi::ExposureMask | ffi::ResizeRedirectMask |
+ swa.event_mask = ffi::ExposureMask | ffi::StructureNotifyMask |
ffi::VisibilityChangeMask | ffi::KeyPressMask | ffi::PointerMotionMask |
ffi::KeyReleaseMask | ffi::ButtonPressMask |
ffi::ButtonReleaseMask | ffi::KeymapStateMask;
@@ -152,11 +167,12 @@ impl Window {
let wm_delete_window = unsafe {
use std::c_str::ToCStr;
+ let delete_window = "WM_DELETE_WINDOW".to_c_str();
ffi::XMapWindow(display, window);
- let mut wm_delete_window = ffi::XInternAtom(display,
- "WM_DELETE_WINDOW".to_c_str().as_ptr() as *const libc::c_char, 0);
+ let mut wm_delete_window = ffi::XInternAtom(display, delete_window.as_ptr(), 0);
ffi::XSetWMProtocols(display, window, &mut wm_delete_window, 1);
- ffi::XStoreName(display, window, mem::transmute(builder.title.as_slice().as_ptr()));
+ let c_title = builder.title.to_c_str();
+ ffi::XStoreName(display, window, c_title.as_ptr());
ffi::XFlush(display);
wm_delete_window
@@ -175,8 +191,10 @@ impl Window {
let ic = unsafe {
use std::c_str::ToCStr;
- let ic = ffi::XCreateIC(im, "inputStyle".to_c_str().as_ptr(),
- ffi::XIMPreeditNothing | ffi::XIMStatusNothing, "clientWindow".to_c_str().as_ptr(),
+ 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());
if ic.is_null() {
return Err(format!("XCreateIC failed"));
@@ -231,6 +249,9 @@ impl Window {
context
};
+ // Make context current before call to glViewport below.
+ unsafe { ffi::glx::MakeCurrent(display, window, context) };
+
// creating the window object
let window = Window {
display: display,
@@ -243,6 +264,8 @@ impl Window {
xf86_desk_mode: xf86_desk_mode,
screen_id: screen_id,
is_fullscreen: builder.monitor.is_some(),
+ current_modifiers: Cell::new(KeyModifiers::empty()),
+ current_size: Cell::new((0, 0)),
};
// calling glViewport
@@ -260,14 +283,15 @@ impl Window {
}
pub fn is_closed(&self) -> bool {
- use std::sync::atomics::Relaxed;
+ use std::sync::atomic::Relaxed;
self.is_closed.load(Relaxed)
}
pub fn set_title(&self, title: &str) {
+ let c_title = title.to_c_str();
unsafe {
- ffi::XStoreName(self.display, self.window,
- mem::transmute(title.as_slice().as_ptr()));
+ ffi::XStoreName(self.display, self.window, c_title.as_ptr());
+ ffi::XFlush(self.display);
}
}
@@ -340,7 +364,7 @@ impl Window {
ffi::ClientMessage => {
use Closed;
- use std::sync::atomics::Relaxed;
+ use std::sync::atomic::Relaxed;
let client_msg: &ffi::XClientMessageEvent = unsafe { mem::transmute(&xev) };
@@ -350,10 +374,14 @@ impl Window {
}
},
- ffi::ResizeRequest => {
+ ffi::ConfigureNotify => {
use Resized;
- let rs_event: &ffi::XResizeRequestEvent = unsafe { mem::transmute(&xev) };
- events.push(Resized(rs_event.width as uint, rs_event.height as uint));
+ let cfg_event: &ffi::XConfigureEvent = unsafe { mem::transmute(&xev) };
+ 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));
+ }
},
ffi::MotionNotify => {
@@ -363,7 +391,10 @@ impl Window {
},
ffi::KeyPress | ffi::KeyRelease => {
- use {KeyboardInput, Pressed, Released, ReceivedCharacter, KeyModifiers};
+ use {KeyboardInput, Pressed, Released, ReceivedCharacter};
+ use {LEFT_CONTROL_MODIFIER, RIGHT_CONTROL_MODIFIER};
+ use {LEFT_SHIFT_MODIFIER, RIGHT_SHIFT_MODIFIER};
+ use {LEFT_ALT_MODIFIER, RIGHT_ALT_MODIFIER, CAPS_LOCK_MODIFIER};
let event: &mut ffi::XKeyEvent = unsafe { mem::transmute(&xev) };
if event.type_ == ffi::KeyPress {
@@ -394,16 +425,38 @@ impl Window {
ffi::XKeycodeToKeysym(self.display, event.keycode as ffi::KeyCode, 0)
};
+ let modifier_flag = match keysym as u32 {
+ ffi::XK_Shift_L => Some(LEFT_SHIFT_MODIFIER),
+ ffi::XK_Shift_R => Some(RIGHT_SHIFT_MODIFIER),
+ ffi::XK_Control_L => Some(LEFT_CONTROL_MODIFIER),
+ ffi::XK_Control_R => Some(RIGHT_CONTROL_MODIFIER),
+ ffi::XK_Caps_Lock => Some(CAPS_LOCK_MODIFIER),
+ ffi::XK_Meta_L => Some(LEFT_ALT_MODIFIER),
+ ffi::XK_Meta_R => Some(RIGHT_ALT_MODIFIER),
+ _ => None,
+ };
+ match modifier_flag {
+ Some(flag) => {
+ let mut current_modifiers = self.current_modifiers.get();
+ match state {
+ Pressed => current_modifiers.insert(flag),
+ Released => current_modifiers.remove(flag),
+ }
+ self.current_modifiers.set(current_modifiers);
+ }
+ None => {}
+ }
+
let vkey = events::keycode_to_element(keysym as libc::c_uint);
events.push(KeyboardInput(state, event.keycode as u8,
- vkey, KeyModifiers::empty()));
+ vkey, self.current_modifiers.get()));
//
},
ffi::ButtonPress | ffi::ButtonRelease => {
- use {MouseInput, Pressed, Released};
- use {LeftMouseButton, RightMouseButton, MiddleMouseButton, OtherMouseButton};
+ use {MouseInput, MouseWheel, Pressed, Released};
+ use {LeftMouseButton, RightMouseButton, MiddleMouseButton};
let event: &ffi::XButtonEvent = unsafe { mem::transmute(&xev) };
let state = if xev.type_ == ffi::ButtonPress { Pressed } else { Released };
@@ -412,8 +465,14 @@ impl Window {
ffi::Button1 => Some(LeftMouseButton),
ffi::Button2 => Some(MiddleMouseButton),
ffi::Button3 => Some(RightMouseButton),
- ffi::Button4 => Some(OtherMouseButton(4)),
- ffi::Button5 => Some(OtherMouseButton(5)),
+ ffi::Button4 => {
+ events.push(MouseWheel(1));
+ None
+ }
+ ffi::Button5 => {
+ events.push(MouseWheel(-1));
+ None
+ }
_ => None
};
@@ -451,7 +510,7 @@ impl Window {
pub unsafe fn make_current(&self) {
let res = ffi::glx::MakeCurrent(self.display, self.window, self.context);
if res == 0 {
- fail!("glx::MakeCurrent failed");
+ panic!("glx::MakeCurrent failed");
}
}
@@ -469,6 +528,10 @@ impl Window {
pub fn swap_buffers(&self) {
unsafe { ffi::glx::SwapBuffers(self.display, self.window) }
}
+
+ pub fn platform_display(&self) -> *mut libc::c_void {
+ self.display as *mut libc::c_void
+ }
}
impl Drop for Window {
diff --git a/src/x11/window/monitor.rs b/src/x11/window/monitor.rs
index b72ed15..f62a8ef 100644
--- a/src/x11/window/monitor.rs
+++ b/src/x11/window/monitor.rs
@@ -1,13 +1,15 @@
use std::{ptr};
use super::super::ffi;
+use super::ensure_thread_init;
pub struct MonitorID(pub uint);
pub fn get_available_monitors() -> Vec<MonitorID> {
+ ensure_thread_init();
let nb_monitors = unsafe {
let display = ffi::XOpenDisplay(ptr::null());
if display.is_null() {
- fail!("get_available_monitors failed");
+ panic!("get_available_monitors failed");
}
let nb_monitors = ffi::XScreenCount(display);
ffi::XCloseDisplay(display);
@@ -20,10 +22,11 @@ pub fn get_available_monitors() -> Vec<MonitorID> {
}
pub fn get_primary_monitor() -> MonitorID {
+ ensure_thread_init();
let primary_monitor = unsafe {
let display = ffi::XOpenDisplay(ptr::null());
if display.is_null() {
- fail!("get_available_monitors failed");
+ panic!("get_available_monitors failed");
}
let primary_monitor = ffi::XDefaultScreen(display);
ffi::XCloseDisplay(display);
@@ -46,6 +49,7 @@ impl MonitorID {
let screen = ffi::XScreenOfDisplay(display, screen_num as i32);
let width = ffi::XWidthOfScreen(screen);
let height = ffi::XHeightOfScreen(screen);
+ ffi::XCloseDisplay(display);
(width as uint, height as uint)
};
diff --git a/tests/headless.rs b/tests/headless.rs
index ffc74b3..3c587ea 100644
--- a/tests/headless.rs
+++ b/tests/headless.rs
@@ -7,7 +7,12 @@ extern crate glutin;
extern crate libc;
mod gl {
- generate_gl_bindings!("gl", "core", "1.1", "struct")
+ generate_gl_bindings! {
+ api: "gl",
+ profile: "core",
+ version: "1.1",
+ generator: "struct"
+ }
}
#[cfg(feature = "headless")]
@@ -25,5 +30,6 @@ fn main() {
let mut value: (u8, u8, u8, u8) = unsafe { std::mem::uninitialized() };
unsafe { gl.ReadPixels(0, 0, 1, 1, gl::RGBA, gl::UNSIGNED_BYTE, std::mem::transmute(&mut value)) };
- assert_eq!(value, (0, 255, 0, 255));
+ assert!(value == (0, 255, 0, 255) || value == (0, 64, 0, 255) ||
+ value == (0, 64, 0, 255) || value == (0, 64, 0, 0));
}