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) { 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.current_cursor = cursor;
if self.cursor_visible {
self.set_cursor_icon_impl(cursor); 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(..) { for locked_pointer in self.locked_pointers.drain(..) {
locked_pointer.destroy(); locked_pointer.destroy();
} }
@ -230,6 +235,8 @@ pub struct EventLoop<T: 'static> {
// Our sink, shared with some handlers, buffering the events // Our sink, shared with some handlers, buffering the events
sink: Arc<Mutex<WindowEventsSink<T>>>, sink: Arc<Mutex<WindowEventsSink<T>>>,
pending_user_events: Rc<RefCell<VecDeque<T>>>, pending_user_events: Rc<RefCell<VecDeque<T>>>,
// The cursor manager
cursor_manager: Arc<Mutex<CursorManager>>,
// Utility for grabbing the cursor and changing visibility // Utility for grabbing the cursor and changing visibility
_user_source: ::calloop::Source<::calloop::channel::Channel<T>>, _user_source: ::calloop::Source<::calloop::channel::Channel<T>>,
user_sender: ::calloop::channel::Sender<T>, user_sender: ::calloop::channel::Sender<T>,
@ -416,6 +423,7 @@ impl<T: 'static> EventLoop<T> {
outputs: env.outputs.clone(), outputs: env.outputs.clone(),
_user_source: user_source, _user_source: user_source,
user_sender, user_sender,
cursor_manager,
_kbd_source: kbd_source, _kbd_source: kbd_source,
window_target: RootELW { window_target: RootELW {
p: crate::platform_impl::EventLoopWindowTarget::Wayland(EventLoopWindowTarget { p: crate::platform_impl::EventLoopWindowTarget::Wayland(EventLoopWindowTarget {
@ -654,7 +662,16 @@ impl<T> EventLoop<T> {
} }
// process pending resize/refresh // process pending resize/refresh
window_target.store.lock().unwrap().for_each( 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(frame) = frame {
if let Some((w, h)) = newsize { if let Some((w, h)) = newsize {
frame.resize(w, h); frame.resize(w, h);
@ -684,6 +701,11 @@ impl<T> EventLoop<T> {
if closed { if closed {
sink.send_window_event(crate::event::WindowEvent::CloseRequested, wid); 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);
}
}, },
) )
} }

View file

@ -40,6 +40,7 @@ pub struct Window {
need_frame_refresh: Arc<Mutex<bool>>, need_frame_refresh: Arc<Mutex<bool>>,
need_refresh: Arc<Mutex<bool>>, need_refresh: Arc<Mutex<bool>>,
fullscreen: Arc<Mutex<bool>>, fullscreen: Arc<Mutex<bool>>,
cursor_grab_changed: Arc<Mutex<Option<bool>>>, // Update grab state
} }
impl Window { impl Window {
@ -143,6 +144,7 @@ impl Window {
let need_frame_refresh = Arc::new(Mutex::new(true)); let need_frame_refresh = Arc::new(Mutex::new(true));
let frame = Arc::new(Mutex::new(frame)); let frame = Arc::new(Mutex::new(frame));
let need_refresh = Arc::new(Mutex::new(true)); let need_refresh = Arc::new(Mutex::new(true));
let cursor_grab_changed = Arc::new(Mutex::new(None));
evlp.store.lock().unwrap().windows.push(InternalWindow { evlp.store.lock().unwrap().windows.push(InternalWindow {
closed: false, closed: false,
@ -150,6 +152,7 @@ impl Window {
size: size.clone(), size: size.clone(),
need_refresh: need_refresh.clone(), need_refresh: need_refresh.clone(),
fullscreen: fullscreen.clone(), fullscreen: fullscreen.clone(),
cursor_grab_changed: cursor_grab_changed.clone(),
need_frame_refresh: need_frame_refresh.clone(), need_frame_refresh: need_frame_refresh.clone(),
surface: surface.clone(), surface: surface.clone(),
kill_switch: kill_switch.clone(), kill_switch: kill_switch.clone(),
@ -170,6 +173,7 @@ impl Window {
need_refresh, need_refresh,
cursor_manager, cursor_manager,
fullscreen, fullscreen,
cursor_grab_changed,
}) })
} }
@ -309,12 +313,7 @@ impl Window {
#[inline] #[inline]
pub fn set_cursor_grab(&self, grab: bool) -> Result<(), ExternalError> { pub fn set_cursor_grab(&self, grab: bool) -> Result<(), ExternalError> {
let mut cursor_manager = self.cursor_manager.lock().unwrap(); *self.cursor_grab_changed.lock().unwrap() = Some(grab);
if grab {
cursor_manager.grab_pointer(Some(&self.surface));
} else {
cursor_manager.grab_pointer(None);
}
Ok(()) Ok(())
} }
@ -374,6 +373,7 @@ struct InternalWindow {
need_refresh: Arc<Mutex<bool>>, need_refresh: Arc<Mutex<bool>>,
fullscreen: Arc<Mutex<bool>>, fullscreen: Arc<Mutex<bool>>,
need_frame_refresh: Arc<Mutex<bool>>, need_frame_refresh: Arc<Mutex<bool>>,
cursor_grab_changed: Arc<Mutex<Option<bool>>>,
closed: bool, closed: bool,
kill_switch: Arc<Mutex<bool>>, kill_switch: Arc<Mutex<bool>>,
frame: Weak<Mutex<SWindow<ConceptFrame>>>, frame: Weak<Mutex<SWindow<ConceptFrame>>>,
@ -441,6 +441,8 @@ impl WindowStore {
bool, bool,
bool, bool,
bool, bool,
Option<bool>,
&wl_surface::WlSurface,
WindowId, WindowId,
Option<&mut SWindow<ConceptFrame>>, Option<&mut SWindow<ConceptFrame>>,
), ),
@ -455,6 +457,8 @@ impl WindowStore {
replace(&mut *window.need_refresh.lock().unwrap(), false), replace(&mut *window.need_refresh.lock().unwrap(), false),
replace(&mut *window.need_frame_refresh.lock().unwrap(), false), replace(&mut *window.need_frame_refresh.lock().unwrap(), false),
window.closed, window.closed,
window.cursor_grab_changed.lock().unwrap().take(),
&window.surface,
make_wid(&window.surface), make_wid(&window.surface),
opt_mutex_lock.as_mut().map(|m| &mut **m), opt_mutex_lock.as_mut().map(|m| &mut **m),
); );