Wayland: Fix panic when calling set_cursor_grab from a different thread than evlp's one. (#1206)

This commit also start following X11 behavior on cursor icon update when
cursor is invisible.

Fixes regression introdced in 5ced36e319
This commit is contained in:
Kirill Chibisov 2019-10-16 19:16:23 +03:00 committed by Osspial
parent 34dce8069f
commit 765225d918
2 changed files with 37 additions and 11 deletions

View file

@ -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<T: 'static> {
// Our sink, shared with some handlers, buffering the events
sink: Arc<Mutex<WindowEventsSink<T>>>,
pending_user_events: Rc<RefCell<VecDeque<T>>>,
// The cursor manager
cursor_manager: Arc<Mutex<CursorManager>>,
// Utility for grabbing the cursor and changing visibility
_user_source: ::calloop::Source<::calloop::channel::Channel<T>>,
user_sender: ::calloop::channel::Sender<T>,
@ -416,6 +423,7 @@ impl<T: 'static> EventLoop<T> {
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<T> EventLoop<T> {
}
// 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<T> EventLoop<T> {
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);
}
},
)
}