Linux: Sync with server/compositor before exiting run_ondemand

Although we document that applications can't keep windows between
separate run_ondemand calls it's possible that the application has only
just dropped their windows and we need to flush these requests to the
server/compositor.

This fixes the window_ondemand example - by ensuring the window from
the first loop really is destroyed before waiting for 5 seconds
and starting the second loop.
This commit is contained in:
Robert Bragg 2023-07-04 22:53:17 +01:00 committed by Kirill Chibisov
parent 9e46dffcc5
commit ec11b4877f
2 changed files with 42 additions and 7 deletions

View file

@ -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> {

View file

@ -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