diff --git a/CHANGELOG.md b/CHANGELOG.md index 5f2d3741..0c55d004 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # Unreleased - On macOS, fix application termination on `ControlFlow::Exit` +- On X11, fix events not being reported when using `run_return`. - On X11, fix key modifiers being incorrectly reported. # 0.20.0 Alpha 4 (2019-10-18) diff --git a/examples/timer.rs b/examples/timer.rs index e1e3f290..75bf2831 100644 --- a/examples/timer.rs +++ b/examples/timer.rs @@ -17,7 +17,10 @@ fn main() { let timer_length = Duration::new(1, 0); event_loop.run(move |event, _, control_flow| { - println!("{:?}", event); + if let Event::WindowEvent { event, .. } = &event { + // Print only Window events to reduce noise + println!("{:?}", event); + } match event { Event::NewEvents(StartCause::Init) => { diff --git a/examples/window_run_return.rs b/examples/window_run_return.rs index 29ea7b3c..5096ef31 100644 --- a/examples/window_run_return.rs +++ b/examples/window_run_return.rs @@ -9,6 +9,7 @@ target_os = "openbsd" ))] fn main() { + use std::{thread::sleep, time::Duration}; use winit::{ event::{Event, WindowEvent}, event_loop::{ControlFlow, EventLoop}, @@ -17,36 +18,38 @@ fn main() { }; let mut event_loop = EventLoop::new(); - let window = WindowBuilder::new() + let _window = WindowBuilder::new() .with_title("A fantastic window!") .build(&event_loop) .unwrap(); - println!("Close the window to continue."); - event_loop.run_return(|event, _, control_flow| match event { - Event::WindowEvent { - event: WindowEvent::CloseRequested, - .. - } => *control_flow = ControlFlow::Exit, - _ => *control_flow = ControlFlow::Wait, - }); - drop(window); + let mut quit = false; - let _window_2 = WindowBuilder::new() - .with_title("A second, fantasticer window!") - .build(&event_loop) - .unwrap(); + while !quit { + event_loop.run_return(|event, _, control_flow| { + if let Event::WindowEvent { event, .. } = &event { + // Print only Window events to reduce noise + println!("{:?}", event); + } - println!("Wa ha ha! You thought that closing the window would finish this?!"); - event_loop.run_return(|event, _, control_flow| match event { - Event::WindowEvent { - event: WindowEvent::CloseRequested, - .. - } => *control_flow = ControlFlow::Exit, - _ => *control_flow = ControlFlow::Wait, - }); + match event { + Event::WindowEvent { + event: WindowEvent::CloseRequested, + .. + } => { + quit = true; + *control_flow = ControlFlow::Exit; + } + Event::EventsCleared => { + *control_flow = ControlFlow::Exit; + } + _ => *control_flow = ControlFlow::Wait, + } + }); - println!("Okay we're done now for real."); + // Sleep for 1/60 second to simulate rendering + sleep(Duration::from_millis(16)); + } } #[cfg(any(target_os = "ios", target_os = "android", target_arch = "wasm32"))] diff --git a/src/platform_impl/linux/x11/event_processor.rs b/src/platform_impl/linux/x11/event_processor.rs index 53178ebf..bce77e8e 100644 --- a/src/platform_impl/linux/x11/event_processor.rs +++ b/src/platform_impl/linux/x11/event_processor.rs @@ -66,6 +66,13 @@ impl EventProcessor { self.with_window(window_id, |_| ()).is_some() } + pub(super) fn poll(&self) -> bool { + let wt = get_xtarget(&self.target); + let result = unsafe { (wt.xconn.xlib.XPending)(wt.xconn.display) }; + + result != 0 + } + pub(super) unsafe fn poll_one_event(&mut self, event_ptr: *mut ffi::XEvent) -> bool { let wt = get_xtarget(&self.target); // This function is used to poll and remove a single event diff --git a/src/platform_impl/linux/x11/mod.rs b/src/platform_impl/linux/x11/mod.rs index 90f09cfb..25e8b07a 100644 --- a/src/platform_impl/linux/x11/mod.rs +++ b/src/platform_impl/linux/x11/mod.rs @@ -26,6 +26,7 @@ use std::{ rc::Rc, slice, sync::{mpsc, Arc, Mutex, Weak}, + time::{Duration, Instant}, }; use libc::{self, setlocale, LC_CTYPE}; @@ -38,7 +39,7 @@ use self::{ }; use crate::{ error::OsError as RootOsError, - event::{Event, WindowEvent}, + event::{Event, StartCause, WindowEvent}, event_loop::{ControlFlow, EventLoopClosed, EventLoopWindowTarget as RootELW}, platform_impl::{platform::sticky_exit_callback, PlatformSpecificWindowBuilderAttributes}, window::WindowAttributes, @@ -262,6 +263,8 @@ impl EventLoop { ); loop { + self.drain_events(); + // Empty the event buffer { let mut guard = self.pending_events.borrow_mut(); @@ -309,69 +312,58 @@ impl EventLoop { ); } + let start = Instant::now(); + let (mut cause, deadline, mut timeout); + match control_flow { ControlFlow::Exit => break, ControlFlow::Poll => { - // non-blocking dispatch - self.inner_loop - .dispatch(Some(::std::time::Duration::from_millis(0)), &mut ()) - .unwrap(); - callback( - crate::event::Event::NewEvents(crate::event::StartCause::Poll), - &self.target, - &mut control_flow, - ); + cause = StartCause::Poll; + deadline = None; + timeout = Some(Duration::from_millis(0)); } ControlFlow::Wait => { - self.inner_loop.dispatch(None, &mut ()).unwrap(); - callback( - crate::event::Event::NewEvents(crate::event::StartCause::WaitCancelled { - start: ::std::time::Instant::now(), - requested_resume: None, - }), - &self.target, - &mut control_flow, - ); - } - ControlFlow::WaitUntil(deadline) => { - let start = ::std::time::Instant::now(); - // compute the blocking duration - let duration = if deadline > start { - deadline - start - } else { - ::std::time::Duration::from_millis(0) + cause = StartCause::WaitCancelled { + start, + requested_resume: None, }; - self.inner_loop.dispatch(Some(duration), &mut ()).unwrap(); - let now = std::time::Instant::now(); - if now < deadline { - callback( - crate::event::Event::NewEvents( - crate::event::StartCause::WaitCancelled { - start, - requested_resume: Some(deadline), - }, - ), - &self.target, - &mut control_flow, - ); + deadline = None; + timeout = None; + } + ControlFlow::WaitUntil(wait_deadline) => { + cause = StartCause::ResumeTimeReached { + start, + requested_resume: wait_deadline, + }; + timeout = if wait_deadline > start { + Some(wait_deadline - start) } else { - callback( - crate::event::Event::NewEvents( - crate::event::StartCause::ResumeTimeReached { - start, - requested_resume: deadline, - }, - ), - &self.target, - &mut control_flow, - ); - } + Some(Duration::from_millis(0)) + }; + deadline = Some(wait_deadline); } } - // If the user callback had any interaction with the X server, - // it may have received and buffered some user input events. - self.drain_events(); + if self.events_waiting() { + timeout = Some(Duration::from_millis(0)); + } + + self.inner_loop.dispatch(timeout, &mut ()).unwrap(); + + if let Some(deadline) = deadline { + if deadline > Instant::now() { + cause = StartCause::WaitCancelled { + start, + requested_resume: Some(deadline), + }; + } + } + + callback( + crate::event::Event::NewEvents(cause), + &self.target, + &mut control_flow, + ); } callback( @@ -395,6 +387,10 @@ impl EventLoop { drain_events(&mut processor, &mut pending_events); } + + fn events_waiting(&self) -> bool { + !self.pending_events.borrow().is_empty() || self.event_processor.borrow().poll() + } } fn drain_events(