aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Cargo.toml24
-rw-r--r--README.md12
-rw-r--r--build.rs14
-rw-r--r--examples/cursor.rs35
-rw-r--r--examples/fullscreen.rs10
-rw-r--r--examples/grabbing.rs48
-rw-r--r--examples/multiwindow.rs13
-rw-r--r--examples/transparent.rs13
-rw-r--r--examples/vsync.rs46
-rw-r--r--examples/window.rs11
-rw-r--r--src/api/android/mod.rs5
-rw-r--r--src/api/caca/mod.rs11
-rw-r--r--src/api/cocoa/headless.rs8
-rw-r--r--src/api/cocoa/mod.rs56
-rw-r--r--src/api/egl/mod.rs120
-rw-r--r--src/api/emscripten/mod.rs16
-rw-r--r--src/api/glx/mod.rs101
-rw-r--r--src/api/osmesa/mod.rs26
-rw-r--r--src/api/wayland/context.rs34
-rw-r--r--src/api/wayland/mod.rs15
-rw-r--r--src/api/wgl/mod.rs69
-rw-r--r--src/api/win32/callback.rs5
-rw-r--r--src/api/win32/init.rs1
-rw-r--r--src/api/win32/mod.rs38
-rw-r--r--src/api/x11/window.rs103
-rw-r--r--src/events.rs24
-rw-r--r--src/headless.rs14
-rw-r--r--src/lib.rs65
-rw-r--r--src/platform/android/mod.rs4
-rw-r--r--src/platform/emscripten/mod.rs5
-rw-r--r--src/platform/linux/api_dispatch.rs12
-rw-r--r--src/platform/linux/mod.rs5
-rw-r--r--src/platform/windows/mod.rs5
-rw-r--r--src/window.rs22
34 files changed, 647 insertions, 343 deletions
diff --git a/Cargo.toml b/Cargo.toml
index edec13a..18e7e0a 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "glutin"
-version = "0.1.6"
+version = "0.2.2"
authors = ["tomaka <pierre.krieger1708@gmail.com>"]
description = "Cross-plaform OpenGL context provider."
keywords = ["windowing", "opengl"]
@@ -22,7 +22,7 @@ shared_library = "0.1.0"
[build-dependencies]
gl_generator = "0.0.26"
-khronos_api = "0.0.5"
+khronos_api = "0.0.6"
[dev-dependencies]
clock_ticks = "0.0.5"
@@ -44,6 +44,7 @@ objc = "0.1"
[target.x86_64-apple-darwin.dependencies]
objc = "0.1"
+cgl = "0"
cocoa = "0"
core-foundation = "0"
core-graphics = "0"
@@ -62,20 +63,27 @@ user32-sys = "~0.1.1"
kernel32-sys = "0.1"
dwmapi-sys = "0.1"
+[target.x86_64-pc-windows-msvc.dependencies]
+winapi = "~0.1.18"
+gdi32-sys = "0.1"
+user32-sys = "~0.1.1"
+kernel32-sys = "0.1"
+dwmapi-sys = "0.1"
+
[target.i686-unknown-linux-gnu.dependencies]
osmesa-sys = "0.0.5"
-wayland-client = "0.1.6"
-wayland-kbd = "0.1.1"
+wayland-client = { version = "0.2.0", features = ["egl", "dlopen"] }
+wayland-kbd = "0.2.0"
x11-dl = "=1.0.1"
[target.x86_64-unknown-linux-gnu.dependencies]
osmesa-sys = "0.0.5"
-wayland-client = "0.1.6"
-wayland-kbd = "0.1.1"
+wayland-client = { version = "0.2.0", features = ["egl", "dlopen"] }
+wayland-kbd = "0.2.0"
x11-dl = "=1.0.1"
[target.arm-unknown-linux-gnueabihf.dependencies]
osmesa-sys = "0.0.5"
-wayland-client = "0.1.6"
-wayland-kbd = "0.1.1"
+wayland-client = { version = "0.2.0", features = ["egl", "dlopen"] }
+wayland-kbd = "0.2.0"
x11-dl = "=1.0.1"
diff --git a/README.md b/README.md
index 935e110..9ca5757 100644
--- a/README.md
+++ b/README.md
@@ -34,9 +34,9 @@ libc = "*"
```
```rust
+extern crate gl;
extern crate glutin;
extern crate libc;
-extern crate gl;
fn main() {
let window = glutin::Window::new().unwrap();
@@ -49,12 +49,14 @@ fn main() {
gl::ClearColor(0.0, 1.0, 0.0, 1.0);
}
- while !window.is_closed() {
- window.wait_events();
-
+ for event in window.wait_events() {
unsafe { gl::Clear(gl::COLOR_BUFFER_BIT) };
-
window.swap_buffers();
+
+ match event {
+ glutin::Event::Closed => break,
+ _ => ()
+ }
}
}
```
diff --git a/build.rs b/build.rs
index c713351..c73f687 100644
--- a/build.rs
+++ b/build.rs
@@ -25,6 +25,7 @@ fn main() {
vec![
"WGL_ARB_create_context".to_string(),
"WGL_ARB_create_context_profile".to_string(),
+ "WGL_ARB_create_context_robustness".to_string(),
"WGL_ARB_extensions_string".to_string(),
"WGL_ARB_framebuffer_sRGB".to_string(),
"WGL_ARB_multisample".to_string(),
@@ -42,7 +43,9 @@ fn main() {
gl_generator::Fallbacks::All,
khronos_api::EGL_XML,
vec![
- "EGL_KHR_create_context".to_string()
+ "EGL_KHR_create_context".to_string(),
+ "EGL_EXT_create_context_robustness".to_string(),
+ "EGL_KHR_create_context_no_error".to_string(),
],
"1.5", "core", &mut file).unwrap();
}
@@ -63,6 +66,7 @@ fn main() {
vec![
"GLX_ARB_create_context".to_string(),
"GLX_ARB_create_context_profile".to_string(),
+ "GLX_ARB_create_context_robustness".to_string(),
"GLX_ARB_framebuffer_sRGB".to_string(),
"GLX_EXT_framebuffer_sRGB".to_string(),
"GLX_EXT_swap_control".to_string(),
@@ -76,7 +80,9 @@ fn main() {
gl_generator::Fallbacks::All,
khronos_api::EGL_XML,
vec![
- "EGL_KHR_create_context".to_string()
+ "EGL_KHR_create_context".to_string(),
+ "EGL_EXT_create_context_robustness".to_string(),
+ "EGL_KHR_create_context_no_error".to_string(),
],
"1.5", "core", &mut file).unwrap();
}
@@ -88,7 +94,9 @@ fn main() {
gl_generator::Fallbacks::All,
khronos_api::EGL_XML,
vec![
- "EGL_KHR_create_context".to_string()
+ "EGL_KHR_create_context".to_string(),
+ "EGL_EXT_create_context_robustness".to_string(),
+ "EGL_KHR_create_context_no_error".to_string(),
],
"1.5", "core", &mut file).unwrap();
}
diff --git a/examples/cursor.rs b/examples/cursor.rs
index 0dced66..d15deff 100644
--- a/examples/cursor.rs
+++ b/examples/cursor.rs
@@ -17,7 +17,7 @@ fn main() { println!("This example requires glutin to be compiled with the `wind
#[cfg(feature = "window")]
fn main() {
- let mut window = glutin::Window::new().unwrap();
+ let window = glutin::WindowBuilder::new().with_gl_profile(glutin::GlProfile::Compatibility).build().unwrap();
window.set_title("A fantastic window!");
unsafe { window.make_current() };
@@ -25,25 +25,22 @@ fn main() {
let cursors = [MouseCursor::Default, MouseCursor::Crosshair, MouseCursor::Hand, MouseCursor::Arrow, MouseCursor::Move, MouseCursor::Text, MouseCursor::Wait, MouseCursor::Help, MouseCursor::Progress, MouseCursor::NotAllowed, MouseCursor::ContextMenu, MouseCursor::NoneCursor, MouseCursor::Cell, MouseCursor::VerticalText, MouseCursor::Alias, MouseCursor::Copy, MouseCursor::NoDrop, MouseCursor::Grab, MouseCursor::Grabbing, MouseCursor::AllScroll, MouseCursor::ZoomIn, MouseCursor::ZoomOut, MouseCursor::EResize, MouseCursor::NResize, MouseCursor::NeResize, MouseCursor::NwResize, MouseCursor::SResize, MouseCursor::SeResize, MouseCursor::SwResize, MouseCursor::WResize, MouseCursor::EwResize, MouseCursor::NsResize, MouseCursor::NeswResize, MouseCursor::NwseResize, MouseCursor::ColResize, MouseCursor::RowResize];
let mut cursor_idx = 0;
- while !window.is_closed() {
+ for event in window.wait_events() {
+ match event {
+ Event::KeyboardInput(ElementState::Pressed, _, _) => {
+ println!("Setting cursor to \"{:?}\"", cursors[cursor_idx]);
+ window.set_cursor(cursors[cursor_idx]);
+ if cursor_idx < cursors.len() - 1 {
+ cursor_idx += 1;
+ } else {
+ cursor_idx = 0;
+ }
+ },
+ Event::Closed => break,
+ _ => (),
+ }
+
context.draw_frame((0.0, 1.0, 0.0, 1.0));
window.swap_buffers();
-
- for event in window.wait_events() {
- match event {
- Event::KeyboardInput(ElementState::Pressed, _, _) => {
- println!("Setting cursor to \"{:?}\"", cursors[cursor_idx]);
- window.set_cursor(cursors[cursor_idx]);
- if cursor_idx < cursors.len() - 1 {
- cursor_idx += 1;
- } else {
- cursor_idx = 0;
- }
- },
- _ => (),
- }
-
- }
-
}
}
diff --git a/examples/fullscreen.rs b/examples/fullscreen.rs
index d64224b..707fd7d 100644
--- a/examples/fullscreen.rs
+++ b/examples/fullscreen.rs
@@ -35,6 +35,7 @@ fn main() {
};
let window = glutin::WindowBuilder::new()
+ .with_gl_profile(glutin::GlProfile::Compatibility)
.with_title("Hello world!".to_string())
.with_fullscreen(monitor)
.build()
@@ -45,10 +46,15 @@ fn main() {
let context = support::load(&window);
- while !window.is_closed() {
+ for event in window.wait_events() {
context.draw_frame((0.0, 1.0, 0.0, 1.0));
window.swap_buffers();
- println!("{:?}", window.wait_events().next());
+ println!("{:?}", event);
+
+ match event {
+ glutin::Event::Closed => break,
+ _ => ()
+ }
}
}
diff --git a/examples/grabbing.rs b/examples/grabbing.rs
index 8a46750..a0a8fda 100644
--- a/examples/grabbing.rs
+++ b/examples/grabbing.rs
@@ -16,40 +16,36 @@ fn main() { println!("This example requires glutin to be compiled with the `wind
#[cfg(feature = "window")]
fn main() {
- let window = glutin::Window::new().unwrap();
+ let window = glutin::WindowBuilder::new().with_gl_profile(glutin::GlProfile::Compatibility).build().unwrap();
window.set_title("glutin - Cursor grabbing test");
unsafe { window.make_current() };
let context = support::load(&window);
let mut grabbed = false;
- while !window.is_closed() {
+ for event in window.poll_events() {
+ match event {
+ Event::KeyboardInput(ElementState::Pressed, _, _) => {
+ if grabbed {
+ grabbed = false;
+ window.set_cursor_state(glutin::CursorState::Normal)
+ .ok().expect("could not ungrab mouse cursor");
+ } else {
+ grabbed = true;
+ window.set_cursor_state(glutin::CursorState::Grab)
+ .ok().expect("could not grab mouse cursor");
+ }
+ },
+
+ a @ Event::MouseMoved(_) => {
+ println!("{:?}", a);
+ },
+
+ _ => (),
+ }
+
context.draw_frame((0.0, 1.0, 0.0, 1.0));
window.swap_buffers();
-
- for event in window.poll_events() {
- match event {
- Event::KeyboardInput(ElementState::Pressed, _, _) => {
- if grabbed {
- grabbed = false;
- window.set_cursor_state(glutin::CursorState::Normal)
- .ok().expect("could not ungrab mouse cursor");
- } else {
- grabbed = true;
- window.set_cursor_state(glutin::CursorState::Grab)
- .ok().expect("could not grab mouse cursor");
- }
- },
-
- a @ Event::MouseMoved(_) => {
- println!("{:?}", a);
- },
-
- _ => (),
- }
-
- }
-
}
}
diff --git a/examples/multiwindow.rs b/examples/multiwindow.rs
index a9a5bac..074fe14 100644
--- a/examples/multiwindow.rs
+++ b/examples/multiwindow.rs
@@ -16,9 +16,9 @@ fn main() { println!("This example requires glutin to be compiled with the `wind
#[cfg(feature = "window")]
fn main() {
- let window1 = glutin::Window::new().unwrap();
- let window2 = glutin::Window::new().unwrap();
- let window3 = glutin::Window::new().unwrap();
+ let window1 = glutin::WindowBuilder::new().with_gl_profile(glutin::GlProfile::Compatibility).build().unwrap();
+ let window2 = glutin::WindowBuilder::new().with_gl_profile(glutin::GlProfile::Compatibility).build().unwrap();
+ let window3 = glutin::WindowBuilder::new().with_gl_profile(glutin::GlProfile::Compatibility).build().unwrap();
let t1 = thread::spawn(move || {
run(window1, (0.0, 1.0, 0.0, 1.0));
@@ -43,10 +43,13 @@ fn run(window: glutin::Window, color: (f32, f32, f32, f32)) {
let context = support::load(&window);
- while !window.is_closed() {
+ for event in window.wait_events() {
context.draw_frame(color);
window.swap_buffers();
- window.wait_events().next();
+ match event {
+ glutin::Event::Closed => break,
+ _ => ()
+ }
}
}
diff --git a/examples/transparent.rs b/examples/transparent.rs
index 553c16d..fa6a8de 100644
--- a/examples/transparent.rs
+++ b/examples/transparent.rs
@@ -19,7 +19,9 @@ fn resize_callback(width: u32, height: u32) {
#[cfg(feature = "window")]
fn main() {
- let mut window = glutin::WindowBuilder::new().with_decorations(false).with_transparency(true)
+ let mut window = glutin::WindowBuilder::new().with_gl_profile(glutin::GlProfile::Compatibility)
+ .with_decorations(false)
+ .with_transparency(true)
.build().unwrap();
window.set_title("A fantastic window!");
window.set_window_resize_callback(Some(resize_callback as fn(u32, u32)));
@@ -29,10 +31,15 @@ fn main() {
let context = support::load(&window);
- while !window.is_closed() {
+ for event in window.wait_events() {
context.draw_frame((0.0, 0.0, 0.0, 0.0));
window.swap_buffers();
- println!("{:?}", window.wait_events().next());
+ println!("{:?}", event);
+
+ match event {
+ glutin::Event::Closed => break,
+ _ => ()
+ }
}
}
diff --git a/examples/vsync.rs b/examples/vsync.rs
deleted file mode 100644
index ec9ea79..0000000
--- a/examples/vsync.rs
+++ /dev/null
@@ -1,46 +0,0 @@
-#[cfg(target_os = "android")]
-#[macro_use]
-extern crate android_glue;
-
-extern crate clock_ticks;
-extern crate glutin;
-
-mod support;
-
-#[cfg(target_os = "android")]
-android_start!(main);
-
-#[cfg(not(feature = "window"))]
-fn main() { println!("This example requires glutin to be compiled with the `window` feature"); }
-
-#[cfg(feature = "window")]
-fn resize_callback(width: u32, height: u32) {
- println!("Window resized to {}x{}", width, height);
-}
-
-#[cfg(feature = "window")]
-fn main() {
- println!("Vsync example. This example may panic if your driver or your system forces \
- you out of vsync. This is intended when `build_strict` is used.");
-
- let mut window = glutin::WindowBuilder::new().with_vsync().build_strict().unwrap();
- window.set_window_resize_callback(Some(resize_callback as fn(u32, u32)));
- unsafe { window.make_current() };
-
- let context = support::load(&window);
-
- while !window.is_closed() {
- let before = clock_ticks::precise_time_ns();
-
- context.draw_frame((0.0, 1.0, 0.0, 1.0));
- window.swap_buffers();
-
- for ev in window.poll_events() {
- println!("{:?}", ev);
- }
-
- let after = clock_ticks::precise_time_ns();
- println!("Vsync example - Time of previous frame: {}ms",
- (after - before) as f32 / 1000000.0);
- }
-}
diff --git a/examples/window.rs b/examples/window.rs
index 4077399..f686a51 100644
--- a/examples/window.rs
+++ b/examples/window.rs
@@ -19,7 +19,7 @@ fn resize_callback(width: u32, height: u32) {
#[cfg(feature = "window")]
fn main() {
- let mut window = glutin::Window::new().unwrap();
+ let mut window = glutin::WindowBuilder::new().with_gl_profile(glutin::GlProfile::Compatibility).build().unwrap();
window.set_title("A fantastic window!");
window.set_window_resize_callback(Some(resize_callback as fn(u32, u32)));
unsafe { window.make_current() };
@@ -28,10 +28,15 @@ fn main() {
let context = support::load(&window);
- while !window.is_closed() {
+ for event in window.wait_events() {
context.draw_frame((0.0, 1.0, 0.0, 1.0));
window.swap_buffers();
- println!("{:?}", window.wait_events().next());
+ println!("{:?}", event);
+
+ match event {
+ glutin::Event::Closed => break,
+ _ => ()
+ }
}
}
diff --git a/src/api/android/mod.rs b/src/api/android/mod.rs
index d1281e3..1649772 100644
--- a/src/api/android/mod.rs
+++ b/src/api/android/mod.rs
@@ -15,6 +15,7 @@ use std::collections::VecDeque;
use Api;
use BuilderAttribs;
+use ContextError;
use CursorState;
use GlContext;
use GlRequest;
@@ -213,7 +214,7 @@ unsafe impl Send for Window {}
unsafe impl Sync for Window {}
impl GlContext for Window {
- unsafe fn make_current(&self) {
+ unsafe fn make_current(&self) -> Result<(), ContextError> {
self.context.make_current()
}
@@ -225,7 +226,7 @@ impl GlContext for Window {
self.context.get_proc_address(addr)
}
- fn swap_buffers(&self) {
+ fn swap_buffers(&self) -> Result<(), ContextError> {
self.context.swap_buffers()
}
diff --git a/src/api/caca/mod.rs b/src/api/caca/mod.rs
index 06a6931..3b4018e 100644
--- a/src/api/caca/mod.rs
+++ b/src/api/caca/mod.rs
@@ -6,6 +6,7 @@ use api::osmesa::{OsMesaContext, OsMesaCreationError};
use Api;
use BuilderAttribs;
+use ContextError;
use CreationError;
use Event;
use GlContext;
@@ -129,10 +130,6 @@ impl Window {
})
}
- pub fn is_closed(&self) -> bool {
- false
- }
-
pub fn set_title(&self, title: &str) {
}
@@ -209,7 +206,7 @@ impl Window {
}
impl GlContext for Window {
- unsafe fn make_current(&self) {
+ unsafe fn make_current(&self) -> Result<(), ContextError> {
self.opengl.make_current()
}
@@ -221,7 +218,7 @@ impl GlContext for Window {
self.opengl.get_proc_address(addr)
}
- fn swap_buffers(&self) {
+ fn swap_buffers(&self) -> Result<(), ContextError> {
unsafe {
let canvas = (self.libcaca.caca_get_canvas)(self.display);
let width = (self.libcaca.caca_get_canvas_width)(canvas);
@@ -235,6 +232,8 @@ impl GlContext for Window {
buffer.as_ptr() as *const _);
(self.libcaca.caca_refresh_display)(self.display);
};
+
+ Ok(())
}
fn get_api(&self) -> Api {
diff --git a/src/api/cocoa/headless.rs b/src/api/cocoa/headless.rs
index 75cca8d..7cd0f88 100644
--- a/src/api/cocoa/headless.rs
+++ b/src/api/cocoa/headless.rs
@@ -1,3 +1,4 @@
+use ContextError;
use CreationError;
use CreationError::OsError;
use BuilderAttribs;
@@ -61,7 +62,7 @@ impl HeadlessContext {
}
impl GlContext for HeadlessContext {
- unsafe fn make_current(&self) {
+ unsafe fn make_current(&self) -> Result<(), ContextError> {
self.context.makeCurrentContext();
gl::GenFramebuffersEXT(1, &mut framebuffer);
@@ -78,6 +79,8 @@ impl GlContext for HeadlessContext {
if status != gl::FRAMEBUFFER_COMPLETE_EXT {
panic!("Error while creating the framebuffer");
}
+
+ Ok(())
}
fn is_current(&self) -> bool {
@@ -96,7 +99,8 @@ impl GlContext for HeadlessContext {
symbol as *const libc::c_void
}
- fn swap_buffers(&self) {
+ fn swap_buffers(&self) -> Result<(), ContextError> {
+ Ok(())
}
fn get_api(&self) -> ::Api {
diff --git a/src/api/cocoa/mod.rs b/src/api/cocoa/mod.rs
index 511148b..332244e 100644
--- a/src/api/cocoa/mod.rs
+++ b/src/api/cocoa/mod.rs
@@ -8,15 +8,21 @@ use libc;
use Api;
use BuilderAttribs;
+use ContextError;
use GlContext;
use GlProfile;
use GlRequest;
use PixelFormat;
+use Robustness;
use native_monitor::NativeMonitorId;
use objc::runtime::{Class, Object, Sel, BOOL, YES, NO};
use objc::declare::ClassDecl;
+use cgl;
+use cgl::{CGLEnable, kCGLCECrashOnRemovedFunctions, CGLSetParameter, kCGLCPSurfaceOpacity};
+use cgl::CGLContextObj as CGL_CGLContextObj;
+
use cocoa::base::{id, nil};
use cocoa::foundation::{NSAutoreleasePool, NSDate, NSDefaultRunLoopMode, NSPoint, NSRect, NSSize,
NSString, NSUInteger};
@@ -55,7 +61,6 @@ static mut win_pressed: bool = false;
static mut alt_pressed: bool = false;
struct DelegateState {
- is_closed: bool,
context: IdRef,
view: IdRef,
window: IdRef,
@@ -79,8 +84,6 @@ impl WindowDelegate {
unsafe {
let state: *mut libc::c_void = *this.get_ivar("glutinState");
let state = state as *mut DelegateState;
- (*state).is_closed = true;
-
(*state).pending_events.lock().unwrap().push_back(Closed);
}
YES
@@ -275,7 +278,15 @@ impl<'a> Iterator for PollEventsIterator<'a> {
self.window.delegate.state.pending_events.lock().unwrap().extend(events.into_iter());
event
},
- NSScrollWheel => { Some(MouseWheel(event.scrollingDeltaX() as f64, event.scrollingDeltaY() as f64)) },
+ NSScrollWheel => {
+ use events::MouseScrollDelta::{LineDelta, PixelDelta};
+ let delta = if event.hasPreciseScrollingDeltas() == YES {
+ PixelDelta(event.scrollingDeltaX() as f32, event.scrollingDeltaY() as f32)
+ } else {
+ LineDelta(event.scrollingDeltaX() as f32, event.scrollingDeltaY() as f32)
+ };
+ Some(MouseWheel(delta))
+ },
_ => { None },
};
@@ -322,6 +333,13 @@ impl Window {
unimplemented!()
}
+ match builder.gl_robustness {
+ Robustness::RobustNoResetNotification | Robustness::RobustLoseContextOnReset => {
+ return Err(CreationError::NotSupported);
+ },
+ _ => ()
+ }
+
let app = match Window::create_app() {
Some(app) => app,
None => { return Err(OsError(format!("Couldn't create NSApplication"))); },
@@ -345,6 +363,21 @@ impl Window {
};
unsafe {
+ if builder.transparent {
+ let clear_col = {
+ let cls = Class::get("NSColor").unwrap();
+
+ msg_send![cls, clearColor]
+ };
+ window.setOpaque_(NO);
+ window.setBackgroundColor_(clear_col);
+
+ let obj = context.CGLContextObj();
+
+ let mut opacity = 0;
+ CGLSetParameter(obj, kCGLCPSurfaceOpacity, &mut opacity);
+ }
+
app.activateIgnoringOtherApps_(YES);
if builder.visible {
window.makeKeyAndOrderFront_(nil);
@@ -354,7 +387,6 @@ impl Window {
}
let ds = DelegateState {
- is_closed: false,
context: context.clone(),
view: view.clone(),
window: window.clone(),
@@ -425,7 +457,7 @@ impl Window {
}
};
- let masks = if screen.is_some() {
+ let masks = if screen.is_some() || !builder.decorations {
NSBorderlessWindowMask as NSUInteger
} else {
NSTitledWindowMask as NSUInteger |
@@ -564,6 +596,8 @@ impl Window {
let value = if builder.vsync { 1 } else { 0 };
cxt.setValues_forParameter_(&value, NSOpenGLContextParameter::NSOpenGLCPSwapInterval);
+ CGLEnable(cxt.CGLContextObj(), kCGLCECrashOnRemovedFunctions);
+
Ok((cxt, pf))
} else {
Err(CreationError::NotSupported)
@@ -574,10 +608,6 @@ impl Window {
}
}
- pub fn is_closed(&self) -> bool {
- self.delegate.state.is_closed
- }
-
pub fn set_title(&self, title: &str) {
unsafe {
let title = IdRef::new(NSString::alloc(nil).init_str(title));
@@ -752,9 +782,10 @@ impl Window {
}
impl GlContext for Window {
- unsafe fn make_current(&self) {
+ unsafe fn make_current(&self) -> Result<(), ContextError> {
let _: () = msg_send![*self.context, update];
self.context.makeCurrentContext();
+ Ok(())
}
fn is_current(&self) -> bool {
@@ -781,8 +812,9 @@ impl GlContext for Window {
symbol as *const _
}
- fn swap_buffers(&self) {
+ fn swap_buffers(&self) -> Result<(), ContextError> {
unsafe { self.context.flushBuffer(); }
+ Ok(())
}
fn get_api(&self) -> ::Api {
diff --git a/src/api/egl/mod.rs b/src/api/egl/mod.rs
index 3335de0..1a6cc06 100644
--- a/src/api/egl/mod.rs
+++ b/src/api/egl/mod.rs
@@ -2,10 +2,12 @@
#![allow(unused_variables)]
use BuilderAttribs;
+use ContextError;
use CreationError;
use GlContext;
use GlRequest;
use PixelFormat;
+use Robustness;
use Api;
use libc;
@@ -115,15 +117,16 @@ impl Context {
let context = unsafe {
if let Some(version) = version {
try!(create_context(&egl, display, &egl_version, api, version, config_id,
- builder.gl_debug).map_err(|_| CreationError::NotSupported))
+ builder.gl_debug, builder.gl_robustness))
} else if api == Api::OpenGlEs {
if let Ok(ctxt) = create_context(&egl, display, &egl_version, api, (2, 0),
- config_id, builder.gl_debug)
+ config_id, builder.gl_debug, builder.gl_robustness)
{
ctxt
} else if let Ok(ctxt) = create_context(&egl, display, &egl_version, api, (1, 0),
- config_id, builder.gl_debug)
+ config_id, builder.gl_debug,
+ builder.gl_robustness)
{
ctxt
} else {
@@ -132,15 +135,17 @@ impl Context {
} else {
if let Ok(ctxt) = create_context(&egl, display, &egl_version, api, (3, 2),
- config_id, builder.gl_debug)
+ config_id, builder.gl_debug, builder.gl_robustness)
{
ctxt
} else if let Ok(ctxt) = create_context(&egl, display, &egl_version, api, (3, 1),
- config_id, builder.gl_debug)
+ config_id, builder.gl_debug,
+ builder.gl_robustness)
{
ctxt
} else if let Ok(ctxt) = create_context(&egl, display, &egl_version, api, (1, 0),
- config_id, builder.gl_debug)
+ config_id, builder.gl_debug,
+ builder.gl_robustness)
{
ctxt
} else {
@@ -161,11 +166,18 @@ impl Context {
}
impl GlContext for Context {
- unsafe fn make_current(&self) {
+ unsafe fn make_current(&self) -> Result<(), ContextError> {
let ret = self.egl.MakeCurrent(self.display, self.surface, self.surface, self.context);
if ret == 0 {
- panic!("eglMakeCurrent failed");
+ if self.egl.GetError() as u32 == ffi::egl::CONTEXT_LOST {
+ return Err(ContextError::ContextLost);
+ } else {
+ panic!("eglMakeCurrent failed");
+ }
+
+ } else {
+ Ok(())
}
}
@@ -181,13 +193,20 @@ impl GlContext for Context {
}
}
- fn swap_buffers(&self) {
+ fn swap_buffers(&self) -> Result<(), ContextError> {
let ret = unsafe {
self.egl.SwapBuffers(self.display, self.surface)
};
if ret == 0 {
- panic!("eglSwapBuffers failed");
+ if unsafe { self.egl.GetError() } as u32 == ffi::egl::CONTEXT_LOST {
+ return Err(ContextError::ContextLost);
+ } else {
+ panic!("eglSwapBuffers failed");
+ }
+
+ } else {
+ Ok(())
}
}
@@ -320,8 +339,8 @@ unsafe fn enumerate_configs(egl: &ffi::egl::Egl, display: ffi::egl::types::EGLDi
unsafe fn create_context(egl: &ffi::egl::Egl, display: ffi::egl::types::EGLDisplay,
egl_version: &(ffi::egl::types::EGLint, ffi::egl::types::EGLint),
api: Api, version: (u8, u8), config_id: ffi::egl::types::EGLConfig,
- gl_debug: bool)
- -> Result<ffi::egl::types::EGLContext, ()>
+ gl_debug: bool, gl_robustness: Robustness)
+ -> Result<ffi::egl::types::EGLContext, CreationError>
{
let extensions = if egl_version >= &(1, 2) {
let p = CStr::from_ptr(egl.QueryString(display, ffi::egl::EXTENSIONS as i32));
@@ -330,7 +349,8 @@ unsafe fn create_context(egl: &ffi::egl::Egl, display: ffi::egl::types::EGLDispl
format!("")
};
- let mut context_attributes = vec![];
+ let mut context_attributes = Vec::with_capacity(10);
+ let mut flags = 0;
if egl_version >= &(1, 5) ||
extensions.contains("EGL_KHR_create_context ") ||
@@ -341,17 +361,85 @@ unsafe fn create_context(egl: &ffi::egl::Egl, display: ffi::egl::types::EGLDispl
context_attributes.push(ffi::egl::CONTEXT_MINOR_VERSION as i32);
context_attributes.push(version.1 as i32);
+ // handling robustness
+ let supports_robustness = egl_version >= &(1, 5) ||
+ extensions.contains("EGL_EXT_create_context_robustness ") ||
+ extensions.ends_with("EGL_EXT_create_context_robustness");
+
+ match gl_robustness {
+ Robustness::NotRobust => (),
+
+ Robustness::NoError => {
+ if extensions.contains("EGL_KHR_create_context_no_error ") ||
+ extensions.ends_with("EGL_KHR_create_context_no_error")
+ {
+ context_attributes.push(ffi::egl::CONTEXT_OPENGL_NO_ERROR_KHR as libc::c_int);
+ context_attributes.push(1);
+ }
+ },
+
+ Robustness::RobustNoResetNotification => {
+ if supports_robustness {
+ context_attributes.push(ffi::egl::CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY
+ as libc::c_int);
+ context_attributes.push(ffi::egl::NO_RESET_NOTIFICATION as libc::c_int);
+ flags = flags | ffi::egl::CONTEXT_OPENGL_ROBUST_ACCESS as libc::c_int;
+ } else {
+ return Err(CreationError::NotSupported);
+ }
+ },
+
+ Robustness::TryRobustNoResetNotification => {
+ if supports_robustness {
+ context_attributes.push(ffi::egl::CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY
+ as libc::c_int);
+ context_attributes.push(ffi::egl::NO_RESET_NOTIFICATION as libc::c_int);
+ flags = flags | ffi::egl::CONTEXT_OPENGL_ROBUST_ACCESS as libc::c_int;
+ }
+ },
+
+ Robustness::RobustLoseContextOnReset => {
+ if supports_robustness {
+ context_attributes.push(ffi::egl::CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY
+ as libc::c_int);
+ context_attributes.push(ffi::egl::LOSE_CONTEXT_ON_RESET as libc::c_int);
+ flags = flags | ffi::egl::CONTEXT_OPENGL_ROBUST_ACCESS as libc::c_int;
+ } else {
+ return Err(CreationError::NotSupported);
+ }
+ },
+
+ Robustness::TryRobustLoseContextOnReset => {
+ if supports_robustness {
+ context_attributes.push(ffi::egl::CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY
+ as libc::c_int);
+ context_attributes.push(ffi::egl::LOSE_CONTEXT_ON_RESET as libc::c_int);
+ flags = flags | ffi::egl::CONTEXT_OPENGL_ROBUST_ACCESS as libc::c_int;
+ }
+ },
+ }
+
if gl_debug {
if egl_version >= &(1, 5) {
context_attributes.push(ffi::egl::CONTEXT_OPENGL_DEBUG as i32);
context_attributes.push(ffi::egl::TRUE as i32);
} else {
- context_attributes.push(ffi::egl::CONTEXT_FLAGS_KHR as i32);
- context_attributes.push(ffi::egl::CONTEXT_OPENGL_DEBUG_BIT_KHR as i32);
+ flags = flags | ffi::egl::CONTEXT_OPENGL_DEBUG_BIT_KHR as i32;
}
}
+ context_attributes.push(ffi::egl::CONTEXT_FLAGS_KHR as i32);
+ context_attributes.push(flags);
+
} else if egl_version >= &(1, 3) && api == Api::OpenGlEs {
+ // robustness is not supported
+ match gl_robustness {
+ Robustness::RobustNoResetNotification | Robustness::RobustLoseContextOnReset => {
+ return Err(CreationError::NotSupported);
+ },
+ _ => ()
+ }
+
context_attributes.push(ffi::egl::CONTEXT_CLIENT_VERSION as i32);
context_attributes.push(version.0 as i32);
}
@@ -362,7 +450,7 @@ unsafe fn create_context(egl: &ffi::egl::Egl, display: ffi::egl::types::EGLDispl
context_attributes.as_ptr());
if context.is_null() {
- return Err(());
+ return Err(CreationError::NotSupported);
}
Ok(context)
diff --git a/src/api/emscripten/mod.rs b/src/api/emscripten/mod.rs
index 48b31a9..79dda6b 100644
--- a/src/api/emscripten/mod.rs
+++ b/src/api/emscripten/mod.rs
@@ -5,6 +5,7 @@ use libc;
use {Event, BuilderAttribs, CreationError, MouseCursor};
use Api;
use PixelFormat;
+use ContextError;
use GlContext;
use std::collections::VecDeque;
@@ -108,11 +109,6 @@ impl Window {
})
}
- pub fn is_closed(&self) -> bool {
- use std::ptr;
- unsafe { ffi::emscripten_is_webgl_context_lost(ptr::null()) != 0 }
- }
-
pub fn set_title(&self, _title: &str) {
}
@@ -191,9 +187,10 @@ impl Window {
}
impl GlContext for Window {
- unsafe fn make_current(&self) {
+ unsafe fn make_current(&self) -> Result<(), ContextError> {
// TOOD: check if == EMSCRIPTEN_RESULT
ffi::emscripten_webgl_make_context_current(self.context);
+ Ok(())
}
fn is_current(&self) -> bool {
@@ -209,10 +206,9 @@ impl GlContext for Window {
}
}
- fn swap_buffers(&self) {
- unsafe {
- ffi::emscripten_sleep(1); // FIXME:
- }
+ fn swap_buffers(&self) -> Result<(), ContextError> {
+ unsafe { ffi::emscripten_sleep(1); } // FIXME:
+ Ok(())
}
fn get_api(&self) -> Api {
diff --git a/src/api/glx/mod.rs b/src/api/glx/mod.rs
index f1eb436..d286813 100644
--- a/src/api/glx/mod.rs
+++ b/src/api/glx/mod.rs
@@ -1,15 +1,17 @@
#![cfg(all(target_os = "linux", feature = "window"))]
use BuilderAttribs;
+use ContextError;
use CreationError;
use GlContext;
use GlProfile;
use GlRequest;
use Api;
use PixelFormat;
+use Robustness;
use libc;
-use std::ffi::CString;
+use std::ffi::{CStr, CString};
use std::{mem, ptr};
use api::x11::ffi;
@@ -47,6 +49,13 @@ impl Context {
ptr::null()
};
+ // loading the list of extensions
+ let extensions = unsafe {
+ let extensions = glx.QueryExtensionsString(display as *mut _, 0); // FIXME: screen number
+ let extensions = CStr::from_ptr(extensions).to_bytes().to_vec();
+ String::from_utf8(extensions).unwrap()
+ };
+
// loading the extra GLX functions
let extra_functions = ffi::glx_extra::Glx::load_with(|addr| {
with_c_str(addr, |s| {
@@ -57,32 +66,35 @@ impl Context {
// creating GL context
let context = match builder.gl_version {
GlRequest::Latest => {
- if let Ok(ctxt) = create_context(&glx, &extra_functions, (3, 2),
- builder.gl_profile, builder.gl_debug, share,
+ if let Ok(ctxt) = create_context(&glx, &extra_functions, &extensions, (3, 2),
+ builder.gl_profile, builder.gl_debug,
+ builder.gl_robustness, share,
display, fb_config, &mut visual_infos)
{
ctxt
- } else if let Ok(ctxt) = create_context(&glx, &extra_functions, (3, 1),
+ } else if let Ok(ctxt) = create_context(&glx, &extra_functions, &extensions, (3, 1),
builder.gl_profile, builder.gl_debug,
- share, display, fb_config,
- &mut visual_infos)
+ builder.gl_robustness, share, display,
+ fb_config, &mut visual_infos)
{
ctxt
} else {
- try!(create_context(&glx, &extra_functions, (1, 0), builder.gl_profile,
- builder.gl_debug, share, display, fb_config,
- &mut visual_infos))
+ try!(create_context(&glx, &extra_functions, &extensions, (1, 0),
+ builder.gl_profile, builder.gl_debug, builder.gl_robustness,
+ share, display, fb_config, &mut visual_infos))
}
},
GlRequest::Specific(Api::OpenGl, (major, minor)) => {
- try!(create_context(&glx, &extra_functions, (major, minor), builder.gl_profile,
- builder.gl_debug, share, display, fb_config, &mut visual_infos))
+ try!(create_context(&glx, &extra_functions, &extensions, (major, minor),
+ builder.gl_profile, builder.gl_debug, builder.gl_robustness,
+ share, display, fb_config, &mut visual_infos))
},
GlRequest::Specific(_, _) => panic!("Only OpenGL is supported"),
GlRequest::GlThenGles { opengl_version: (major, minor), .. } => {
- try!(create_context(&glx, &extra_functions, (major, minor), builder.gl_profile,
- builder.gl_debug, share, display, fb_config, &mut visual_infos))
+ try!(create_context(&glx, &extra_functions, &extensions, (major, minor),
+ builder.gl_profile, builder.gl_debug, builder.gl_robustness,
+ share, display, fb_config, &mut visual_infos))
},
};
@@ -139,11 +151,13 @@ impl Context {
}
impl GlContext for Context {
- unsafe fn make_current(&self) {
+ unsafe fn make_current(&self) -> Result<(), ContextError> {
+ // TODO: glutin needs some internal changes for proper error recovery
let res = self.glx.MakeCurrent(self.display as *mut _, self.window, self.context);
if res == 0 {
panic!("glx::MakeCurrent failed");
}
+ Ok(())
}
fn is_current(&self) -> bool {
@@ -158,10 +172,10 @@ impl GlContext for Context {
}
}
- fn swap_buffers(&self) {
- unsafe {
- self.glx.SwapBuffers(self.display as *mut _, self.window)
- }
+ fn swap_buffers(&self) -> Result<(), ContextError> {
+ // TODO: glutin needs some internal changes for proper error recovery
+ unsafe { self.glx.SwapBuffers(self.display as *mut _, self.window); }
+ Ok(())
}
fn get_api(&self) -> ::Api {
@@ -179,16 +193,18 @@ unsafe impl Sync for Context {}
impl Drop for Context {
fn drop(&mut self) {
unsafe {
- // we don't call MakeCurrent(0, 0) because we are not sure that the context
- // is still the current one
+ if self.is_current() {
+ self.glx.MakeCurrent(self.display as *mut _, 0, ptr::null_mut());
+ }
+
self.glx.DestroyContext(self.display as *mut _, self.context);
}
}
}
-fn create_context(glx: &ffi::glx::Glx, extra_functions: &ffi::glx_extra::Glx,
+fn create_context(glx: &ffi::glx::Glx, extra_functions: &ffi::glx_extra::Glx, extensions: &str,
version: (u8, u8), profile: Option<GlProfile>, debug: bool,
- share: ffi::GLXContext, display: *mut ffi::Display,
+ robustness: Robustness, share: ffi::GLXContext, display: *mut ffi::Display,
fb_config: ffi::glx::types::GLXFBConfig,
visual_infos: &mut ffi::glx::types::XVisualInfo)
-> Result<ffi::GLXContext, CreationError>
@@ -214,10 +230,43 @@ fn create_context(glx: &ffi::glx::Glx, extra_functions: &ffi::glx_extra::Glx,
attributes.push(flag as libc::c_int);
}
- if debug {
- attributes.push(ffi::glx_extra::CONTEXT_FLAGS_ARB as libc::c_int);
- attributes.push(ffi::glx_extra::CONTEXT_DEBUG_BIT_ARB as libc::c_int);
- }
+ let flags = {
+ let mut flags = 0;
+
+ // robustness
+ if extensions.split(' ').find(|&i| i == "GLX_ARB_create_context_robustness").is_some() {
+ match robustness {
+ Robustness::RobustNoResetNotification | Robustness::TryRobustNoResetNotification => {
+ attributes.push(ffi::glx_extra::CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB as libc::c_int);
+ attributes.push(ffi::glx_extra::NO_RESET_NOTIFICATION_ARB as libc::c_int);
+ flags = flags | ffi::glx_extra::CONTEXT_ROBUST_ACCESS_BIT_ARB as libc::c_int;
+ },
+ Robustness::RobustLoseContextOnReset | Robustness::TryRobustLoseContextOnReset => {
+ attributes.push(ffi::glx_extra::CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB as libc::c_int);
+ attributes.push(ffi::glx_extra::LOSE_CONTEXT_ON_RESET_ARB as libc::c_int);
+ flags = flags | ffi::glx_extra::CONTEXT_ROBUST_ACCESS_BIT_ARB as libc::c_int;
+ },
+ Robustness::NotRobust => (),
+ Robustness::NoError => (),
+ }
+ } else {
+ match robustness {
+ Robustness::RobustNoResetNotification | Robustness::RobustLoseContextOnReset => {
+ return Err(CreationError::NotSupported);
+ },
+ _ => ()
+ }
+ }
+
+ if debug {
+ flags = flags | ffi::glx_extra::CONTEXT_DEBUG_BIT_ARB as libc::c_int;
+ }
+
+ flags
+ };
+
+ attributes.push(ffi::glx_extra::CONTEXT_FLAGS_ARB as libc::c_int);
+ attributes.push(flags);
attributes.push(0);
diff --git a/src/api/osmesa/mod.rs b/src/api/osmesa/mod.rs
index 26808f7..db0a1e7 100644
--- a/src/api/osmesa/mod.rs
+++ b/src/api/osmesa/mod.rs
@@ -4,9 +4,11 @@ extern crate osmesa_sys;
use Api;
use BuilderAttribs;
+use ContextError;
use CreationError;
use GlContext;
use PixelFormat;
+use Robustness;
use libc;
use std::{mem, ptr};
use std::ffi::CString;
@@ -37,6 +39,13 @@ impl OsMesaContext {
let dimensions = builder.dimensions.unwrap();
+ match builder.gl_robustness {
+ Robustness::RobustNoResetNotification | Robustness::RobustLoseContextOnReset => {
+ return Err(CreationError::NotSupported.into());
+ },
+ _ => ()
+ }
+
Ok(OsMesaContext {
width: dimensions.0,
height: dimensions.1,
@@ -67,14 +76,18 @@ impl OsMesaContext {
}
impl GlContext for OsMesaContext {
- unsafe fn make_current(&self) {
- let ret = osmesa_sys::OSMesaMakeCurrent(self.context,
- self.buffer.as_ptr() as *mut libc::c_void,
- 0x1401, self.width as libc::c_int, self.height as libc::c_int);
+ unsafe fn make_current(&self) -> Result<(), ContextError> {
+ let ret = osmesa_sys::OSMesaMakeCurrent(self.context, self.buffer.as_ptr()
+ as *mut libc::c_void, 0x1401, self.width
+ as libc::c_int, self.height as libc::c_int);
+ // an error can only happen in case of invalid parameter, which would indicate a bug
+ // in glutin
if ret == 0 {
- panic!("OSMesaMakeCurrent failed")
+ panic!("OSMesaMakeCurrent failed");
}
+
+ Ok(())
}
fn is_current(&self) -> bool {
@@ -88,7 +101,8 @@ impl GlContext for OsMesaContext {
}
}
- fn swap_buffers(&self) {
+ fn swap_buffers(&self) -> Result<(), ContextError> {
+ Ok(())
}
fn get_api(&self) -> Api {
diff --git a/src/api/wayland/context.rs b/src/api/wayland/context.rs
index 3b6c0b8..1af6311 100644
--- a/src/api/wayland/context.rs
+++ b/src/api/wayland/context.rs
@@ -1,6 +1,8 @@
-use super::wayland::core::{Display, Registry, Compositor, Shell, Output, ButtonState,
- Seat, Pointer, default_display, WSurface, SurfaceId, Keyboard,
- KeyState};
+use super::wayland::core::{default_display, Display, Registry};
+use super::wayland::core::compositor::{Compositor, SurfaceId, WSurface};
+use super::wayland::core::output::Output;
+use super::wayland::core::seat::{ButtonState, Seat, Pointer, Keyboard, KeyState};
+use super::wayland::core::shell::Shell;
use super::wayland_kbd::MappedKeyboard;
use super::keyboard::keycode_to_vkey;
@@ -68,11 +70,11 @@ impl WaylandContext {
if let Some(ref mut p) = pointer {
// set the enter/leave callbacks
let current_surface = current_pointer_surface.clone();
- p.set_enter_action(move |_, sid, x, y| {
+ p.set_enter_action(move |_, _, sid, x, y| {
*current_surface.lock().unwrap() = Some(sid);
});
let current_surface = current_pointer_surface.clone();
- p.set_leave_action(move |_, sid| {
+ p.set_leave_action(move |_, _, sid| {
*current_surface.lock().unwrap() = None;
});
// set the events callbacks
@@ -90,7 +92,7 @@ impl WaylandContext {
});
let current_surface = current_pointer_surface.clone();
let event_queues = windows_event_queues.clone();
- p.set_button_action(move |_, sid, b, s| {
+ p.set_button_action(move |_, _, sid, b, s| {
let button = match b {
0x110 => MouseButton::Left,
0x111 => MouseButton::Right,
@@ -98,8 +100,8 @@ impl WaylandContext {
_ => return
};
let state = match s {
- ButtonState::WL_POINTER_BUTTON_STATE_RELEASED => ElementState::Released,
- ButtonState::WL_POINTER_BUTTON_STATE_PRESSED => ElementState::Pressed
+ ButtonState::Released => ElementState::Released,
+ ButtonState::Pressed => ElementState::Pressed
};
// dispatch to the appropriate queue
let sid = *current_surface.lock().unwrap();
@@ -119,11 +121,11 @@ impl WaylandContext {
display.sync_roundtrip();
let current_surface = current_keyboard_surface.clone();
- wkbd.set_enter_action(move |_, sid, _| {
+ wkbd.set_enter_action(move |_, _, sid, _| {
*current_surface.lock().unwrap() = Some(sid);
});
let current_surface = current_keyboard_surface.clone();
- wkbd.set_leave_action(move |_, sid| {
+ wkbd.set_leave_action(move |_, _, sid| {
*current_surface.lock().unwrap() = None;
});
@@ -132,10 +134,10 @@ impl WaylandContext {
// We managed to load a keymap
let current_surface = current_keyboard_surface.clone();
let event_queues = windows_event_queues.clone();
- mkbd.set_key_action(move |state, _, _, keycode, keystate| {
+ mkbd.set_key_action(move |state, _, _, _, keycode, keystate| {
let kstate = match keystate {
- KeyState::WL_KEYBOARD_KEY_STATE_RELEASED => ElementState::Released,
- KeyState::WL_KEYBOARD_KEY_STATE_PRESSED => ElementState::Pressed
+ KeyState::Released => ElementState::Released,
+ KeyState::Pressed => ElementState::Pressed
};
let mut events = Vec::new();
// key event
@@ -167,10 +169,10 @@ impl WaylandContext {
// fallback to raw inputs, no virtual keycodes
let current_surface = current_keyboard_surface.clone();
let event_queues = windows_event_queues.clone();
- rkbd.set_key_action(move |_, _, keycode, keystate| {
+ rkbd.set_key_action(move |_, _, _, keycode, keystate| {
let kstate = match keystate {
- KeyState::WL_KEYBOARD_KEY_STATE_RELEASED => ElementState::Released,
- KeyState::WL_KEYBOARD_KEY_STATE_PRESSED => ElementState::Pressed
+ KeyState::Released => ElementState::Released,
+ KeyState::Pressed => ElementState::Pressed
};
let event = Event::KeyboardInput(kstate, (keycode & 0xff) as u8, None);
// dispatch to the appropriate queue
diff --git a/src/api/wayland/mod.rs b/src/api/wayland/mod.rs
index b9bfa18..0af5496 100644
--- a/src/api/wayland/mod.rs
+++ b/src/api/wayland/mod.rs
@@ -2,13 +2,16 @@
#![allow(unused_variables, dead_code)]
use self::wayland::egl::{EGLSurface, is_egl_available};
-use self::wayland::core::{ShellSurface, Surface, Output, ShellFullscreenMethod};
+use self::wayland::core::Surface;
+use self::wayland::core::output::Output;
+use self::wayland::core::shell::{ShellSurface, ShellFullscreenMethod};
use libc;
use api::dlopen;
use api::egl::Context as EglContext;
use BuilderAttribs;
+use ContextError;
use CreationError;
use Event;
use PixelFormat;
@@ -184,11 +187,6 @@ impl Window {
})
}
- pub fn is_closed(&self) -> bool {
- // TODO
- false
- }
-
pub fn set_title(&self, title: &str) {
let ctitle = CString::new(title).unwrap();
self.shell_surface.set_title(&ctitle);
@@ -282,8 +280,7 @@ impl Window {
}
impl GlContext for Window {
-
- unsafe fn make_current(&self) {
+ unsafe fn make_current(&self) -> Result<(), ContextError> {
self.context.make_current()
}
@@ -295,7 +292,7 @@ impl GlContext for Window {
self.context.get_proc_address(addr)
}
- fn swap_buffers(&self) {
+ fn swap_buffers(&self) -> Result<(), ContextError> {
self.context.swap_buffers()
}
diff --git a/src/api/wgl/mod.rs b/src/api/wgl/mod.rs
index d1f42d2..cf09ad0 100644
--- a/src/api/wgl/mod.rs
+++ b/src/api/wgl/mod.rs
@@ -1,11 +1,13 @@
#![cfg(any(target_os = "windows"))]
use BuilderAttribs;
+use ContextError;
use CreationError;
use GlContext;
use GlRequest;
use GlProfile;
use PixelFormat;
+use Robustness;
use Api;
use self::make_current_guard::CurrentContextGuard;
@@ -130,9 +132,7 @@ impl Context {
// handling vsync
if builder.vsync {
- // contrary to most extensions, it is permitted to discover the presence of
- // `WGL_EXT_swap_control` by seeing if the function pointer is available
- if extra_functions.SwapIntervalEXT.is_loaded() {
+ if extensions.split(' ').find(|&i| i == "WGL_EXT_swap_control").is_some() {
let _guard = try!(CurrentContextGuard::make_current(hdc, context.0));
if extra_functions.SwapIntervalEXT(1) == 0 {
@@ -156,9 +156,12 @@ impl Context {
}
impl GlContext for Context {
- unsafe fn make_current(&self) {
- // TODO: check return value
- gl::wgl::MakeCurrent(self.hdc as *const _, self.context.0 as *const _);
+ unsafe fn make_current(&self) -> Result<(), ContextError> {
+ if gl::wgl::MakeCurrent(self.hdc as *const _, self.context.0 as *const _) != 0 {
+ Ok(())
+ } else {
+ Err(ContextError::IoError(io::Error::last_os_error()))
+ }
}
fn is_current(&self) -> bool {
@@ -176,10 +179,15 @@ impl GlContext for Context {
}
}
- fn swap_buffers(&self) {
- unsafe {
- gdi32::SwapBuffers(self.hdc);
- }
+ fn swap_buffers(&self) -> Result<(), ContextError> {
+ // TODO: decide how to handle the error
+ /*if unsafe { gdi32::SwapBuffers(self.hdc) } != 0 {
+ Ok(())
+ } else {
+ Err(ContextError::IoError(io::Error::last_os_error()))
+ }*/
+ unsafe { gdi32::SwapBuffers(self.hdc) };
+ Ok(())
}
fn get_api(&self) -> Api {
@@ -260,10 +268,43 @@ unsafe fn create_context(extra: Option<(&gl::wgl_extra::Wgl, &BuilderAttribs<'st
}
}
- if builder.gl_debug {
- attributes.push(gl::wgl_extra::CONTEXT_FLAGS_ARB as libc::c_int);
- attributes.push(gl::wgl_extra::CONTEXT_DEBUG_BIT_ARB as libc::c_int);
- }
+ let flags = {
+ let mut flags = 0;
+
+ // robustness
+ if extensions.split(' ').find(|&i| i == "WGL_ARB_create_context_robustness").is_some() {
+ match builder.gl_robustness {
+ Robustness::RobustNoResetNotification | Robustness::TryRobustNoResetNotification => {
+ attributes.push(gl::wgl_extra::CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB as libc::c_int);
+ attributes.push(gl::wgl_extra::NO_RESET_NOTIFICATION_ARB as libc::c_int);
+ flags = flags | gl::wgl_extra::CONTEXT_ROBUST_ACCESS_BIT_ARB as libc::c_int;
+ },
+ Robustness::RobustLoseContextOnReset | Robustness::TryRobustLoseContextOnReset => {
+ attributes.push(gl::wgl_extra::CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB as libc::c_int);
+ attributes.push(gl::wgl_extra::LOSE_CONTEXT_ON_RESET_ARB as libc::c_int);
+ flags = flags | gl::wgl_extra::CONTEXT_ROBUST_ACCESS_BIT_ARB as libc::c_int;
+ },
+ Robustness::NotRobust => (),
+ Robustness::NoError => (),
+ }
+ } else {
+ match builder.gl_robustness {
+ Robustness::RobustNoResetNotification | Robustness::RobustLoseContextOnReset => {
+ return Err(CreationError::NotSupported);
+ },
+ _ => ()
+ }
+ }
+
+ if builder.gl_debug {
+ flags = flags | gl::wgl_extra::CONTEXT_DEBUG_BIT_ARB as libc::c_int;
+ }
+
+ flags
+ };
+
+ attributes.push(gl::wgl_extra::CONTEXT_FLAGS_ARB as libc::c_int);
+ attributes.push(flags);
attributes.push(0);
diff --git a/src/api/win32/callback.rs b/src/api/win32/callback.rs
index 86d5f1c..6ac56f3 100644
--- a/src/api/win32/callback.rs
+++ b/src/api/win32/callback.rs
@@ -112,12 +112,13 @@ pub unsafe extern "system" fn callback(window: winapi::HWND, msg: winapi::UINT,
winapi::WM_MOUSEWHEEL => {
use events::Event::MouseWheel;
+ use events::MouseScrollDelta::LineDelta;
let value = (wparam >> 16) as i16;
let value = value as i32;
- let value = value as f64 / winapi::WHEEL_DELTA as f64;
+ let value = value as f32 / winapi::WHEEL_DELTA as f32;
- send_event(window, MouseWheel(0.0, value));
+ send_event(window, MouseWheel(LineDelta(0.0, value)));
0
},
diff --git a/src/api/win32/init.rs b/src/api/win32/init.rs
index f46c395..7cb5433 100644
--- a/src/api/win32/init.rs
+++ b/src/api/win32/init.rs
@@ -257,7 +257,6 @@ unsafe fn init(title: Vec<u16>, builder: BuilderAttribs<'static>,
window: real_window,
context: context,
events_receiver: events_receiver,
- is_closed: AtomicBool::new(false),
cursor_state: cursor_state,
})
}
diff --git a/src/api/win32/mod.rs b/src/api/win32/mod.rs
index af339c5..d21f16d 100644
--- a/src/api/win32/mod.rs
+++ b/src/api/win32/mod.rs
@@ -11,6 +11,7 @@ use std::sync::{
};
use std::sync::mpsc::Receiver;
use libc;
+use ContextError;
use {CreationError, Event, MouseCursor};
use CursorState;
use GlContext;
@@ -47,9 +48,6 @@ pub struct Window {
/// Receiver for the events dispatched by the window callback.
events_receiver: Receiver<Event>,
- /// True if a `Closed` event has been received.
- is_closed: AtomicBool,
-
/// The current cursor state.
cursor_state: Arc<Mutex<CursorState>>,
}
@@ -98,12 +96,6 @@ impl Window {
}
/// See the docs in the crate root file.
- pub fn is_closed(&self) -> bool {
- 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) {
@@ -315,7 +307,7 @@ impl Window {
}
impl GlContext for Window {
- unsafe fn make_current(&self) {
+ unsafe fn make_current(&self) -> Result<(), ContextError> {
match self.context {
Context::Wgl(ref c) => c.make_current(),
Context::Egl(ref c) => c.make_current(),
@@ -336,7 +328,7 @@ impl GlContext for Window {
}
}
- fn swap_buffers(&self) {
+ fn swap_buffers(&self) -> Result<(), ContextError> {
match self.context {
Context::Wgl(ref c) => c.swap_buffers(),
Context::Egl(ref c) => c.swap_buffers(),
@@ -366,17 +358,7 @@ impl<'a> Iterator for PollEventsIterator<'a> {
type Item = Event;
fn next(&mut self) -> Option<Event> {
- use events::Event::Closed;
-
- match self.window.events_receiver.try_recv() {
- Ok(Closed) => {
- use std::sync::atomic::Ordering::Relaxed;
- self.window.is_closed.store(true, Relaxed);
- Some(Closed)
- },
- Ok(ev) => Some(ev),
- Err(_) => None
- }
+ self.window.events_receiver.try_recv().ok()
}
}
@@ -388,17 +370,7 @@ impl<'a> Iterator for WaitEventsIterator<'a> {
type Item = Event;
fn next(&mut self) -> Option<Event> {
- use events::Event::Closed;
-
- match self.window.events_receiver.recv() {
- Ok(Closed) => {
- use std::sync::atomic::Ordering::Relaxed;
- self.window.is_closed.store(true, Relaxed);
- Some(Closed)
- },
- Ok(ev) => Some(ev),
- Err(_) => None
- }
+ self.window.events_receiver.recv().ok()
}
}
diff --git a/src/api/x11/window.rs b/src/api/x11/window.rs
index 42134d0..15e27ce 100644
--- a/src/api/x11/window.rs
+++ b/src/api/x11/window.rs
@@ -9,6 +9,7 @@ use std::collections::VecDeque;
use std::sync::{Arc, Mutex};
use Api;
+use ContextError;
use CursorState;
use GlContext;
use GlRequest;
@@ -43,6 +44,7 @@ pub struct XWindow {
xf86_desk_mode: *mut ffi::XF86VidModeModeInfo,
ic: ffi::XIC,
im: ffi::XIM,
+ colormap: ffi::Colormap,
}
pub enum Context {
@@ -64,6 +66,8 @@ impl Drop for XWindow {
// is still the current one
self.context = Context::None;
+ let _lock = GLOBAL_XOPENIM_LOCK.lock().unwrap();
+
if self.is_fullscreen {
(self.display.xf86vmode.XF86VidModeSwitchToMode)(self.display.display, self.screen_id, self.xf86_desk_mode);
(self.display.xf86vmode.XF86VidModeSetViewPort)(self.display.display, self.screen_id, 0, 0);
@@ -72,6 +76,7 @@ impl Drop for XWindow {
(self.display.xlib.XDestroyIC)(self.ic);
(self.display.xlib.XCloseIM)(self.im);
(self.display.xlib.XDestroyWindow)(self.display.display, self.window);
+ (self.display.xlib.XFreeColormap)(self.display.display, self.colormap);
}
}
}
@@ -215,6 +220,7 @@ impl<'a> Iterator for PollEventsIterator<'a> {
use events::Event::{MouseInput, MouseWheel};
use events::ElementState::{Pressed, Released};
use events::MouseButton::{Left, Right, Middle};
+ use events::MouseScrollDelta::{LineDelta};
let event: &ffi::XButtonEvent = unsafe { mem::transmute(&xev) };
@@ -225,11 +231,13 @@ impl<'a> Iterator for PollEventsIterator<'a> {
ffi::Button2 => Some(Middle),
ffi::Button3 => Some(Right),
ffi::Button4 => {
- self.window.pending_events.lock().unwrap().push_back(MouseWheel(0.0, 1.0));
+ let delta = LineDelta(0.0, 1.0);
+ self.window.pending_events.lock().unwrap().push_back(MouseWheel(delta));
None
}
ffi::Button5 => {
- self.window.pending_events.lock().unwrap().push_back(MouseWheel(0.0, -1.0));
+ let delta = LineDelta(0.0, -1.0);
+ self.window.pending_events.lock().unwrap().push_back(MouseWheel(delta));
None
}
_ => None
@@ -256,9 +264,10 @@ impl<'a> Iterator for WaitEventsIterator<'a> {
type Item = Event;
fn next(&mut self) -> Option<Event> {
+ use std::sync::atomic::Ordering::Relaxed;
use std::mem;
- while !self.window.is_closed() {
+ while !self.window.is_closed.load(Relaxed) {
if let Some(ev) = self.window.pending_events.lock().unwrap().pop_front() {
return Some(ev);
}
@@ -335,34 +344,65 @@ impl Window {
if fb.is_null() {
return Err(OsError(format!("glx::ChooseFBConfig failed")));
}
- let preferred_fb = *fb; // TODO: choose more wisely
+
+ let preferred_fb = if builder.transparent {
+ let mut best_fbi_for_transparent = 0isize;
+
+ for i in 0isize..num_fb as isize {
+ let vi = display.glx.as_ref().unwrap().GetVisualFromFBConfig(display.display as *mut _, *fb.offset(i));
+ if (*vi).depth == 32 {
+ best_fbi_for_transparent = i;
+ break;
+ }
+ }
+
+ *fb.offset(best_fbi_for_transparent)
+ } else {
+ *fb // TODO: choose more wisely
+ };
+
(display.xlib.XFree)(fb as *mut _);
preferred_fb
};
- let mut best_mode = -1;
- let modes = unsafe {
+ // finding the mode to switch to if necessary
+ let (mode_to_switch_to, xf86_desk_mode) = unsafe {
let mut mode_num: libc::c_int = mem::uninitialized();
let mut modes: *mut *mut ffi::XF86VidModeModeInfo = mem::uninitialized();
if (display.xf86vmode.XF86VidModeGetAllModeLines)(display.display, screen_id, &mut mode_num, &mut modes) == 0 {
return Err(OsError(format!("Could not query the video modes")));
}
- for i in 0..mode_num {
- 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;
+ let xf86_desk_mode = *modes.offset(0);
+
+ // FIXME: `XF86VidModeModeInfo` is missing its `hskew` field. Therefore we point to
+ // `vsyncstart` instead of `vdisplay` as a temporary hack.
+
+ let mode_to_switch_to = if builder.monitor.is_some() {
+ let matching_mode = (0 .. mode_num).map(|i| {
+ let m: ffi::XF86VidModeModeInfo = ptr::read(*modes.offset(i as isize) as *const _); m
+ }).find(|m| m.hdisplay == dimensions.0 as u16 && m.vsyncstart == dimensions.1 as u16);
+
+ if let Some(matching_mode) = matching_mode {
+ Some(matching_mode)
+
+ } else {
+ let m = (0 .. mode_num).map(|i| {
+ let m: ffi::XF86VidModeModeInfo = ptr::read(*modes.offset(i as isize) as *const _); m
+ }).find(|m| m.hdisplay >= dimensions.0 as u16 && m.vsyncstart == dimensions.1 as u16);
+
+ match m {
+ Some(m) => Some(m),
+ None => return Err(OsError(format!("Could not find a suitable graphics mode")))
+ }
}
+ } else {
+ None
};
- if best_mode == -1 && builder.monitor.is_some() {
- return Err(OsError(format!("Could not find a suitable graphics mode")));
- }
- modes
- };
+ (display.xlib.XFree)(modes as *mut _);
- let xf86_desk_mode = unsafe {
- *modes.offset(0)
+ (mode_to_switch_to, xf86_desk_mode)
};
// getting the visual infos
@@ -421,15 +461,24 @@ impl Window {
ffi::KeyReleaseMask | ffi::ButtonPressMask |
ffi::ButtonReleaseMask | ffi::KeymapStateMask;
swa.border_pixel = 0;
+ if builder.transparent {
+ swa.background_pixel = 0;
+ }
swa.override_redirect = 0;
swa
};
- let mut window_attributes = ffi::CWBorderPixel | ffi::CWColormap | ffi:: CWEventMask;
- if builder.monitor.is_some() {
+ let mut window_attributes = ffi::CWBorderPixel | ffi::CWColormap | ffi::CWEventMask;
+
+ if builder.transparent {
+ window_attributes |= ffi::CWBackPixel;
+ }
+
+ // switching to fullscreen
+ if let Some(mut mode_to_switch_to) = mode_to_switch_to {
window_attributes |= ffi::CWOverrideRedirect;
unsafe {
- (display.xf86vmode.XF86VidModeSwitchToMode)(display.display, screen_id, *modes.offset(best_mode as isize));
+ (display.xf86vmode.XF86VidModeSwitchToMode)(display.display, screen_id, &mut mode_to_switch_to);
(display.xf86vmode.XF86VidModeSetViewPort)(display.display, screen_id, 0, 0);
set_win_attr.override_redirect = 1;
}
@@ -551,6 +600,7 @@ impl Window {
screen_id: screen_id,
is_fullscreen: is_fullscreen,
xf86_desk_mode: xf86_desk_mode,
+ colormap: cmap,
}),
is_closed: AtomicBool::new(false),
wm_delete_window: wm_delete_window,
@@ -564,11 +614,6 @@ impl Window {
Ok(window)
}
- pub fn is_closed(&self) -> bool {
- use std::sync::atomic::Ordering::Relaxed;
- self.is_closed.load(Relaxed)
- }
-
pub fn set_title(&self, title: &str) {
with_c_str(title, |title| unsafe {
(self.x.display.xlib.XStoreName)(self.x.display.display, self.x.window, title);
@@ -768,11 +813,11 @@ impl Window {
}
impl GlContext for Window {
- unsafe fn make_current(&self) {
+ unsafe fn make_current(&self) -> Result<(), ContextError> {
match self.x.context {
Context::Glx(ref ctxt) => ctxt.make_current(),
Context::Egl(ref ctxt) => ctxt.make_current(),
- Context::None => {}
+ Context::None => Ok(())
}
}
@@ -792,11 +837,11 @@ impl GlContext for Window {
}
}
- fn swap_buffers(&self) {
+ fn swap_buffers(&self) -> Result<(), ContextError> {
match self.x.context {
Context::Glx(ref ctxt) => ctxt.swap_buffers(),
Context::Egl(ref ctxt) => ctxt.swap_buffers(),
- Context::None => {}
+ Context::None => Ok(())
}
}
diff --git a/src/events.rs b/src/events.rs
index 6c4dc5b..5a5e2ab 100644
--- a/src/events.rs
+++ b/src/events.rs
@@ -25,11 +25,8 @@ pub enum Event {
/// The parameter are the (x,y) coords in pixels relative to the top-left corner of the window.
MouseMoved((i32, i32)),
- /// Returns the horizontal and vertical mouse scrolling.
- ///
- /// 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.
- MouseWheel(f64, f64),
+ /// A mouse wheel movement or touchpad scroll occurred.
+ MouseWheel(MouseScrollDelta),
/// An event from the mouse has been received.
MouseInput(ElementState, MouseButton),
@@ -97,6 +94,23 @@ pub enum MouseButton {
Other(u8),
}
+#[derive(Debug, Clone, Copy)]
+pub enum MouseScrollDelta {
+ /// Amount in lines or rows to scroll in the horizontal
+ /// and vertical directions.
+ ///
+ /// Positive values indicate movement forward
+ /// (away from the user) or rightwards.
+ LineDelta(f32, f32),
+ /// Amount in pixels to scroll in the horizontal and
+ /// vertical direction.
+ ///
+ /// Scroll events are expressed as a PixelDelta if
+ /// supported by the device (eg. a touchpad) and
+ /// platform.
+ PixelDelta(f32, f32)
+}
+
#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
pub enum VirtualKeyCode {
/// The '1' key over the letters.
diff --git a/src/headless.rs b/src/headless.rs
index 997d87a..69f9aab 100644
--- a/src/headless.rs
+++ b/src/headless.rs
@@ -1,9 +1,11 @@
use Api;
use BuilderAttribs;
+use ContextError;
use CreationError;
use GlRequest;
use GlContext;
use PixelFormat;
+use Robustness;
use gl_common;
use libc;
@@ -42,6 +44,12 @@ impl HeadlessRendererBuilder {
self
}
+ /// Sets the robustness of the OpenGL context. See the docs of `Robustness`.
+ pub fn with_gl_robustness(mut self, robustness: Robustness) -> HeadlessRendererBuilder {
+ self.attribs.gl_robustness = robustness;
+ self
+ }
+
/// Builds the headless context.
///
/// Error should be very rare and only occur in case of permission denied, incompatible system,
@@ -69,7 +77,7 @@ impl HeadlessContext {
/// Creates a new OpenGL context
/// Sets the context as the current context.
#[inline]
- pub unsafe fn make_current(&self) {
+ pub unsafe fn make_current(&self) -> Result<(), ContextError> {
self.context.make_current()
}
@@ -105,7 +113,7 @@ impl gl_common::GlFunctionsSource for HeadlessContext {
}
impl GlContext for HeadlessContext {
- unsafe fn make_current(&self) {
+ unsafe fn make_current(&self) -> Result<(), ContextError> {
self.context.make_current()
}
@@ -117,7 +125,7 @@ impl GlContext for HeadlessContext {
self.context.get_proc_address(addr)
}
- fn swap_buffers(&self) {
+ fn swap_buffers(&self) -> Result<(), ContextError> {
self.context.swap_buffers()
}
diff --git a/src/lib.rs b/src/lib.rs
index f787b26..b292869 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -46,6 +46,8 @@ extern crate dwmapi;
#[macro_use]
extern crate objc;
#[cfg(target_os = "macos")]
+extern crate cgl;
+#[cfg(target_os = "macos")]
extern crate cocoa;
#[cfg(target_os = "macos")]
extern crate core_foundation;
@@ -63,6 +65,8 @@ pub use window::{AvailableMonitorsIter, MonitorID, get_available_monitors, get_p
#[cfg(feature = "window")]
pub use native_monitor::NativeMonitorId;
+use std::io;
+
mod api;
mod platform;
mod events;
@@ -73,7 +77,7 @@ mod window;
/// Trait that describes objects that have access to an OpenGL context.
pub trait GlContext {
/// Sets the context as the current context.
- unsafe fn make_current(&self);
+ unsafe fn make_current(&self) -> Result<(), ContextError>;
/// Returns true if this context is the current one in this thread.
fn is_current(&self) -> bool;
@@ -84,12 +88,12 @@ pub trait GlContext {
/// Swaps the buffers in case of double or triple buffering.
///
/// You should call this function every time you have finished rendering, or the image
- /// may not be displayed on the screen.
+ /// 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.
- fn swap_buffers(&self);
+ fn swap_buffers(&self) -> Result<(), ContextError>;
/// Returns the OpenGL API being used.
fn get_api(&self) -> Api;
@@ -126,6 +130,13 @@ impl std::error::Error for CreationError {
}
}
+/// Error that can happen when manipulating an OpenGL context.
+#[derive(Debug)]
+pub enum ContextError {
+ IoError(io::Error),
+ ContextLost,
+}
+
/// All APIs related to OpenGL that you can possibly get while using glutin.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Api {
@@ -186,6 +197,40 @@ impl GlRequest {
/// the compatibility profile features.
pub static GL_CORE: GlRequest = GlRequest::Specific(Api::OpenGl, (3, 2));
+/// Specifies the tolerance of the OpenGL context to faults. If you accept raw OpenGL commands
+/// and/or raw shader code from an untrusted source, you should definitely care about this.
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub enum Robustness {
+ /// Not everything is checked. Your application can crash if you do something wrong with your
+ /// shaders.
+ NotRobust,
+
+ /// The driver doesn't check anything. This option is very dangerous. Please know what you're
+ /// doing before using it. See the `GL_KHR_no_error` extension.
+ ///
+ /// Since this option is purely an optimisation, no error will be returned if the backend
+ /// doesn't support it. Instead it will automatically fall back to `NotRobust`.
+ NoError,
+
+ /// Everything is checked to avoid any crash. The driver will attempt to avoid any problem,
+ /// but if a problem occurs the behavior is implementation-defined. You are just guaranteed not
+ /// to get a crash.
+ RobustNoResetNotification,
+
+ /// Same as `RobustNoResetNotification` but the context creation doesn't fail if it's not
+ /// supported.
+ TryRobustNoResetNotification,
+
+ /// Everything is checked to avoid any crash. If a problem occurs, the context will enter a
+ /// "context lost" state. It must then be recreated. For the moment, glutin doesn't provide a
+ /// way to recreate a context with the same window :-/
+ RobustLoseContextOnReset,
+
+ /// Same as `RobustLoseContextOnReset` but the context creation doesn't fail if it's not
+ /// supported.
+ TryRobustLoseContextOnReset,
+}
+
#[derive(Debug, Copy, Clone)]
pub enum MouseCursor {
/// The platform-dependent default cursor.
@@ -288,6 +333,7 @@ pub struct BuilderAttribs<'a> {
gl_version: GlRequest,
gl_profile: Option<GlProfile>,
gl_debug: bool,
+ gl_robustness: Robustness,
vsync: bool,
visible: bool,
multisampling: Option<u16>,
@@ -314,6 +360,7 @@ impl BuilderAttribs<'static> {
gl_version: GlRequest::Latest,
gl_profile: None,
gl_debug: cfg!(debug_assertions),
+ gl_robustness: Robustness::NotRobust,
vsync: false,
visible: true,
multisampling: None,
@@ -345,6 +392,7 @@ impl<'a> BuilderAttribs<'a> {
gl_version: self.gl_version,
gl_profile: self.gl_profile,
gl_debug: self.gl_debug,
+ gl_robustness: self.gl_robustness,
vsync: self.vsync,
visible: self.visible,
multisampling: self.multisampling,
@@ -390,8 +438,15 @@ impl<'a> BuilderAttribs<'a> {
continue;
}
- if self.multisampling.is_some() && format.multisampling.is_none() {
- continue;
+ if let Some(req_ms) = self.multisampling {
+ match format.multisampling {
+ Some(val) if val >= req_ms => (),
+ _ => continue
+ }
+ } else {
+ if format.multisampling.is_some() {
+ continue;
+ }
}
if let Some(srgb) = self.srgb {
diff --git a/src/platform/android/mod.rs b/src/platform/android/mod.rs
index a1b9416..50f554b 100644
--- a/src/platform/android/mod.rs
+++ b/src/platform/android/mod.rs
@@ -2,6 +2,8 @@
pub use api::android::*;
+use ContextError;
+
pub struct HeadlessContext(i32);
impl HeadlessContext {
@@ -11,7 +13,7 @@ impl HeadlessContext {
}
/// See the docs in the crate root file.
- pub unsafe fn make_current(&self) {
+ pub unsafe fn make_current(&self) -> Result<(), ContextError> {
unimplemented!()
}
diff --git a/src/platform/emscripten/mod.rs b/src/platform/emscripten/mod.rs
index 56a7e9f..d3aa6d6 100644
--- a/src/platform/emscripten/mod.rs
+++ b/src/platform/emscripten/mod.rs
@@ -1,5 +1,6 @@
#![cfg(target_os = "emscripten")]
+use ContextError;
use GlContext;
pub use api::emscripten::{Window, WindowProxy, MonitorID, get_available_monitors};
@@ -15,7 +16,7 @@ impl HeadlessContext {
}
impl GlContext for HeadlessContext {
- unsafe fn make_current(&self) {
+ unsafe fn make_current(&self) -> Result<(), ContextError> {
self.0.make_current()
}
@@ -27,7 +28,7 @@ impl GlContext for HeadlessContext {
self.0.get_proc_address(addr)
}
- fn swap_buffers(&self) {
+ fn swap_buffers(&self) -> Result<(), ContextError> {
self.0.swap_buffers()
}
diff --git a/src/platform/linux/api_dispatch.rs b/src/platform/linux/api_dispatch.rs
index d04a1fb..b2cd741 100644
--- a/src/platform/linux/api_dispatch.rs
+++ b/src/platform/linux/api_dispatch.rs
@@ -7,6 +7,7 @@ use std::collections::VecDeque;
use std::sync::Arc;
use BuilderAttribs;
+use ContextError;
use CreationError;
use CursorState;
use Event;
@@ -154,13 +155,6 @@ impl Window {
}
}
- pub fn is_closed(&self) -> bool {
- match self {
- &Window::X(ref w) => w.is_closed(),
- &Window::Wayland(ref w) => w.is_closed()
- }
- }
-
pub fn set_title(&self, title: &str) {
match self {
&Window::X(ref w) => w.set_title(title),
@@ -289,7 +283,7 @@ impl Window {
}
impl GlContext for Window {
- unsafe fn make_current(&self) {
+ unsafe fn make_current(&self) -> Result<(), ContextError> {
match self {
&Window::X(ref w) => w.make_current(),
&Window::Wayland(ref w) => w.make_current()
@@ -310,7 +304,7 @@ impl GlContext for Window {
}
}
- fn swap_buffers(&self) {
+ fn swap_buffers(&self) -> Result<(), ContextError> {
match self {
&Window::X(ref w) => w.swap_buffers(),
&Window::Wayland(ref w) => w.swap_buffers()
diff --git a/src/platform/linux/mod.rs b/src/platform/linux/mod.rs
index 323a21a..fc42f18 100644
--- a/src/platform/linux/mod.rs
+++ b/src/platform/linux/mod.rs
@@ -2,6 +2,7 @@
use Api;
use BuilderAttribs;
+use ContextError;
use CreationError;
use GlContext;
use PixelFormat;
@@ -37,7 +38,7 @@ impl HeadlessContext {
impl GlContext for HeadlessContext {
#[inline]
- unsafe fn make_current(&self) {
+ unsafe fn make_current(&self) -> Result<(), ContextError> {
self.0.make_current()
}
@@ -52,7 +53,7 @@ impl GlContext for HeadlessContext {
}
#[inline]
- fn swap_buffers(&self) {
+ fn swap_buffers(&self) -> Result<(), ContextError> {
self.0.swap_buffers()
}
diff --git a/src/platform/windows/mod.rs b/src/platform/windows/mod.rs
index 260ab94..b33b8ee 100644
--- a/src/platform/windows/mod.rs
+++ b/src/platform/windows/mod.rs
@@ -6,6 +6,7 @@ use libc;
use Api;
use BuilderAttribs;
+use ContextError;
use CreationError;
use PixelFormat;
use GlContext;
@@ -21,7 +22,7 @@ impl HeadlessContext {
}
impl GlContext for HeadlessContext {
- unsafe fn make_current(&self) {
+ unsafe fn make_current(&self) -> Result<(), ContextError> {
self.0.make_current()
}
@@ -33,7 +34,7 @@ impl GlContext for HeadlessContext {
self.0.get_proc_address(addr)
}
- fn swap_buffers(&self) {
+ fn swap_buffers(&self) -> Result<(), ContextError> {
self.0.swap_buffers()
}
diff --git a/src/window.rs b/src/window.rs
index 664868b..8757efc 100644
--- a/src/window.rs
+++ b/src/window.rs
@@ -3,6 +3,7 @@ use std::default::Default;
use Api;
use BuilderAttribs;
+use ContextError;
use CreationError;
use CursorState;
use Event;
@@ -11,6 +12,7 @@ use GlProfile;
use GlRequest;
use MouseCursor;
use PixelFormat;
+use Robustness;
use native_monitor::NativeMonitorId;
use gl_common;
@@ -83,6 +85,12 @@ impl<'a> WindowBuilder<'a> {
self
}
+ /// Sets the robustness of the OpenGL context. See the docs of `Robustness`.
+ pub fn with_gl_robustness(mut self, robustness: Robustness) -> WindowBuilder<'a> {
+ self.attribs.gl_robustness = robustness;
+ self
+ }
+
/// Requests that the window has vsync enabled.
pub fn with_vsync(mut self) -> WindowBuilder<'a> {
self.attribs.vsync = true;
@@ -230,12 +238,6 @@ impl Window {
builder.build()
}
- /// Returns true if the window has previously been closed by the user.
- #[inline]
- pub fn is_closed(&self) -> bool {
- self.window.is_closed()
- }
-
/// Modifies the title of the window.
///
/// This is a no-op if the window has already been closed.
@@ -345,7 +347,7 @@ impl Window {
/// Sets the context as the current context.
#[inline]
- pub unsafe fn make_current(&self) {
+ pub unsafe fn make_current(&self) -> Result<(), ContextError> {
self.window.make_current()
}
@@ -372,7 +374,7 @@ impl Window {
/// 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) {
+ pub fn swap_buffers(&self) -> Result<(), ContextError> {
self.window.swap_buffers()
}
@@ -455,7 +457,7 @@ impl gl_common::GlFunctionsSource for Window {
}
impl GlContext for Window {
- unsafe fn make_current(&self) {
+ unsafe fn make_current(&self) -> Result<(), ContextError> {
self.make_current()
}
@@ -467,7 +469,7 @@ impl GlContext for Window {
self.get_proc_address(addr)
}
- fn swap_buffers(&self) {
+ fn swap_buffers(&self) -> Result<(), ContextError> {
self.swap_buffers()
}