diff --git a/src/platform_impl/linux/wayland/event_loop/mod.rs b/src/platform_impl/linux/wayland/event_loop/mod.rs index afe7c3e5..2a00afa6 100644 --- a/src/platform_impl/linux/wayland/event_loop/mod.rs +++ b/src/platform_impl/linux/wayland/event_loop/mod.rs @@ -16,13 +16,13 @@ use sctk::reexports::client::globals; use sctk::reexports::client::{Connection, Proxy, QueueHandle, WaylandSource}; use crate::dpi::{LogicalSize, PhysicalSize}; -use crate::error::RunLoopError; +use crate::error::{OsError as RootOsError, RunLoopError}; use crate::event::{Event, StartCause, WindowEvent}; use crate::event_loop::{ControlFlow, EventLoopWindowTarget as RootEventLoopWindowTarget}; use crate::platform::pump_events::PumpStatus; use crate::platform_impl::platform::min_timeout; use crate::platform_impl::platform::sticky_exit_callback; -use crate::platform_impl::EventLoopWindowTarget as PlatformEventLoopWindowTarget; +use crate::platform_impl::{EventLoopWindowTarget as PlatformEventLoopWindowTarget, OsError}; mod proxy; pub mod sink; @@ -153,7 +153,7 @@ impl<T: 'static> EventLoop<T> { return Err(RunLoopError::AlreadyRunning); } - loop { + let exit = loop { match self.pump_events_with_timeout(None, &mut event_handler) { PumpStatus::Exit(0) => { break Ok(()); @@ -165,7 +165,15 @@ impl<T: 'static> EventLoop<T> { continue; } } - } + }; + + // Applications aren't allowed to carry windows between separate + // `run_ondemand` calls but if they have only just dropped their + // windows we need to make sure those last requests are sent to the + // compositor. + let _ = self.roundtrip().map_err(RunLoopError::Os); + + exit } pub fn pump_events<F>(&mut self, event_handler: F) -> PumpStatus @@ -574,6 +582,22 @@ impl<T: 'static> EventLoop<T> { error.into() }) } + + fn roundtrip(&mut self) -> Result<usize, RootOsError> { + let state = match &mut self.window_target.p { + PlatformEventLoopWindowTarget::Wayland(window_target) => window_target.state.get_mut(), + #[cfg(feature = "x11")] + _ => unreachable!(), + }; + + let mut wayland_source = self.wayland_dispatcher.as_source_mut(); + let event_queue = wayland_source.queue(); + event_queue.roundtrip(state).map_err(|_| { + os_error!(OsError::WaylandMisc( + "failed to do a final roundtrip before exiting the loop." + )) + }) + } } pub struct EventLoopWindowTarget<T> { diff --git a/src/platform_impl/linux/x11/mod.rs b/src/platform_impl/linux/x11/mod.rs index c6381288..897fded3 100644 --- a/src/platform_impl/linux/x11/mod.rs +++ b/src/platform_impl/linux/x11/mod.rs @@ -62,7 +62,7 @@ use self::{ event_processor::EventProcessor, ime::{Ime, ImeCreationError, ImeReceiver, ImeRequest, ImeSender}, }; -use super::common::xkb_state::KbdState; +use super::{common::xkb_state::KbdState, OsError}; use crate::{ error::{OsError as RootOsError, RunLoopError}, event::{Event, StartCause}, @@ -440,7 +440,7 @@ impl<T: 'static> EventLoop<T> { return Err(RunLoopError::AlreadyRunning); } - loop { + let exit = loop { match self.pump_events_with_timeout(None, &mut event_handler) { PumpStatus::Exit(0) => { break Ok(()); @@ -452,7 +452,18 @@ impl<T: 'static> EventLoop<T> { continue; } } - } + }; + + // Applications aren't allowed to carry windows between separate + // `run_ondemand` calls but if they have only just dropped their + // windows we need to make sure those last requests are sent to the + // X Server. + let wt = get_xtarget(&self.target); + wt.x_connection().sync_with_server().map_err(|x_err| { + RunLoopError::Os(os_error!(OsError::XError(Arc::new(X11Error::Xlib(x_err))))) + })?; + + exit } pub fn pump_events<F>(&mut self, event_handler: F) -> PumpStatus