diff options
author | tomaka <pierre.krieger1708@gmail.com> | 2015-03-26 16:48:40 +0100 |
---|---|---|
committer | tomaka <pierre.krieger1708@gmail.com> | 2015-03-26 16:48:40 +0100 |
commit | d6ebaaaf5cbb1839e74c3c7c0573b1f842c59e6b (patch) | |
tree | 1e09474e9664d06ca0bb5539afe849348bba8c51 | |
parent | 506c2bca27abbdec446a6683c665025ba4350ae8 (diff) | |
parent | 77d033d672d5bcd6e3e933da682467e53414e934 (diff) | |
download | glutin-d6ebaaaf5cbb1839e74c3c7c0573b1f842c59e6b.tar.gz glutin-d6ebaaaf5cbb1839e74c3c7c0573b1f842c59e6b.zip |
Merge pull request #227 from aepsil0n/grab-cursor
Implement grabbing of the mouse pointer for X11
-rw-r--r-- | examples/grabbing.rs | 50 | ||||
-rw-r--r-- | src/android/mod.rs | 4 | ||||
-rw-r--r-- | src/win32/mod.rs | 8 | ||||
-rw-r--r-- | src/window.rs | 16 | ||||
-rw-r--r-- | src/x11/ffi.rs | 15 | ||||
-rw-r--r-- | src/x11/window/mod.rs | 27 |
6 files changed, 120 insertions, 0 deletions
diff --git a/examples/grabbing.rs b/examples/grabbing.rs new file mode 100644 index 0000000..436dd9b --- /dev/null +++ b/examples/grabbing.rs @@ -0,0 +1,50 @@ +#[cfg(target_os = "android")] +#[macro_use] +extern crate android_glue; + +extern crate glutin; + +use glutin::{Event, ElementState}; + +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 main() { + + let window = glutin::Window::new().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() { + 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.ungrab_cursor(); + } + else { + grabbed = true; + window.grab_cursor().ok().expect("could not grab mouse cursor"); + } + }, + _ => (), + } + + } + + } +} + diff --git a/src/android/mod.rs b/src/android/mod.rs index 71dae54..653ae39 100644 --- a/src/android/mod.rs +++ b/src/android/mod.rs @@ -358,6 +358,10 @@ impl Window { pub fn set_cursor(&self, _: MouseCursor) { } + pub fn grab_cursor(&self) -> Result<(), String> { Ok(()) } + + pub fn ungrab_cursor(&self) {} + pub fn hidpi_factor(&self) -> f32 { 1.0 } diff --git a/src/win32/mod.rs b/src/win32/mod.rs index 380342e..9daf0c3 100644 --- a/src/win32/mod.rs +++ b/src/win32/mod.rs @@ -255,6 +255,14 @@ impl Window { unimplemented!() } + pub fn grab_cursor(&self) -> Result<(), String> { + unimplemented!() + } + + pub fn ungrab_cursor(&self) { + unimplemented!() + } + pub fn hidpi_factor(&self) -> f32 { 1.0 } diff --git a/src/window.rs b/src/window.rs index d670e04..22fd400 100644 --- a/src/window.rs +++ b/src/window.rs @@ -414,6 +414,22 @@ impl Window { pub fn set_cursor_position(&self, x: i32, y: i32) -> Result<(), ()> { self.window.set_cursor_position(x, y) } + + /// 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. + /// 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. + pub fn grab_cursor(&self) -> Result<(), String> { + self.window.grab_cursor() + } + + /// Release a previously grabbed mouse cursor. + pub fn ungrab_cursor(&self) { + self.window.ungrab_cursor(); + } + } impl gl_common::GlFunctionsSource for Window { diff --git a/src/x11/ffi.rs b/src/x11/ffi.rs index 1d91cab..e33ea24 100644 --- a/src/x11/ffi.rs +++ b/src/x11/ffi.rs @@ -42,6 +42,17 @@ pub const Button5: libc::c_uint = 5; pub const InputOutput: libc::c_uint = 1; pub const InputOnly: libc::c_uint = 2; +pub const CurrentTime: Time = 0; + +pub const GrabModeSync: libc::c_int = 0; +pub const GrabModeAsync: libc::c_int = 1; + +pub const GrabSuccess: libc::c_int = 0; +pub const AlreadyGrabbed: libc::c_int = 1; +pub const GrabInvalidTime: libc::c_int = 2; +pub const GrabNotViewable: libc::c_int = 3; +pub const GrabFrozen: libc::c_int = 4; + pub const CWBackPixmap: libc::c_ulong = (1<<0); pub const CWBackPixel: libc::c_ulong = (1<<1); pub const CWBorderPixmap: libc::c_ulong = (1<<2); @@ -1470,6 +1481,10 @@ extern "C" { pub fn XcursorLibraryLoadCursor(dpy: *mut Display, name: *const libc::c_char) -> Cursor; pub fn XDefineCursor(dby: *mut Display, w: Window, cursor: Cursor); + pub fn XGrabPointer(dpy: *mut Display, w: Window, owner_events: bool, event_mask: libc::c_long, + pointer_mode: libc::c_int, keyboard_mode: libc::c_int, confine_to: Window, cursor: Cursor, + time: Time) -> libc::c_int; + pub fn XUngrabPointer(dpy: *mut Display, time: Time); } /* diff --git a/src/x11/window/mod.rs b/src/x11/window/mod.rs index 385a913..d576150 100644 --- a/src/x11/window/mod.rs +++ b/src/x11/window/mod.rs @@ -782,6 +782,33 @@ impl Window { } } + pub fn grab_cursor(&self) -> Result<(), String> { + unsafe { + 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) { + unsafe { + ffi::XUngrabPointer(self.x.display, ffi::CurrentTime); + } + } + pub fn hidpi_factor(&self) -> f32 { 1.0 } |