diff --git a/src/platform_impl/linux/wayland/event_loop.rs b/src/platform_impl/linux/wayland/event_loop.rs index cbe08799..ca922c5f 100644 --- a/src/platform_impl/linux/wayland/event_loop.rs +++ b/src/platform_impl/linux/wayland/event_loop.rs @@ -132,10 +132,11 @@ impl CursorManager { } pub fn set_cursor_icon(&mut self, cursor: CursorIcon) { - if self.cursor_visible && cursor != self.current_cursor { + if cursor != self.current_cursor { self.current_cursor = cursor; - - self.set_cursor_icon_impl(cursor); + if self.cursor_visible { + self.set_cursor_icon_impl(cursor); + } } } @@ -191,7 +192,11 @@ impl CursorManager { } } - pub fn grab_pointer(&mut self, surface: Option<&WlSurface>) { + // This function can only be called from a thread on which `pointer_constraints_proxy` event + // queue is located, so calling it directly from a Window doesn't work well, in case + // you've sent your window to another thread, so we need to pass cursor grab updates to + // the event loop and call this function from there. + fn grab_pointer(&mut self, surface: Option<&WlSurface>) { for locked_pointer in self.locked_pointers.drain(..) { locked_pointer.destroy(); } @@ -230,6 +235,8 @@ pub struct EventLoop { // Our sink, shared with some handlers, buffering the events sink: Arc>>, pending_user_events: Rc>>, + // The cursor manager + cursor_manager: Arc>, // Utility for grabbing the cursor and changing visibility _user_source: ::calloop::Source<::calloop::channel::Channel>, user_sender: ::calloop::channel::Sender, @@ -416,6 +423,7 @@ impl EventLoop { outputs: env.outputs.clone(), _user_source: user_source, user_sender, + cursor_manager, _kbd_source: kbd_source, window_target: RootELW { p: crate::platform_impl::EventLoopWindowTarget::Wayland(EventLoopWindowTarget { @@ -654,7 +662,16 @@ impl EventLoop { } // process pending resize/refresh window_target.store.lock().unwrap().for_each( - |newsize, size, new_dpi, refresh, frame_refresh, closed, wid, frame| { + |newsize, + size, + new_dpi, + refresh, + frame_refresh, + closed, + grab_cursor, + surface, + wid, + frame| { if let Some(frame) = frame { if let Some((w, h)) = newsize { frame.resize(w, h); @@ -684,6 +701,11 @@ impl EventLoop { if closed { sink.send_window_event(crate::event::WindowEvent::CloseRequested, wid); } + + if let Some(grab_cursor) = grab_cursor { + let surface = if grab_cursor { Some(surface) } else { None }; + self.cursor_manager.lock().unwrap().grab_pointer(surface); + } }, ) } diff --git a/src/platform_impl/linux/wayland/window.rs b/src/platform_impl/linux/wayland/window.rs index f94b8177..49849ba6 100644 --- a/src/platform_impl/linux/wayland/window.rs +++ b/src/platform_impl/linux/wayland/window.rs @@ -40,6 +40,7 @@ pub struct Window { need_frame_refresh: Arc>, need_refresh: Arc>, fullscreen: Arc>, + cursor_grab_changed: Arc>>, // Update grab state } impl Window { @@ -143,6 +144,7 @@ impl Window { let need_frame_refresh = Arc::new(Mutex::new(true)); let frame = Arc::new(Mutex::new(frame)); let need_refresh = Arc::new(Mutex::new(true)); + let cursor_grab_changed = Arc::new(Mutex::new(None)); evlp.store.lock().unwrap().windows.push(InternalWindow { closed: false, @@ -150,6 +152,7 @@ impl Window { size: size.clone(), need_refresh: need_refresh.clone(), fullscreen: fullscreen.clone(), + cursor_grab_changed: cursor_grab_changed.clone(), need_frame_refresh: need_frame_refresh.clone(), surface: surface.clone(), kill_switch: kill_switch.clone(), @@ -170,6 +173,7 @@ impl Window { need_refresh, cursor_manager, fullscreen, + cursor_grab_changed, }) } @@ -309,12 +313,7 @@ impl Window { #[inline] pub fn set_cursor_grab(&self, grab: bool) -> Result<(), ExternalError> { - let mut cursor_manager = self.cursor_manager.lock().unwrap(); - if grab { - cursor_manager.grab_pointer(Some(&self.surface)); - } else { - cursor_manager.grab_pointer(None); - } + *self.cursor_grab_changed.lock().unwrap() = Some(grab); Ok(()) } @@ -374,6 +373,7 @@ struct InternalWindow { need_refresh: Arc>, fullscreen: Arc>, need_frame_refresh: Arc>, + cursor_grab_changed: Arc>>, closed: bool, kill_switch: Arc>, frame: Weak>>, @@ -441,6 +441,8 @@ impl WindowStore { bool, bool, bool, + Option, + &wl_surface::WlSurface, WindowId, Option<&mut SWindow>, ), @@ -455,6 +457,8 @@ impl WindowStore { replace(&mut *window.need_refresh.lock().unwrap(), false), replace(&mut *window.need_frame_refresh.lock().unwrap(), false), window.closed, + window.cursor_grab_changed.lock().unwrap().take(), + &window.surface, make_wid(&window.surface), opt_mutex_lock.as_mut().map(|m| &mut **m), );