From 19cd53193b3e8db6247fe17bc8b9b69422bd2a00 Mon Sep 17 00:00:00 2001 From: Tristam MacDonald Date: Sun, 15 Apr 2018 10:16:44 -0700 Subject: [PATCH] Discard mouse down after Cocoa window resize (#466) * Discard mouse down after Cocoa window resize We are sending the mouse down event after the window resize has completed, because Cocoa uses a modal event loop to implement window resize. This leads to a mouse down without a matching mouse up. * Also handle event discard in poll_events Add some explanatory comments and a changelog entry. --- CHANGELOG.md | 1 + src/platform/macos/events_loop.rs | 26 ++++++++++++++++++++++++-- src/platform/macos/window.rs | 5 +++++ 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e3705c57..71526355 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ - Implemented `Refresh` event on Windows. - Properly calculate the minimum and maximum window size on Windows, including window decorations. - Map more `MouseCursor` variants to cursor icons on Windows. +- Discard the stray mouse down event being delivered after window resize on macOS. # Version 0.12.0 (2018-04-06) diff --git a/src/platform/macos/events_loop.rs b/src/platform/macos/events_loop.rs index 1d822dc1..ea756812 100644 --- a/src/platform/macos/events_loop.rs +++ b/src/platform/macos/events_loop.rs @@ -6,6 +6,7 @@ use std::collections::VecDeque; use std::sync::{Arc, Mutex, Weak}; use super::window::Window2; use std; +use std::cell::RefCell; use super::DeviceId; @@ -18,6 +19,7 @@ pub struct EventsLoop { pub struct Shared { pub windows: Mutex>>, pub pending_events: Mutex>, + pub discard_event: RefCell, // The user event callback given via either of the `poll_events` or `run_forever` methods. // // We store the user's callback here so that it may be accessed by each of the window delegate @@ -55,6 +57,7 @@ impl Shared { Shared { windows: Mutex::new(Vec::new()), pending_events: Mutex::new(VecDeque::new()), + discard_event: RefCell::new(false), user_callback: UserCallback { mutex: Mutex::new(None) }, } } @@ -99,6 +102,19 @@ impl Shared { } } + // Instructs the `EventsLoop` to discard the next input event. + // + // This is called when the window is resized, to avoid a delayed mouse down event being posted + // after the resize completes. + pub fn discard_next_event(&self) { + *self.discard_event.borrow_mut() = true; + } + + fn should_discard_next_event(&self) -> bool { + let result = *self.discard_event.borrow(); + *self.discard_event.borrow_mut() = false; + result + } } @@ -201,7 +217,11 @@ impl EventsLoop { match event { // Call the user's callback. - Some(event) => self.shared.user_callback.call_with_event(event), + Some(event) => { + if !self.shared.should_discard_next_event() { + self.shared.user_callback.call_with_event(event); + } + }, None => break, } } @@ -254,7 +274,9 @@ impl EventsLoop { let _: () = msg_send![pool, release]; if let Some(event) = maybe_event { - self.shared.user_callback.call_with_event(event); + if !self.shared.should_discard_next_event() { + self.shared.user_callback.call_with_event(event); + } if let ControlFlow::Break = control_flow.get() { break; } diff --git a/src/platform/macos/window.rs b/src/platform/macos/window.rs index 2d6f31ae..bdae5aea 100644 --- a/src/platform/macos/window.rs +++ b/src/platform/macos/window.rs @@ -87,6 +87,11 @@ impl WindowDelegate { let state: *mut c_void = *this.get_ivar("winitState"); let state = &mut *(state as *mut DelegateState); emit_resize_event(state); + + // discard the pending mouse down event + if let Some(shared) = state.shared.upgrade() { + shared.discard_next_event(); + } } }