Merge pull request #333 from tomaka/fix

Change grab_cursor and ungrab_cursor to set_cursor_state
This commit is contained in:
tomaka 2015-03-28 11:24:18 +01:00
commit 125ebed031
7 changed files with 80 additions and 52 deletions

View file

@ -1,3 +1,5 @@
#![feature(std_misc)]
#[cfg(target_os = "android")] #[cfg(target_os = "android")]
#[macro_use] #[macro_use]
extern crate android_glue; extern crate android_glue;
@ -16,7 +18,6 @@ fn main() { println!("This example requires glutin to be compiled with the `wind
#[cfg(feature = "window")] #[cfg(feature = "window")]
fn main() { fn main() {
let window = glutin::Window::new().unwrap(); let window = glutin::Window::new().unwrap();
window.set_title("glutin - Cursor grabbing test"); window.set_title("glutin - Cursor grabbing test");
unsafe { window.make_current() }; unsafe { window.make_current() };
@ -33,11 +34,12 @@ fn main() {
Event::KeyboardInput(ElementState::Pressed, _, _) => { Event::KeyboardInput(ElementState::Pressed, _, _) => {
if grabbed { if grabbed {
grabbed = false; grabbed = false;
window.ungrab_cursor(); window.set_cursor_state(glutin::CursorState::Normal)
} .ok().expect("could not ungrab mouse cursor");
else { } else {
grabbed = true; grabbed = true;
window.grab_cursor().ok().expect("could not grab mouse cursor"); window.set_cursor_state(glutin::CursorState::Grab)
.ok().expect("could not grab mouse cursor");
} }
}, },
_ => (), _ => (),

View file

@ -13,6 +13,7 @@ use std::collections::VecDeque;
use Api; use Api;
use BuilderAttribs; use BuilderAttribs;
use CursorState;
use GlRequest; use GlRequest;
use native_monitor::NativeMonitorId; use native_monitor::NativeMonitorId;
@ -358,9 +359,9 @@ impl Window {
pub fn set_cursor(&self, _: MouseCursor) { pub fn set_cursor(&self, _: MouseCursor) {
} }
pub fn grab_cursor(&self) -> Result<(), String> { Ok(()) } pub fn set_cursor_state(&self, state: CursorState) -> Result<(), String> {
Ok(())
pub fn ungrab_cursor(&self) {} }
pub fn hidpi_factor(&self) -> f32 { pub fn hidpi_factor(&self) -> f32 {
1.0 1.0

View file

@ -1,7 +1,7 @@
#[cfg(feature = "headless")] #[cfg(feature = "headless")]
pub use self::headless::HeadlessContext; pub use self::headless::HeadlessContext;
use {CreationError, Event, MouseCursor}; use {CreationError, Event, MouseCursor, CursorState};
use CreationError::OsError; use CreationError::OsError;
use libc; use libc;
@ -661,6 +661,10 @@ impl Window {
} }
} }
pub fn set_cursor_state(&self, state: CursorState) -> Result<(), String> {
unimplemented!();
}
pub fn hidpi_factor(&self) -> f32 { pub fn hidpi_factor(&self) -> f32 {
unsafe { unsafe {
NSWindow::backingScaleFactor(*self.window) as f32 NSWindow::backingScaleFactor(*self.window) as f32

View file

@ -32,7 +32,7 @@ extern crate libc;
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
extern crate winapi; extern crate winapi;
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
extern crate kernel32_sys as kernel32; extern crate kernel32;
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
extern crate gdi32_sys as gdi32; extern crate gdi32_sys as gdi32;
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
@ -198,6 +198,23 @@ pub enum MouseCursor {
RowResize, RowResize,
} }
/// Describes how glutin handles the cursor.
#[derive(Debug, Copy)]
pub enum CursorState {
/// Normal cursor behavior.
Normal,
/// The cursor will be invisible when over the window.
Hide,
/// Grabs the mouse cursor. The cursor's motion will be confined to this
/// window and the window has exclusive access to further events regarding
/// the cursor.
///
/// This is useful for first-person cameras for example.
Grab,
}
/// Describes a possible format. Unused. /// Describes a possible format. Unused.
#[allow(missing_docs)] #[allow(missing_docs)]
#[derive(Debug, Clone)] #[derive(Debug, Clone)]

View file

@ -4,6 +4,7 @@ use std::ffi::CString;
use std::sync::mpsc::Receiver; use std::sync::mpsc::Receiver;
use libc; use libc;
use {CreationError, Event, MouseCursor}; use {CreationError, Event, MouseCursor};
use CursorState;
use BuilderAttribs; use BuilderAttribs;
@ -255,12 +256,8 @@ impl Window {
unimplemented!() unimplemented!()
} }
pub fn grab_cursor(&self) -> Result<(), String> { pub fn set_cursor_state(&self, state: CursorState) -> Result<(), String> {
unimplemented!() unimplemented!();
}
pub fn ungrab_cursor(&self) {
unimplemented!()
} }
pub fn hidpi_factor(&self) -> f32 { pub fn hidpi_factor(&self) -> f32 {

View file

@ -4,6 +4,7 @@ use std::default::Default;
use Api; use Api;
use BuilderAttribs; use BuilderAttribs;
use CreationError; use CreationError;
use CursorState;
use Event; use Event;
use GlRequest; use GlRequest;
use MouseCursor; use MouseCursor;
@ -415,21 +416,12 @@ impl Window {
self.window.set_cursor_position(x, y) self.window.set_cursor_position(x, y)
} }
/// Grabs the mouse cursor. The cursor's motion will be confined to this /// Sets how glutin handles the cursor. See the documentation of `CursorState` for details.
/// window and the window has exclusive access to further events regarding ///
/// the cursor.
/// Fails if it is not possible to grab the window for some reason, e.g.
/// when another window has already done so.
/// Has no effect on Android. /// Has no effect on Android.
pub fn grab_cursor(&self) -> Result<(), String> { pub fn set_cursor_state(&self, state: CursorState) -> Result<(), String> {
self.window.grab_cursor() self.window.set_cursor_state(state)
} }
/// Release a previously grabbed mouse cursor.
pub fn ungrab_cursor(&self) {
self.window.ungrab_cursor();
}
} }
impl gl_common::GlFunctionsSource for Window { impl gl_common::GlFunctionsSource for Window {

View file

@ -11,6 +11,7 @@ use std::sync::{Arc, Mutex, Once, ONCE_INIT, Weak};
use std::sync::{StaticMutex, MUTEX_INIT}; use std::sync::{StaticMutex, MUTEX_INIT};
use Api; use Api;
use CursorState;
use GlRequest; use GlRequest;
pub use self::monitor::{MonitorID, get_available_monitors, get_primary_monitor}; pub use self::monitor::{MonitorID, get_available_monitors, get_primary_monitor};
@ -282,6 +283,7 @@ pub struct Window {
current_size: Cell<(libc::c_int, libc::c_int)>, current_size: Cell<(libc::c_int, libc::c_int)>,
/// Events that have been retreived with XLib but not dispatched with iterators yet /// Events that have been retreived with XLib but not dispatched with iterators yet
pending_events: Mutex<VecDeque<Event>>, pending_events: Mutex<VecDeque<Event>>,
cursor_state: Mutex<CursorState>,
} }
impl Window { impl Window {
@ -601,6 +603,7 @@ impl Window {
wm_delete_window: wm_delete_window, wm_delete_window: wm_delete_window,
current_size: Cell::new((0, 0)), current_size: Cell::new((0, 0)),
pending_events: Mutex::new(VecDeque::new()), pending_events: Mutex::new(VecDeque::new()),
cursor_state: Mutex::new(CursorState::Normal),
}; };
// returning // returning
@ -782,30 +785,42 @@ impl Window {
} }
} }
pub fn grab_cursor(&self) -> Result<(), String> { pub fn set_cursor_state(&self, state: CursorState) -> Result<(), String> {
unsafe { let mut cursor_state = self.cursor_state.lock().unwrap();
match ffi::XGrabPointer(
self.x.display, self.x.window, false,
ffi::ButtonPressMask | ffi::ButtonReleaseMask | ffi::EnterWindowMask |
ffi::LeaveWindowMask | ffi::PointerMotionMask | ffi::PointerMotionHintMask |
ffi::Button1MotionMask | ffi::Button2MotionMask | ffi::Button3MotionMask |
ffi::Button4MotionMask | ffi::Button5MotionMask | ffi::ButtonMotionMask |
ffi::KeymapStateMask,
ffi::GrabModeAsync, ffi::GrabModeAsync,
self.x.window, 0, ffi::CurrentTime
) {
ffi::GrabSuccess => Ok(()),
ffi::AlreadyGrabbed | ffi::GrabInvalidTime |
ffi::GrabNotViewable | ffi::GrabFrozen
=> Err("cursor could not be grabbed".to_string()),
_ => unreachable!(),
}
}
}
pub fn ungrab_cursor(&self) { match (state, *cursor_state) {
unsafe { (CursorState::Normal, CursorState::Grab) => {
ffi::XUngrabPointer(self.x.display, ffi::CurrentTime); unsafe {
ffi::XUngrabPointer(self.x.display, ffi::CurrentTime);
*cursor_state = CursorState::Normal;
Ok(())
}
},
(CursorState::Grab, CursorState::Normal) => {
unsafe {
*cursor_state = CursorState::Grab;
match ffi::XGrabPointer(
self.x.display, self.x.window, false,
ffi::ButtonPressMask | ffi::ButtonReleaseMask | ffi::EnterWindowMask |
ffi::LeaveWindowMask | ffi::PointerMotionMask | ffi::PointerMotionHintMask |
ffi::Button1MotionMask | ffi::Button2MotionMask | ffi::Button3MotionMask |
ffi::Button4MotionMask | ffi::Button5MotionMask | ffi::ButtonMotionMask |
ffi::KeymapStateMask,
ffi::GrabModeAsync, ffi::GrabModeAsync,
self.x.window, 0, ffi::CurrentTime
) {
ffi::GrabSuccess => Ok(()),
ffi::AlreadyGrabbed | ffi::GrabInvalidTime |
ffi::GrabNotViewable | ffi::GrabFrozen
=> Err("cursor could not be grabbed".to_string()),
_ => unreachable!(),
}
}
},
_ => unimplemented!(),
} }
} }