Refine Window::set_cursor_grab API
This commit renames `Window::set_cursor_grab` to `Window::set_cursor_grab_mode`. The new API now accepts enumeration to control the way cursor grab is performed. The value could be: `lock`, `confine`, or `none`. This commit also implements `Window::set_cursor_position` for Wayland, since it's tied to locked cursor. Implements API from #1677.
This commit is contained in:
parent
8ef9fe44c7
commit
9e6f666616
19 changed files with 359 additions and 131 deletions
|
|
@ -22,7 +22,7 @@ use crate::{
|
|||
MonitorHandle as PlatformMonitorHandle, OsError, PlatformSpecificWindowBuilderAttributes,
|
||||
VideoMode as PlatformVideoMode,
|
||||
},
|
||||
window::{CursorIcon, Fullscreen, Icon, UserAttentionType, WindowAttributes},
|
||||
window::{CursorGrabMode, CursorIcon, Fullscreen, Icon, UserAttentionType, WindowAttributes},
|
||||
};
|
||||
|
||||
use super::{
|
||||
|
|
@ -106,7 +106,7 @@ pub struct UnownedWindow {
|
|||
root: ffi::Window, // never changes
|
||||
screen_id: i32, // never changes
|
||||
cursor: Mutex<CursorIcon>,
|
||||
cursor_grabbed: Mutex<bool>,
|
||||
cursor_grabbed_mode: Mutex<CursorGrabMode>,
|
||||
cursor_visible: Mutex<bool>,
|
||||
ime_sender: Mutex<ImeSender>,
|
||||
pub shared_state: Mutex<SharedState>,
|
||||
|
|
@ -276,7 +276,7 @@ impl UnownedWindow {
|
|||
root,
|
||||
screen_id,
|
||||
cursor: Default::default(),
|
||||
cursor_grabbed: Mutex::new(false),
|
||||
cursor_grabbed_mode: Mutex::new(CursorGrabMode::None),
|
||||
cursor_visible: Mutex::new(true),
|
||||
ime_sender: Mutex::new(event_loop.ime_sender.clone()),
|
||||
shared_state: SharedState::new(guessed_monitor, &window_attrs),
|
||||
|
|
@ -1272,64 +1272,75 @@ impl UnownedWindow {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_cursor_grab(&self, grab: bool) -> Result<(), ExternalError> {
|
||||
let mut grabbed_lock = self.cursor_grabbed.lock();
|
||||
if grab == *grabbed_lock {
|
||||
pub fn set_cursor_grab(&self, mode: CursorGrabMode) -> Result<(), ExternalError> {
|
||||
let mut grabbed_lock = self.cursor_grabbed_mode.lock();
|
||||
if mode == *grabbed_lock {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
unsafe {
|
||||
// We ungrab before grabbing to prevent passive grabs from causing `AlreadyGrabbed`.
|
||||
// Therefore, this is common to both codepaths.
|
||||
(self.xconn.xlib.XUngrabPointer)(self.xconn.display, ffi::CurrentTime);
|
||||
}
|
||||
let result = if grab {
|
||||
let result = unsafe {
|
||||
(self.xconn.xlib.XGrabPointer)(
|
||||
self.xconn.display,
|
||||
self.xwindow,
|
||||
ffi::True,
|
||||
(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) as c_uint,
|
||||
ffi::GrabModeAsync,
|
||||
ffi::GrabModeAsync,
|
||||
self.xwindow,
|
||||
0,
|
||||
ffi::CurrentTime,
|
||||
)
|
||||
};
|
||||
|
||||
match result {
|
||||
ffi::GrabSuccess => Ok(()),
|
||||
ffi::AlreadyGrabbed => {
|
||||
Err("Cursor could not be grabbed: already grabbed by another client")
|
||||
}
|
||||
ffi::GrabInvalidTime => Err("Cursor could not be grabbed: invalid time"),
|
||||
ffi::GrabNotViewable => {
|
||||
Err("Cursor could not be grabbed: grab location not viewable")
|
||||
}
|
||||
ffi::GrabFrozen => Err("Cursor could not be grabbed: frozen by another client"),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
.map_err(|err| ExternalError::Os(os_error!(OsError::XMisc(err))))
|
||||
} else {
|
||||
self.xconn
|
||||
let result = match mode {
|
||||
CursorGrabMode::None => self
|
||||
.xconn
|
||||
.flush_requests()
|
||||
.map_err(|err| ExternalError::Os(os_error!(OsError::XError(err))))
|
||||
.map_err(|err| ExternalError::Os(os_error!(OsError::XError(err)))),
|
||||
CursorGrabMode::Confined => {
|
||||
let result = unsafe {
|
||||
(self.xconn.xlib.XGrabPointer)(
|
||||
self.xconn.display,
|
||||
self.xwindow,
|
||||
ffi::True,
|
||||
(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) as c_uint,
|
||||
ffi::GrabModeAsync,
|
||||
ffi::GrabModeAsync,
|
||||
self.xwindow,
|
||||
0,
|
||||
ffi::CurrentTime,
|
||||
)
|
||||
};
|
||||
|
||||
match result {
|
||||
ffi::GrabSuccess => Ok(()),
|
||||
ffi::AlreadyGrabbed => {
|
||||
Err("Cursor could not be confined: already confined by another client")
|
||||
}
|
||||
ffi::GrabInvalidTime => Err("Cursor could not be confined: invalid time"),
|
||||
ffi::GrabNotViewable => {
|
||||
Err("Cursor could not be confined: confine location not viewable")
|
||||
}
|
||||
ffi::GrabFrozen => {
|
||||
Err("Cursor could not be confined: frozen by another client")
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
.map_err(|err| ExternalError::Os(os_error!(OsError::XMisc(err))))
|
||||
}
|
||||
CursorGrabMode::Locked => {
|
||||
return Err(ExternalError::NotSupported(NotSupportedError::new()));
|
||||
}
|
||||
};
|
||||
|
||||
if result.is_ok() {
|
||||
*grabbed_lock = grab;
|
||||
*grabbed_lock = mode;
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
|
|
@ -1386,14 +1397,14 @@ impl UnownedWindow {
|
|||
|
||||
// we can't use `set_cursor_grab(false)` here because it doesn't run `XUngrabPointer`
|
||||
// if the cursor isn't currently grabbed
|
||||
let mut grabbed_lock = self.cursor_grabbed.lock();
|
||||
let mut grabbed_lock = self.cursor_grabbed_mode.lock();
|
||||
unsafe {
|
||||
(self.xconn.xlib.XUngrabPointer)(self.xconn.display, ffi::CurrentTime);
|
||||
}
|
||||
self.xconn
|
||||
.flush_requests()
|
||||
.map_err(|err| ExternalError::Os(os_error!(OsError::XError(err))))?;
|
||||
*grabbed_lock = false;
|
||||
*grabbed_lock = CursorGrabMode::None;
|
||||
|
||||
// we keep the lock until we are done
|
||||
self.xconn
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue