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.
This commit is contained in:
Tristam MacDonald 2018-04-15 10:16:44 -07:00 committed by Francesca Frangipane
parent 2477d8ce46
commit 19cd53193b
3 changed files with 30 additions and 2 deletions

View file

@ -9,6 +9,7 @@
- Implemented `Refresh` event on Windows. - Implemented `Refresh` event on Windows.
- Properly calculate the minimum and maximum window size on Windows, including window decorations. - Properly calculate the minimum and maximum window size on Windows, including window decorations.
- Map more `MouseCursor` variants to cursor icons on Windows. - 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) # Version 0.12.0 (2018-04-06)

View file

@ -6,6 +6,7 @@ use std::collections::VecDeque;
use std::sync::{Arc, Mutex, Weak}; use std::sync::{Arc, Mutex, Weak};
use super::window::Window2; use super::window::Window2;
use std; use std;
use std::cell::RefCell;
use super::DeviceId; use super::DeviceId;
@ -18,6 +19,7 @@ pub struct EventsLoop {
pub struct Shared { pub struct Shared {
pub windows: Mutex<Vec<Weak<Window2>>>, pub windows: Mutex<Vec<Weak<Window2>>>,
pub pending_events: Mutex<VecDeque<Event>>, pub pending_events: Mutex<VecDeque<Event>>,
pub discard_event: RefCell<bool>,
// The user event callback given via either of the `poll_events` or `run_forever` methods. // 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 // 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 { Shared {
windows: Mutex::new(Vec::new()), windows: Mutex::new(Vec::new()),
pending_events: Mutex::new(VecDeque::new()), pending_events: Mutex::new(VecDeque::new()),
discard_event: RefCell::new(false),
user_callback: UserCallback { mutex: Mutex::new(None) }, 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 { match event {
// Call the user's callback. // 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, None => break,
} }
} }
@ -254,7 +274,9 @@ impl EventsLoop {
let _: () = msg_send![pool, release]; let _: () = msg_send![pool, release];
if let Some(event) = maybe_event { 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() { if let ControlFlow::Break = control_flow.get() {
break; break;
} }

View file

@ -87,6 +87,11 @@ impl WindowDelegate {
let state: *mut c_void = *this.get_ivar("winitState"); let state: *mut c_void = *this.get_ivar("winitState");
let state = &mut *(state as *mut DelegateState); let state = &mut *(state as *mut DelegateState);
emit_resize_event(state); emit_resize_event(state);
// discard the pending mouse down event
if let Some(shared) = state.shared.upgrade() {
shared.discard_next_event();
}
} }
} }