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
|
|
@ -17,7 +17,9 @@ use crate::platform_impl::{
|
|||
MonitorHandle as PlatformMonitorHandle, OsError,
|
||||
PlatformSpecificWindowBuilderAttributes as PlatformAttributes,
|
||||
};
|
||||
use crate::window::{CursorIcon, Fullscreen, Theme, UserAttentionType, WindowAttributes};
|
||||
use crate::window::{
|
||||
CursorGrabMode, CursorIcon, Fullscreen, Theme, UserAttentionType, WindowAttributes,
|
||||
};
|
||||
|
||||
use super::env::WindowingFeatures;
|
||||
use super::event_loop::WinitState;
|
||||
|
|
@ -72,6 +74,9 @@ pub struct Window {
|
|||
|
||||
/// Whether the window is decorated.
|
||||
decorated: AtomicBool,
|
||||
|
||||
/// Grabbing mode.
|
||||
cursor_grab_mode: Mutex<CursorGrabMode>,
|
||||
}
|
||||
|
||||
impl Window {
|
||||
|
|
@ -285,6 +290,7 @@ impl Window {
|
|||
windowing_features,
|
||||
resizeable: AtomicBool::new(attributes.resizable),
|
||||
decorated: AtomicBool::new(attributes.decorations),
|
||||
cursor_grab_mode: Mutex::new(CursorGrabMode::None),
|
||||
};
|
||||
|
||||
Ok(window)
|
||||
|
|
@ -474,12 +480,17 @@ impl Window {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_cursor_grab(&self, grab: bool) -> Result<(), ExternalError> {
|
||||
if !self.windowing_features.cursor_grab() {
|
||||
pub fn set_cursor_grab(&self, mode: CursorGrabMode) -> Result<(), ExternalError> {
|
||||
if !self.windowing_features.pointer_constraints() {
|
||||
if mode == CursorGrabMode::None {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
return Err(ExternalError::NotSupported(NotSupportedError::new()));
|
||||
}
|
||||
|
||||
self.send_request(WindowRequest::GrabCursor(grab));
|
||||
*self.cursor_grab_mode.lock().unwrap() = mode;
|
||||
self.send_request(WindowRequest::SetCursorGrabMode(mode));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -494,15 +505,19 @@ impl Window {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_cursor_position(&self, _: Position) -> Result<(), ExternalError> {
|
||||
// XXX This is possible if the locked pointer is being used. We don't have any
|
||||
// API for that right now, but it could be added in
|
||||
// https://github.com/rust-windowing/winit/issues/1677.
|
||||
//
|
||||
// This function is essential for the locked pointer API.
|
||||
//
|
||||
// See pointer-constraints-unstable-v1.xml.
|
||||
Err(ExternalError::NotSupported(NotSupportedError::new()))
|
||||
pub fn set_cursor_position(&self, position: Position) -> Result<(), ExternalError> {
|
||||
// Positon can be set only for locked cursor.
|
||||
if *self.cursor_grab_mode.lock().unwrap() != CursorGrabMode::Locked {
|
||||
return Err(ExternalError::Os(os_error!(OsError::WaylandMisc(
|
||||
"cursor position can be set only for locked cursor."
|
||||
))));
|
||||
}
|
||||
|
||||
let scale_factor = self.scale_factor() as f64;
|
||||
let position = position.to_logical(scale_factor);
|
||||
self.send_request(WindowRequest::SetLockedCursorPosition(position));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ use crate::platform_impl::wayland::event_loop::{EventSink, WinitState};
|
|||
use crate::platform_impl::wayland::seat::pointer::WinitPointer;
|
||||
use crate::platform_impl::wayland::seat::text_input::TextInputHandler;
|
||||
use crate::platform_impl::wayland::WindowId;
|
||||
use crate::window::{CursorIcon, Theme, UserAttentionType};
|
||||
use crate::window::{CursorGrabMode, CursorIcon, Theme, UserAttentionType};
|
||||
|
||||
use super::WinitFrame;
|
||||
|
||||
|
|
@ -40,8 +40,11 @@ pub enum WindowRequest {
|
|||
/// Change the cursor icon.
|
||||
NewCursorIcon(CursorIcon),
|
||||
|
||||
/// Grab cursor.
|
||||
GrabCursor(bool),
|
||||
/// Change cursor grabbing mode.
|
||||
SetCursorGrabMode(CursorGrabMode),
|
||||
|
||||
/// Set cursor position.
|
||||
SetLockedCursorPosition(LogicalPosition<u32>),
|
||||
|
||||
/// Drag window.
|
||||
DragWindow,
|
||||
|
|
@ -172,7 +175,7 @@ pub struct WindowHandle {
|
|||
cursor_visible: Cell<bool>,
|
||||
|
||||
/// Cursor confined to the surface.
|
||||
confined: Cell<bool>,
|
||||
cursor_grab_mode: Cell<CursorGrabMode>,
|
||||
|
||||
/// Pointers over the current surface.
|
||||
pointers: Vec<WinitPointer>,
|
||||
|
|
@ -208,7 +211,7 @@ impl WindowHandle {
|
|||
pending_window_requests,
|
||||
cursor_icon: Cell::new(CursorIcon::Default),
|
||||
is_resizable: Cell::new(true),
|
||||
confined: Cell::new(false),
|
||||
cursor_grab_mode: Cell::new(CursorGrabMode::None),
|
||||
cursor_visible: Cell::new(true),
|
||||
pointers: Vec::new(),
|
||||
text_inputs: Vec::new(),
|
||||
|
|
@ -219,24 +222,37 @@ impl WindowHandle {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn set_cursor_grab(&self, grab: bool) {
|
||||
pub fn set_cursor_grab(&self, mode: CursorGrabMode) {
|
||||
// The new requested state matches the current confine status, return.
|
||||
if self.confined.get() == grab {
|
||||
let old_mode = self.cursor_grab_mode.replace(mode);
|
||||
if old_mode == mode {
|
||||
return;
|
||||
}
|
||||
|
||||
self.confined.replace(grab);
|
||||
// Clear old pointer data.
|
||||
match old_mode {
|
||||
CursorGrabMode::None => (),
|
||||
CursorGrabMode::Confined => self.pointers.iter().for_each(|p| p.unconfine()),
|
||||
CursorGrabMode::Locked => self.pointers.iter().for_each(|p| p.unlock()),
|
||||
}
|
||||
|
||||
for pointer in self.pointers.iter() {
|
||||
if self.confined.get() {
|
||||
let surface = self.window.surface();
|
||||
pointer.confine(surface);
|
||||
} else {
|
||||
pointer.unconfine();
|
||||
let surface = self.window.surface();
|
||||
match mode {
|
||||
CursorGrabMode::Locked => self.pointers.iter().for_each(|p| p.lock(surface)),
|
||||
CursorGrabMode::Confined => self.pointers.iter().for_each(|p| p.confine(surface)),
|
||||
CursorGrabMode::None => {
|
||||
// Current lock/confine was already removed.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_locked_cursor_position(&self, position: LogicalPosition<u32>) {
|
||||
// XXX the cursor locking is ensured inside `Window`.
|
||||
self.pointers
|
||||
.iter()
|
||||
.for_each(|p| p.set_cursor_position(position.x, position.y));
|
||||
}
|
||||
|
||||
pub fn set_user_attention(&self, request_type: Option<UserAttentionType>) {
|
||||
let xdg_activation = match self.xdg_activation.as_ref() {
|
||||
None => return,
|
||||
|
|
@ -284,10 +300,13 @@ impl WindowHandle {
|
|||
let position = self.pointers.iter().position(|p| *p == pointer);
|
||||
|
||||
if position.is_none() {
|
||||
if self.confined.get() {
|
||||
let surface = self.window.surface();
|
||||
pointer.confine(surface);
|
||||
let surface = self.window.surface();
|
||||
match self.cursor_grab_mode.get() {
|
||||
CursorGrabMode::None => (),
|
||||
CursorGrabMode::Locked => pointer.lock(surface),
|
||||
CursorGrabMode::Confined => pointer.confine(surface),
|
||||
}
|
||||
|
||||
self.pointers.push(pointer);
|
||||
}
|
||||
|
||||
|
|
@ -302,9 +321,11 @@ impl WindowHandle {
|
|||
if let Some(position) = position {
|
||||
let pointer = self.pointers.remove(position);
|
||||
|
||||
// Drop the confined pointer.
|
||||
if self.confined.get() {
|
||||
pointer.unconfine();
|
||||
// Drop the grabbing mode.
|
||||
match self.cursor_grab_mode.get() {
|
||||
CursorGrabMode::None => (),
|
||||
CursorGrabMode::Locked => pointer.unlock(),
|
||||
CursorGrabMode::Confined => pointer.unconfine(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -428,8 +449,11 @@ pub fn handle_window_requests(winit_state: &mut WinitState) {
|
|||
let event_sink = &mut winit_state.event_sink;
|
||||
window_handle.set_ime_allowed(allow, event_sink);
|
||||
}
|
||||
WindowRequest::GrabCursor(grab) => {
|
||||
window_handle.set_cursor_grab(grab);
|
||||
WindowRequest::SetCursorGrabMode(mode) => {
|
||||
window_handle.set_cursor_grab(mode);
|
||||
}
|
||||
WindowRequest::SetLockedCursorPosition(position) => {
|
||||
window_handle.set_locked_cursor_position(position);
|
||||
}
|
||||
WindowRequest::DragWindow => {
|
||||
window_handle.drag_window();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue