From 34348435fd926cbb6080f4ca2c3ff750459f87fd Mon Sep 17 00:00:00 2001 From: Osspial Date: Fri, 27 Sep 2019 17:35:16 -0400 Subject: [PATCH 1/4] Update to 1.38.0 formatting (#1188) --- src/platform_impl/ios/view.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/platform_impl/ios/view.rs b/src/platform_impl/ios/view.rs index 5868059b47..6f712dd30f 100644 --- a/src/platform_impl/ios/view.rs +++ b/src/platform_impl/ios/view.rs @@ -500,9 +500,7 @@ pub unsafe fn create_window( let () = msg_send![uiscreen, setCurrentMode: video_mode.video_mode.screen_mode]; msg_send![window, setScreen:video_mode.monitor().ui_screen()] } - Some(Fullscreen::Borderless(ref monitor)) => { - msg_send![window, setScreen:monitor.ui_screen()] - } + Some(Fullscreen::Borderless(ref monitor)) => msg_send![window, setScreen:monitor.ui_screen()], None => (), } From 18a0119b06e5922d4a4759b5167b413fdd29179f Mon Sep 17 00:00:00 2001 From: msiglreith Date: Mon, 30 Sep 2019 17:17:01 +0200 Subject: [PATCH 2/4] Update raw-window-handle to 0.2 (#1191) --- Cargo.toml | 2 +- src/platform_impl/android/mod.rs | 10 ++++++++++ src/platform_impl/linux/mod.rs | 2 +- src/platform_impl/linux/x11/window.rs | 8 ++++---- 4 files changed, 16 insertions(+), 6 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index cc992c6a1c..3e8161db35 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,7 @@ libc = "0.2" log = "0.4" serde = { version = "1", optional = true, features = ["serde_derive"] } derivative = "1.0.2" -raw-window-handle = "0.1" +raw-window-handle = "0.2" [dev-dependencies] image = "0.21" diff --git a/src/platform_impl/android/mod.rs b/src/platform_impl/android/mod.rs index f88251ea86..2c05e4bbe7 100644 --- a/src/platform_impl/android/mod.rs +++ b/src/platform_impl/android/mod.rs @@ -19,6 +19,7 @@ use crate::{ CreationError, CursorIcon, Event, LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize, WindowAttributes, WindowEvent, WindowId as RootWindowId, }; +use raw_window_handle::{android::AndroidHandle, RawWindowHandle}; use CreationError::OsError; pub type OsError = std::io::Error; @@ -421,6 +422,15 @@ impl Window { pub fn id(&self) -> WindowId { WindowId } + + #[inline] + pub fn raw_window_handle(&self) -> RawWindowHandle { + let handle = AndroidHandle { + a_native_window: self.native_window, + ..WindowsHandle::empty() + }; + RawWindowHandle::Android(handle) + } } unsafe impl Send for Window {} diff --git a/src/platform_impl/linux/mod.rs b/src/platform_impl/linux/mod.rs index 60430a2c40..7b71de280f 100644 --- a/src/platform_impl/linux/mod.rs +++ b/src/platform_impl/linux/mod.rs @@ -461,7 +461,7 @@ impl Window { pub fn raw_window_handle(&self) -> RawWindowHandle { match self { - &Window::X(ref window) => RawWindowHandle::X11(window.raw_window_handle()), + &Window::X(ref window) => RawWindowHandle::Xlib(window.raw_window_handle()), &Window::Wayland(ref window) => RawWindowHandle::Wayland(window.raw_window_handle()), } } diff --git a/src/platform_impl/linux/x11/window.rs b/src/platform_impl/linux/x11/window.rs index cf7759ecd3..305414f10e 100644 --- a/src/platform_impl/linux/x11/window.rs +++ b/src/platform_impl/linux/x11/window.rs @@ -1,4 +1,4 @@ -use raw_window_handle::unix::X11Handle; +use raw_window_handle::unix::XlibHandle; use std::{ cmp, collections::HashSet, @@ -1296,11 +1296,11 @@ impl UnownedWindow { } #[inline] - pub fn raw_window_handle(&self) -> X11Handle { - X11Handle { + pub fn raw_window_handle(&self) -> XlibHandle { + XlibHandle { window: self.xwindow, display: self.xconn.display as _, - ..X11Handle::empty() + ..XlibHandle::empty() } } } From 237e7ee2e603524c5652192521a94e62db9c823c Mon Sep 17 00:00:00 2001 From: andersrein Date: Wed, 2 Oct 2019 03:25:59 +0200 Subject: [PATCH 3/4] Wayland support for set_cursor_grab and set_cursor_visible (#1180) * Fixed relative_pointer not being set up when the "zwp_relative_pointer_manager_v1" callback comes after the "wl_seat" callback * Ran cargo fmt * Updated changelog * Added wayland support for set_grab_cursor and set_cursor_visible * Updated changelog * Ran cargo fmt * Fixed set_cursor_visible and set_cursor_grab so they can be called from any thread. * Ran cargo_fmt * Improved CHANGELOG * Added workaround so that when cursor is hidden it takes effect before the cursor enters the surface. Making the cursor visible again still only happens once the cursor re-enters the surface * Switched to using Rc instead of Arc since all accesses to the relative_pointer_manager_proxy will happen on the same thread. * Forgot to run cargo fmt * Switched to using Rc and RefCell instead of Arc and Mutex where applicable. * Improved comments and documentation relating to changing a hidden cursor back to visible on wayland. * Wayland: Fixed cursor not appearing immendiately when setting the cursor to visible. * Forgot to run cargo fmt * Switched to only storing the pointers in CursorManager as AutoPointer. * Fixed typo and removed println * Update CHANGELOG.md Co-Authored-By: Kirill Chibisov --- CHANGELOG.md | 1 + src/platform_impl/linux/wayland/event_loop.rs | 159 +++++++++++++++++- src/platform_impl/linux/wayland/pointer.rs | 24 +++ src/platform_impl/linux/wayland/window.rs | 25 ++- src/window.rs | 3 + 5 files changed, 207 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5be8107c0b..7a32a84551 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ - On X11, return dummy monitor data to avoid panicking when no monitors exist. - On X11, prevent stealing input focus when creating a new window. Only steal input focus when entering fullscreen mode. +- On Wayland, add support for set_cursor_visible and set_cursor_grab. - On Wayland, fixed DeviceEvents for relative mouse movement is not always produced # 0.20.0 Alpha 3 (2019-08-14) diff --git a/src/platform_impl/linux/wayland/event_loop.rs b/src/platform_impl/linux/wayland/event_loop.rs index 272fc832f3..0d8a24d6b8 100644 --- a/src/platform_impl/linux/wayland/event_loop.rs +++ b/src/platform_impl/linux/wayland/event_loop.rs @@ -7,11 +7,19 @@ use std::{ time::Instant, }; +use smithay_client_toolkit::reexports::protocols::unstable::pointer_constraints::v1::client::{ + zwp_locked_pointer_v1::ZwpLockedPointerV1, zwp_pointer_constraints_v1::ZwpPointerConstraintsV1, +}; use smithay_client_toolkit::reexports::protocols::unstable::relative_pointer::v1::client::{ zwp_relative_pointer_manager_v1::ZwpRelativePointerManagerV1, zwp_relative_pointer_v1::ZwpRelativePointerV1, }; +use smithay_client_toolkit::pointer::{AutoPointer, AutoThemer}; +use smithay_client_toolkit::reexports::client::protocol::{ + wl_compositor::WlCompositor, wl_shm::WlShm, wl_surface::WlSurface, +}; + use crate::{ dpi::{PhysicalPosition, PhysicalSize}, event::ModifiersState, @@ -69,6 +77,79 @@ impl WindowEventsSink { } } +pub struct CursorManager { + pointer_constraints_proxy: Rc>>, + auto_themer: Option, + pointers: Vec, + locked_pointers: Vec, + cursor_visible: Rc>, +} + +impl CursorManager { + fn new(constraints: Rc>>) -> CursorManager { + CursorManager { + pointer_constraints_proxy: constraints, + auto_themer: None, + pointers: Vec::new(), + locked_pointers: Vec::new(), + cursor_visible: Rc::new(RefCell::new(true)), + } + } + + fn register_pointer(&mut self, pointer: wl_pointer::WlPointer) { + let auto_themer = self + .auto_themer + .as_ref() + .expect("AutoThemer not initialized. Server did not advertise shm or compositor?"); + self.pointers.push(auto_themer.theme_pointer(pointer)); + } + + fn set_auto_themer(&mut self, auto_themer: AutoThemer) { + self.auto_themer = Some(auto_themer); + } + + fn set_cursor_visible(&mut self, visible: bool) { + if !visible { + for pointer in self.pointers.iter() { + (**pointer).set_cursor(0, None, 0, 0); + } + } else { + for pointer in self.pointers.iter() { + pointer.set_cursor("left_ptr", None).unwrap(); + } + } + (*self.cursor_visible.try_borrow_mut().unwrap()) = visible; + } + + fn grab_pointer(&mut self, surface: Option<&WlSurface>) { + for lp in self.locked_pointers.drain(..) { + lp.destroy(); + } + + if let Some(surface) = surface { + for pointer in self.pointers.iter() { + let locked_pointer = self + .pointer_constraints_proxy + .try_borrow() + .unwrap() + .as_ref() + .and_then(|pointer_constraints| { + super::pointer::implement_locked_pointer( + surface, + &**pointer, + pointer_constraints, + ) + .ok() + }); + + if let Some(locked_pointer) = locked_pointer { + self.locked_pointers.push(locked_pointer); + } + } + } + } +} + pub struct EventLoop { // The loop inner_loop: ::calloop::EventLoop<()>, @@ -79,6 +160,8 @@ pub struct EventLoop { // our sink, shared with some handlers, buffering the events sink: Arc>>, pending_user_events: Rc>>, + // Utility for grabbing the cursor and changing visibility + cursor_manager: Rc>, _user_source: ::calloop::Source<::calloop::channel::Channel>, user_sender: ::calloop::channel::Sender, _kbd_source: ::calloop::Source< @@ -146,14 +229,24 @@ impl EventLoop { }) .unwrap(); + let pointer_constraints_proxy = Rc::new(RefCell::new(None)); + let mut seat_manager = SeatManager { sink: sink.clone(), relative_pointer_manager_proxy: Rc::new(RefCell::new(None)), + pointer_constraints_proxy: pointer_constraints_proxy.clone(), store: store.clone(), seats: seats.clone(), kbd_sender, + cursor_manager: Rc::new(RefCell::new(CursorManager::new(pointer_constraints_proxy))), }; + let cursor_manager = seat_manager.cursor_manager.clone(); + let cursor_manager2 = cursor_manager.clone(); + + let shm_cell = Rc::new(RefCell::new(None)); + let compositor_cell = Rc::new(RefCell::new(None)); + let env = Environment::from_display_with_cb( &display, &mut event_queue, @@ -175,6 +268,39 @@ impl EventLoop { .try_borrow_mut() .unwrap() = Some(relative_pointer_manager_proxy); } + if interface == "zwp_pointer_constraints_v1" { + let pointer_constraints_proxy = registry + .bind(version, id, move |pointer_constraints| { + pointer_constraints.implement_closure(|_, _| (), ()) + }) + .unwrap(); + + *seat_manager.pointer_constraints_proxy.borrow_mut() = + Some(pointer_constraints_proxy); + } + if interface == "wl_shm" { + let shm: WlShm = registry + .bind(version, id, move |shm| shm.implement_closure(|_, _| (), ())) + .unwrap(); + + (*shm_cell.borrow_mut()) = Some(shm); + } + if interface == "wl_compositor" { + let compositor: WlCompositor = registry + .bind(version, id, move |compositor| { + compositor.implement_closure(|_, _| (), ()) + }) + .unwrap(); + (*compositor_cell.borrow_mut()) = Some(compositor); + } + + if compositor_cell.borrow().is_some() && shm_cell.borrow().is_some() { + let compositor = compositor_cell.borrow_mut().take().unwrap(); + let shm = shm_cell.borrow_mut().take().unwrap(); + let auto_themer = AutoThemer::init(None, compositor, &shm); + cursor_manager2.borrow_mut().set_auto_themer(auto_themer); + } + if interface == "wl_seat" { seat_manager.add_seat(id, version, registry) } @@ -213,6 +339,7 @@ impl EventLoop { pending_user_events, display: display.clone(), outputs: env.outputs.clone(), + cursor_manager, _user_source: user_source, user_sender, _kbd_source: kbd_source, @@ -452,7 +579,17 @@ 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, + cursor_visible, + cursor_grab, + surface, + wid, + frame| { if let Some(frame) = frame { if let Some((w, h)) = newsize { frame.resize(w, h); @@ -482,6 +619,17 @@ impl EventLoop { if closed { sink.send_window_event(crate::event::WindowEvent::CloseRequested, wid); } + if let Some(grab) = cursor_grab { + self.cursor_manager.borrow_mut().grab_pointer(if grab { + Some(surface) + } else { + None + }); + } + + if let Some(visible) = cursor_visible { + self.cursor_manager.borrow_mut().set_cursor_visible(visible); + } }, ) } @@ -497,6 +645,8 @@ struct SeatManager { seats: Arc>>, kbd_sender: ::calloop::channel::Sender<(crate::event::WindowEvent, super::WindowId)>, relative_pointer_manager_proxy: Rc>>, + pointer_constraints_proxy: Rc>>, + cursor_manager: Rc>, } impl SeatManager { @@ -513,6 +663,7 @@ impl SeatManager { touch: None, kbd_sender: self.kbd_sender.clone(), modifiers_tracker: Arc::new(Mutex::new(ModifiersState::default())), + cursor_manager: self.cursor_manager.clone(), }; let seat = registry .bind(min(version, 5), id, move |seat| { @@ -544,6 +695,7 @@ struct SeatData { keyboard: Option, touch: Option, modifiers_tracker: Arc>, + cursor_manager: Rc>, } impl SeatData { @@ -558,8 +710,13 @@ impl SeatData { self.sink.clone(), self.store.clone(), self.modifiers_tracker.clone(), + self.cursor_manager.borrow().cursor_visible.clone(), )); + self.cursor_manager + .borrow_mut() + .register_pointer(self.pointer.as_ref().unwrap().clone()); + self.relative_pointer = self .relative_pointer_manager_proxy .try_borrow() diff --git a/src/platform_impl/linux/wayland/pointer.rs b/src/platform_impl/linux/wayland/pointer.rs index 7ffcdd72df..1a0cff9f66 100644 --- a/src/platform_impl/linux/wayland/pointer.rs +++ b/src/platform_impl/linux/wayland/pointer.rs @@ -1,3 +1,5 @@ +use std::cell::RefCell; +use std::rc::Rc; use std::sync::{Arc, Mutex}; use crate::event::{ @@ -17,11 +19,19 @@ use smithay_client_toolkit::reexports::protocols::unstable::relative_pointer::v1 zwp_relative_pointer_v1::ZwpRelativePointerV1, }; +use smithay_client_toolkit::reexports::protocols::unstable::pointer_constraints::v1::client::{ + zwp_locked_pointer_v1::ZwpLockedPointerV1, zwp_pointer_constraints_v1::Lifetime, + zwp_pointer_constraints_v1::ZwpPointerConstraintsV1, +}; + +use smithay_client_toolkit::reexports::client::protocol::wl_surface::WlSurface; + pub fn implement_pointer( seat: &wl_seat::WlSeat, sink: Arc>>, store: Arc>, modifiers_tracker: Arc>, + cursor_visible: Rc>, ) -> WlPointer { seat.get_pointer(|pointer| { let mut mouse_focus = None; @@ -62,6 +72,10 @@ pub fn implement_pointer( wid, ); } + + if *cursor_visible.borrow() == false { + pointer.set_cursor(0, None, 0, 0); + } } PtrEvent::Leave { surface, .. } => { mouse_focus = None; @@ -241,3 +255,13 @@ pub fn implement_relative_pointer( ) }) } + +pub fn implement_locked_pointer( + surface: &WlSurface, + pointer: &WlPointer, + constraints: &ZwpPointerConstraintsV1, +) -> Result { + constraints.lock_pointer(surface, pointer, None, Lifetime::Persistent.to_raw(), |c| { + c.implement_closure(|_, _| (), ()) + }) +} diff --git a/src/platform_impl/linux/wayland/window.rs b/src/platform_impl/linux/wayland/window.rs index ddd4b4b9f0..9fdde832e3 100644 --- a/src/platform_impl/linux/wayland/window.rs +++ b/src/platform_impl/linux/wayland/window.rs @@ -38,6 +38,8 @@ pub struct Window { need_frame_refresh: Arc>, need_refresh: Arc>, fullscreen: Arc>, + cursor_grab_changed: Arc>>, + cursor_visible_changed: Arc>>, } impl Window { @@ -140,6 +142,8 @@ 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)); + let cursor_visible_changed = Arc::new(Mutex::new(None)); evlp.store.lock().unwrap().windows.push(InternalWindow { closed: false, @@ -148,6 +152,8 @@ impl Window { need_refresh: need_refresh.clone(), fullscreen: fullscreen.clone(), need_frame_refresh: need_frame_refresh.clone(), + cursor_grab_changed: cursor_grab_changed.clone(), + cursor_visible_changed: cursor_visible_changed.clone(), surface: surface.clone(), kill_switch: kill_switch.clone(), frame: Arc::downgrade(&frame), @@ -166,6 +172,8 @@ impl Window { need_frame_refresh, need_refresh, fullscreen, + cursor_grab_changed, + cursor_visible_changed, }) } @@ -297,13 +305,14 @@ impl Window { } #[inline] - pub fn set_cursor_visible(&self, _visible: bool) { - // TODO: This isn't possible on Wayland yet + pub fn set_cursor_visible(&self, visible: bool) { + *self.cursor_visible_changed.lock().unwrap() = Some(visible); } #[inline] - pub fn set_cursor_grab(&self, _grab: bool) -> Result<(), ExternalError> { - Err(ExternalError::NotSupported(NotSupportedError::new())) + pub fn set_cursor_grab(&self, grab: bool) -> Result<(), ExternalError> { + *self.cursor_grab_changed.lock().unwrap() = Some(grab); + Ok(()) } #[inline] @@ -362,6 +371,8 @@ struct InternalWindow { need_refresh: Arc>, fullscreen: Arc>, need_frame_refresh: Arc>, + cursor_grab_changed: Arc>>, + cursor_visible_changed: Arc>>, closed: bool, kill_switch: Arc>, frame: Weak>>, @@ -429,6 +440,9 @@ impl WindowStore { bool, bool, bool, + Option, + Option, + &wl_surface::WlSurface, WindowId, Option<&mut SWindow>, ), @@ -443,6 +457,9 @@ impl WindowStore { ::std::mem::replace(&mut *window.need_refresh.lock().unwrap(), false), ::std::mem::replace(&mut *window.need_frame_refresh.lock().unwrap(), false), window.closed, + window.cursor_visible_changed.lock().unwrap().take(), + window.cursor_grab_changed.lock().unwrap().take(), + &window.surface, make_wid(&window.surface), opt_mutex_lock.as_mut().map(|m| &mut **m), ); diff --git a/src/window.rs b/src/window.rs index 1eaeec477f..248c8317d3 100644 --- a/src/window.rs +++ b/src/window.rs @@ -655,6 +655,8 @@ impl Window { /// /// - **macOS:** This presently merely locks the cursor in a fixed location, which looks visually /// awkward. + /// - **Wayland:** This presently merely locks the cursor in a fixed location, which looks visually + /// awkward. /// - **Android:** Has no effect. /// - **iOS:** Always returns an Err. #[inline] @@ -670,6 +672,7 @@ impl Window { /// /// - **Windows:** The cursor is only hidden within the confines of the window. /// - **X11:** The cursor is only hidden within the confines of the window. + /// - **Wayland:** The cursor is only hidden within the confines of the window. /// - **macOS:** The cursor is hidden as long as the window has input focus, even if the cursor is /// outside of the window. /// - **iOS:** Has no effect. From 5ced36e319d55178dd943de033e4aacdbd0d0327 Mon Sep 17 00:00:00 2001 From: Kirill Chibisov Date: Thu, 3 Oct 2019 16:02:59 +0300 Subject: [PATCH 4/4] Wayland support for set_cursor_icon (#1204) --- CHANGELOG.md | 1 + FEATURES.md | 4 +- src/platform_impl/linux/wayland/event_loop.rs | 163 ++++++++++++------ src/platform_impl/linux/wayland/pointer.rs | 15 +- src/platform_impl/linux/wayland/window.rs | 41 ++--- 5 files changed, 138 insertions(+), 86 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7a32a84551..282a8dd69c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ Only steal input focus when entering fullscreen mode. - On Wayland, add support for set_cursor_visible and set_cursor_grab. - On Wayland, fixed DeviceEvents for relative mouse movement is not always produced +- On Wayland, add support for set_cursor_icon. # 0.20.0 Alpha 3 (2019-08-14) diff --git a/FEATURES.md b/FEATURES.md index 9610b7ba11..d634eaf504 100644 --- a/FEATURES.md +++ b/FEATURES.md @@ -190,8 +190,8 @@ Legend: |----------------------- | ----- | ---- | ------- | ----------- | ----- | ----- | -------- | |Mouse events |✔️ |▢[#63] |✔️ |✔️ |**N/A**|**N/A**|❓ | |Mouse set location |✔️ |✔️ |✔️ |❓ |**N/A**|**N/A**|❓ | -|Cursor grab |✔️ |▢[#165] |▢[#242] |❌[#306] |**N/A**|**N/A**|❓ | -|Cursor icon |✔️ |✔️ |✔️ |❌[#306] |**N/A**|**N/A**|❓ | +|Cursor grab |✔️ |▢[#165] |▢[#242] |✔️ |**N/A**|**N/A**|❓ | +|Cursor icon |✔️ |✔️ |✔️ |✔️ |**N/A**|**N/A**|❓ | |Touch events |✔️ |❌ |✔️ |✔️ |✔️ |✔️ |❓ | |Touch pressure |✔️ |❌ |❌ |❌ |❌ |✔️ |❓ | |Multitouch |✔️ |❌ |✔️ |✔️ |❓ |✔️ |❓ | diff --git a/src/platform_impl/linux/wayland/event_loop.rs b/src/platform_impl/linux/wayland/event_loop.rs index 0d8a24d6b8..cbe08799ff 100644 --- a/src/platform_impl/linux/wayland/event_loop.rs +++ b/src/platform_impl/linux/wayland/event_loop.rs @@ -29,6 +29,7 @@ use crate::{ sticky_exit_callback, MonitorHandle as PlatformMonitorHandle, VideoMode as PlatformVideoMode, }, + window::CursorIcon, }; use super::{window::WindowStore, DeviceId, WindowId}; @@ -78,21 +79,23 @@ impl WindowEventsSink { } pub struct CursorManager { - pointer_constraints_proxy: Rc>>, + pointer_constraints_proxy: Arc>>, auto_themer: Option, pointers: Vec, locked_pointers: Vec, - cursor_visible: Rc>, + cursor_visible: bool, + current_cursor: CursorIcon, } impl CursorManager { - fn new(constraints: Rc>>) -> CursorManager { + fn new(constraints: Arc>>) -> CursorManager { CursorManager { pointer_constraints_proxy: constraints, auto_themer: None, pointers: Vec::new(), locked_pointers: Vec::new(), - cursor_visible: Rc::new(RefCell::new(true)), + cursor_visible: true, + current_cursor: CursorIcon::default(), } } @@ -108,29 +111,96 @@ impl CursorManager { self.auto_themer = Some(auto_themer); } - fn set_cursor_visible(&mut self, visible: bool) { + pub fn set_cursor_visible(&mut self, visible: bool) { if !visible { for pointer in self.pointers.iter() { (**pointer).set_cursor(0, None, 0, 0); } } else { - for pointer in self.pointers.iter() { - pointer.set_cursor("left_ptr", None).unwrap(); - } + self.set_cursor_icon_impl(self.current_cursor); + } + self.cursor_visible = visible; + } + + /// A helper function to restore cursor styles on PtrEvent::Enter. + pub fn reload_cursor_style(&mut self) { + if !self.cursor_visible { + self.set_cursor_visible(false); + } else { + self.set_cursor_icon_impl(self.current_cursor); } - (*self.cursor_visible.try_borrow_mut().unwrap()) = visible; } - fn grab_pointer(&mut self, surface: Option<&WlSurface>) { - for lp in self.locked_pointers.drain(..) { - lp.destroy(); + pub fn set_cursor_icon(&mut self, cursor: CursorIcon) { + if self.cursor_visible && cursor != self.current_cursor { + self.current_cursor = cursor; + + self.set_cursor_icon_impl(cursor); + } + } + + fn set_cursor_icon_impl(&mut self, cursor: CursorIcon) { + let cursor = match cursor { + CursorIcon::Alias => "link", + CursorIcon::Arrow => "arrow", + CursorIcon::Cell => "plus", + CursorIcon::Copy => "copy", + CursorIcon::Crosshair => "crosshair", + CursorIcon::Default => "left_ptr", + CursorIcon::Hand => "hand", + CursorIcon::Help => "question_arrow", + CursorIcon::Move => "move", + CursorIcon::Grab => "grab", + CursorIcon::Grabbing => "grabbing", + CursorIcon::Progress => "progress", + CursorIcon::AllScroll => "all-scroll", + CursorIcon::ContextMenu => "context-menu", + + CursorIcon::NoDrop => "no-drop", + CursorIcon::NotAllowed => "crossed_circle", + + // Resize cursors + CursorIcon::EResize => "right_side", + CursorIcon::NResize => "top_side", + CursorIcon::NeResize => "top_right_corner", + CursorIcon::NwResize => "top_left_corner", + CursorIcon::SResize => "bottom_side", + CursorIcon::SeResize => "bottom_right_corner", + CursorIcon::SwResize => "bottom_left_corner", + CursorIcon::WResize => "left_side", + CursorIcon::EwResize => "h_double_arrow", + CursorIcon::NsResize => "v_double_arrow", + CursorIcon::NwseResize => "bd_double_arrow", + CursorIcon::NeswResize => "fd_double_arrow", + CursorIcon::ColResize => "h_double_arrow", + CursorIcon::RowResize => "v_double_arrow", + + CursorIcon::Text => "text", + CursorIcon::VerticalText => "vertical-text", + + CursorIcon::Wait => "watch", + + CursorIcon::ZoomIn => "zoom-in", + CursorIcon::ZoomOut => "zoom-out", + }; + + for pointer in self.pointers.iter() { + // Ignore erros, since we don't want to fail hard in case we can't find a proper cursor + // in a given theme. + let _ = pointer.set_cursor(cursor, None); + } + } + + pub fn grab_pointer(&mut self, surface: Option<&WlSurface>) { + for locked_pointer in self.locked_pointers.drain(..) { + locked_pointer.destroy(); } if let Some(surface) = surface { for pointer in self.pointers.iter() { let locked_pointer = self .pointer_constraints_proxy - .try_borrow() + .try_lock() .unwrap() .as_ref() .and_then(|pointer_constraints| { @@ -155,13 +225,12 @@ pub struct EventLoop { inner_loop: ::calloop::EventLoop<()>, // The wayland display pub display: Arc, - // the output manager + // The output manager pub outputs: OutputMgr, - // our sink, shared with some handlers, buffering the events + // Our sink, shared with some handlers, buffering the events sink: Arc>>, pending_user_events: Rc>>, // Utility for grabbing the cursor and changing visibility - cursor_manager: Rc>, _user_source: ::calloop::Source<::calloop::channel::Channel>, user_sender: ::calloop::channel::Sender, _kbd_source: ::calloop::Source< @@ -174,17 +243,19 @@ pub struct EventLoop { // // We should only try and wake up the `EventLoop` if it still exists, so we hold Weak ptrs. pub struct EventLoopProxy { - user_sender: ::calloop::channel::Sender, + user_sender: calloop::channel::Sender, } pub struct EventLoopWindowTarget { - // the event queue + // The event queue pub evq: RefCell<::calloop::Source>, // The window store pub store: Arc>, - // the env + // The cursor manager + pub cursor_manager: Arc>, + // The env pub env: Environment, - // a cleanup switch to prune dead windows + // A cleanup switch to prune dead windows pub cleanup_needed: Arc>, // The wayland display pub display: Arc, @@ -229,7 +300,7 @@ impl EventLoop { }) .unwrap(); - let pointer_constraints_proxy = Rc::new(RefCell::new(None)); + let pointer_constraints_proxy = Arc::new(Mutex::new(None)); let mut seat_manager = SeatManager { sink: sink.clone(), @@ -238,11 +309,11 @@ impl EventLoop { store: store.clone(), seats: seats.clone(), kbd_sender, - cursor_manager: Rc::new(RefCell::new(CursorManager::new(pointer_constraints_proxy))), + cursor_manager: Arc::new(Mutex::new(CursorManager::new(pointer_constraints_proxy))), }; let cursor_manager = seat_manager.cursor_manager.clone(); - let cursor_manager2 = cursor_manager.clone(); + let cursor_manager_clone = cursor_manager.clone(); let shm_cell = Rc::new(RefCell::new(None)); let compositor_cell = Rc::new(RefCell::new(None)); @@ -275,7 +346,7 @@ impl EventLoop { }) .unwrap(); - *seat_manager.pointer_constraints_proxy.borrow_mut() = + *seat_manager.pointer_constraints_proxy.lock().unwrap() = Some(pointer_constraints_proxy); } if interface == "wl_shm" { @@ -298,7 +369,10 @@ impl EventLoop { let compositor = compositor_cell.borrow_mut().take().unwrap(); let shm = shm_cell.borrow_mut().take().unwrap(); let auto_themer = AutoThemer::init(None, compositor, &shm); - cursor_manager2.borrow_mut().set_auto_themer(auto_themer); + cursor_manager_clone + .lock() + .unwrap() + .set_auto_themer(auto_themer); } if interface == "wl_seat" { @@ -333,13 +407,13 @@ impl EventLoop { }) .unwrap(); + let cursor_manager_clone = cursor_manager.clone(); Ok(EventLoop { inner_loop, sink, pending_user_events, display: display.clone(), outputs: env.outputs.clone(), - cursor_manager, _user_source: user_source, user_sender, _kbd_source: kbd_source, @@ -348,6 +422,7 @@ impl EventLoop { evq: RefCell::new(source), store, env, + cursor_manager: cursor_manager_clone, cleanup_needed: Arc::new(Mutex::new(false)), seats, display, @@ -369,7 +444,7 @@ impl EventLoop { F: 'static + FnMut(crate::event::Event, &RootELW, &mut ControlFlow), { self.run_return(callback); - ::std::process::exit(0); + std::process::exit(0); } pub fn run_return(&mut self, mut callback: F) @@ -579,17 +654,7 @@ impl EventLoop { } // process pending resize/refresh window_target.store.lock().unwrap().for_each( - |newsize, - size, - new_dpi, - refresh, - frame_refresh, - closed, - cursor_visible, - cursor_grab, - surface, - wid, - frame| { + |newsize, size, new_dpi, refresh, frame_refresh, closed, wid, frame| { if let Some(frame) = frame { if let Some((w, h)) = newsize { frame.resize(w, h); @@ -619,17 +684,6 @@ impl EventLoop { if closed { sink.send_window_event(crate::event::WindowEvent::CloseRequested, wid); } - if let Some(grab) = cursor_grab { - self.cursor_manager.borrow_mut().grab_pointer(if grab { - Some(surface) - } else { - None - }); - } - - if let Some(visible) = cursor_visible { - self.cursor_manager.borrow_mut().set_cursor_visible(visible); - } }, ) } @@ -645,8 +699,8 @@ struct SeatManager { seats: Arc>>, kbd_sender: ::calloop::channel::Sender<(crate::event::WindowEvent, super::WindowId)>, relative_pointer_manager_proxy: Rc>>, - pointer_constraints_proxy: Rc>>, - cursor_manager: Rc>, + pointer_constraints_proxy: Arc>>, + cursor_manager: Arc>, } impl SeatManager { @@ -695,7 +749,7 @@ struct SeatData { keyboard: Option, touch: Option, modifiers_tracker: Arc>, - cursor_manager: Rc>, + cursor_manager: Arc>, } impl SeatData { @@ -710,11 +764,12 @@ impl SeatData { self.sink.clone(), self.store.clone(), self.modifiers_tracker.clone(), - self.cursor_manager.borrow().cursor_visible.clone(), + self.cursor_manager.clone(), )); self.cursor_manager - .borrow_mut() + .lock() + .unwrap() .register_pointer(self.pointer.as_ref().unwrap().clone()); self.relative_pointer = self diff --git a/src/platform_impl/linux/wayland/pointer.rs b/src/platform_impl/linux/wayland/pointer.rs index 1a0cff9f66..cad299e470 100644 --- a/src/platform_impl/linux/wayland/pointer.rs +++ b/src/platform_impl/linux/wayland/pointer.rs @@ -1,5 +1,3 @@ -use std::cell::RefCell; -use std::rc::Rc; use std::sync::{Arc, Mutex}; use crate::event::{ @@ -7,7 +5,11 @@ use crate::event::{ WindowEvent, }; -use super::{event_loop::WindowEventsSink, window::WindowStore, DeviceId}; +use super::{ + event_loop::{CursorManager, WindowEventsSink}, + window::WindowStore, + DeviceId, +}; use smithay_client_toolkit::reexports::client::protocol::{ wl_pointer::{self, Event as PtrEvent, WlPointer}, @@ -31,7 +33,7 @@ pub fn implement_pointer( sink: Arc>>, store: Arc>, modifiers_tracker: Arc>, - cursor_visible: Rc>, + cursor_manager: Arc>, ) -> WlPointer { seat.get_pointer(|pointer| { let mut mouse_focus = None; @@ -43,6 +45,7 @@ pub fn implement_pointer( move |evt, pointer| { let mut sink = sink.lock().unwrap(); let store = store.lock().unwrap(); + let mut cursor_manager = cursor_manager.lock().unwrap(); match evt { PtrEvent::Enter { surface, @@ -73,9 +76,7 @@ pub fn implement_pointer( ); } - if *cursor_visible.borrow() == false { - pointer.set_cursor(0, None, 0, 0); - } + cursor_manager.reload_cursor_style(); } PtrEvent::Leave { surface, .. } => { mouse_focus = None; diff --git a/src/platform_impl/linux/wayland/window.rs b/src/platform_impl/linux/wayland/window.rs index 9fdde832e3..f94b8177a9 100644 --- a/src/platform_impl/linux/wayland/window.rs +++ b/src/platform_impl/linux/wayland/window.rs @@ -1,6 +1,7 @@ use raw_window_handle::unix::WaylandHandle; use std::{ collections::VecDeque, + mem::replace, sync::{Arc, Mutex, Weak}, }; @@ -26,11 +27,12 @@ use smithay_client_toolkit::{ window::{ConceptFrame, Event as WEvent, State as WState, Theme, Window as SWindow}, }; -use super::{make_wid, EventLoopWindowTarget, MonitorHandle, WindowId}; +use super::{event_loop::CursorManager, make_wid, EventLoopWindowTarget, MonitorHandle, WindowId}; pub struct Window { surface: wl_surface::WlSurface, frame: Arc>>, + cursor_manager: Arc>, outputs: OutputMgr, // Access to info for all monitors size: Arc>, kill_switch: (Arc>, Arc>), @@ -38,8 +40,6 @@ pub struct Window { need_frame_refresh: Arc>, need_refresh: Arc>, fullscreen: Arc>, - cursor_grab_changed: Arc>>, - cursor_visible_changed: Arc>>, } impl Window { @@ -54,6 +54,7 @@ impl Window { let fullscreen = Arc::new(Mutex::new(false)); let window_store = evlp.store.clone(); + let cursor_manager = evlp.cursor_manager.clone(); let surface = evlp.env.create_surface(move |dpi, surface| { window_store.lock().unwrap().dpi_change(&surface, dpi); surface.set_buffer_scale(dpi); @@ -142,8 +143,6 @@ 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)); - let cursor_visible_changed = Arc::new(Mutex::new(None)); evlp.store.lock().unwrap().windows.push(InternalWindow { closed: false, @@ -152,8 +151,6 @@ impl Window { need_refresh: need_refresh.clone(), fullscreen: fullscreen.clone(), need_frame_refresh: need_frame_refresh.clone(), - cursor_grab_changed: cursor_grab_changed.clone(), - cursor_visible_changed: cursor_visible_changed.clone(), surface: surface.clone(), kill_switch: kill_switch.clone(), frame: Arc::downgrade(&frame), @@ -171,9 +168,8 @@ impl Window { kill_switch: (kill_switch, evlp.cleanup_needed.clone()), need_frame_refresh, need_refresh, + cursor_manager, fullscreen, - cursor_grab_changed, - cursor_visible_changed, }) } @@ -300,18 +296,25 @@ impl Window { } #[inline] - pub fn set_cursor_icon(&self, _cursor: CursorIcon) { - // TODO + pub fn set_cursor_icon(&self, cursor: CursorIcon) { + let mut cursor_manager = self.cursor_manager.lock().unwrap(); + cursor_manager.set_cursor_icon(cursor); } #[inline] pub fn set_cursor_visible(&self, visible: bool) { - *self.cursor_visible_changed.lock().unwrap() = Some(visible); + let mut cursor_manager = self.cursor_manager.lock().unwrap(); + cursor_manager.set_cursor_visible(visible); } #[inline] pub fn set_cursor_grab(&self, grab: bool) -> Result<(), ExternalError> { - *self.cursor_grab_changed.lock().unwrap() = Some(grab); + let mut cursor_manager = self.cursor_manager.lock().unwrap(); + if grab { + cursor_manager.grab_pointer(Some(&self.surface)); + } else { + cursor_manager.grab_pointer(None); + } Ok(()) } @@ -371,8 +374,6 @@ struct InternalWindow { need_refresh: Arc>, fullscreen: Arc>, need_frame_refresh: Arc>, - cursor_grab_changed: Arc>>, - cursor_visible_changed: Arc>>, closed: bool, kill_switch: Arc>, frame: Weak>>, @@ -440,9 +441,6 @@ impl WindowStore { bool, bool, bool, - Option, - Option, - &wl_surface::WlSurface, WindowId, Option<&mut SWindow>, ), @@ -454,12 +452,9 @@ impl WindowStore { window.newsize.take(), &mut *(window.size.lock().unwrap()), window.new_dpi, - ::std::mem::replace(&mut *window.need_refresh.lock().unwrap(), false), - ::std::mem::replace(&mut *window.need_frame_refresh.lock().unwrap(), false), + replace(&mut *window.need_refresh.lock().unwrap(), false), + replace(&mut *window.need_frame_refresh.lock().unwrap(), false), window.closed, - window.cursor_visible_changed.lock().unwrap().take(), - window.cursor_grab_changed.lock().unwrap().take(), - &window.surface, make_wid(&window.surface), opt_mutex_lock.as_mut().map(|m| &mut **m), );