Skip to content

Commit

Permalink
Linux: Implement EventLoopExtPumpEvents and EventLoopExtRunOnDemand
Browse files Browse the repository at this point in the history
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 (4ac2006) 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.
  • Loading branch information
rib committed Jun 26, 2023
1 parent ac89238 commit c2496ea
Show file tree
Hide file tree
Showing 5 changed files with 771 additions and 501 deletions.
20 changes: 16 additions & 4 deletions src/platform/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@
//!
//! And the following platform-specific modules:
//!
//! - `run_ondemand` (available on `windows`, `macos`, `android`)
//! - `pump_events` (available on `windows`, `macos`, `android`)
//! - `run_ondemand` (available on `windows`, `unix`, `macos`, `android`)
//! - `pump_events` (available on `windows`, `unix`, `macos`, `android`)
//! - `run_return` (available on `windows`, `unix`, `macos`, and `android`)
//!
//! However only the module corresponding to the platform you're compiling to will be available.
Expand All @@ -34,10 +34,22 @@ pub mod windows;
#[cfg(x11_platform)]
pub mod x11;

#[cfg(any(windows_platform, macos_platform, android_platform))]
#[cfg(any(
windows_platform,
macos_platform,
android_platform,
x11_platform,
wayland_platform
))]
pub mod run_ondemand;

#[cfg(any(windows_platform, macos_platform, android_platform,))]
#[cfg(any(
windows_platform,
macos_platform,
android_platform,
x11_platform,
wayland_platform
))]
pub mod pump_events;

#[cfg(any(
Expand Down
31 changes: 29 additions & 2 deletions src/platform_impl/linux/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -28,12 +29,15 @@ use self::x11::{ffi::XVisualInfo, util::WindowType as XWindowType, XConnection,
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::{ControlFlow, DeviceEvents, EventLoopClosed, EventLoopWindowTarget as RootELW},
icon::Icon,
keyboard::{Key, KeyCode},
platform::{modifier_supplement::KeyEventExtModifierSupplement, scancode::KeyCodeExtScancode},
platform::{
modifier_supplement::KeyEventExtModifierSupplement, pump_events::PumpStatus,
scancode::KeyCodeExtScancode,
},
window::{
CursorGrabMode, CursorIcon, ImePurpose, ResizeDirection, Theme, UserAttentionType,
WindowAttributes, WindowButtons, WindowLevel,
Expand Down Expand Up @@ -830,6 +834,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())
}
Expand Down Expand Up @@ -923,6 +941,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 {
use libc::{c_long, getpid, syscall, SYS_gettid};
Expand Down
Loading

0 comments on commit c2496ea

Please sign in to comment.