Linux: Implement EventLoopExtPumpEvents and EventLoopExtRunOnDemand
Wayland:
I found the calloop abstraction a little awkward to work with while I was
trying to understand why there was surprising workaround code in the wayland
backend for manually dispatching pending events.
Investigating this further it looks like there may currently be several issues
with the calloop WaylandSource (with how prepare_read is used and with (not)
flushing writes before polling)
Considering the current minimal needs for polling in all winit backends I do
personally tend to think it would be simpler to just own the responsibility for
polling more directly, so the logic for wayland-client `prepare_read` wouldn't
be in a separate crate (and in this current situation would also be easier to fix)
I've tried to maintain the status quo with calloop + workarounds.
X11:
I found that the recent changes (4ac2006cbc) to port the X11 backend
from mio to calloop lost the ability to check for pending events before
needing to poll/dispatch. (The `has_pending` state being queried
before dispatching() was based on state that was filled in during
dispatching)
As part of the rebase this re-introduces the PeekableReceiver and
WakeSender which are small utilities on top of
`std::sync::mpsc::channel()`. This adds a calloop `PingSource`
so we can use a `Ping` as a generic event loop waker.
For taking into account false positive wake ups the X11 source now
tracks when the file descriptor is readable so after we poll via
calloop we can then specifically check if there are new X11 events
or pending redraw/user events when deciding whether to skip the
event loop iteration.
This commit is contained in:
parent
461efaf99f
commit
c47d0846fa
5 changed files with 835 additions and 578 deletions
|
|
@ -19,6 +19,7 @@ use std::{
|
|||
use once_cell::sync::Lazy;
|
||||
use raw_window_handle::{RawDisplayHandle, RawWindowHandle};
|
||||
use smol_str::SmolStr;
|
||||
use std::time::Duration;
|
||||
|
||||
#[cfg(x11_platform)]
|
||||
pub use self::x11::XNotSupported;
|
||||
|
|
@ -28,7 +29,7 @@ use self::x11::{ffi::XVisualInfo, util::WindowType as XWindowType, X11Error, XCo
|
|||
use crate::platform::x11::XlibErrorHook;
|
||||
use crate::{
|
||||
dpi::{PhysicalPosition, PhysicalSize, Position, Size},
|
||||
error::{ExternalError, NotSupportedError, OsError as RootOsError},
|
||||
error::{ExternalError, NotSupportedError, OsError as RootOsError, RunLoopError},
|
||||
event::{Event, KeyEvent},
|
||||
event_loop::{
|
||||
AsyncRequestSerial, ControlFlow, DeviceEvents, EventLoopClosed,
|
||||
|
|
@ -36,7 +37,10 @@ use crate::{
|
|||
},
|
||||
icon::Icon,
|
||||
keyboard::{Key, KeyCode},
|
||||
platform::{modifier_supplement::KeyEventExtModifierSupplement, scancode::KeyCodeExtScancode},
|
||||
platform::{
|
||||
modifier_supplement::KeyEventExtModifierSupplement, pump_events::PumpStatus,
|
||||
scancode::KeyCodeExtScancode,
|
||||
},
|
||||
window::{
|
||||
ActivationToken, CursorGrabMode, CursorIcon, ImePurpose, ResizeDirection, Theme,
|
||||
UserAttentionType, WindowAttributes, WindowButtons, WindowLevel,
|
||||
|
|
@ -840,6 +844,20 @@ impl<T: 'static> EventLoop<T> {
|
|||
x11_or_wayland!(match self; EventLoop(evlp) => evlp.run(callback))
|
||||
}
|
||||
|
||||
pub fn run_ondemand<F>(&mut self, callback: F) -> Result<(), RunLoopError>
|
||||
where
|
||||
F: FnMut(crate::event::Event<'_, T>, &RootELW<T>, &mut ControlFlow),
|
||||
{
|
||||
x11_or_wayland!(match self; EventLoop(evlp) => evlp.run_ondemand(callback))
|
||||
}
|
||||
|
||||
pub fn pump_events<F>(&mut self, callback: F) -> PumpStatus
|
||||
where
|
||||
F: FnMut(crate::event::Event<'_, T>, &RootELW<T>, &mut ControlFlow),
|
||||
{
|
||||
x11_or_wayland!(match self; EventLoop(evlp) => evlp.pump_events(callback))
|
||||
}
|
||||
|
||||
pub fn window_target(&self) -> &crate::event_loop::EventLoopWindowTarget<T> {
|
||||
x11_or_wayland!(match self; EventLoop(evlp) => evlp.window_target())
|
||||
}
|
||||
|
|
@ -933,6 +951,15 @@ fn sticky_exit_callback<T, F>(
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns the minimum `Option<Duration>`, taking into account that `None`
|
||||
/// equates to an infinite timeout, not a zero timeout (so can't just use
|
||||
/// `Option::min`)
|
||||
fn min_timeout(a: Option<Duration>, b: Option<Duration>) -> Option<Duration> {
|
||||
a.map_or(b, |a_timeout| {
|
||||
b.map_or(Some(a_timeout), |b_timeout| Some(a_timeout.min(b_timeout)))
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn is_main_thread() -> bool {
|
||||
rustix::thread::gettid() == rustix::process::getpid()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue