From 18f9bc44c9c71d6d368a9e9255c1288b85ae509a Mon Sep 17 00:00:00 2001 From: Eduard Bopp Date: Sun, 25 Jan 2015 12:06:50 +0100 Subject: Implement grabbing of the mouse pointer for X11 Contains new methods in the Window API that closely mirror the Xlib API. The methods are left unimplemented for other platforms for now. --- src/android/mod.rs | 4 ++++ src/win32/mod.rs | 8 ++++++++ src/window.rs | 16 ++++++++++++++++ src/x11/ffi.rs | 15 +++++++++++++++ src/x11/window/mod.rs | 27 +++++++++++++++++++++++++++ 5 files changed, 70 insertions(+) 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 07f76e8..6b90f65 100644 --- a/src/win32/mod.rs +++ b/src/win32/mod.rs @@ -256,6 +256,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 12e8538..ad12e30 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 } -- cgit v1.2.3 From 77d033d672d5bcd6e3e933da682467e53414e934 Mon Sep 17 00:00:00 2001 From: Eduard Bopp Date: Wed, 25 Mar 2015 13:17:47 +0100 Subject: Add an example for (un-)grabbing the mouse cursor --- examples/grabbing.rs | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 examples/grabbing.rs 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"); + } + }, + _ => (), + } + + } + + } +} + -- cgit v1.2.3