From 237e7ee2e603524c5652192521a94e62db9c823c Mon Sep 17 00:00:00 2001 From: andersrein Date: Wed, 2 Oct 2019 03:25:59 +0200 Subject: [PATCH 1/9] 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 5be8107c..7a32a845 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 272fc832..0d8a24d6 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 7ffcdd72..1a0cff9f 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 ddd4b4b9..9fdde832 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 1eaeec47..248c8317 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 2/9] 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 7a32a845..282a8dd6 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 9610b7ba..d634eaf5 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 0d8a24d6..cbe08799 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.try_borrow_mut().unwrap()) = visible; + self.cursor_visible = visible; } - fn grab_pointer(&mut self, surface: Option<&WlSurface>) { - for lp in self.locked_pointers.drain(..) { - lp.destroy(); + /// 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); + } + } + + 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 1a0cff9f..cad299e4 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 9fdde832..f94b8177 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), ); From 4f6ca8792cac0b006205c117fdf9c205a8240657 Mon Sep 17 00:00:00 2001 From: Alex Butler Date: Thu, 3 Oct 2019 21:19:10 +0100 Subject: [PATCH 3/9] Remove derivative dependency (#1201) * Remove derivative dependency * Update CHANGELOG.md --- CHANGELOG.md | 3 ++- Cargo.toml | 1 - src/lib.rs | 2 -- src/monitor.rs | 9 +++++-- src/platform_impl/macos/monitor.rs | 35 +++++++++++++++++++++++++--- src/platform_impl/windows/monitor.rs | 35 +++++++++++++++++++++++++--- 6 files changed, 73 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 282a8dd6..b6d84a55 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,7 +21,8 @@ - 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 +- On Wayland, fixed DeviceEvents for relative mouse movement is not always produced. +- Removed `derivative` crate dependency. - On Wayland, add support for set_cursor_icon. # 0.20.0 Alpha 3 (2019-08-14) diff --git a/Cargo.toml b/Cargo.toml index 3e8161db..5720ae7b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,7 +19,6 @@ lazy_static = "1" libc = "0.2" log = "0.4" serde = { version = "1", optional = true, features = ["serde_derive"] } -derivative = "1.0.2" raw-window-handle = "0.2" [dev-dependencies] diff --git a/src/lib.rs b/src/lib.rs index 4a85a2ca..ba8e910f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -121,8 +121,6 @@ extern crate log; #[macro_use] extern crate serde; #[macro_use] -extern crate derivative; -#[macro_use] #[cfg(any(target_os = "ios", target_os = "windows"))] extern crate bitflags; #[cfg(any(target_os = "macos", target_os = "ios"))] diff --git a/src/monitor.rs b/src/monitor.rs index 8e085a58..106c3e52 100644 --- a/src/monitor.rs +++ b/src/monitor.rs @@ -52,12 +52,17 @@ impl Iterator for AvailableMonitorsIter { /// - [`MonitorHandle::video_modes`][monitor_get]. /// /// [monitor_get]: ../monitor/struct.MonitorHandle.html#method.video_modes -#[derive(Derivative)] -#[derivative(Clone, Debug = "transparent", PartialEq, Eq, Hash)] +#[derive(Clone, PartialEq, Eq, Hash)] pub struct VideoMode { pub(crate) video_mode: platform_impl::VideoMode, } +impl std::fmt::Debug for VideoMode { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.video_mode.fmt(f) + } +} + impl PartialOrd for VideoMode { fn partial_cmp(&self, other: &VideoMode) -> Option { Some(self.cmp(other)) diff --git a/src/platform_impl/macos/monitor.rs b/src/platform_impl/macos/monitor.rs index c9408890..7688e31a 100644 --- a/src/platform_impl/macos/monitor.rs +++ b/src/platform_impl/macos/monitor.rs @@ -22,17 +22,46 @@ use core_video_sys::{ CVDisplayLinkGetNominalOutputVideoRefreshPeriod, CVDisplayLinkRelease, }; -#[derive(Derivative)] -#[derivative(Debug, Clone, PartialEq, Hash)] +#[derive(Clone)] pub struct VideoMode { pub(crate) size: (u32, u32), pub(crate) bit_depth: u16, pub(crate) refresh_rate: u16, pub(crate) monitor: MonitorHandle, - #[derivative(Debug = "ignore", PartialEq = "ignore", Hash = "ignore")] pub(crate) native_mode: NativeDisplayMode, } +impl PartialEq for VideoMode { + fn eq(&self, other: &Self) -> bool { + self.size == other.size + && self.bit_depth == other.bit_depth + && self.refresh_rate == other.refresh_rate + && self.monitor == other.monitor + } +} + +impl Eq for VideoMode {} + +impl std::hash::Hash for VideoMode { + fn hash(&self, state: &mut H) { + self.size.hash(state); + self.bit_depth.hash(state); + self.refresh_rate.hash(state); + self.monitor.hash(state); + } +} + +impl std::fmt::Debug for VideoMode { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("VideoMode") + .field("size", &self.size) + .field("bit_depth", &self.bit_depth) + .field("refresh_rate", &self.refresh_rate) + .field("monitor", &self.monitor) + .finish() + } +} + pub struct NativeDisplayMode(pub ffi::CGDisplayModeRef); unsafe impl Send for NativeDisplayMode {} diff --git a/src/platform_impl/windows/monitor.rs b/src/platform_impl/windows/monitor.rs index cc2e1646..6705f334 100644 --- a/src/platform_impl/windows/monitor.rs +++ b/src/platform_impl/windows/monitor.rs @@ -21,17 +21,46 @@ use crate::{ }, }; -#[derive(Derivative)] -#[derivative(Debug, Clone, Eq, PartialEq, Hash)] +#[derive(Clone)] pub struct VideoMode { pub(crate) size: (u32, u32), pub(crate) bit_depth: u16, pub(crate) refresh_rate: u16, pub(crate) monitor: MonitorHandle, - #[derivative(Debug = "ignore", PartialEq = "ignore", Hash = "ignore")] pub(crate) native_video_mode: wingdi::DEVMODEW, } +impl PartialEq for VideoMode { + fn eq(&self, other: &Self) -> bool { + self.size == other.size + && self.bit_depth == other.bit_depth + && self.refresh_rate == other.refresh_rate + && self.monitor == other.monitor + } +} + +impl Eq for VideoMode {} + +impl std::hash::Hash for VideoMode { + fn hash(&self, state: &mut H) { + self.size.hash(state); + self.bit_depth.hash(state); + self.refresh_rate.hash(state); + self.monitor.hash(state); + } +} + +impl std::fmt::Debug for VideoMode { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("VideoMode") + .field("size", &self.size) + .field("bit_depth", &self.bit_depth) + .field("refresh_rate", &self.refresh_rate) + .field("monitor", &self.monitor) + .finish() + } +} + impl VideoMode { pub fn size(&self) -> PhysicalSize { self.size.into() From 55640a91aeff665b4eec5791ee115c4ea554ccb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=BAc=C3=A1s=20Meier?= Date: Sat, 5 Oct 2019 16:49:24 +0200 Subject: [PATCH 4/9] Use consistent return types for available_monitors() (#1207) * [#1111] Use consistent return types for available_monitors() Always use `impl Iterator` instead of `AvailableMonitorsIter`. Fix an example that used the Debug implementation of `AvailableMonitorsIter`. * [#1111] Update changelog * [#1111] Remove AvailableMonitorsIter type completely * [#1111] Remove doc references to AvailableMonitorsIter --- CHANGELOG.md | 1 + examples/monitor_list.rs | 2 +- src/event_loop.rs | 14 +++++--------- src/monitor.rs | 36 ++---------------------------------- src/window.rs | 12 ++++++------ 5 files changed, 15 insertions(+), 50 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b6d84a55..77ae2ff9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,7 @@ - On Wayland, fixed DeviceEvents for relative mouse movement is not always produced. - Removed `derivative` crate dependency. - On Wayland, add support for set_cursor_icon. +- Use `impl Iterator` instead of `AvailableMonitorsIter` consistently. # 0.20.0 Alpha 3 (2019-08-14) diff --git a/examples/monitor_list.rs b/examples/monitor_list.rs index 55a2dde8..a6b24d29 100644 --- a/examples/monitor_list.rs +++ b/examples/monitor_list.rs @@ -4,6 +4,6 @@ fn main() { let event_loop = EventLoop::new(); let window = WindowBuilder::new().build(&event_loop).unwrap(); - dbg!(window.available_monitors()); + dbg!(window.available_monitors().collect::>()); dbg!(window.primary_monitor()); } diff --git a/src/event_loop.rs b/src/event_loop.rs index a2d90d3e..0b120573 100644 --- a/src/event_loop.rs +++ b/src/event_loop.rs @@ -11,11 +11,7 @@ //! [send_event]: ./struct.EventLoopProxy.html#method.send_event use std::{error, fmt, ops::Deref, time::Instant}; -use crate::{ - event::Event, - monitor::{AvailableMonitorsIter, MonitorHandle}, - platform_impl, -}; +use crate::{event::Event, monitor::MonitorHandle, platform_impl}; /// Provides a way to retrieve events from the system and from the windows that were registered to /// the events loop. @@ -150,10 +146,10 @@ impl EventLoop { /// Returns the list of all the monitors available on the system. #[inline] pub fn available_monitors(&self) -> impl Iterator { - let data = self.event_loop.available_monitors(); - AvailableMonitorsIter { - data: data.into_iter(), - } + self.event_loop + .available_monitors() + .into_iter() + .map(|inner| MonitorHandle { inner }) } /// Returns the primary monitor of the system. diff --git a/src/monitor.rs b/src/monitor.rs index 106c3e52..a8949020 100644 --- a/src/monitor.rs +++ b/src/monitor.rs @@ -1,51 +1,19 @@ //! Types useful for interacting with a user's monitors. //! //! If you want to get basic information about a monitor, you can use the [`MonitorHandle`][monitor_id] -//! type. This is retreived from an [`AvailableMonitorsIter`][monitor_iter], which can be acquired -//! with: +//! type. This is retreived from one of the following methods, which return an iterator of +//! [`MonitorHandle`][monitor_id]: //! - [`EventLoop::available_monitors`][loop_get] //! - [`Window::available_monitors`][window_get]. //! //! [monitor_id]: ./struct.MonitorHandle.html -//! [monitor_iter]: ./struct.AvailableMonitorsIter.html //! [loop_get]: ../event_loop/struct.EventLoop.html#method.available_monitors //! [window_get]: ../window/struct.Window.html#method.available_monitors -use std::collections::vec_deque::IntoIter as VecDequeIter; - use crate::{ dpi::{PhysicalPosition, PhysicalSize}, platform_impl, }; -/// An iterator over all available monitors. -/// -/// Can be acquired with: -/// - [`EventLoop::available_monitors`][loop_get] -/// - [`Window::available_monitors`][window_get]. -/// -/// [loop_get]: ../event_loop/struct.EventLoop.html#method.available_monitors -/// [window_get]: ../window/struct.Window.html#method.available_monitors -// Implementation note: we retrieve the list once, then serve each element by one by one. -// This may change in the future. -#[derive(Debug)] -pub struct AvailableMonitorsIter { - pub(crate) data: VecDequeIter, -} - -impl Iterator for AvailableMonitorsIter { - type Item = MonitorHandle; - - #[inline] - fn next(&mut self) -> Option { - self.data.next().map(|id| MonitorHandle { inner: id }) - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.data.size_hint() - } -} - /// Describes a fullscreen video mode of a monitor. /// /// Can be acquired with: diff --git a/src/window.rs b/src/window.rs index 248c8317..a74fab01 100644 --- a/src/window.rs +++ b/src/window.rs @@ -5,7 +5,7 @@ use crate::{ dpi::{LogicalPosition, LogicalSize}, error::{ExternalError, NotSupportedError, OsError}, event_loop::EventLoopWindowTarget, - monitor::{AvailableMonitorsIter, MonitorHandle, VideoMode}, + monitor::{MonitorHandle, VideoMode}, platform_impl, }; @@ -703,11 +703,11 @@ impl Window { /// /// **iOS:** Can only be called on the main thread. #[inline] - pub fn available_monitors(&self) -> AvailableMonitorsIter { - let data = self.window.available_monitors(); - AvailableMonitorsIter { - data: data.into_iter(), - } + pub fn available_monitors(&self) -> impl Iterator { + self.window + .available_monitors() + .into_iter() + .map(|inner| MonitorHandle { inner }) } /// Returns the primary monitor of the system. From 42e0ccfa1c7e42b12985044d36e1dc8b54b57818 Mon Sep 17 00:00:00 2001 From: Antonino Siena Date: Sat, 5 Oct 2019 20:52:40 +0200 Subject: [PATCH 5/9] Implemented a HINSTANCE getter function for Windows (#1213) * Expose HINSTANCE now using a getter function * Missing changes * remove unused import * Required changes for the PR * Rust fmt * Use GetWindowLong * Use GetWindowLong --- CHANGELOG.md | 1 + src/platform/windows.rs | 7 +++++++ src/platform_impl/windows/window.rs | 7 ++++++- 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 77ae2ff9..1c780b6b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ # Unreleased +- On Windows, implemented function to get HINSTANCE - On macOS, implement `run_return`. - On iOS, fix inverted parameter in `set_prefers_home_indicator_hidden`. - On X11, performance is improved when rapidly calling `Window::set_cursor_icon`. diff --git a/src/platform/windows.rs b/src/platform/windows.rs index 43133e04..0b93b330 100644 --- a/src/platform/windows.rs +++ b/src/platform/windows.rs @@ -34,6 +34,8 @@ impl EventLoopExtWindows for EventLoop { /// Additional methods on `Window` that are specific to Windows. pub trait WindowExtWindows { + /// Returns the HINSTANCE of the window + fn hinstance(&self) -> *mut libc::c_void; /// Returns the native handle that is used by this window. /// /// The pointer will become invalid when the native window was destroyed. @@ -44,6 +46,11 @@ pub trait WindowExtWindows { } impl WindowExtWindows for Window { + #[inline] + fn hinstance(&self) -> *mut libc::c_void { + self.window.hinstance() as *mut _ + } + #[inline] fn hwnd(&self) -> *mut libc::c_void { self.window.hwnd() as *mut _ diff --git a/src/platform_impl/windows/window.rs b/src/platform_impl/windows/window.rs index cb32c2ac..4a00962b 100644 --- a/src/platform_impl/windows/window.rs +++ b/src/platform_impl/windows/window.rs @@ -14,7 +14,7 @@ use std::{ use winapi::{ ctypes::c_int, shared::{ - minwindef::{DWORD, LPARAM, UINT, WORD, WPARAM}, + minwindef::{DWORD, HINSTANCE, LPARAM, UINT, WORD, WPARAM}, windef::{HWND, POINT, RECT}, }, um::{ @@ -358,6 +358,11 @@ impl Window { self.window.0 } + #[inline] + pub fn hinstance(&self) -> HINSTANCE { + unsafe { winuser::GetWindowLongW(self.hwnd(), winuser::GWL_HINSTANCE) as *mut _ } + } + #[inline] pub fn raw_window_handle(&self) -> RawWindowHandle { let handle = WindowsHandle { From 2d41a7d1b08c6a4a123d23cea3fba689043cfecd Mon Sep 17 00:00:00 2001 From: Benjamin Saunders Date: Sat, 5 Oct 2019 12:00:54 -0700 Subject: [PATCH 6/9] Fix use-after-free in XConnection::get_output_info (#1211) --- CHANGELOG.md | 1 + src/platform_impl/linux/x11/util/randr.rs | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1c780b6b..e92fb8fa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,7 @@ - Removed `derivative` crate dependency. - On Wayland, add support for set_cursor_icon. - Use `impl Iterator` instead of `AvailableMonitorsIter` consistently. +- On X11, fix use-after-free during window creation # 0.20.0 Alpha 3 (2019-08-14) diff --git a/src/platform_impl/linux/x11/util/randr.rs b/src/platform_impl/linux/x11/util/randr.rs index 1fbef41d..28fcb601 100644 --- a/src/platform_impl/linux/x11/util/randr.rs +++ b/src/platform_impl/linux/x11/util/randr.rs @@ -99,7 +99,8 @@ impl XConnection { // video mode is returned to the user monitor: None, } - }); + }) + .collect(); let name_slice = slice::from_raw_parts( (*output_info).name as *mut u8, @@ -119,7 +120,7 @@ impl XConnection { }; (self.xrandr.XRRFreeOutputInfo)(output_info); - Some((name, hidpi_factor, modes.collect())) + Some((name, hidpi_factor, modes)) } pub fn set_crtc_config(&self, crtc_id: RRCrtc, mode_id: RRMode) -> Result<(), ()> { unsafe { From d69e41eba8edf5f0667fde42bceedd78a75c6814 Mon Sep 17 00:00:00 2001 From: Aleksi Juvani <3168386+aleksijuvani@users.noreply.github.com> Date: Sat, 5 Oct 2019 23:23:06 +0300 Subject: [PATCH 7/9] Update fullscreen state on macOS before entering fullscreen (#1196) --- CHANGELOG.md | 3 ++ src/platform_impl/macos/window_delegate.rs | 38 ++++++++++------------ 2 files changed, 21 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e92fb8fa..efbf56e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,9 @@ - Removed `derivative` crate dependency. - On Wayland, add support for set_cursor_icon. - Use `impl Iterator` instead of `AvailableMonitorsIter` consistently. +- On macOS, fix fullscreen state being updated after entering fullscreen instead of before, + resulting in `Window::fullscreen` returning the old state in `Resized` events instead of + reflecting the new fullscreen state - On X11, fix use-after-free during window creation # 0.20.0 Alpha 3 (2019-08-14) diff --git a/src/platform_impl/macos/window_delegate.rs b/src/platform_impl/macos/window_delegate.rs index 041edf61..cb1bf3c2 100644 --- a/src/platform_impl/macos/window_delegate.rs +++ b/src/platform_impl/macos/window_delegate.rs @@ -402,7 +402,24 @@ extern "C" fn window_will_enter_fullscreen(this: &Object, _: Sel, _: id) { with_state(this, |state| { state.with_window(|window| { trace!("Locked shared state in `window_will_enter_fullscreen`"); - window.shared_state.lock().unwrap().maximized = window.is_zoomed(); + let mut shared_state = window.shared_state.lock().unwrap(); + shared_state.maximized = window.is_zoomed(); + match shared_state.fullscreen { + // Exclusive mode sets the state in `set_fullscreen` as the user + // can't enter exclusive mode by other means (like the + // fullscreen button on the window decorations) + Some(Fullscreen::Exclusive(_)) => (), + // `window_will_enter_fullscreen` was triggered and we're already + // in fullscreen, so we must've reached here by `set_fullscreen` + // as it updates the state + Some(Fullscreen::Borderless(_)) => (), + // Otherwise, we must've reached fullscreen by the user clicking + // on the green fullscreen button. Update state! + None => { + shared_state.fullscreen = Some(Fullscreen::Borderless(window.current_monitor())) + } + } + trace!("Unlocked shared state in `window_will_enter_fullscreen`"); }) }); @@ -433,25 +450,6 @@ extern "C" fn window_will_use_fullscreen_presentation_options( extern "C" fn window_did_enter_fullscreen(this: &Object, _: Sel, _: id) { trace!("Triggered `windowDidEnterFullscreen:`"); with_state(this, |state| { - state.with_window(|window| { - let monitor = window.current_monitor(); - trace!("Locked shared state in `window_did_enter_fullscreen`"); - let mut shared_state = window.shared_state.lock().unwrap(); - match shared_state.fullscreen { - // Exclusive mode sets the state in `set_fullscreen` as the user - // can't enter exclusive mode by other means (like the - // fullscreen button on the window decorations) - Some(Fullscreen::Exclusive(_)) => (), - // `window_did_enter_fullscreen` was triggered and we're already - // in fullscreen, so we must've reached here by `set_fullscreen` - // as it updates the state - Some(Fullscreen::Borderless(_)) => (), - // Otherwise, we must've reached fullscreen by the user clicking - // on the green fullscreen button. Update state! - None => shared_state.fullscreen = Some(Fullscreen::Borderless(monitor)), - } - trace!("Unlocked shared state in `window_did_enter_fullscreen`"); - }); state.initial_fullscreen = false; }); trace!("Completed `windowDidEnterFullscreen:`"); From df7571b369a6bc502e2abfb5aefcac4e60e94063 Mon Sep 17 00:00:00 2001 From: Osspial Date: Sat, 5 Oct 2019 16:23:30 -0400 Subject: [PATCH 8/9] Improve interaction between fullscreen windows and monitor-switching keyboard shortcuts (#1171) * Update to 1.38.0 formatting * Improve fullscreen window monitor switching on Windows * Format --- CHANGELOG.md | 2 ++ src/platform_impl/windows/event_loop.rs | 48 ++++++++++++++++++++++++- 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index efbf56e8..ae7eb7ec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,8 @@ resulting in `Window::fullscreen` returning the old state in `Resized` events instead of reflecting the new fullscreen state - On X11, fix use-after-free during window creation +- On Windows, disable monitor change keyboard shortcut while in exclusive fullscreen. +- On Windows, ensure that changing a borderless fullscreen window's monitor via keyboard shortcuts keeps the window fullscreen on the new monitor. # 0.20.0 Alpha 3 (2019-08-14) diff --git a/src/platform_impl/windows/event_loop.rs b/src/platform_impl/windows/event_loop.rs index 94f7255e..b9a0846a 100644 --- a/src/platform_impl/windows/event_loop.rs +++ b/src/platform_impl/windows/event_loop.rs @@ -54,13 +54,14 @@ use crate::{ }, drop_handler::FileDropHandler, event::{self, handle_extended_keys, process_key_params, vkey_to_winit_vkey}, + monitor, raw_input::{get_raw_input_data, get_raw_mouse_button_state}, util, window::adjust_size, window_state::{CursorFlags, WindowFlags, WindowState}, wrap_device_id, WindowId, DEVICE_ID, }, - window::WindowId as RootWindowId, + window::{Fullscreen, WindowId as RootWindowId}, }; type GetPointerFrameInfoHistory = unsafe extern "system" fn( @@ -982,6 +983,51 @@ unsafe extern "system" fn public_window_callback( commctrl::DefSubclassProc(window, msg, wparam, lparam) } + winuser::WM_WINDOWPOSCHANGING => { + let mut window_state = subclass_input.window_state.lock(); + if let Some(ref mut fullscreen) = window_state.fullscreen { + let window_pos = &mut *(lparam as *mut winuser::WINDOWPOS); + let new_rect = RECT { + left: window_pos.x, + top: window_pos.y, + right: window_pos.x + window_pos.cx, + bottom: window_pos.y + window_pos.cy, + }; + let new_monitor = + winuser::MonitorFromRect(&new_rect, winuser::MONITOR_DEFAULTTONULL); + match fullscreen { + Fullscreen::Borderless(ref mut fullscreen_monitor) => { + if new_monitor != fullscreen_monitor.inner.hmonitor() + && new_monitor != ptr::null_mut() + { + if let Ok(new_monitor_info) = monitor::get_monitor_info(new_monitor) { + let new_monitor_rect = new_monitor_info.rcMonitor; + window_pos.x = new_monitor_rect.left; + window_pos.y = new_monitor_rect.top; + window_pos.cx = new_monitor_rect.right - new_monitor_rect.left; + window_pos.cy = new_monitor_rect.bottom - new_monitor_rect.top; + } + *fullscreen_monitor = crate::monitor::MonitorHandle { + inner: monitor::MonitorHandle::new(new_monitor), + }; + } + } + Fullscreen::Exclusive(ref video_mode) => { + let old_monitor = video_mode.video_mode.monitor.hmonitor(); + if let Ok(old_monitor_info) = monitor::get_monitor_info(old_monitor) { + let old_monitor_rect = old_monitor_info.rcMonitor; + window_pos.x = old_monitor_rect.left; + window_pos.y = old_monitor_rect.top; + window_pos.cx = old_monitor_rect.right - old_monitor_rect.left; + window_pos.cy = old_monitor_rect.bottom - old_monitor_rect.top; + } + } + } + } + + 0 + } + // WM_MOVE supplies client area positions, so we send Moved here instead. winuser::WM_WINDOWPOSCHANGED => { use crate::event::WindowEvent::Moved; From 6f5e7e170cd7bd9be1bb302dd91ebd906d29cfe1 Mon Sep 17 00:00:00 2001 From: Osspial Date: Sat, 5 Oct 2019 21:34:27 -0400 Subject: [PATCH 9/9] Update raw-window-handle to 0.3 (#1215) --- Cargo.toml | 2 +- src/platform_impl/windows/window.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 5720ae7b..8dc3e2e5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,7 +19,7 @@ lazy_static = "1" libc = "0.2" log = "0.4" serde = { version = "1", optional = true, features = ["serde_derive"] } -raw-window-handle = "0.2" +raw-window-handle = "0.3" [dev-dependencies] image = "0.21" diff --git a/src/platform_impl/windows/window.rs b/src/platform_impl/windows/window.rs index 4a00962b..629eae17 100644 --- a/src/platform_impl/windows/window.rs +++ b/src/platform_impl/windows/window.rs @@ -367,6 +367,7 @@ impl Window { pub fn raw_window_handle(&self) -> RawWindowHandle { let handle = WindowsHandle { hwnd: self.window.0 as *mut _, + hinstance: self.hinstance() as *mut _, ..WindowsHandle::empty() }; RawWindowHandle::Windows(handle)