event_loop: remove generic user event
Let the users wake up the event loop and then they could poll their user sources. Co-authored-by: Mads Marquart <mads@marquart.dk> Co-authored-by: daxpedda <daxpedda@gmail.com>
This commit is contained in:
parent
7d1287958f
commit
ecb887e5c3
|
@ -85,7 +85,7 @@ fn main() -> Result<(), impl std::error::Error> {
|
||||||
event_loop.create_window(window_attributes).unwrap()
|
event_loop.create_window(window_attributes).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
let event_loop: EventLoop<()> = EventLoop::new().unwrap();
|
let event_loop = EventLoop::new().unwrap();
|
||||||
let mut app = Application::default();
|
let mut app = Application::default();
|
||||||
event_loop.run_app(&mut app)
|
event_loop.run_app(&mut app)
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,7 +44,7 @@ fn main() -> Result<(), Box<dyn Error>> {
|
||||||
|
|
||||||
tracing::init();
|
tracing::init();
|
||||||
|
|
||||||
let event_loop = EventLoop::<UserEvent>::with_user_event().build()?;
|
let event_loop = EventLoop::new()?;
|
||||||
let _event_loop_proxy = event_loop.create_proxy();
|
let _event_loop_proxy = event_loop.create_proxy();
|
||||||
|
|
||||||
// Wire the user event from another thread.
|
// Wire the user event from another thread.
|
||||||
|
@ -54,7 +54,7 @@ fn main() -> Result<(), Box<dyn Error>> {
|
||||||
// from a different thread.
|
// from a different thread.
|
||||||
info!("Starting to send user event every second");
|
info!("Starting to send user event every second");
|
||||||
loop {
|
loop {
|
||||||
let _ = _event_loop_proxy.send_event(UserEvent::WakeUp);
|
_event_loop_proxy.wake_up();
|
||||||
std::thread::sleep(std::time::Duration::from_secs(1));
|
std::thread::sleep(std::time::Duration::from_secs(1));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -64,12 +64,6 @@ fn main() -> Result<(), Box<dyn Error>> {
|
||||||
event_loop.run_app(&mut state).map_err(Into::into)
|
event_loop.run_app(&mut state).map_err(Into::into)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
enum UserEvent {
|
|
||||||
WakeUp,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Application state and event handling.
|
/// Application state and event handling.
|
||||||
struct Application {
|
struct Application {
|
||||||
/// Custom cursors assets.
|
/// Custom cursors assets.
|
||||||
|
@ -85,7 +79,7 @@ struct Application {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Application {
|
impl Application {
|
||||||
fn new<T>(event_loop: &EventLoop<T>) -> Self {
|
fn new(event_loop: &EventLoop) -> Self {
|
||||||
// SAFETY: we drop the context right before the event loop is stopped, thus making it safe.
|
// SAFETY: we drop the context right before the event loop is stopped, thus making it safe.
|
||||||
#[cfg(not(any(android_platform, ios_platform)))]
|
#[cfg(not(any(android_platform, ios_platform)))]
|
||||||
let context = Some(
|
let context = Some(
|
||||||
|
@ -308,9 +302,9 @@ impl Application {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ApplicationHandler<UserEvent> for Application {
|
impl ApplicationHandler for Application {
|
||||||
fn user_event(&mut self, _event_loop: &ActiveEventLoop, event: UserEvent) {
|
fn proxy_wake_up(&mut self, _event_loop: &ActiveEventLoop) {
|
||||||
info!("User event: {event:?}");
|
info!("User wake up");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn window_event(
|
fn window_event(
|
||||||
|
|
|
@ -5,7 +5,7 @@ use crate::event_loop::ActiveEventLoop;
|
||||||
use crate::window::WindowId;
|
use crate::window::WindowId;
|
||||||
|
|
||||||
/// The handler of the application events.
|
/// The handler of the application events.
|
||||||
pub trait ApplicationHandler<T: 'static = ()> {
|
pub trait ApplicationHandler {
|
||||||
/// Emitted when new events arrive from the OS to be processed.
|
/// Emitted when new events arrive from the OS to be processed.
|
||||||
///
|
///
|
||||||
/// This is a useful place to put code that should be done before you start processing
|
/// This is a useful place to put code that should be done before you start processing
|
||||||
|
@ -82,11 +82,95 @@ pub trait ApplicationHandler<T: 'static = ()> {
|
||||||
/// [`Suspended`]: Self::suspended
|
/// [`Suspended`]: Self::suspended
|
||||||
fn resumed(&mut self, event_loop: &ActiveEventLoop);
|
fn resumed(&mut self, event_loop: &ActiveEventLoop);
|
||||||
|
|
||||||
/// Emitted when an event is sent from [`EventLoopProxy::send_event`].
|
/// Called after a wake up is requested using [`EventLoopProxy::wake_up()`].
|
||||||
///
|
///
|
||||||
/// [`EventLoopProxy::send_event`]: crate::event_loop::EventLoopProxy::send_event
|
/// Multiple calls to the aforementioned method will be merged, and will only wake the event
|
||||||
fn user_event(&mut self, event_loop: &ActiveEventLoop, event: T) {
|
/// loop once; however, due to the nature of multi-threading some wake ups may appear
|
||||||
let _ = (event_loop, event);
|
/// spuriously. For these reasons, you should not rely on the number of times that this was
|
||||||
|
/// called.
|
||||||
|
///
|
||||||
|
/// The order in which this is emitted in relation to other events is not guaranteed. The time
|
||||||
|
/// at which this will be emitted is not guaranteed, only that it will happen "soon". That is,
|
||||||
|
/// there may be several executions of the event loop, including multiple redraws to windows,
|
||||||
|
/// between [`EventLoopProxy::wake_up()`] being called and the event being delivered.
|
||||||
|
///
|
||||||
|
/// [`EventLoopProxy::wake_up()`]: crate::event_loop::EventLoopProxy::wake_up
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// Use a [`std::sync::mpsc`] channel to handle events from a different thread.
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// use std::sync::mpsc;
|
||||||
|
/// use std::thread;
|
||||||
|
/// use std::time::Duration;
|
||||||
|
///
|
||||||
|
/// use winit::application::ApplicationHandler;
|
||||||
|
/// use winit::event_loop::{ActiveEventLoop, EventLoop};
|
||||||
|
///
|
||||||
|
/// struct MyApp {
|
||||||
|
/// receiver: mpsc::Receiver<u64>,
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// impl ApplicationHandler for MyApp {
|
||||||
|
/// # fn window_event(
|
||||||
|
/// # &mut self,
|
||||||
|
/// # _event_loop: &ActiveEventLoop,
|
||||||
|
/// # _window_id: winit::window::WindowId,
|
||||||
|
/// # _event: winit::event::WindowEvent,
|
||||||
|
/// # ) {
|
||||||
|
/// # }
|
||||||
|
/// #
|
||||||
|
/// # fn resumed(&mut self, _event_loop: &ActiveEventLoop) {}
|
||||||
|
/// #
|
||||||
|
/// fn proxy_wake_up(&mut self, _event_loop: &ActiveEventLoop) {
|
||||||
|
/// // Iterate current events, since wake-ups may have been merged.
|
||||||
|
/// //
|
||||||
|
/// // Note: We take care not to use `recv` or `iter` here, as those are blocking,
|
||||||
|
/// // and that would be bad for performance and might lead to a deadlock.
|
||||||
|
/// for i in self.receiver.try_iter() {
|
||||||
|
/// println!("received: {i}");
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// // Rest of `ApplicationHandler`
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
/// let event_loop = EventLoop::new()?;
|
||||||
|
///
|
||||||
|
/// let (sender, receiver) = mpsc::channel();
|
||||||
|
///
|
||||||
|
/// let mut app = MyApp { receiver };
|
||||||
|
///
|
||||||
|
/// // Send an event in a loop
|
||||||
|
/// let proxy = event_loop.create_proxy();
|
||||||
|
/// let background_thread = thread::spawn(move || {
|
||||||
|
/// let mut i = 0;
|
||||||
|
/// loop {
|
||||||
|
/// println!("sending: {i}");
|
||||||
|
/// if sender.send(i).is_err() {
|
||||||
|
/// // Stop sending once `MyApp` is dropped
|
||||||
|
/// break;
|
||||||
|
/// }
|
||||||
|
/// // Trigger the wake-up _after_ we placed the event in the channel.
|
||||||
|
/// // Otherwise, `proxy_wake_up` might be triggered prematurely.
|
||||||
|
/// proxy.wake_up();
|
||||||
|
/// i += 1;
|
||||||
|
/// thread::sleep(Duration::from_secs(1));
|
||||||
|
/// }
|
||||||
|
/// });
|
||||||
|
///
|
||||||
|
/// event_loop.run_app(&mut app)?;
|
||||||
|
///
|
||||||
|
/// drop(app);
|
||||||
|
/// background_thread.join().unwrap();
|
||||||
|
///
|
||||||
|
/// Ok(())
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
fn proxy_wake_up(&mut self, event_loop: &ActiveEventLoop) {
|
||||||
|
let _ = event_loop;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Emitted when the OS sends an event to a winit window.
|
/// Emitted when the OS sends an event to a winit window.
|
||||||
|
@ -224,7 +308,7 @@ pub trait ApplicationHandler<T: 'static = ()> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<A: ?Sized + ApplicationHandler<T>, T: 'static> ApplicationHandler<T> for &mut A {
|
impl<A: ?Sized + ApplicationHandler> ApplicationHandler for &mut A {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn new_events(&mut self, event_loop: &ActiveEventLoop, cause: StartCause) {
|
fn new_events(&mut self, event_loop: &ActiveEventLoop, cause: StartCause) {
|
||||||
(**self).new_events(event_loop, cause);
|
(**self).new_events(event_loop, cause);
|
||||||
|
@ -236,8 +320,8 @@ impl<A: ?Sized + ApplicationHandler<T>, T: 'static> ApplicationHandler<T> for &m
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn user_event(&mut self, event_loop: &ActiveEventLoop, event: T) {
|
fn proxy_wake_up(&mut self, event_loop: &ActiveEventLoop) {
|
||||||
(**self).user_event(event_loop, event);
|
(**self).proxy_wake_up(event_loop);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -281,7 +365,7 @@ impl<A: ?Sized + ApplicationHandler<T>, T: 'static> ApplicationHandler<T> for &m
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<A: ?Sized + ApplicationHandler<T>, T: 'static> ApplicationHandler<T> for Box<A> {
|
impl<A: ?Sized + ApplicationHandler> ApplicationHandler for Box<A> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn new_events(&mut self, event_loop: &ActiveEventLoop, cause: StartCause) {
|
fn new_events(&mut self, event_loop: &ActiveEventLoop, cause: StartCause) {
|
||||||
(**self).new_events(event_loop, cause);
|
(**self).new_events(event_loop, cause);
|
||||||
|
@ -293,8 +377,8 @@ impl<A: ?Sized + ApplicationHandler<T>, T: 'static> ApplicationHandler<T> for Bo
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn user_event(&mut self, event_loop: &ActiveEventLoop, event: T) {
|
fn proxy_wake_up(&mut self, event_loop: &ActiveEventLoop) {
|
||||||
(**self).user_event(event_loop, event);
|
(**self).proxy_wake_up(event_loop);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -44,9 +44,18 @@ changelog entry.
|
||||||
|
|
||||||
- On Web, let events wake up event loop immediately when using `ControlFlow::Poll`.
|
- On Web, let events wake up event loop immediately when using `ControlFlow::Poll`.
|
||||||
- Bump MSRV from `1.70` to `1.73`.
|
- Bump MSRV from `1.70` to `1.73`.
|
||||||
|
- Changed `ApplicationHandler::user_event` to `user_wake_up`, removing the
|
||||||
|
generic user event.
|
||||||
|
|
||||||
|
Winit will now only indicate that wake up happened, you will have to pair
|
||||||
|
this with an external mechanism like `std::sync::mpsc::channel` if you want
|
||||||
|
to send specific data to be processed on the main thread.
|
||||||
|
- Changed `EventLoopProxy::send_event` to `EventLoopProxy::wake_up`, it now
|
||||||
|
only wakes up the loop.
|
||||||
|
|
||||||
### Removed
|
### Removed
|
||||||
|
|
||||||
- Remove `EventLoop::run`.
|
- Remove `EventLoop::run`.
|
||||||
- Remove `EventLoopExtRunOnDemand::run_on_demand`.
|
- Remove `EventLoopExtRunOnDemand::run_on_demand`.
|
||||||
- Remove `EventLoopExtPumpEvents::pump_events`.
|
- Remove `EventLoopExtPumpEvents::pump_events`.
|
||||||
|
- Remove `Event`.
|
||||||
|
|
|
@ -148,7 +148,7 @@
|
||||||
we move particular `match event` arms into methods on `ApplicationHandler`,
|
we move particular `match event` arms into methods on `ApplicationHandler`,
|
||||||
for example:
|
for example:
|
||||||
|
|
||||||
```rust,no_run
|
```rust,no_run,ignore
|
||||||
use winit::application::ApplicationHandler;
|
use winit::application::ApplicationHandler;
|
||||||
use winit::event::{Event, WindowEvent, DeviceEvent, DeviceId};
|
use winit::event::{Event, WindowEvent, DeviceEvent, DeviceId};
|
||||||
use winit::event_loop::{EventLoop, ActiveEventLoop};
|
use winit::event_loop::{EventLoop, ActiveEventLoop};
|
||||||
|
@ -211,7 +211,7 @@
|
||||||
|
|
||||||
Using the migration example from above, you can change your code as follows:
|
Using the migration example from above, you can change your code as follows:
|
||||||
|
|
||||||
```rust,no_run
|
```rust,no_run,ignore
|
||||||
use winit::application::ApplicationHandler;
|
use winit::application::ApplicationHandler;
|
||||||
use winit::event::{Event, WindowEvent, DeviceEvent, DeviceId};
|
use winit::event::{Event, WindowEvent, DeviceEvent, DeviceId};
|
||||||
use winit::event_loop::{EventLoop, ActiveEventLoop};
|
use winit::event_loop::{EventLoop, ActiveEventLoop};
|
||||||
|
|
52
src/event.rs
52
src/event.rs
|
@ -1,4 +1,4 @@
|
||||||
//! The [`Event`] enum and assorted supporting types.
|
//! The event enums and assorted supporting types.
|
||||||
//!
|
//!
|
||||||
//! These are sent to the closure given to [`EventLoop::run_app(...)`], where they get
|
//! These are sent to the closure given to [`EventLoop::run_app(...)`], where they get
|
||||||
//! processed and used to modify the program state. For more details, see the root-level
|
//! processed and used to modify the program state. For more details, see the root-level
|
||||||
|
@ -54,11 +54,15 @@ use crate::platform_impl;
|
||||||
use crate::window::Window;
|
use crate::window::Window;
|
||||||
use crate::window::{ActivationToken, Theme, WindowId};
|
use crate::window::{ActivationToken, Theme, WindowId};
|
||||||
|
|
||||||
|
// TODO: Remove once the backends can call `ApplicationHandler` methods directly. For now backends
|
||||||
|
// like Windows and Web require `Event` to wire user events, otherwise each backend will have to
|
||||||
|
// wrap `Event` in some other structure.
|
||||||
/// Describes a generic event.
|
/// Describes a generic event.
|
||||||
///
|
///
|
||||||
/// See the module-level docs for more information on the event loop manages each event.
|
/// See the module-level docs for more information on the event loop manages each event.
|
||||||
|
#[allow(dead_code)]
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub enum Event<T: 'static> {
|
pub(crate) enum Event {
|
||||||
/// See [`ApplicationHandler::new_events`] for details.
|
/// See [`ApplicationHandler::new_events`] for details.
|
||||||
///
|
///
|
||||||
/// [`ApplicationHandler::new_events`]: crate::application::ApplicationHandler::new_events
|
/// [`ApplicationHandler::new_events`]: crate::application::ApplicationHandler::new_events
|
||||||
|
@ -67,18 +71,15 @@ pub enum Event<T: 'static> {
|
||||||
/// See [`ApplicationHandler::window_event`] for details.
|
/// See [`ApplicationHandler::window_event`] for details.
|
||||||
///
|
///
|
||||||
/// [`ApplicationHandler::window_event`]: crate::application::ApplicationHandler::window_event
|
/// [`ApplicationHandler::window_event`]: crate::application::ApplicationHandler::window_event
|
||||||
|
#[allow(clippy::enum_variant_names)]
|
||||||
WindowEvent { window_id: WindowId, event: WindowEvent },
|
WindowEvent { window_id: WindowId, event: WindowEvent },
|
||||||
|
|
||||||
/// See [`ApplicationHandler::device_event`] for details.
|
/// See [`ApplicationHandler::device_event`] for details.
|
||||||
///
|
///
|
||||||
/// [`ApplicationHandler::device_event`]: crate::application::ApplicationHandler::device_event
|
/// [`ApplicationHandler::device_event`]: crate::application::ApplicationHandler::device_event
|
||||||
|
#[allow(clippy::enum_variant_names)]
|
||||||
DeviceEvent { device_id: DeviceId, event: DeviceEvent },
|
DeviceEvent { device_id: DeviceId, event: DeviceEvent },
|
||||||
|
|
||||||
/// See [`ApplicationHandler::user_event`] for details.
|
|
||||||
///
|
|
||||||
/// [`ApplicationHandler::user_event`]: crate::application::ApplicationHandler::user_event
|
|
||||||
UserEvent(T),
|
|
||||||
|
|
||||||
/// See [`ApplicationHandler::suspended`] for details.
|
/// See [`ApplicationHandler::suspended`] for details.
|
||||||
///
|
///
|
||||||
/// [`ApplicationHandler::suspended`]: crate::application::ApplicationHandler::suspended
|
/// [`ApplicationHandler::suspended`]: crate::application::ApplicationHandler::suspended
|
||||||
|
@ -103,24 +104,9 @@ pub enum Event<T: 'static> {
|
||||||
///
|
///
|
||||||
/// [`ApplicationHandler::memory_warning`]: crate::application::ApplicationHandler::memory_warning
|
/// [`ApplicationHandler::memory_warning`]: crate::application::ApplicationHandler::memory_warning
|
||||||
MemoryWarning,
|
MemoryWarning,
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> Event<T> {
|
/// User requested a wake up.
|
||||||
#[allow(clippy::result_large_err)]
|
UserWakeUp,
|
||||||
pub fn map_nonuser_event<U>(self) -> Result<Event<U>, Event<T>> {
|
|
||||||
use self::Event::*;
|
|
||||||
match self {
|
|
||||||
UserEvent(_) => Err(self),
|
|
||||||
WindowEvent { window_id, event } => Ok(WindowEvent { window_id, event }),
|
|
||||||
DeviceEvent { device_id, event } => Ok(DeviceEvent { device_id, event }),
|
|
||||||
NewEvents(cause) => Ok(NewEvents(cause)),
|
|
||||||
AboutToWait => Ok(AboutToWait),
|
|
||||||
LoopExiting => Ok(LoopExiting),
|
|
||||||
Suspended => Ok(Suspended),
|
|
||||||
Resumed => Ok(Resumed),
|
|
||||||
MemoryWarning => Ok(MemoryWarning),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Describes the reason the event loop is resuming.
|
/// Describes the reason the event loop is resuming.
|
||||||
|
@ -1032,7 +1018,6 @@ mod tests {
|
||||||
|
|
||||||
// Mainline events.
|
// Mainline events.
|
||||||
let wid = unsafe { WindowId::dummy() };
|
let wid = unsafe { WindowId::dummy() };
|
||||||
x(UserEvent(()));
|
|
||||||
x(NewEvents(event::StartCause::Init));
|
x(NewEvents(event::StartCause::Init));
|
||||||
x(AboutToWait);
|
x(AboutToWait);
|
||||||
x(LoopExiting);
|
x(LoopExiting);
|
||||||
|
@ -1116,25 +1101,12 @@ mod tests {
|
||||||
#[allow(clippy::redundant_clone)]
|
#[allow(clippy::redundant_clone)]
|
||||||
#[test]
|
#[test]
|
||||||
fn test_event_clone() {
|
fn test_event_clone() {
|
||||||
foreach_event!(|event: event::Event<()>| {
|
foreach_event!(|event: event::Event| {
|
||||||
let event2 = event.clone();
|
let event2 = event.clone();
|
||||||
assert_eq!(event, event2);
|
assert_eq!(event, event2);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_map_nonuser_event() {
|
|
||||||
foreach_event!(|event: event::Event<()>| {
|
|
||||||
let is_user = matches!(event, event::Event::UserEvent(()));
|
|
||||||
let event2 = event.map_nonuser_event::<()>();
|
|
||||||
if is_user {
|
|
||||||
assert_eq!(event2, Err(event::Event::UserEvent(())));
|
|
||||||
} else {
|
|
||||||
assert!(event2.is_ok());
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_force_normalize() {
|
fn test_force_normalize() {
|
||||||
let force = event::Force::Normalized(0.0);
|
let force = event::Force::Normalized(0.0);
|
||||||
|
@ -1155,7 +1127,7 @@ mod tests {
|
||||||
#[allow(clippy::clone_on_copy)]
|
#[allow(clippy::clone_on_copy)]
|
||||||
#[test]
|
#[test]
|
||||||
fn ensure_attrs_do_not_panic() {
|
fn ensure_attrs_do_not_panic() {
|
||||||
foreach_event!(|event: event::Event<()>| {
|
foreach_event!(|event: event::Event| {
|
||||||
let _ = format!("{:?}", event);
|
let _ = format!("{:?}", event);
|
||||||
});
|
});
|
||||||
let _ = event::StartCause::Init.clone();
|
let _ = event::StartCause::Init.clone();
|
||||||
|
|
|
@ -3,15 +3,16 @@
|
||||||
//!
|
//!
|
||||||
//! If you want to send custom events to the event loop, use
|
//! If you want to send custom events to the event loop, use
|
||||||
//! [`EventLoop::create_proxy`] to acquire an [`EventLoopProxy`] and call its
|
//! [`EventLoop::create_proxy`] to acquire an [`EventLoopProxy`] and call its
|
||||||
//! [`send_event`][EventLoopProxy::send_event] method.
|
//! [`wake_up`][EventLoopProxy::wake_up] method. Then during handling the wake up
|
||||||
|
//! you can poll your event sources.
|
||||||
//!
|
//!
|
||||||
//! See the root-level documentation for information on how to create and use an event loop to
|
//! See the root-level documentation for information on how to create and use an event loop to
|
||||||
//! handle events.
|
//! handle events.
|
||||||
|
use std::fmt;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
#[cfg(any(x11_platform, wayland_platform))]
|
#[cfg(any(x11_platform, wayland_platform))]
|
||||||
use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, RawFd};
|
use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, RawFd};
|
||||||
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
|
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
|
||||||
use std::{error, fmt};
|
|
||||||
|
|
||||||
#[cfg(not(web_platform))]
|
#[cfg(not(web_platform))]
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
|
@ -39,8 +40,8 @@ use crate::window::{CustomCursor, CustomCursorSource, Window, WindowAttributes};
|
||||||
/// [`EventLoopProxy`] allows you to wake up an `EventLoop` from another thread.
|
/// [`EventLoopProxy`] allows you to wake up an `EventLoop` from another thread.
|
||||||
///
|
///
|
||||||
/// [`Window`]: crate::window::Window
|
/// [`Window`]: crate::window::Window
|
||||||
pub struct EventLoop<T: 'static> {
|
pub struct EventLoop {
|
||||||
pub(crate) event_loop: platform_impl::EventLoop<T>,
|
pub(crate) event_loop: platform_impl::EventLoop,
|
||||||
pub(crate) _marker: PhantomData<*mut ()>, // Not Send nor Sync
|
pub(crate) _marker: PhantomData<*mut ()>, // Not Send nor Sync
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,16 +59,15 @@ pub struct ActiveEventLoop {
|
||||||
/// This is used to make specifying options that affect the whole application
|
/// This is used to make specifying options that affect the whole application
|
||||||
/// easier. But note that constructing multiple event loops is not supported.
|
/// easier. But note that constructing multiple event loops is not supported.
|
||||||
///
|
///
|
||||||
/// This can be created using [`EventLoop::new`] or [`EventLoop::with_user_event`].
|
/// This can be created using [`EventLoop::builder`].
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct EventLoopBuilder<T: 'static> {
|
pub struct EventLoopBuilder {
|
||||||
pub(crate) platform_specific: platform_impl::PlatformSpecificEventLoopAttributes,
|
pub(crate) platform_specific: platform_impl::PlatformSpecificEventLoopAttributes,
|
||||||
_p: PhantomData<T>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static EVENT_LOOP_CREATED: AtomicBool = AtomicBool::new(false);
|
static EVENT_LOOP_CREATED: AtomicBool = AtomicBool::new(false);
|
||||||
|
|
||||||
impl EventLoopBuilder<()> {
|
impl EventLoopBuilder {
|
||||||
/// Start building a new event loop.
|
/// Start building a new event loop.
|
||||||
#[inline]
|
#[inline]
|
||||||
#[deprecated = "use `EventLoop::builder` instead"]
|
#[deprecated = "use `EventLoop::builder` instead"]
|
||||||
|
@ -76,7 +76,7 @@ impl EventLoopBuilder<()> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> EventLoopBuilder<T> {
|
impl EventLoopBuilder {
|
||||||
/// Builds a new event loop.
|
/// Builds a new event loop.
|
||||||
///
|
///
|
||||||
/// ***For cross-platform compatibility, the [`EventLoop`] must be created on the main thread,
|
/// ***For cross-platform compatibility, the [`EventLoop`] must be created on the main thread,
|
||||||
|
@ -111,7 +111,7 @@ impl<T> EventLoopBuilder<T> {
|
||||||
doc = "[`.with_android_app(app)`]: #only-available-on-android"
|
doc = "[`.with_android_app(app)`]: #only-available-on-android"
|
||||||
)]
|
)]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn build(&mut self) -> Result<EventLoop<T>, EventLoopError> {
|
pub fn build(&mut self) -> Result<EventLoop, EventLoopError> {
|
||||||
let _span = tracing::debug_span!("winit::EventLoopBuilder::build").entered();
|
let _span = tracing::debug_span!("winit::EventLoopBuilder::build").entered();
|
||||||
|
|
||||||
if EVENT_LOOP_CREATED.swap(true, Ordering::Relaxed) {
|
if EVENT_LOOP_CREATED.swap(true, Ordering::Relaxed) {
|
||||||
|
@ -132,7 +132,7 @@ impl<T> EventLoopBuilder<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> fmt::Debug for EventLoop<T> {
|
impl fmt::Debug for EventLoop {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
f.pad("EventLoop { .. }")
|
f.pad("EventLoop { .. }")
|
||||||
}
|
}
|
||||||
|
@ -146,12 +146,12 @@ impl fmt::Debug for ActiveEventLoop {
|
||||||
|
|
||||||
/// Set through [`ActiveEventLoop::set_control_flow()`].
|
/// Set through [`ActiveEventLoop::set_control_flow()`].
|
||||||
///
|
///
|
||||||
/// Indicates the desired behavior of the event loop after [`Event::AboutToWait`] is emitted.
|
/// Indicates the desired behavior of the event loop after [`about_to_wait`] is called.
|
||||||
///
|
///
|
||||||
/// Defaults to [`Wait`].
|
/// Defaults to [`Wait`].
|
||||||
///
|
///
|
||||||
/// [`Wait`]: Self::Wait
|
/// [`Wait`]: Self::Wait
|
||||||
/// [`Event::AboutToWait`]: crate::event::Event::AboutToWait
|
/// [`about_to_wait`]: crate::application::ApplicationHandler::about_to_wait
|
||||||
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
|
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
|
||||||
pub enum ControlFlow {
|
pub enum ControlFlow {
|
||||||
/// When the current loop iteration finishes, immediately begin a new iteration regardless of
|
/// When the current loop iteration finishes, immediately begin a new iteration regardless of
|
||||||
|
@ -189,12 +189,12 @@ impl ControlFlow {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EventLoop<()> {
|
impl EventLoop {
|
||||||
/// Create the event loop.
|
/// Create the event loop.
|
||||||
///
|
///
|
||||||
/// This is an alias of `EventLoop::builder().build()`.
|
/// This is an alias of `EventLoop::builder().build()`.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new() -> Result<EventLoop<()>, EventLoopError> {
|
pub fn new() -> Result<EventLoop, EventLoopError> {
|
||||||
Self::builder().build()
|
Self::builder().build()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -204,18 +204,12 @@ impl EventLoop<()> {
|
||||||
///
|
///
|
||||||
/// To get the actual event loop, call [`build`][EventLoopBuilder::build] on that.
|
/// To get the actual event loop, call [`build`][EventLoopBuilder::build] on that.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn builder() -> EventLoopBuilder<()> {
|
pub fn builder() -> EventLoopBuilder {
|
||||||
Self::with_user_event()
|
EventLoopBuilder { platform_specific: Default::default() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> EventLoop<T> {
|
impl EventLoop {
|
||||||
/// Start building a new event loop, with the given type as the user event
|
|
||||||
/// type.
|
|
||||||
pub fn with_user_event() -> EventLoopBuilder<T> {
|
|
||||||
EventLoopBuilder { platform_specific: Default::default(), _p: PhantomData }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Run the application with the event loop on the calling thread.
|
/// Run the application with the event loop on the calling thread.
|
||||||
///
|
///
|
||||||
/// See the [`set_control_flow()`] docs on how to change the event loop's behavior.
|
/// See the [`set_control_flow()`] docs on how to change the event loop's behavior.
|
||||||
|
@ -246,13 +240,13 @@ impl<T> EventLoop<T> {
|
||||||
/// [^1]: `EventLoopExtWebSys::spawn_app()` is only available on Web.
|
/// [^1]: `EventLoopExtWebSys::spawn_app()` is only available on Web.
|
||||||
#[inline]
|
#[inline]
|
||||||
#[cfg(not(all(web_platform, target_feature = "exception-handling")))]
|
#[cfg(not(all(web_platform, target_feature = "exception-handling")))]
|
||||||
pub fn run_app<A: ApplicationHandler<T>>(self, app: &mut A) -> Result<(), EventLoopError> {
|
pub fn run_app<A: ApplicationHandler>(self, app: &mut A) -> Result<(), EventLoopError> {
|
||||||
self.event_loop.run_app(app)
|
self.event_loop.run_app(app)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates an [`EventLoopProxy`] that can be used to dispatch user events
|
/// Creates an [`EventLoopProxy`] that can be used to dispatch user events
|
||||||
/// to the main event loop, possibly from another thread.
|
/// to the main event loop, possibly from another thread.
|
||||||
pub fn create_proxy(&self) -> EventLoopProxy<T> {
|
pub fn create_proxy(&self) -> EventLoopProxy {
|
||||||
EventLoopProxy { event_loop_proxy: self.event_loop.create_proxy() }
|
EventLoopProxy { event_loop_proxy: self.event_loop.create_proxy() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -308,14 +302,14 @@ impl<T> EventLoop<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "rwh_06")]
|
#[cfg(feature = "rwh_06")]
|
||||||
impl<T> rwh_06::HasDisplayHandle for EventLoop<T> {
|
impl rwh_06::HasDisplayHandle for EventLoop {
|
||||||
fn display_handle(&self) -> Result<rwh_06::DisplayHandle<'_>, rwh_06::HandleError> {
|
fn display_handle(&self) -> Result<rwh_06::DisplayHandle<'_>, rwh_06::HandleError> {
|
||||||
rwh_06::HasDisplayHandle::display_handle(self.event_loop.window_target())
|
rwh_06::HasDisplayHandle::display_handle(self.event_loop.window_target())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "rwh_05")]
|
#[cfg(feature = "rwh_05")]
|
||||||
unsafe impl<T> rwh_05::HasRawDisplayHandle for EventLoop<T> {
|
unsafe impl rwh_05::HasRawDisplayHandle for EventLoop {
|
||||||
/// Returns a [`rwh_05::RawDisplayHandle`] for the event loop.
|
/// Returns a [`rwh_05::RawDisplayHandle`] for the event loop.
|
||||||
fn raw_display_handle(&self) -> rwh_05::RawDisplayHandle {
|
fn raw_display_handle(&self) -> rwh_05::RawDisplayHandle {
|
||||||
rwh_05::HasRawDisplayHandle::raw_display_handle(self.event_loop.window_target())
|
rwh_05::HasRawDisplayHandle::raw_display_handle(self.event_loop.window_target())
|
||||||
|
@ -323,7 +317,7 @@ unsafe impl<T> rwh_05::HasRawDisplayHandle for EventLoop<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(x11_platform, wayland_platform))]
|
#[cfg(any(x11_platform, wayland_platform))]
|
||||||
impl<T> AsFd for EventLoop<T> {
|
impl AsFd for EventLoop {
|
||||||
/// Get the underlying [EventLoop]'s `fd` which you can register
|
/// Get the underlying [EventLoop]'s `fd` which you can register
|
||||||
/// into other event loop, like [`calloop`] or [`mio`]. When doing so, the
|
/// into other event loop, like [`calloop`] or [`mio`]. When doing so, the
|
||||||
/// loop must be polled with the [`pump_app_events`] API.
|
/// loop must be polled with the [`pump_app_events`] API.
|
||||||
|
@ -337,7 +331,7 @@ impl<T> AsFd for EventLoop<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(x11_platform, wayland_platform))]
|
#[cfg(any(x11_platform, wayland_platform))]
|
||||||
impl<T> AsRawFd for EventLoop<T> {
|
impl AsRawFd for EventLoop {
|
||||||
/// Get the underlying [EventLoop]'s raw `fd` which you can register
|
/// Get the underlying [EventLoop]'s raw `fd` which you can register
|
||||||
/// into other event loop, like [`calloop`] or [`mio`]. When doing so, the
|
/// into other event loop, like [`calloop`] or [`mio`]. When doing so, the
|
||||||
/// loop must be polled with the [`pump_app_events`] API.
|
/// loop must be polled with the [`pump_app_events`] API.
|
||||||
|
@ -434,7 +428,7 @@ impl ActiveEventLoop {
|
||||||
|
|
||||||
/// This exits the event loop.
|
/// This exits the event loop.
|
||||||
///
|
///
|
||||||
/// See [`LoopExiting`][crate::event::Event::LoopExiting].
|
/// See [`exiting`][crate::application::ApplicationHandler::exiting].
|
||||||
pub fn exit(&self) {
|
pub fn exit(&self) {
|
||||||
let _span = tracing::debug_span!("winit::ActiveEventLoop::exit",).entered();
|
let _span = tracing::debug_span!("winit::ActiveEventLoop::exit",).entered();
|
||||||
|
|
||||||
|
@ -519,53 +513,39 @@ unsafe impl rwh_05::HasRawDisplayHandle for OwnedDisplayHandle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Used to send custom events to [`EventLoop`].
|
/// Control the [`EventLoop`], possibly from a different thread, without referencing it directly.
|
||||||
pub struct EventLoopProxy<T: 'static> {
|
#[derive(Clone)]
|
||||||
event_loop_proxy: platform_impl::EventLoopProxy<T>,
|
pub struct EventLoopProxy {
|
||||||
|
event_loop_proxy: platform_impl::EventLoopProxy,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: 'static> Clone for EventLoopProxy<T> {
|
impl EventLoopProxy {
|
||||||
fn clone(&self) -> Self {
|
/// Wake up the [`EventLoop`], resulting in [`ApplicationHandler::proxy_wake_up()`] being
|
||||||
Self { event_loop_proxy: self.event_loop_proxy.clone() }
|
/// called.
|
||||||
|
///
|
||||||
|
/// Calls to this method are coalesced into a single call to [`proxy_wake_up`], see the
|
||||||
|
/// documentation on that for details.
|
||||||
|
///
|
||||||
|
/// If the event loop is no longer running, this is a no-op.
|
||||||
|
///
|
||||||
|
/// [`proxy_wake_up`]: ApplicationHandler::proxy_wake_up
|
||||||
|
///
|
||||||
|
/// # Platform-specific
|
||||||
|
///
|
||||||
|
/// - **Windows**: The wake-up may be ignored under high contention, see [#3687].
|
||||||
|
///
|
||||||
|
/// [#3687]: https://github.com/rust-windowing/winit/pull/3687
|
||||||
|
pub fn wake_up(&self) {
|
||||||
|
self.event_loop_proxy.wake_up();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: 'static> EventLoopProxy<T> {
|
impl fmt::Debug for EventLoopProxy {
|
||||||
/// Send an event to the [`EventLoop`] from which this proxy was created. This emits a
|
|
||||||
/// `UserEvent(event)` event in the event loop, where `event` is the value passed to this
|
|
||||||
/// function.
|
|
||||||
///
|
|
||||||
/// Returns an `Err` if the associated [`EventLoop`] no longer exists.
|
|
||||||
///
|
|
||||||
/// [`UserEvent(event)`]: Event::UserEvent
|
|
||||||
pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed<T>> {
|
|
||||||
let _span = tracing::debug_span!("winit::EventLoopProxy::send_event",).entered();
|
|
||||||
|
|
||||||
self.event_loop_proxy.send_event(event)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: 'static> fmt::Debug for EventLoopProxy<T> {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
f.pad("EventLoopProxy { .. }")
|
f.pad("EventLoopProxy { .. }")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The error that is returned when an [`EventLoopProxy`] attempts to wake up an [`EventLoop`] that
|
|
||||||
/// no longer exists.
|
|
||||||
///
|
|
||||||
/// Contains the original event given to [`EventLoopProxy::send_event`].
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
|
||||||
pub struct EventLoopClosed<T>(pub T);
|
|
||||||
|
|
||||||
impl<T> fmt::Display for EventLoopClosed<T> {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
f.write_str("Tried to wake up a closed `EventLoop`")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: fmt::Debug> error::Error for EventLoopClosed<T> {}
|
|
||||||
|
|
||||||
/// Control when device events are captured.
|
/// Control when device events are captured.
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Default)]
|
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Default)]
|
||||||
pub enum DeviceEvents {
|
pub enum DeviceEvents {
|
||||||
|
|
|
@ -19,12 +19,11 @@
|
||||||
//! window or a key getting pressed while the window is focused. Devices can generate
|
//! window or a key getting pressed while the window is focused. Devices can generate
|
||||||
//! [`DeviceEvent`]s, which contain unfiltered event data that isn't specific to a certain window.
|
//! [`DeviceEvent`]s, which contain unfiltered event data that isn't specific to a certain window.
|
||||||
//! Some user activity, like mouse movement, can generate both a [`WindowEvent`] *and* a
|
//! Some user activity, like mouse movement, can generate both a [`WindowEvent`] *and* a
|
||||||
//! [`DeviceEvent`]. You can also create and handle your own custom [`Event::UserEvent`]s, if
|
//! [`DeviceEvent`].
|
||||||
//! desired.
|
|
||||||
//!
|
//!
|
||||||
//! You can retrieve events by calling [`EventLoop::run_app()`]. This function will
|
//! You can retrieve events by calling [`EventLoop::run_app()`]. This function will
|
||||||
//! dispatch events for every [`Window`] that was created with that particular [`EventLoop`], and
|
//! dispatch events for every [`Window`] that was created with that particular [`EventLoop`], and
|
||||||
//! will run until [`exit()`] is used, at which point [`Event::LoopExiting`].
|
//! will run until [`exit()`] is used, at which point [`exiting()`] is called.
|
||||||
//!
|
//!
|
||||||
//! Winit no longer uses a `EventLoop::poll_events() -> impl Iterator<Event>`-based event loop
|
//! Winit no longer uses a `EventLoop::poll_events() -> impl Iterator<Event>`-based event loop
|
||||||
//! model, since that can't be implemented properly on some platforms (e.g web, iOS) and works
|
//! model, since that can't be implemented properly on some platforms (e.g web, iOS) and works
|
||||||
|
@ -163,7 +162,7 @@
|
||||||
//! [`WindowEvent`]: event::WindowEvent
|
//! [`WindowEvent`]: event::WindowEvent
|
||||||
//! [`DeviceEvent`]: event::DeviceEvent
|
//! [`DeviceEvent`]: event::DeviceEvent
|
||||||
//! [`Event::UserEvent`]: event::Event::UserEvent
|
//! [`Event::UserEvent`]: event::Event::UserEvent
|
||||||
//! [`Event::LoopExiting`]: event::Event::LoopExiting
|
//! [`exiting()`]: crate::application::ApplicationHandler::exiting
|
||||||
//! [`raw_window_handle`]: ./window/struct.Window.html#method.raw_window_handle
|
//! [`raw_window_handle`]: ./window/struct.Window.html#method.raw_window_handle
|
||||||
//! [`raw_display_handle`]: ./window/struct.Window.html#method.raw_display_handle
|
//! [`raw_display_handle`]: ./window/struct.Window.html#method.raw_display_handle
|
||||||
//! [^1]: `EventLoopExtPumpEvents::pump_app_events()` is only available on Windows, macOS, Android, X11 and Wayland.
|
//! [^1]: `EventLoopExtPumpEvents::pump_app_events()` is only available on Windows, macOS, Android, X11 and Wayland.
|
||||||
|
|
|
@ -78,7 +78,7 @@ use self::activity::{AndroidApp, ConfigurationRef, Rect};
|
||||||
/// Additional methods on [`EventLoop`] that are specific to Android.
|
/// Additional methods on [`EventLoop`] that are specific to Android.
|
||||||
pub trait EventLoopExtAndroid {}
|
pub trait EventLoopExtAndroid {}
|
||||||
|
|
||||||
impl<T> EventLoopExtAndroid for EventLoop<T> {}
|
impl EventLoopExtAndroid for EventLoop {}
|
||||||
|
|
||||||
/// Additional methods on [`ActiveEventLoop`] that are specific to Android.
|
/// Additional methods on [`ActiveEventLoop`] that are specific to Android.
|
||||||
pub trait ActiveEventLoopExtAndroid {}
|
pub trait ActiveEventLoopExtAndroid {}
|
||||||
|
@ -119,7 +119,7 @@ pub trait EventLoopBuilderExtAndroid {
|
||||||
fn handle_volume_keys(&mut self) -> &mut Self;
|
fn handle_volume_keys(&mut self) -> &mut Self;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> EventLoopBuilderExtAndroid for EventLoopBuilder<T> {
|
impl EventLoopBuilderExtAndroid for EventLoopBuilder {
|
||||||
fn with_android_app(&mut self, app: AndroidApp) -> &mut Self {
|
fn with_android_app(&mut self, app: AndroidApp) -> &mut Self {
|
||||||
self.platform_specific.android_app = Some(app);
|
self.platform_specific.android_app = Some(app);
|
||||||
self
|
self
|
||||||
|
|
|
@ -76,7 +76,7 @@ pub trait EventLoopExtIOS {
|
||||||
fn idiom(&self) -> Idiom;
|
fn idiom(&self) -> Idiom;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: 'static> EventLoopExtIOS for EventLoop<T> {
|
impl EventLoopExtIOS for EventLoop {
|
||||||
fn idiom(&self) -> Idiom {
|
fn idiom(&self) -> Idiom {
|
||||||
self.event_loop.idiom()
|
self.event_loop.idiom()
|
||||||
}
|
}
|
||||||
|
|
|
@ -338,7 +338,7 @@ pub trait EventLoopBuilderExtMacOS {
|
||||||
fn with_activate_ignoring_other_apps(&mut self, ignore: bool) -> &mut Self;
|
fn with_activate_ignoring_other_apps(&mut self, ignore: bool) -> &mut Self;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> EventLoopBuilderExtMacOS for EventLoopBuilder<T> {
|
impl EventLoopBuilderExtMacOS for EventLoopBuilder {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn with_activation_policy(&mut self, activation_policy: ActivationPolicy) -> &mut Self {
|
fn with_activation_policy(&mut self, activation_policy: ActivationPolicy) -> &mut Self {
|
||||||
self.platform_specific.activation_policy = activation_policy;
|
self.platform_specific.activation_policy = activation_policy;
|
||||||
|
|
|
@ -5,11 +5,6 @@ use crate::event_loop::EventLoop;
|
||||||
|
|
||||||
/// Additional methods on [`EventLoop`] for pumping events within an external event loop
|
/// Additional methods on [`EventLoop`] for pumping events within an external event loop
|
||||||
pub trait EventLoopExtPumpEvents {
|
pub trait EventLoopExtPumpEvents {
|
||||||
/// A type provided by the user that can be passed through [`Event::UserEvent`].
|
|
||||||
///
|
|
||||||
/// [`Event::UserEvent`]: crate::event::Event::UserEvent
|
|
||||||
type UserEvent: 'static;
|
|
||||||
|
|
||||||
/// Pump the `EventLoop` to check for and dispatch pending events.
|
/// Pump the `EventLoop` to check for and dispatch pending events.
|
||||||
///
|
///
|
||||||
/// This API is designed to enable applications to integrate Winit into an
|
/// This API is designed to enable applications to integrate Winit into an
|
||||||
|
@ -104,17 +99,15 @@ pub trait EventLoopExtPumpEvents {
|
||||||
/// If you render outside of Winit you are likely to see window resizing artifacts
|
/// If you render outside of Winit you are likely to see window resizing artifacts
|
||||||
/// since MacOS expects applications to render synchronously during any `drawRect`
|
/// since MacOS expects applications to render synchronously during any `drawRect`
|
||||||
/// callback.
|
/// callback.
|
||||||
fn pump_app_events<A: ApplicationHandler<Self::UserEvent>>(
|
fn pump_app_events<A: ApplicationHandler>(
|
||||||
&mut self,
|
&mut self,
|
||||||
timeout: Option<Duration>,
|
timeout: Option<Duration>,
|
||||||
app: &mut A,
|
app: &mut A,
|
||||||
) -> PumpStatus;
|
) -> PumpStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> EventLoopExtPumpEvents for EventLoop<T> {
|
impl EventLoopExtPumpEvents for EventLoop {
|
||||||
type UserEvent = T;
|
fn pump_app_events<A: ApplicationHandler>(
|
||||||
|
|
||||||
fn pump_app_events<A: ApplicationHandler<Self::UserEvent>>(
|
|
||||||
&mut self,
|
&mut self,
|
||||||
timeout: Option<Duration>,
|
timeout: Option<Duration>,
|
||||||
app: &mut A,
|
app: &mut A,
|
||||||
|
|
|
@ -7,11 +7,6 @@ use crate::{platform::pump_events::EventLoopExtPumpEvents, window::Window};
|
||||||
|
|
||||||
/// Additional methods on [`EventLoop`] to return control flow to the caller.
|
/// Additional methods on [`EventLoop`] to return control flow to the caller.
|
||||||
pub trait EventLoopExtRunOnDemand {
|
pub trait EventLoopExtRunOnDemand {
|
||||||
/// A type provided by the user that can be passed through [`Event::UserEvent`].
|
|
||||||
///
|
|
||||||
/// [`Event::UserEvent`]: crate::event::Event::UserEvent
|
|
||||||
type UserEvent: 'static;
|
|
||||||
|
|
||||||
/// Run the application with the event loop on the calling thread.
|
/// Run the application with the event loop on the calling thread.
|
||||||
///
|
///
|
||||||
/// Unlike [`EventLoop::run_app`], this function accepts non-`'static` (i.e. non-`move`)
|
/// Unlike [`EventLoop::run_app`], this function accepts non-`'static` (i.e. non-`move`)
|
||||||
|
@ -58,16 +53,14 @@ pub trait EventLoopExtRunOnDemand {
|
||||||
///
|
///
|
||||||
/// [`exit()`]: ActiveEventLoop::exit()
|
/// [`exit()`]: ActiveEventLoop::exit()
|
||||||
/// [`set_control_flow()`]: ActiveEventLoop::set_control_flow()
|
/// [`set_control_flow()`]: ActiveEventLoop::set_control_flow()
|
||||||
fn run_app_on_demand<A: ApplicationHandler<Self::UserEvent>>(
|
fn run_app_on_demand<A: ApplicationHandler>(
|
||||||
&mut self,
|
&mut self,
|
||||||
app: &mut A,
|
app: &mut A,
|
||||||
) -> Result<(), EventLoopError>;
|
) -> Result<(), EventLoopError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> EventLoopExtRunOnDemand for EventLoop<T> {
|
impl EventLoopExtRunOnDemand for EventLoop {
|
||||||
type UserEvent = T;
|
fn run_app_on_demand<A: ApplicationHandler>(
|
||||||
|
|
||||||
fn run_app_on_demand<A: ApplicationHandler<Self::UserEvent>>(
|
|
||||||
&mut self,
|
&mut self,
|
||||||
app: &mut A,
|
app: &mut A,
|
||||||
) -> Result<(), EventLoopError> {
|
) -> Result<(), EventLoopError> {
|
||||||
|
|
|
@ -38,7 +38,7 @@ pub trait EventLoopExtWayland {
|
||||||
fn is_wayland(&self) -> bool;
|
fn is_wayland(&self) -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: 'static> EventLoopExtWayland for EventLoop<T> {
|
impl EventLoopExtWayland for EventLoop {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn is_wayland(&self) -> bool {
|
fn is_wayland(&self) -> bool {
|
||||||
self.event_loop.is_wayland()
|
self.event_loop.is_wayland()
|
||||||
|
@ -57,7 +57,7 @@ pub trait EventLoopBuilderExtWayland {
|
||||||
fn with_any_thread(&mut self, any_thread: bool) -> &mut Self;
|
fn with_any_thread(&mut self, any_thread: bool) -> &mut Self;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> EventLoopBuilderExtWayland for EventLoopBuilder<T> {
|
impl EventLoopBuilderExtWayland for EventLoopBuilder {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn with_wayland(&mut self) -> &mut Self {
|
fn with_wayland(&mut self) -> &mut Self {
|
||||||
self.platform_specific.forced_backend = Some(crate::platform_impl::Backend::Wayland);
|
self.platform_specific.forced_backend = Some(crate::platform_impl::Backend::Wayland);
|
||||||
|
|
|
@ -155,11 +155,6 @@ impl WindowAttributesExtWebSys for WindowAttributes {
|
||||||
|
|
||||||
/// Additional methods on `EventLoop` that are specific to the web.
|
/// Additional methods on `EventLoop` that are specific to the web.
|
||||||
pub trait EventLoopExtWebSys {
|
pub trait EventLoopExtWebSys {
|
||||||
/// A type provided by the user that can be passed through [`Event::UserEvent`].
|
|
||||||
///
|
|
||||||
/// [`Event::UserEvent`]: crate::event::Event::UserEvent
|
|
||||||
type UserEvent: 'static;
|
|
||||||
|
|
||||||
/// Initializes the winit event loop.
|
/// Initializes the winit event loop.
|
||||||
///
|
///
|
||||||
/// Unlike
|
/// Unlike
|
||||||
|
@ -182,7 +177,7 @@ pub trait EventLoopExtWebSys {
|
||||||
doc = "[`run_app()`]: EventLoop::run_app()"
|
doc = "[`run_app()`]: EventLoop::run_app()"
|
||||||
)]
|
)]
|
||||||
/// [^1]: `run_app()` is _not_ available on WASM when the target supports `exception-handling`.
|
/// [^1]: `run_app()` is _not_ available on WASM when the target supports `exception-handling`.
|
||||||
fn spawn_app<A: ApplicationHandler<Self::UserEvent> + 'static>(self, app: A);
|
fn spawn_app<A: ApplicationHandler + 'static>(self, app: A);
|
||||||
|
|
||||||
/// Sets the strategy for [`ControlFlow::Poll`].
|
/// Sets the strategy for [`ControlFlow::Poll`].
|
||||||
///
|
///
|
||||||
|
@ -213,10 +208,8 @@ pub trait EventLoopExtWebSys {
|
||||||
fn wait_until_strategy(&self) -> WaitUntilStrategy;
|
fn wait_until_strategy(&self) -> WaitUntilStrategy;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> EventLoopExtWebSys for EventLoop<T> {
|
impl EventLoopExtWebSys for EventLoop {
|
||||||
type UserEvent = T;
|
fn spawn_app<A: ApplicationHandler + 'static>(self, app: A) {
|
||||||
|
|
||||||
fn spawn_app<A: ApplicationHandler<Self::UserEvent> + 'static>(self, app: A) {
|
|
||||||
self.event_loop.spawn_app(app);
|
self.event_loop.spawn_app(app);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -227,7 +227,7 @@ pub trait EventLoopBuilderExtWindows {
|
||||||
F: FnMut(*const c_void) -> bool + 'static;
|
F: FnMut(*const c_void) -> bool + 'static;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> EventLoopBuilderExtWindows for EventLoopBuilder<T> {
|
impl EventLoopBuilderExtWindows for EventLoopBuilder {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn with_any_thread(&mut self, any_thread: bool) -> &mut Self {
|
fn with_any_thread(&mut self, any_thread: bool) -> &mut Self {
|
||||||
self.platform_specific.any_thread = any_thread;
|
self.platform_specific.any_thread = any_thread;
|
||||||
|
|
|
@ -105,7 +105,7 @@ pub trait EventLoopExtX11 {
|
||||||
fn is_x11(&self) -> bool;
|
fn is_x11(&self) -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: 'static> EventLoopExtX11 for EventLoop<T> {
|
impl EventLoopExtX11 for EventLoop {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn is_x11(&self) -> bool {
|
fn is_x11(&self) -> bool {
|
||||||
!self.event_loop.is_wayland()
|
!self.event_loop.is_wayland()
|
||||||
|
@ -124,7 +124,7 @@ pub trait EventLoopBuilderExtX11 {
|
||||||
fn with_any_thread(&mut self, any_thread: bool) -> &mut Self;
|
fn with_any_thread(&mut self, any_thread: bool) -> &mut Self;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> EventLoopBuilderExtX11 for EventLoopBuilder<T> {
|
impl EventLoopBuilderExtX11 for EventLoopBuilder {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn with_x11(&mut self) -> &mut Self {
|
fn with_x11(&mut self) -> &mut Self {
|
||||||
self.platform_specific.forced_backend = Some(crate::platform_impl::Backend::X);
|
self.platform_specific.forced_backend = Some(crate::platform_impl::Backend::X);
|
||||||
|
|
|
@ -3,7 +3,7 @@ use std::collections::VecDeque;
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
use std::sync::{mpsc, Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
use android_activity::input::{InputEvent, KeyAction, Keycode, MotionAction};
|
use android_activity::input::{InputEvent, KeyAction, Keycode, MotionAction};
|
||||||
|
@ -42,41 +42,6 @@ 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))))
|
a.map_or(b, |a_timeout| b.map_or(Some(a_timeout), |b_timeout| Some(a_timeout.min(b_timeout))))
|
||||||
}
|
}
|
||||||
|
|
||||||
struct PeekableReceiver<T> {
|
|
||||||
recv: mpsc::Receiver<T>,
|
|
||||||
first: Option<T>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> PeekableReceiver<T> {
|
|
||||||
pub fn from_recv(recv: mpsc::Receiver<T>) -> Self {
|
|
||||||
Self { recv, first: None }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn has_incoming(&mut self) -> bool {
|
|
||||||
if self.first.is_some() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
match self.recv.try_recv() {
|
|
||||||
Ok(v) => {
|
|
||||||
self.first = Some(v);
|
|
||||||
true
|
|
||||||
},
|
|
||||||
Err(mpsc::TryRecvError::Empty) => false,
|
|
||||||
Err(mpsc::TryRecvError::Disconnected) => {
|
|
||||||
warn!("Channel was disconnected when checking incoming");
|
|
||||||
false
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn try_recv(&mut self) -> Result<T, mpsc::TryRecvError> {
|
|
||||||
if let Some(first) = self.first.take() {
|
|
||||||
return Ok(first);
|
|
||||||
}
|
|
||||||
self.recv.try_recv()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
struct SharedFlagSetter {
|
struct SharedFlagSetter {
|
||||||
flag: Arc<AtomicBool>,
|
flag: Arc<AtomicBool>,
|
||||||
|
@ -132,13 +97,12 @@ impl RedrawRequester {
|
||||||
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
||||||
pub struct KeyEventExtra {}
|
pub struct KeyEventExtra {}
|
||||||
|
|
||||||
pub struct EventLoop<T: 'static> {
|
pub struct EventLoop {
|
||||||
android_app: AndroidApp,
|
android_app: AndroidApp,
|
||||||
window_target: event_loop::ActiveEventLoop,
|
window_target: event_loop::ActiveEventLoop,
|
||||||
redraw_flag: SharedFlag,
|
redraw_flag: SharedFlag,
|
||||||
user_events_sender: mpsc::Sender<T>,
|
proxy_wake_up: Arc<AtomicBool>,
|
||||||
user_events_receiver: PeekableReceiver<T>, // must wake looper whenever something gets sent
|
loop_running: bool, // Dispatched `NewEvents<Init>`
|
||||||
loop_running: bool, // Dispatched `NewEvents<Init>`
|
|
||||||
running: bool,
|
running: bool,
|
||||||
pending_redraw: bool,
|
pending_redraw: bool,
|
||||||
cause: StartCause,
|
cause: StartCause,
|
||||||
|
@ -158,11 +122,11 @@ impl Default for PlatformSpecificEventLoopAttributes {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: 'static> EventLoop<T> {
|
impl EventLoop {
|
||||||
pub(crate) fn new(
|
pub(crate) fn new(
|
||||||
attributes: &PlatformSpecificEventLoopAttributes,
|
attributes: &PlatformSpecificEventLoopAttributes,
|
||||||
) -> Result<Self, EventLoopError> {
|
) -> Result<Self, EventLoopError> {
|
||||||
let (user_events_sender, user_events_receiver) = mpsc::channel();
|
let proxy_wake_up = Arc::new(AtomicBool::new(false));
|
||||||
|
|
||||||
let android_app = attributes.android_app.as_ref().expect(
|
let android_app = attributes.android_app.as_ref().expect(
|
||||||
"An `AndroidApp` as passed to android_main() is required to create an `EventLoop` on \
|
"An `AndroidApp` as passed to android_main() is required to create an `EventLoop` on \
|
||||||
|
@ -185,8 +149,7 @@ impl<T: 'static> EventLoop<T> {
|
||||||
_marker: PhantomData,
|
_marker: PhantomData,
|
||||||
},
|
},
|
||||||
redraw_flag,
|
redraw_flag,
|
||||||
user_events_sender,
|
proxy_wake_up,
|
||||||
user_events_receiver: PeekableReceiver::from_recv(user_events_receiver),
|
|
||||||
loop_running: false,
|
loop_running: false,
|
||||||
running: false,
|
running: false,
|
||||||
pending_redraw: false,
|
pending_redraw: false,
|
||||||
|
@ -196,7 +159,7 @@ impl<T: 'static> EventLoop<T> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn single_iteration<A: ApplicationHandler<T>>(
|
fn single_iteration<A: ApplicationHandler>(
|
||||||
&mut self,
|
&mut self,
|
||||||
main_event: Option<MainEvent<'_>>,
|
main_event: Option<MainEvent<'_>>,
|
||||||
app: &mut A,
|
app: &mut A,
|
||||||
|
@ -315,11 +278,8 @@ impl<T: 'static> EventLoop<T> {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// Empty the user event buffer
|
if self.proxy_wake_up.swap(false, Ordering::Relaxed) {
|
||||||
{
|
app.proxy_wake_up(self.window_target());
|
||||||
while let Ok(event) = self.user_events_receiver.try_recv() {
|
|
||||||
app.user_event(self.window_target(), event);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.running {
|
if self.running {
|
||||||
|
@ -351,7 +311,7 @@ impl<T: 'static> EventLoop<T> {
|
||||||
self.pending_redraw = pending_redraw;
|
self.pending_redraw = pending_redraw;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_input_event<A: ApplicationHandler<T>>(
|
fn handle_input_event<A: ApplicationHandler>(
|
||||||
&mut self,
|
&mut self,
|
||||||
android_app: &AndroidApp,
|
android_app: &AndroidApp,
|
||||||
event: &InputEvent<'_>,
|
event: &InputEvent<'_>,
|
||||||
|
@ -458,11 +418,11 @@ impl<T: 'static> EventLoop<T> {
|
||||||
input_status
|
input_status
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_app<A: ApplicationHandler<T>>(mut self, app: &mut A) -> Result<(), EventLoopError> {
|
pub fn run_app<A: ApplicationHandler>(mut self, app: &mut A) -> Result<(), EventLoopError> {
|
||||||
self.run_app_on_demand(app)
|
self.run_app_on_demand(app)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_app_on_demand<A: ApplicationHandler<T>>(
|
pub fn run_app_on_demand<A: ApplicationHandler>(
|
||||||
&mut self,
|
&mut self,
|
||||||
app: &mut A,
|
app: &mut A,
|
||||||
) -> Result<(), EventLoopError> {
|
) -> Result<(), EventLoopError> {
|
||||||
|
@ -481,7 +441,7 @@ impl<T: 'static> EventLoop<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pump_app_events<A: ApplicationHandler<T>>(
|
pub fn pump_app_events<A: ApplicationHandler>(
|
||||||
&mut self,
|
&mut self,
|
||||||
timeout: Option<Duration>,
|
timeout: Option<Duration>,
|
||||||
app: &mut A,
|
app: &mut A,
|
||||||
|
@ -515,7 +475,7 @@ impl<T: 'static> EventLoop<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn poll_events_with_timeout<A: ApplicationHandler<T>>(
|
fn poll_events_with_timeout<A: ApplicationHandler>(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut timeout: Option<Duration>,
|
mut timeout: Option<Duration>,
|
||||||
app: &mut A,
|
app: &mut A,
|
||||||
|
@ -524,22 +484,23 @@ impl<T: 'static> EventLoop<T> {
|
||||||
|
|
||||||
self.pending_redraw |= self.redraw_flag.get_and_reset();
|
self.pending_redraw |= self.redraw_flag.get_and_reset();
|
||||||
|
|
||||||
timeout =
|
timeout = if self.running
|
||||||
if self.running && (self.pending_redraw || self.user_events_receiver.has_incoming()) {
|
&& (self.pending_redraw || self.proxy_wake_up.load(Ordering::Relaxed))
|
||||||
// If we already have work to do then we don't want to block on the next poll
|
{
|
||||||
Some(Duration::ZERO)
|
// If we already have work to do then we don't want to block on the next poll
|
||||||
} else {
|
Some(Duration::ZERO)
|
||||||
let control_flow_timeout = match self.control_flow() {
|
} else {
|
||||||
ControlFlow::Wait => None,
|
let control_flow_timeout = match self.control_flow() {
|
||||||
ControlFlow::Poll => Some(Duration::ZERO),
|
ControlFlow::Wait => None,
|
||||||
ControlFlow::WaitUntil(wait_deadline) => {
|
ControlFlow::Poll => Some(Duration::ZERO),
|
||||||
Some(wait_deadline.saturating_duration_since(start))
|
ControlFlow::WaitUntil(wait_deadline) => {
|
||||||
},
|
Some(wait_deadline.saturating_duration_since(start))
|
||||||
};
|
},
|
||||||
|
|
||||||
min_timeout(control_flow_timeout, timeout)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
min_timeout(control_flow_timeout, timeout)
|
||||||
|
};
|
||||||
|
|
||||||
let android_app = self.android_app.clone(); // Don't borrow self as part of poll expression
|
let android_app = self.android_app.clone(); // Don't borrow self as part of poll expression
|
||||||
android_app.poll_events(timeout, |poll_event| {
|
android_app.poll_events(timeout, |poll_event| {
|
||||||
let mut main_event = None;
|
let mut main_event = None;
|
||||||
|
@ -556,7 +517,7 @@ impl<T: 'static> EventLoop<T> {
|
||||||
// We also ignore wake ups while suspended.
|
// We also ignore wake ups while suspended.
|
||||||
self.pending_redraw |= self.redraw_flag.get_and_reset();
|
self.pending_redraw |= self.redraw_flag.get_and_reset();
|
||||||
if !self.running
|
if !self.running
|
||||||
|| (!self.pending_redraw && !self.user_events_receiver.has_incoming())
|
|| (!self.pending_redraw && !self.proxy_wake_up.load(Ordering::Relaxed))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -590,9 +551,9 @@ impl<T: 'static> EventLoop<T> {
|
||||||
&self.window_target
|
&self.window_target
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_proxy(&self) -> EventLoopProxy<T> {
|
pub fn create_proxy(&self) -> EventLoopProxy {
|
||||||
EventLoopProxy {
|
EventLoopProxy {
|
||||||
user_events_sender: self.user_events_sender.clone(),
|
proxy_wake_up: self.proxy_wake_up.clone(),
|
||||||
waker: self.android_app.create_waker(),
|
waker: self.android_app.create_waker(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -606,25 +567,16 @@ impl<T: 'static> EventLoop<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct EventLoopProxy<T: 'static> {
|
#[derive(Clone)]
|
||||||
user_events_sender: mpsc::Sender<T>,
|
pub struct EventLoopProxy {
|
||||||
|
proxy_wake_up: Arc<AtomicBool>,
|
||||||
waker: AndroidAppWaker,
|
waker: AndroidAppWaker,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: 'static> Clone for EventLoopProxy<T> {
|
impl EventLoopProxy {
|
||||||
fn clone(&self) -> Self {
|
pub fn wake_up(&self) {
|
||||||
EventLoopProxy {
|
self.proxy_wake_up.store(true, Ordering::Relaxed);
|
||||||
user_events_sender: self.user_events_sender.clone(),
|
|
||||||
waker: self.waker.clone(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> EventLoopProxy<T> {
|
|
||||||
pub fn send_event(&self, event: T) -> Result<(), event_loop::EventLoopClosed<T>> {
|
|
||||||
self.user_events_sender.send(event).map_err(|err| event_loop::EventLoopClosed(err.0))?;
|
|
||||||
self.waker.wake();
|
self.waker.wake();
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,12 +40,9 @@ macro_rules! bug_assert {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub(crate) struct HandlePendingUserEvents;
|
|
||||||
|
|
||||||
pub(crate) struct EventLoopHandler {
|
pub(crate) struct EventLoopHandler {
|
||||||
#[allow(clippy::type_complexity)]
|
#[allow(clippy::type_complexity)]
|
||||||
pub(crate) handler: Box<dyn FnMut(Event<HandlePendingUserEvents>, &RootActiveEventLoop)>,
|
pub(crate) handler: Box<dyn FnMut(Event, &RootActiveEventLoop)>,
|
||||||
pub(crate) event_loop: RootActiveEventLoop,
|
pub(crate) event_loop: RootActiveEventLoop,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,14 +56,14 @@ impl fmt::Debug for EventLoopHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EventLoopHandler {
|
impl EventLoopHandler {
|
||||||
fn handle_event(&mut self, event: Event<HandlePendingUserEvents>) {
|
fn handle_event(&mut self, event: Event) {
|
||||||
(self.handler)(event, &self.event_loop)
|
(self.handler)(event, &self.event_loop)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) enum EventWrapper {
|
pub(crate) enum EventWrapper {
|
||||||
StaticEvent(Event<HandlePendingUserEvents>),
|
StaticEvent(Event),
|
||||||
ScaleFactorChanged(ScaleFactorChanged),
|
ScaleFactorChanged(ScaleFactorChanged),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,7 +85,7 @@ enum UserCallbackTransitionResult<'a> {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Event<HandlePendingUserEvents> {
|
impl Event {
|
||||||
fn is_redraw(&self) -> bool {
|
fn is_redraw(&self) -> bool {
|
||||||
matches!(self, Event::WindowEvent { event: WindowEvent::RedrawRequested, .. })
|
matches!(self, Event::WindowEvent { event: WindowEvent::RedrawRequested, .. })
|
||||||
}
|
}
|
||||||
|
@ -625,7 +622,7 @@ fn handle_user_events(mtm: MainThreadMarker) {
|
||||||
}
|
}
|
||||||
drop(this);
|
drop(this);
|
||||||
|
|
||||||
handler.handle_event(Event::UserEvent(HandlePendingUserEvents));
|
handler.handle_event(Event::UserWakeUp);
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let mut this = AppState::get_mut(mtm);
|
let mut this = AppState::get_mut(mtm);
|
||||||
|
@ -658,7 +655,7 @@ fn handle_user_events(mtm: MainThreadMarker) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handler.handle_event(Event::UserEvent(HandlePendingUserEvents));
|
handler.handle_event(Event::UserWakeUp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,8 @@ use std::collections::VecDeque;
|
||||||
use std::ffi::{c_char, c_int, c_void};
|
use std::ffi::{c_char, c_int, c_void};
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::ptr::{self, NonNull};
|
use std::ptr::{self, NonNull};
|
||||||
use std::sync::mpsc::{self, Receiver, Sender};
|
use std::sync::atomic::{AtomicBool, Ordering as AtomicOrdering};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
use core_foundation::base::{CFIndex, CFRelease};
|
use core_foundation::base::{CFIndex, CFRelease};
|
||||||
use core_foundation::runloop::{
|
use core_foundation::runloop::{
|
||||||
|
@ -19,11 +20,9 @@ use objc2_ui_kit::{UIApplication, UIApplicationMain, UIDevice, UIScreen, UIUserI
|
||||||
use crate::application::ApplicationHandler;
|
use crate::application::ApplicationHandler;
|
||||||
use crate::error::EventLoopError;
|
use crate::error::EventLoopError;
|
||||||
use crate::event::Event;
|
use crate::event::Event;
|
||||||
use crate::event_loop::{
|
use crate::event_loop::{ActiveEventLoop as RootActiveEventLoop, ControlFlow, DeviceEvents};
|
||||||
ActiveEventLoop as RootActiveEventLoop, ControlFlow, DeviceEvents, EventLoopClosed,
|
|
||||||
};
|
|
||||||
use crate::platform::ios::Idiom;
|
use crate::platform::ios::Idiom;
|
||||||
use crate::platform_impl::platform::app_state::{EventLoopHandler, HandlePendingUserEvents};
|
use crate::platform_impl::platform::app_state::EventLoopHandler;
|
||||||
use crate::window::{CustomCursor, CustomCursorSource};
|
use crate::window::{CustomCursor, CustomCursorSource};
|
||||||
|
|
||||||
use super::app_delegate::AppDelegate;
|
use super::app_delegate::AppDelegate;
|
||||||
|
@ -109,10 +108,10 @@ impl OwnedDisplayHandle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn map_user_event<T: 'static, A: ApplicationHandler<T>>(
|
fn map_user_event<A: ApplicationHandler>(
|
||||||
app: &mut A,
|
app: &mut A,
|
||||||
receiver: mpsc::Receiver<T>,
|
proxy_wake_up: Arc<AtomicBool>,
|
||||||
) -> impl FnMut(Event<HandlePendingUserEvents>, &RootActiveEventLoop) + '_ {
|
) -> impl FnMut(Event, &RootActiveEventLoop) + '_ {
|
||||||
move |event, window_target| match event {
|
move |event, window_target| match event {
|
||||||
Event::NewEvents(cause) => app.new_events(window_target, cause),
|
Event::NewEvents(cause) => app.new_events(window_target, cause),
|
||||||
Event::WindowEvent { window_id, event } => {
|
Event::WindowEvent { window_id, event } => {
|
||||||
|
@ -121,9 +120,9 @@ fn map_user_event<T: 'static, A: ApplicationHandler<T>>(
|
||||||
Event::DeviceEvent { device_id, event } => {
|
Event::DeviceEvent { device_id, event } => {
|
||||||
app.device_event(window_target, device_id, event)
|
app.device_event(window_target, device_id, event)
|
||||||
},
|
},
|
||||||
Event::UserEvent(_) => {
|
Event::UserWakeUp => {
|
||||||
for event in receiver.try_iter() {
|
if proxy_wake_up.swap(false, AtomicOrdering::Relaxed) {
|
||||||
app.user_event(window_target, event);
|
app.proxy_wake_up(window_target);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Event::Suspended => app.suspended(window_target),
|
Event::Suspended => app.suspended(window_target),
|
||||||
|
@ -134,20 +133,19 @@ fn map_user_event<T: 'static, A: ApplicationHandler<T>>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct EventLoop<T: 'static> {
|
pub struct EventLoop {
|
||||||
mtm: MainThreadMarker,
|
mtm: MainThreadMarker,
|
||||||
sender: Sender<T>,
|
proxy_wake_up: Arc<AtomicBool>,
|
||||||
receiver: Receiver<T>,
|
|
||||||
window_target: RootActiveEventLoop,
|
window_target: RootActiveEventLoop,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
#[derive(Default, Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
pub(crate) struct PlatformSpecificEventLoopAttributes {}
|
pub(crate) struct PlatformSpecificEventLoopAttributes {}
|
||||||
|
|
||||||
impl<T: 'static> EventLoop<T> {
|
impl EventLoop {
|
||||||
pub(crate) fn new(
|
pub(crate) fn new(
|
||||||
_: &PlatformSpecificEventLoopAttributes,
|
_: &PlatformSpecificEventLoopAttributes,
|
||||||
) -> Result<EventLoop<T>, EventLoopError> {
|
) -> Result<EventLoop, EventLoopError> {
|
||||||
let mtm = MainThreadMarker::new()
|
let mtm = MainThreadMarker::new()
|
||||||
.expect("On iOS, `EventLoop` must be created on the main thread");
|
.expect("On iOS, `EventLoop` must be created on the main thread");
|
||||||
|
|
||||||
|
@ -160,20 +158,19 @@ impl<T: 'static> EventLoop<T> {
|
||||||
SINGLETON_INIT = true;
|
SINGLETON_INIT = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
let (sender, receiver) = mpsc::channel();
|
|
||||||
|
|
||||||
// this line sets up the main run loop before `UIApplicationMain`
|
// this line sets up the main run loop before `UIApplicationMain`
|
||||||
setup_control_flow_observers();
|
setup_control_flow_observers();
|
||||||
|
|
||||||
|
let proxy_wake_up = Arc::new(AtomicBool::new(false));
|
||||||
|
|
||||||
Ok(EventLoop {
|
Ok(EventLoop {
|
||||||
mtm,
|
mtm,
|
||||||
sender,
|
proxy_wake_up,
|
||||||
receiver,
|
|
||||||
window_target: RootActiveEventLoop { p: ActiveEventLoop { mtm }, _marker: PhantomData },
|
window_target: RootActiveEventLoop { p: ActiveEventLoop { mtm }, _marker: PhantomData },
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_app<A: ApplicationHandler<T>>(self, app: &mut A) -> ! {
|
pub fn run_app<A: ApplicationHandler>(self, app: &mut A) -> ! {
|
||||||
let application: Option<Retained<UIApplication>> =
|
let application: Option<Retained<UIApplication>> =
|
||||||
unsafe { msg_send_id![UIApplication::class(), sharedApplication] };
|
unsafe { msg_send_id![UIApplication::class(), sharedApplication] };
|
||||||
assert!(
|
assert!(
|
||||||
|
@ -183,12 +180,12 @@ impl<T: 'static> EventLoop<T> {
|
||||||
`EventLoop::run_app` calls `UIApplicationMain` on iOS",
|
`EventLoop::run_app` calls `UIApplicationMain` on iOS",
|
||||||
);
|
);
|
||||||
|
|
||||||
let handler = map_user_event(app, self.receiver);
|
let handler = map_user_event(app, self.proxy_wake_up.clone());
|
||||||
|
|
||||||
let handler = unsafe {
|
let handler = unsafe {
|
||||||
std::mem::transmute::<
|
std::mem::transmute::<
|
||||||
Box<dyn FnMut(Event<HandlePendingUserEvents>, &RootActiveEventLoop)>,
|
Box<dyn FnMut(Event, &RootActiveEventLoop)>,
|
||||||
Box<dyn FnMut(Event<HandlePendingUserEvents>, &RootActiveEventLoop)>,
|
Box<dyn FnMut(Event, &RootActiveEventLoop)>,
|
||||||
>(Box::new(handler))
|
>(Box::new(handler))
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -216,8 +213,8 @@ impl<T: 'static> EventLoop<T> {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_proxy(&self) -> EventLoopProxy<T> {
|
pub fn create_proxy(&self) -> EventLoopProxy {
|
||||||
EventLoopProxy::new(self.sender.clone())
|
EventLoopProxy::new(self.proxy_wake_up.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn window_target(&self) -> &RootActiveEventLoop {
|
pub fn window_target(&self) -> &RootActiveEventLoop {
|
||||||
|
@ -226,7 +223,7 @@ impl<T: 'static> EventLoop<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// EventLoopExtIOS
|
// EventLoopExtIOS
|
||||||
impl<T: 'static> EventLoop<T> {
|
impl EventLoop {
|
||||||
pub fn idiom(&self) -> Idiom {
|
pub fn idiom(&self) -> Idiom {
|
||||||
match UIDevice::currentDevice(self.mtm).userInterfaceIdiom() {
|
match UIDevice::currentDevice(self.mtm).userInterfaceIdiom() {
|
||||||
UIUserInterfaceIdiom::Unspecified => Idiom::Unspecified,
|
UIUserInterfaceIdiom::Unspecified => Idiom::Unspecified,
|
||||||
|
@ -239,21 +236,21 @@ impl<T: 'static> EventLoop<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct EventLoopProxy<T> {
|
pub struct EventLoopProxy {
|
||||||
sender: Sender<T>,
|
proxy_wake_up: Arc<AtomicBool>,
|
||||||
source: CFRunLoopSourceRef,
|
source: CFRunLoopSourceRef,
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<T: Send> Send for EventLoopProxy<T> {}
|
unsafe impl Send for EventLoopProxy {}
|
||||||
unsafe impl<T: Send> Sync for EventLoopProxy<T> {}
|
unsafe impl Sync for EventLoopProxy {}
|
||||||
|
|
||||||
impl<T> Clone for EventLoopProxy<T> {
|
impl Clone for EventLoopProxy {
|
||||||
fn clone(&self) -> EventLoopProxy<T> {
|
fn clone(&self) -> EventLoopProxy {
|
||||||
EventLoopProxy::new(self.sender.clone())
|
EventLoopProxy::new(self.proxy_wake_up.clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Drop for EventLoopProxy<T> {
|
impl Drop for EventLoopProxy {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
unsafe {
|
unsafe {
|
||||||
CFRunLoopSourceInvalidate(self.source);
|
CFRunLoopSourceInvalidate(self.source);
|
||||||
|
@ -262,8 +259,8 @@ impl<T> Drop for EventLoopProxy<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> EventLoopProxy<T> {
|
impl EventLoopProxy {
|
||||||
fn new(sender: Sender<T>) -> EventLoopProxy<T> {
|
fn new(proxy_wake_up: Arc<AtomicBool>) -> EventLoopProxy {
|
||||||
unsafe {
|
unsafe {
|
||||||
// just wake up the eventloop
|
// just wake up the eventloop
|
||||||
extern "C" fn event_loop_proxy_handler(_: *const c_void) {}
|
extern "C" fn event_loop_proxy_handler(_: *const c_void) {}
|
||||||
|
@ -287,19 +284,18 @@ impl<T> EventLoopProxy<T> {
|
||||||
CFRunLoopAddSource(rl, source, kCFRunLoopCommonModes);
|
CFRunLoopAddSource(rl, source, kCFRunLoopCommonModes);
|
||||||
CFRunLoopWakeUp(rl);
|
CFRunLoopWakeUp(rl);
|
||||||
|
|
||||||
EventLoopProxy { sender, source }
|
EventLoopProxy { proxy_wake_up, source }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed<T>> {
|
pub fn wake_up(&self) {
|
||||||
self.sender.send(event).map_err(|::std::sync::mpsc::SendError(x)| EventLoopClosed(x))?;
|
self.proxy_wake_up.store(true, AtomicOrdering::Relaxed);
|
||||||
unsafe {
|
unsafe {
|
||||||
// let the main thread know there's a new event
|
// let the main thread know there's a new event
|
||||||
CFRunLoopSourceSignal(self.source);
|
CFRunLoopSourceSignal(self.source);
|
||||||
let rl = CFRunLoopGetMain();
|
let rl = CFRunLoopGetMain();
|
||||||
CFRunLoopWakeUp(rl);
|
CFRunLoopWakeUp(rl);
|
||||||
}
|
}
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ use smol_str::SmolStr;
|
||||||
use self::x11::{X11Error, XConnection, XError, XNotSupported};
|
use self::x11::{X11Error, XConnection, XError, XNotSupported};
|
||||||
use crate::dpi::{PhysicalPosition, PhysicalSize, Position, Size};
|
use crate::dpi::{PhysicalPosition, PhysicalSize, Position, Size};
|
||||||
use crate::error::{EventLoopError, ExternalError, NotSupportedError, OsError as RootOsError};
|
use crate::error::{EventLoopError, ExternalError, NotSupportedError, OsError as RootOsError};
|
||||||
use crate::event_loop::{AsyncRequestSerial, ControlFlow, DeviceEvents, EventLoopClosed};
|
use crate::event_loop::{AsyncRequestSerial, ControlFlow, DeviceEvents};
|
||||||
use crate::icon::Icon;
|
use crate::icon::Icon;
|
||||||
use crate::keyboard::Key;
|
use crate::keyboard::Key;
|
||||||
#[cfg(x11_platform)]
|
#[cfg(x11_platform)]
|
||||||
|
@ -691,27 +691,22 @@ unsafe extern "C" fn x_error_callback(
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum EventLoop<T: 'static> {
|
pub enum EventLoop {
|
||||||
#[cfg(wayland_platform)]
|
#[cfg(wayland_platform)]
|
||||||
Wayland(Box<wayland::EventLoop<T>>),
|
Wayland(Box<wayland::EventLoop>),
|
||||||
#[cfg(x11_platform)]
|
#[cfg(x11_platform)]
|
||||||
X(x11::EventLoop<T>),
|
X(x11::EventLoop),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum EventLoopProxy<T: 'static> {
|
#[derive(Clone)]
|
||||||
|
pub enum EventLoopProxy {
|
||||||
#[cfg(x11_platform)]
|
#[cfg(x11_platform)]
|
||||||
X(x11::EventLoopProxy<T>),
|
X(x11::EventLoopProxy),
|
||||||
#[cfg(wayland_platform)]
|
#[cfg(wayland_platform)]
|
||||||
Wayland(wayland::EventLoopProxy<T>),
|
Wayland(wayland::EventLoopProxy),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: 'static> Clone for EventLoopProxy<T> {
|
impl EventLoop {
|
||||||
fn clone(&self) -> Self {
|
|
||||||
x11_or_wayland!(match self; EventLoopProxy(proxy) => proxy.clone(); as EventLoopProxy)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: 'static> EventLoop<T> {
|
|
||||||
pub(crate) fn new(
|
pub(crate) fn new(
|
||||||
attributes: &PlatformSpecificEventLoopAttributes,
|
attributes: &PlatformSpecificEventLoopAttributes,
|
||||||
) -> Result<Self, EventLoopError> {
|
) -> Result<Self, EventLoopError> {
|
||||||
|
@ -770,12 +765,12 @@ impl<T: 'static> EventLoop<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(wayland_platform)]
|
#[cfg(wayland_platform)]
|
||||||
fn new_wayland_any_thread() -> Result<EventLoop<T>, EventLoopError> {
|
fn new_wayland_any_thread() -> Result<EventLoop, EventLoopError> {
|
||||||
wayland::EventLoop::new().map(|evlp| EventLoop::Wayland(Box::new(evlp)))
|
wayland::EventLoop::new().map(|evlp| EventLoop::Wayland(Box::new(evlp)))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(x11_platform)]
|
#[cfg(x11_platform)]
|
||||||
fn new_x11_any_thread() -> Result<EventLoop<T>, EventLoopError> {
|
fn new_x11_any_thread() -> Result<EventLoop, EventLoopError> {
|
||||||
let xconn = match X11_BACKEND.lock().unwrap().as_ref() {
|
let xconn = match X11_BACKEND.lock().unwrap().as_ref() {
|
||||||
Ok(xconn) => xconn.clone(),
|
Ok(xconn) => xconn.clone(),
|
||||||
Err(_) => return Err(EventLoopError::NotSupported(NotSupportedError::new())),
|
Err(_) => return Err(EventLoopError::NotSupported(NotSupportedError::new())),
|
||||||
|
@ -794,22 +789,22 @@ impl<T: 'static> EventLoop<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_proxy(&self) -> EventLoopProxy<T> {
|
pub fn create_proxy(&self) -> EventLoopProxy {
|
||||||
x11_or_wayland!(match self; EventLoop(evlp) => evlp.create_proxy(); as EventLoopProxy)
|
x11_or_wayland!(match self; EventLoop(evlp) => evlp.create_proxy(); as EventLoopProxy)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_app<A: ApplicationHandler<T>>(self, app: &mut A) -> Result<(), EventLoopError> {
|
pub fn run_app<A: ApplicationHandler>(self, app: &mut A) -> Result<(), EventLoopError> {
|
||||||
x11_or_wayland!(match self; EventLoop(evlp) => evlp.run_app(app))
|
x11_or_wayland!(match self; EventLoop(evlp) => evlp.run_app(app))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_app_on_demand<A: ApplicationHandler<T>>(
|
pub fn run_app_on_demand<A: ApplicationHandler>(
|
||||||
&mut self,
|
&mut self,
|
||||||
app: &mut A,
|
app: &mut A,
|
||||||
) -> Result<(), EventLoopError> {
|
) -> Result<(), EventLoopError> {
|
||||||
x11_or_wayland!(match self; EventLoop(evlp) => evlp.run_app_on_demand(app))
|
x11_or_wayland!(match self; EventLoop(evlp) => evlp.run_app_on_demand(app))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pump_app_events<A: ApplicationHandler<T>>(
|
pub fn pump_app_events<A: ApplicationHandler>(
|
||||||
&mut self,
|
&mut self,
|
||||||
timeout: Option<Duration>,
|
timeout: Option<Duration>,
|
||||||
app: &mut A,
|
app: &mut A,
|
||||||
|
@ -822,21 +817,21 @@ impl<T: 'static> EventLoop<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> AsFd for EventLoop<T> {
|
impl AsFd for EventLoop {
|
||||||
fn as_fd(&self) -> BorrowedFd<'_> {
|
fn as_fd(&self) -> BorrowedFd<'_> {
|
||||||
x11_or_wayland!(match self; EventLoop(evlp) => evlp.as_fd())
|
x11_or_wayland!(match self; EventLoop(evlp) => evlp.as_fd())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> AsRawFd for EventLoop<T> {
|
impl AsRawFd for EventLoop {
|
||||||
fn as_raw_fd(&self) -> RawFd {
|
fn as_raw_fd(&self) -> RawFd {
|
||||||
x11_or_wayland!(match self; EventLoop(evlp) => evlp.as_raw_fd())
|
x11_or_wayland!(match self; EventLoop(evlp) => evlp.as_raw_fd())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: 'static> EventLoopProxy<T> {
|
impl EventLoopProxy {
|
||||||
pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed<T>> {
|
pub fn wake_up(&self) {
|
||||||
x11_or_wayland!(match self; EventLoopProxy(proxy) => proxy.send_event(event))
|
x11_or_wayland!(match self; EventLoopProxy(proxy) => proxy.wake_up())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,6 @@ use std::io::Result as IOResult;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, RawFd};
|
use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, RawFd};
|
||||||
use std::rc::Rc;
|
|
||||||
use std::sync::atomic::Ordering;
|
use std::sync::atomic::Ordering;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
|
@ -40,7 +39,7 @@ use super::{logical_to_physical_rounded, DeviceId, WaylandError, WindowId};
|
||||||
type WaylandDispatcher = calloop::Dispatcher<'static, WaylandSource<WinitState>, WinitState>;
|
type WaylandDispatcher = calloop::Dispatcher<'static, WaylandSource<WinitState>, WinitState>;
|
||||||
|
|
||||||
/// The Wayland event loop.
|
/// The Wayland event loop.
|
||||||
pub struct EventLoop<T: 'static> {
|
pub struct EventLoop {
|
||||||
/// Has `run` or `run_on_demand` been called or a call to `pump_events` that starts the loop
|
/// Has `run` or `run_on_demand` been called or a call to `pump_events` that starts the loop
|
||||||
loop_running: bool,
|
loop_running: bool,
|
||||||
|
|
||||||
|
@ -48,13 +47,8 @@ pub struct EventLoop<T: 'static> {
|
||||||
compositor_updates: Vec<WindowCompositorUpdate>,
|
compositor_updates: Vec<WindowCompositorUpdate>,
|
||||||
window_ids: Vec<WindowId>,
|
window_ids: Vec<WindowId>,
|
||||||
|
|
||||||
/// Sender of user events.
|
/// Event loop proxy
|
||||||
user_events_sender: calloop::channel::Sender<T>,
|
event_loop_proxy: EventLoopProxy,
|
||||||
|
|
||||||
// XXX can't remove RefCell out of here, unless we can plumb generics into the `Window`, which
|
|
||||||
// we don't really want, since it'll break public API by a lot.
|
|
||||||
/// Pending events from the user.
|
|
||||||
pending_user_events: Rc<RefCell<Vec<T>>>,
|
|
||||||
|
|
||||||
/// The Wayland dispatcher to has raw access to the queue when needed, such as
|
/// The Wayland dispatcher to has raw access to the queue when needed, such as
|
||||||
/// when creating a new window.
|
/// when creating a new window.
|
||||||
|
@ -71,8 +65,8 @@ pub struct EventLoop<T: 'static> {
|
||||||
event_loop: calloop::EventLoop<'static, WinitState>,
|
event_loop: calloop::EventLoop<'static, WinitState>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: 'static> EventLoop<T> {
|
impl EventLoop {
|
||||||
pub fn new() -> Result<EventLoop<T>, EventLoopError> {
|
pub fn new() -> Result<EventLoop, EventLoopError> {
|
||||||
macro_rules! map_err {
|
macro_rules! map_err {
|
||||||
($e:expr, $err:expr) => {
|
($e:expr, $err:expr) => {
|
||||||
$e.map_err(|error| os_error!($err(error).into()))
|
$e.map_err(|error| os_error!($err(error).into()))
|
||||||
|
@ -115,16 +109,12 @@ impl<T: 'static> EventLoop<T> {
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// Setup the user proxy.
|
// Setup the user proxy.
|
||||||
let pending_user_events = Rc::new(RefCell::new(Vec::new()));
|
let (ping, ping_source) = calloop::ping::make_ping().unwrap();
|
||||||
let pending_user_events_clone = pending_user_events.clone();
|
|
||||||
let (user_events_sender, user_events_channel) = calloop::channel::channel();
|
|
||||||
let result = event_loop
|
let result = event_loop
|
||||||
.handle()
|
.handle()
|
||||||
.insert_source(user_events_channel, move |event, _, winit_state: &mut WinitState| {
|
.insert_source(ping_source, move |_, _, winit_state: &mut WinitState| {
|
||||||
if let calloop::channel::Event::Msg(msg) = event {
|
winit_state.dispatched_events = true;
|
||||||
winit_state.dispatched_events = true;
|
winit_state.proxy_wake_up = true;
|
||||||
pending_user_events_clone.borrow_mut().push(msg);
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.map_err(|error| error.error);
|
.map_err(|error| error.error);
|
||||||
map_err!(result, WaylandError::Calloop)?;
|
map_err!(result, WaylandError::Calloop)?;
|
||||||
|
@ -162,8 +152,7 @@ impl<T: 'static> EventLoop<T> {
|
||||||
window_ids: Vec::new(),
|
window_ids: Vec::new(),
|
||||||
connection,
|
connection,
|
||||||
wayland_dispatcher,
|
wayland_dispatcher,
|
||||||
user_events_sender,
|
event_loop_proxy: EventLoopProxy::new(ping),
|
||||||
pending_user_events,
|
|
||||||
event_loop,
|
event_loop,
|
||||||
window_target: RootActiveEventLoop {
|
window_target: RootActiveEventLoop {
|
||||||
p: PlatformActiveEventLoop::Wayland(window_target),
|
p: PlatformActiveEventLoop::Wayland(window_target),
|
||||||
|
@ -174,11 +163,11 @@ impl<T: 'static> EventLoop<T> {
|
||||||
Ok(event_loop)
|
Ok(event_loop)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_app<A: ApplicationHandler<T>>(mut self, app: &mut A) -> Result<(), EventLoopError> {
|
pub fn run_app<A: ApplicationHandler>(mut self, app: &mut A) -> Result<(), EventLoopError> {
|
||||||
self.run_app_on_demand(app)
|
self.run_app_on_demand(app)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_app_on_demand<A: ApplicationHandler<T>>(
|
pub fn run_app_on_demand<A: ApplicationHandler>(
|
||||||
&mut self,
|
&mut self,
|
||||||
app: &mut A,
|
app: &mut A,
|
||||||
) -> Result<(), EventLoopError> {
|
) -> Result<(), EventLoopError> {
|
||||||
|
@ -205,7 +194,7 @@ impl<T: 'static> EventLoop<T> {
|
||||||
exit
|
exit
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pump_app_events<A: ApplicationHandler<T>>(
|
pub fn pump_app_events<A: ApplicationHandler>(
|
||||||
&mut self,
|
&mut self,
|
||||||
timeout: Option<Duration>,
|
timeout: Option<Duration>,
|
||||||
app: &mut A,
|
app: &mut A,
|
||||||
|
@ -233,7 +222,7 @@ impl<T: 'static> EventLoop<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn poll_events_with_timeout<A: ApplicationHandler<T>>(
|
pub fn poll_events_with_timeout<A: ApplicationHandler>(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut timeout: Option<Duration>,
|
mut timeout: Option<Duration>,
|
||||||
app: &mut A,
|
app: &mut A,
|
||||||
|
@ -302,7 +291,7 @@ impl<T: 'static> EventLoop<T> {
|
||||||
self.single_iteration(app, cause);
|
self.single_iteration(app, cause);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn single_iteration<A: ApplicationHandler<T>>(&mut self, app: &mut A, cause: StartCause) {
|
fn single_iteration<A: ApplicationHandler>(&mut self, app: &mut A, cause: StartCause) {
|
||||||
// NOTE currently just indented to simplify the diff
|
// NOTE currently just indented to simplify the diff
|
||||||
|
|
||||||
// We retain these grow-only scratch buffers as part of the EventLoop
|
// We retain these grow-only scratch buffers as part of the EventLoop
|
||||||
|
@ -321,10 +310,9 @@ impl<T: 'static> EventLoop<T> {
|
||||||
app.resumed(&self.window_target);
|
app.resumed(&self.window_target);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle pending user events. We don't need back buffer, since we can't dispatch
|
// Indicate user wake up.
|
||||||
// user events indirectly via callback to the user.
|
if self.with_state(|state| mem::take(&mut state.proxy_wake_up)) {
|
||||||
for user_event in self.pending_user_events.borrow_mut().drain(..) {
|
app.proxy_wake_up(&self.window_target);
|
||||||
app.user_event(&self.window_target, user_event);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Drain the pending compositor updates.
|
// Drain the pending compositor updates.
|
||||||
|
@ -525,8 +513,8 @@ impl<T: 'static> EventLoop<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn create_proxy(&self) -> EventLoopProxy<T> {
|
pub fn create_proxy(&self) -> EventLoopProxy {
|
||||||
EventLoopProxy::new(self.user_events_sender.clone())
|
self.event_loop_proxy.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -588,13 +576,13 @@ impl<T: 'static> EventLoop<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> AsFd for EventLoop<T> {
|
impl AsFd for EventLoop {
|
||||||
fn as_fd(&self) -> BorrowedFd<'_> {
|
fn as_fd(&self) -> BorrowedFd<'_> {
|
||||||
self.event_loop.as_fd()
|
self.event_loop.as_fd()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> AsRawFd for EventLoop<T> {
|
impl AsRawFd for EventLoop {
|
||||||
fn as_raw_fd(&self) -> RawFd {
|
fn as_raw_fd(&self) -> RawFd {
|
||||||
self.event_loop.as_raw_fd()
|
self.event_loop.as_raw_fd()
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,28 +1,19 @@
|
||||||
//! An event loop proxy.
|
//! An event loop proxy.
|
||||||
|
|
||||||
use std::sync::mpsc::SendError;
|
use sctk::reexports::calloop::ping::Ping;
|
||||||
|
|
||||||
use sctk::reexports::calloop::channel::Sender;
|
|
||||||
|
|
||||||
use crate::event_loop::EventLoopClosed;
|
|
||||||
|
|
||||||
/// A handle that can be sent across the threads and used to wake up the `EventLoop`.
|
/// A handle that can be sent across the threads and used to wake up the `EventLoop`.
|
||||||
pub struct EventLoopProxy<T: 'static> {
|
#[derive(Clone)]
|
||||||
user_events_sender: Sender<T>,
|
pub struct EventLoopProxy {
|
||||||
|
ping: Ping,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: 'static> Clone for EventLoopProxy<T> {
|
impl EventLoopProxy {
|
||||||
fn clone(&self) -> Self {
|
pub fn new(ping: Ping) -> Self {
|
||||||
EventLoopProxy { user_events_sender: self.user_events_sender.clone() }
|
Self { ping }
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: 'static> EventLoopProxy<T> {
|
|
||||||
pub fn new(user_events_sender: Sender<T>) -> Self {
|
|
||||||
Self { user_events_sender }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed<T>> {
|
pub fn wake_up(&self) {
|
||||||
self.user_events_sender.send(event).map_err(|SendError(error)| EventLoopClosed(error))
|
self.ping.ping();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ use super::{DeviceId, WindowId};
|
||||||
/// to the winit's user.
|
/// to the winit's user.
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct EventSink {
|
pub struct EventSink {
|
||||||
pub window_events: Vec<Event<()>>,
|
pub(crate) window_events: Vec<Event>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EventSink {
|
impl EventSink {
|
||||||
|
@ -47,7 +47,7 @@ impl EventSink {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn drain(&mut self) -> Drain<'_, Event<()>> {
|
pub(crate) fn drain(&mut self) -> Drain<'_, Event> {
|
||||||
self.window_events.drain(..)
|
self.window_events.drain(..)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -115,6 +115,9 @@ pub struct WinitState {
|
||||||
/// Whether we have dispatched events to the user thus we want to
|
/// Whether we have dispatched events to the user thus we want to
|
||||||
/// send `AboutToWait` and normally wakeup the user.
|
/// send `AboutToWait` and normally wakeup the user.
|
||||||
pub dispatched_events: bool,
|
pub dispatched_events: bool,
|
||||||
|
|
||||||
|
/// Whether the user initiated a wake up.
|
||||||
|
pub proxy_wake_up: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WinitState {
|
impl WinitState {
|
||||||
|
@ -192,6 +195,7 @@ impl WinitState {
|
||||||
loop_handle,
|
loop_handle,
|
||||||
// Make it true by default.
|
// Make it true by default.
|
||||||
dispatched_events: true,
|
dispatched_events: true,
|
||||||
|
proxy_wake_up: false,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -72,9 +72,9 @@ pub struct EventProcessor {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EventProcessor {
|
impl EventProcessor {
|
||||||
pub fn process_event<T: 'static, F>(&mut self, xev: &mut XEvent, mut callback: F)
|
pub(crate) fn process_event<F>(&mut self, xev: &mut XEvent, mut callback: F)
|
||||||
where
|
where
|
||||||
F: FnMut(&RootAEL, Event<T>),
|
F: FnMut(&RootAEL, Event),
|
||||||
{
|
{
|
||||||
self.process_xevent(xev, &mut callback);
|
self.process_xevent(xev, &mut callback);
|
||||||
|
|
||||||
|
@ -139,9 +139,9 @@ impl EventProcessor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_xevent<T: 'static, F>(&mut self, xev: &mut XEvent, mut callback: F)
|
fn process_xevent<F>(&mut self, xev: &mut XEvent, mut callback: F)
|
||||||
where
|
where
|
||||||
F: FnMut(&RootAEL, Event<T>),
|
F: FnMut(&RootAEL, Event),
|
||||||
{
|
{
|
||||||
let event_type = xev.get_type();
|
let event_type = xev.get_type();
|
||||||
|
|
||||||
|
@ -387,9 +387,9 @@ impl EventProcessor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn client_message<T: 'static, F>(&mut self, xev: &XClientMessageEvent, mut callback: F)
|
fn client_message<F>(&mut self, xev: &XClientMessageEvent, mut callback: F)
|
||||||
where
|
where
|
||||||
F: FnMut(&RootAEL, Event<T>),
|
F: FnMut(&RootAEL, Event),
|
||||||
{
|
{
|
||||||
let wt = Self::window_target(&self.target);
|
let wt = Self::window_target(&self.target);
|
||||||
let atoms = wt.xconn.atoms();
|
let atoms = wt.xconn.atoms();
|
||||||
|
@ -552,9 +552,9 @@ impl EventProcessor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn selection_notify<T: 'static, F>(&mut self, xev: &XSelectionEvent, mut callback: F)
|
fn selection_notify<F>(&mut self, xev: &XSelectionEvent, mut callback: F)
|
||||||
where
|
where
|
||||||
F: FnMut(&RootAEL, Event<T>),
|
F: FnMut(&RootAEL, Event),
|
||||||
{
|
{
|
||||||
let wt = Self::window_target(&self.target);
|
let wt = Self::window_target(&self.target);
|
||||||
let atoms = wt.xconn.atoms();
|
let atoms = wt.xconn.atoms();
|
||||||
|
@ -586,9 +586,9 @@ impl EventProcessor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn configure_notify<T: 'static, F>(&self, xev: &XConfigureEvent, mut callback: F)
|
fn configure_notify<F>(&self, xev: &XConfigureEvent, mut callback: F)
|
||||||
where
|
where
|
||||||
F: FnMut(&RootAEL, Event<T>),
|
F: FnMut(&RootAEL, Event),
|
||||||
{
|
{
|
||||||
let wt = Self::window_target(&self.target);
|
let wt = Self::window_target(&self.target);
|
||||||
|
|
||||||
|
@ -781,9 +781,9 @@ impl EventProcessor {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn map_notify<T: 'static, F>(&self, xev: &XMapEvent, mut callback: F)
|
fn map_notify<F>(&self, xev: &XMapEvent, mut callback: F)
|
||||||
where
|
where
|
||||||
F: FnMut(&RootAEL, Event<T>),
|
F: FnMut(&RootAEL, Event),
|
||||||
{
|
{
|
||||||
let window = xev.window as xproto::Window;
|
let window = xev.window as xproto::Window;
|
||||||
let window_id = mkwid(window);
|
let window_id = mkwid(window);
|
||||||
|
@ -799,9 +799,9 @@ impl EventProcessor {
|
||||||
callback(&self.target, event);
|
callback(&self.target, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn destroy_notify<T: 'static, F>(&self, xev: &XDestroyWindowEvent, mut callback: F)
|
fn destroy_notify<F>(&self, xev: &XDestroyWindowEvent, mut callback: F)
|
||||||
where
|
where
|
||||||
F: FnMut(&RootAEL, Event<T>),
|
F: FnMut(&RootAEL, Event),
|
||||||
{
|
{
|
||||||
let wt = Self::window_target(&self.target);
|
let wt = Self::window_target(&self.target);
|
||||||
|
|
||||||
|
@ -823,9 +823,9 @@ impl EventProcessor {
|
||||||
callback(&self.target, Event::WindowEvent { window_id, event: WindowEvent::Destroyed });
|
callback(&self.target, Event::WindowEvent { window_id, event: WindowEvent::Destroyed });
|
||||||
}
|
}
|
||||||
|
|
||||||
fn property_notify<T: 'static, F>(&mut self, xev: &XPropertyEvent, mut callback: F)
|
fn property_notify<F>(&mut self, xev: &XPropertyEvent, mut callback: F)
|
||||||
where
|
where
|
||||||
F: FnMut(&RootAEL, Event<T>),
|
F: FnMut(&RootAEL, Event),
|
||||||
{
|
{
|
||||||
let wt = Self::window_target(&self.target);
|
let wt = Self::window_target(&self.target);
|
||||||
let atoms = wt.x_connection().atoms();
|
let atoms = wt.x_connection().atoms();
|
||||||
|
@ -838,9 +838,9 @@ impl EventProcessor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visibility_notify<T: 'static, F>(&self, xev: &XVisibilityEvent, mut callback: F)
|
fn visibility_notify<F>(&self, xev: &XVisibilityEvent, mut callback: F)
|
||||||
where
|
where
|
||||||
F: FnMut(&RootAEL, Event<T>),
|
F: FnMut(&RootAEL, Event),
|
||||||
{
|
{
|
||||||
let xwindow = xev.window as xproto::Window;
|
let xwindow = xev.window as xproto::Window;
|
||||||
|
|
||||||
|
@ -855,9 +855,9 @@ impl EventProcessor {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expose<T: 'static, F>(&self, xev: &XExposeEvent, mut callback: F)
|
fn expose<F>(&self, xev: &XExposeEvent, mut callback: F)
|
||||||
where
|
where
|
||||||
F: FnMut(&RootAEL, Event<T>),
|
F: FnMut(&RootAEL, Event),
|
||||||
{
|
{
|
||||||
// Multiple Expose events may be received for subareas of a window.
|
// Multiple Expose events may be received for subareas of a window.
|
||||||
// We issue `RedrawRequested` only for the last event of such a series.
|
// We issue `RedrawRequested` only for the last event of such a series.
|
||||||
|
@ -871,13 +871,9 @@ impl EventProcessor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn xinput_key_input<T: 'static, F>(
|
fn xinput_key_input<F>(&mut self, xev: &mut XKeyEvent, state: ElementState, mut callback: F)
|
||||||
&mut self,
|
where
|
||||||
xev: &mut XKeyEvent,
|
F: FnMut(&RootAEL, Event),
|
||||||
state: ElementState,
|
|
||||||
mut callback: F,
|
|
||||||
) where
|
|
||||||
F: FnMut(&RootAEL, Event<T>),
|
|
||||||
{
|
{
|
||||||
let wt = Self::window_target(&self.target);
|
let wt = Self::window_target(&self.target);
|
||||||
|
|
||||||
|
@ -989,13 +985,13 @@ impl EventProcessor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_synthic_modifier_from_core<T: 'static, F>(
|
fn send_synthic_modifier_from_core<F>(
|
||||||
&mut self,
|
&mut self,
|
||||||
window_id: crate::window::WindowId,
|
window_id: crate::window::WindowId,
|
||||||
state: u16,
|
state: u16,
|
||||||
mut callback: F,
|
mut callback: F,
|
||||||
) where
|
) where
|
||||||
F: FnMut(&RootAEL, Event<T>),
|
F: FnMut(&RootAEL, Event),
|
||||||
{
|
{
|
||||||
let keymap = match self.xkb_context.keymap_mut() {
|
let keymap = match self.xkb_context.keymap_mut() {
|
||||||
Some(keymap) => keymap,
|
Some(keymap) => keymap,
|
||||||
|
@ -1022,13 +1018,9 @@ impl EventProcessor {
|
||||||
callback(&self.target, event);
|
callback(&self.target, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn xinput2_button_input<T: 'static, F>(
|
fn xinput2_button_input<F>(&self, event: &XIDeviceEvent, state: ElementState, mut callback: F)
|
||||||
&self,
|
where
|
||||||
event: &XIDeviceEvent,
|
F: FnMut(&RootAEL, Event),
|
||||||
state: ElementState,
|
|
||||||
mut callback: F,
|
|
||||||
) where
|
|
||||||
F: FnMut(&RootAEL, Event<T>),
|
|
||||||
{
|
{
|
||||||
let wt = Self::window_target(&self.target);
|
let wt = Self::window_target(&self.target);
|
||||||
let window_id = mkwid(event.event as xproto::Window);
|
let window_id = mkwid(event.event as xproto::Window);
|
||||||
|
@ -1079,9 +1071,9 @@ impl EventProcessor {
|
||||||
callback(&self.target, event);
|
callback(&self.target, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn xinput2_mouse_motion<T: 'static, F>(&self, event: &XIDeviceEvent, mut callback: F)
|
fn xinput2_mouse_motion<F>(&self, event: &XIDeviceEvent, mut callback: F)
|
||||||
where
|
where
|
||||||
F: FnMut(&RootAEL, Event<T>),
|
F: FnMut(&RootAEL, Event),
|
||||||
{
|
{
|
||||||
let wt = Self::window_target(&self.target);
|
let wt = Self::window_target(&self.target);
|
||||||
|
|
||||||
|
@ -1157,9 +1149,9 @@ impl EventProcessor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn xinput2_mouse_enter<T: 'static, F>(&self, event: &XIEnterEvent, mut callback: F)
|
fn xinput2_mouse_enter<F>(&self, event: &XIEnterEvent, mut callback: F)
|
||||||
where
|
where
|
||||||
F: FnMut(&RootAEL, Event<T>),
|
F: FnMut(&RootAEL, Event),
|
||||||
{
|
{
|
||||||
let wt = Self::window_target(&self.target);
|
let wt = Self::window_target(&self.target);
|
||||||
|
|
||||||
|
@ -1202,9 +1194,9 @@ impl EventProcessor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn xinput2_mouse_left<T: 'static, F>(&self, event: &XILeaveEvent, mut callback: F)
|
fn xinput2_mouse_left<F>(&self, event: &XILeaveEvent, mut callback: F)
|
||||||
where
|
where
|
||||||
F: FnMut(&RootAEL, Event<T>),
|
F: FnMut(&RootAEL, Event),
|
||||||
{
|
{
|
||||||
let wt = Self::window_target(&self.target);
|
let wt = Self::window_target(&self.target);
|
||||||
let window = event.event as xproto::Window;
|
let window = event.event as xproto::Window;
|
||||||
|
@ -1225,9 +1217,9 @@ impl EventProcessor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn xinput2_focused<T: 'static, F>(&mut self, xev: &XIFocusInEvent, mut callback: F)
|
fn xinput2_focused<F>(&mut self, xev: &XIFocusInEvent, mut callback: F)
|
||||||
where
|
where
|
||||||
F: FnMut(&RootAEL, Event<T>),
|
F: FnMut(&RootAEL, Event),
|
||||||
{
|
{
|
||||||
let wt = Self::window_target(&self.target);
|
let wt = Self::window_target(&self.target);
|
||||||
let window = xev.event as xproto::Window;
|
let window = xev.event as xproto::Window;
|
||||||
|
@ -1284,9 +1276,9 @@ impl EventProcessor {
|
||||||
callback(&self.target, event);
|
callback(&self.target, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn xinput2_unfocused<T: 'static, F>(&mut self, xev: &XIFocusOutEvent, mut callback: F)
|
fn xinput2_unfocused<F>(&mut self, xev: &XIFocusOutEvent, mut callback: F)
|
||||||
where
|
where
|
||||||
F: FnMut(&RootAEL, Event<T>),
|
F: FnMut(&RootAEL, Event),
|
||||||
{
|
{
|
||||||
let wt = Self::window_target(&self.target);
|
let wt = Self::window_target(&self.target);
|
||||||
let window = xev.event as xproto::Window;
|
let window = xev.event as xproto::Window;
|
||||||
|
@ -1336,13 +1328,9 @@ impl EventProcessor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn xinput2_touch<T: 'static, F>(
|
fn xinput2_touch<F>(&mut self, xev: &XIDeviceEvent, phase: TouchPhase, mut callback: F)
|
||||||
&mut self,
|
where
|
||||||
xev: &XIDeviceEvent,
|
F: FnMut(&RootAEL, Event),
|
||||||
phase: TouchPhase,
|
|
||||||
mut callback: F,
|
|
||||||
) where
|
|
||||||
F: FnMut(&RootAEL, Event<T>),
|
|
||||||
{
|
{
|
||||||
let wt = Self::window_target(&self.target);
|
let wt = Self::window_target(&self.target);
|
||||||
|
|
||||||
|
@ -1382,13 +1370,9 @@ impl EventProcessor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn xinput2_raw_button_input<T: 'static, F>(
|
fn xinput2_raw_button_input<F>(&self, xev: &XIRawEvent, state: ElementState, mut callback: F)
|
||||||
&self,
|
where
|
||||||
xev: &XIRawEvent,
|
F: FnMut(&RootAEL, Event),
|
||||||
state: ElementState,
|
|
||||||
mut callback: F,
|
|
||||||
) where
|
|
||||||
F: FnMut(&RootAEL, Event<T>),
|
|
||||||
{
|
{
|
||||||
let wt = Self::window_target(&self.target);
|
let wt = Self::window_target(&self.target);
|
||||||
|
|
||||||
|
@ -1404,9 +1388,9 @@ impl EventProcessor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn xinput2_raw_mouse_motion<T: 'static, F>(&self, xev: &XIRawEvent, mut callback: F)
|
fn xinput2_raw_mouse_motion<F>(&self, xev: &XIRawEvent, mut callback: F)
|
||||||
where
|
where
|
||||||
F: FnMut(&RootAEL, Event<T>),
|
F: FnMut(&RootAEL, Event),
|
||||||
{
|
{
|
||||||
let wt = Self::window_target(&self.target);
|
let wt = Self::window_target(&self.target);
|
||||||
|
|
||||||
|
@ -1464,13 +1448,9 @@ impl EventProcessor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn xinput2_raw_key_input<T: 'static, F>(
|
fn xinput2_raw_key_input<F>(&mut self, xev: &XIRawEvent, state: ElementState, mut callback: F)
|
||||||
&mut self,
|
where
|
||||||
xev: &XIRawEvent,
|
F: FnMut(&RootAEL, Event),
|
||||||
state: ElementState,
|
|
||||||
mut callback: F,
|
|
||||||
) where
|
|
||||||
F: FnMut(&RootAEL, Event<T>),
|
|
||||||
{
|
{
|
||||||
let wt = Self::window_target(&self.target);
|
let wt = Self::window_target(&self.target);
|
||||||
|
|
||||||
|
@ -1490,9 +1470,9 @@ impl EventProcessor {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn xinput2_hierarchy_changed<T: 'static, F>(&mut self, xev: &XIHierarchyEvent, mut callback: F)
|
fn xinput2_hierarchy_changed<F>(&mut self, xev: &XIHierarchyEvent, mut callback: F)
|
||||||
where
|
where
|
||||||
F: FnMut(&RootAEL, Event<T>),
|
F: FnMut(&RootAEL, Event),
|
||||||
{
|
{
|
||||||
let wt = Self::window_target(&self.target);
|
let wt = Self::window_target(&self.target);
|
||||||
|
|
||||||
|
@ -1517,9 +1497,9 @@ impl EventProcessor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn xkb_event<T: 'static, F>(&mut self, xev: &XkbAnyEvent, mut callback: F)
|
fn xkb_event<F>(&mut self, xev: &XkbAnyEvent, mut callback: F)
|
||||||
where
|
where
|
||||||
F: FnMut(&RootAEL, Event<T>),
|
F: FnMut(&RootAEL, Event),
|
||||||
{
|
{
|
||||||
let wt = Self::window_target(&self.target);
|
let wt = Self::window_target(&self.target);
|
||||||
match xev.xkb_type {
|
match xev.xkb_type {
|
||||||
|
@ -1596,14 +1576,14 @@ impl EventProcessor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_mods_from_xinput2_event<T: 'static, F>(
|
pub(crate) fn update_mods_from_xinput2_event<F>(
|
||||||
&mut self,
|
&mut self,
|
||||||
mods: &XIModifierState,
|
mods: &XIModifierState,
|
||||||
group: &XIModifierState,
|
group: &XIModifierState,
|
||||||
force: bool,
|
force: bool,
|
||||||
mut callback: F,
|
mut callback: F,
|
||||||
) where
|
) where
|
||||||
F: FnMut(&RootAEL, Event<T>),
|
F: FnMut(&RootAEL, Event),
|
||||||
{
|
{
|
||||||
if let Some(state) = self.xkb_context.state_mut() {
|
if let Some(state) = self.xkb_context.state_mut() {
|
||||||
state.update_modifiers(
|
state.update_modifiers(
|
||||||
|
@ -1627,12 +1607,9 @@ impl EventProcessor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_mods_from_query<T: 'static, F>(
|
fn update_mods_from_query<F>(&mut self, window_id: crate::window::WindowId, mut callback: F)
|
||||||
&mut self,
|
where
|
||||||
window_id: crate::window::WindowId,
|
F: FnMut(&RootAEL, Event),
|
||||||
mut callback: F,
|
|
||||||
) where
|
|
||||||
F: FnMut(&RootAEL, Event<T>),
|
|
||||||
{
|
{
|
||||||
let wt = Self::window_target(&self.target);
|
let wt = Self::window_target(&self.target);
|
||||||
|
|
||||||
|
@ -1661,13 +1638,13 @@ impl EventProcessor {
|
||||||
self.send_modifiers(window_id, mods.into(), true, &mut callback)
|
self.send_modifiers(window_id, mods.into(), true, &mut callback)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_mods_from_core_event<T: 'static, F>(
|
pub(crate) fn update_mods_from_core_event<F>(
|
||||||
&mut self,
|
&mut self,
|
||||||
window_id: crate::window::WindowId,
|
window_id: crate::window::WindowId,
|
||||||
state: u16,
|
state: u16,
|
||||||
mut callback: F,
|
mut callback: F,
|
||||||
) where
|
) where
|
||||||
F: FnMut(&RootAEL, Event<T>),
|
F: FnMut(&RootAEL, Event),
|
||||||
{
|
{
|
||||||
let xkb_mask = self.xkb_mod_mask_from_core(state);
|
let xkb_mask = self.xkb_mod_mask_from_core(state);
|
||||||
let xkb_state = match self.xkb_context.state_mut() {
|
let xkb_state = match self.xkb_context.state_mut() {
|
||||||
|
@ -1740,7 +1717,7 @@ impl EventProcessor {
|
||||||
///
|
///
|
||||||
/// The event won't be sent when the `modifiers` match the previously `sent` modifiers value,
|
/// The event won't be sent when the `modifiers` match the previously `sent` modifiers value,
|
||||||
/// unless `force` is passed. The `force` should be passed when the active window changes.
|
/// unless `force` is passed. The `force` should be passed when the active window changes.
|
||||||
fn send_modifiers<T: 'static, F: FnMut(&RootAEL, Event<T>)>(
|
fn send_modifiers<F: FnMut(&RootAEL, Event)>(
|
||||||
&self,
|
&self,
|
||||||
window_id: crate::window::WindowId,
|
window_id: crate::window::WindowId,
|
||||||
modifiers: ModifiersState,
|
modifiers: ModifiersState,
|
||||||
|
@ -1758,14 +1735,14 @@ impl EventProcessor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_pressed_keys<T: 'static, F>(
|
fn handle_pressed_keys<F>(
|
||||||
target: &RootAEL,
|
target: &RootAEL,
|
||||||
window_id: crate::window::WindowId,
|
window_id: crate::window::WindowId,
|
||||||
state: ElementState,
|
state: ElementState,
|
||||||
xkb_context: &mut Context,
|
xkb_context: &mut Context,
|
||||||
callback: &mut F,
|
callback: &mut F,
|
||||||
) where
|
) where
|
||||||
F: FnMut(&RootAEL, Event<T>),
|
F: FnMut(&RootAEL, Event),
|
||||||
{
|
{
|
||||||
let device_id = mkdid(util::VIRTUAL_CORE_KEYBOARD);
|
let device_id = mkdid(util::VIRTUAL_CORE_KEYBOARD);
|
||||||
|
|
||||||
|
@ -1800,9 +1777,9 @@ impl EventProcessor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_dpi_change<T: 'static, F>(&self, callback: &mut F)
|
fn process_dpi_change<F>(&self, callback: &mut F)
|
||||||
where
|
where
|
||||||
F: FnMut(&RootAEL, Event<T>),
|
F: FnMut(&RootAEL, Event),
|
||||||
{
|
{
|
||||||
let wt = Self::window_target(&self.target);
|
let wt = Self::window_target(&self.target);
|
||||||
wt.xconn.reload_database().expect("failed to reload Xft database");
|
wt.xconn.reload_database().expect("failed to reload Xft database");
|
||||||
|
|
|
@ -9,7 +9,7 @@ use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, RawFd};
|
||||||
use std::sync::mpsc::{self, Receiver, Sender, TryRecvError};
|
use std::sync::mpsc::{self, Receiver, Sender, TryRecvError};
|
||||||
use std::sync::{Arc, Weak};
|
use std::sync::{Arc, Weak};
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
use std::{fmt, ptr, slice, str};
|
use std::{fmt, mem, ptr, slice, str};
|
||||||
|
|
||||||
use calloop::generic::Generic;
|
use calloop::generic::Generic;
|
||||||
use calloop::ping::Ping;
|
use calloop::ping::Ping;
|
||||||
|
@ -28,7 +28,7 @@ use x11rb::xcb_ffi::ReplyOrIdError;
|
||||||
use crate::application::ApplicationHandler;
|
use crate::application::ApplicationHandler;
|
||||||
use crate::error::{EventLoopError, OsError as RootOsError};
|
use crate::error::{EventLoopError, OsError as RootOsError};
|
||||||
use crate::event::{Event, StartCause, WindowEvent};
|
use crate::event::{Event, StartCause, WindowEvent};
|
||||||
use crate::event_loop::{ActiveEventLoop as RootAEL, ControlFlow, DeviceEvents, EventLoopClosed};
|
use crate::event_loop::{ActiveEventLoop as RootAEL, ControlFlow, DeviceEvents};
|
||||||
use crate::platform::pump_events::PumpStatus;
|
use crate::platform::pump_events::PumpStatus;
|
||||||
use crate::platform_impl::common::xkb::Context;
|
use crate::platform_impl::common::xkb::Context;
|
||||||
use crate::platform_impl::platform::{min_timeout, WindowId};
|
use crate::platform_impl::platform::{min_timeout, WindowId};
|
||||||
|
@ -81,12 +81,11 @@ impl<T> Clone for WakeSender<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> WakeSender<T> {
|
impl<T> WakeSender<T> {
|
||||||
pub fn send(&self, t: T) -> Result<(), EventLoopClosed<T>> {
|
pub fn send(&self, t: T) {
|
||||||
let res = self.sender.send(t).map_err(|e| EventLoopClosed(e.0));
|
let res = self.sender.send(t);
|
||||||
if res.is_ok() {
|
if res.is_ok() {
|
||||||
self.waker.ping();
|
self.waker.ping();
|
||||||
}
|
}
|
||||||
res
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,15 +140,13 @@ pub struct ActiveEventLoop {
|
||||||
device_events: Cell<DeviceEvents>,
|
device_events: Cell<DeviceEvents>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct EventLoop<T: 'static> {
|
pub struct EventLoop {
|
||||||
loop_running: bool,
|
loop_running: bool,
|
||||||
event_loop: Loop<'static, EventLoopState>,
|
event_loop: Loop<'static, EventLoopState>,
|
||||||
waker: calloop::ping::Ping,
|
|
||||||
event_processor: EventProcessor,
|
event_processor: EventProcessor,
|
||||||
redraw_receiver: PeekableReceiver<WindowId>,
|
redraw_receiver: PeekableReceiver<WindowId>,
|
||||||
user_receiver: PeekableReceiver<T>,
|
|
||||||
activation_receiver: PeekableReceiver<ActivationToken>,
|
activation_receiver: PeekableReceiver<ActivationToken>,
|
||||||
user_sender: Sender<T>,
|
event_loop_proxy: EventLoopProxy,
|
||||||
|
|
||||||
/// The current state of the event loop.
|
/// The current state of the event loop.
|
||||||
state: EventLoopState,
|
state: EventLoopState,
|
||||||
|
@ -160,20 +157,13 @@ type ActivationToken = (WindowId, crate::event_loop::AsyncRequestSerial);
|
||||||
struct EventLoopState {
|
struct EventLoopState {
|
||||||
/// The latest readiness state for the x11 file descriptor
|
/// The latest readiness state for the x11 file descriptor
|
||||||
x11_readiness: Readiness,
|
x11_readiness: Readiness,
|
||||||
|
|
||||||
|
/// User requested a wake up.
|
||||||
|
proxy_wake_up: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct EventLoopProxy<T: 'static> {
|
impl EventLoop {
|
||||||
user_sender: WakeSender<T>,
|
pub(crate) fn new(xconn: Arc<XConnection>) -> EventLoop {
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: 'static> Clone for EventLoopProxy<T> {
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
EventLoopProxy { user_sender: self.user_sender.clone() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: 'static> EventLoop<T> {
|
|
||||||
pub(crate) fn new(xconn: Arc<XConnection>) -> EventLoop<T> {
|
|
||||||
let root = xconn.default_root().root;
|
let root = xconn.default_root().root;
|
||||||
let atoms = xconn.atoms();
|
let atoms = xconn.atoms();
|
||||||
|
|
||||||
|
@ -277,7 +267,16 @@ impl<T: 'static> EventLoop<T> {
|
||||||
let (activation_token_sender, activation_token_channel) = mpsc::channel();
|
let (activation_token_sender, activation_token_channel) = mpsc::channel();
|
||||||
|
|
||||||
// Create a channel for sending user events.
|
// Create a channel for sending user events.
|
||||||
let (user_sender, user_channel) = mpsc::channel();
|
let (user_waker, user_waker_source) =
|
||||||
|
calloop::ping::make_ping().expect("Failed to create user event loop waker.");
|
||||||
|
event_loop
|
||||||
|
.handle()
|
||||||
|
.insert_source(user_waker_source, move |_, _, state| {
|
||||||
|
// No extra handling is required, we just need to wake-up.
|
||||||
|
state.proxy_wake_up = true;
|
||||||
|
})
|
||||||
|
.expect("Failed to register the event loop waker source");
|
||||||
|
let event_loop_proxy = EventLoopProxy::new(user_waker);
|
||||||
|
|
||||||
let xkb_context =
|
let xkb_context =
|
||||||
Context::from_x11_xkb(xconn.xcb_connection().get_raw_xcb_connection()).unwrap();
|
Context::from_x11_xkb(xconn.xcb_connection().get_raw_xcb_connection()).unwrap();
|
||||||
|
@ -358,31 +357,27 @@ impl<T: 'static> EventLoop<T> {
|
||||||
EventLoop {
|
EventLoop {
|
||||||
loop_running: false,
|
loop_running: false,
|
||||||
event_loop,
|
event_loop,
|
||||||
waker,
|
|
||||||
event_processor,
|
event_processor,
|
||||||
redraw_receiver: PeekableReceiver::from_recv(redraw_channel),
|
redraw_receiver: PeekableReceiver::from_recv(redraw_channel),
|
||||||
activation_receiver: PeekableReceiver::from_recv(activation_token_channel),
|
activation_receiver: PeekableReceiver::from_recv(activation_token_channel),
|
||||||
user_receiver: PeekableReceiver::from_recv(user_channel),
|
event_loop_proxy,
|
||||||
user_sender,
|
state: EventLoopState { x11_readiness: Readiness::EMPTY, proxy_wake_up: false },
|
||||||
state: EventLoopState { x11_readiness: Readiness::EMPTY },
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_proxy(&self) -> EventLoopProxy<T> {
|
pub fn create_proxy(&self) -> EventLoopProxy {
|
||||||
EventLoopProxy {
|
self.event_loop_proxy.clone()
|
||||||
user_sender: WakeSender { sender: self.user_sender.clone(), waker: self.waker.clone() },
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn window_target(&self) -> &RootAEL {
|
pub(crate) fn window_target(&self) -> &RootAEL {
|
||||||
&self.event_processor.target
|
&self.event_processor.target
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_app<A: ApplicationHandler<T>>(mut self, app: &mut A) -> Result<(), EventLoopError> {
|
pub fn run_app<A: ApplicationHandler>(mut self, app: &mut A) -> Result<(), EventLoopError> {
|
||||||
self.run_app_on_demand(app)
|
self.run_app_on_demand(app)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_app_on_demand<A: ApplicationHandler<T>>(
|
pub fn run_app_on_demand<A: ApplicationHandler>(
|
||||||
&mut self,
|
&mut self,
|
||||||
app: &mut A,
|
app: &mut A,
|
||||||
) -> Result<(), EventLoopError> {
|
) -> Result<(), EventLoopError> {
|
||||||
|
@ -412,7 +407,7 @@ impl<T: 'static> EventLoop<T> {
|
||||||
exit
|
exit
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pump_app_events<A: ApplicationHandler<T>>(
|
pub fn pump_app_events<A: ApplicationHandler>(
|
||||||
&mut self,
|
&mut self,
|
||||||
timeout: Option<Duration>,
|
timeout: Option<Duration>,
|
||||||
app: &mut A,
|
app: &mut A,
|
||||||
|
@ -442,11 +437,11 @@ impl<T: 'static> EventLoop<T> {
|
||||||
|
|
||||||
fn has_pending(&mut self) -> bool {
|
fn has_pending(&mut self) -> bool {
|
||||||
self.event_processor.poll()
|
self.event_processor.poll()
|
||||||
|| self.user_receiver.has_incoming()
|
|| self.state.proxy_wake_up
|
||||||
|| self.redraw_receiver.has_incoming()
|
|| self.redraw_receiver.has_incoming()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn poll_events_with_timeout<A: ApplicationHandler<T>>(
|
pub fn poll_events_with_timeout<A: ApplicationHandler>(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut timeout: Option<Duration>,
|
mut timeout: Option<Duration>,
|
||||||
app: &mut A,
|
app: &mut A,
|
||||||
|
@ -511,7 +506,7 @@ impl<T: 'static> EventLoop<T> {
|
||||||
self.single_iteration(app, cause);
|
self.single_iteration(app, cause);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn single_iteration<A: ApplicationHandler<T>>(&mut self, app: &mut A, cause: StartCause) {
|
fn single_iteration<A: ApplicationHandler>(&mut self, app: &mut A, cause: StartCause) {
|
||||||
app.new_events(&self.event_processor.target, cause);
|
app.new_events(&self.event_processor.target, cause);
|
||||||
|
|
||||||
// NB: For consistency all platforms must emit a 'resumed' event even though X11
|
// NB: For consistency all platforms must emit a 'resumed' event even though X11
|
||||||
|
@ -546,10 +541,8 @@ impl<T: 'static> EventLoop<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Empty the user event buffer
|
// Empty the user event buffer
|
||||||
{
|
if mem::take(&mut self.state.proxy_wake_up) {
|
||||||
while let Ok(event) = self.user_receiver.try_recv() {
|
app.proxy_wake_up(&self.event_processor.target);
|
||||||
app.user_event(&self.event_processor.target, event);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Empty the redraw requests
|
// Empty the redraw requests
|
||||||
|
@ -574,19 +567,19 @@ impl<T: 'static> EventLoop<T> {
|
||||||
app.about_to_wait(&self.event_processor.target);
|
app.about_to_wait(&self.event_processor.target);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn drain_events<A: ApplicationHandler<T>>(&mut self, app: &mut A) {
|
fn drain_events<A: ApplicationHandler>(&mut self, app: &mut A) {
|
||||||
let mut xev = MaybeUninit::uninit();
|
let mut xev = MaybeUninit::uninit();
|
||||||
|
|
||||||
while unsafe { self.event_processor.poll_one_event(xev.as_mut_ptr()) } {
|
while unsafe { self.event_processor.poll_one_event(xev.as_mut_ptr()) } {
|
||||||
let mut xev = unsafe { xev.assume_init() };
|
let mut xev = unsafe { xev.assume_init() };
|
||||||
self.event_processor.process_event(&mut xev, |window_target, event: Event<T>| {
|
self.event_processor.process_event(&mut xev, |window_target, event: Event| {
|
||||||
if let Event::WindowEvent {
|
if let Event::WindowEvent {
|
||||||
window_id: crate::window::WindowId(wid),
|
window_id: crate::window::WindowId(wid),
|
||||||
event: WindowEvent::RedrawRequested,
|
event: WindowEvent::RedrawRequested,
|
||||||
} = event
|
} = event
|
||||||
{
|
{
|
||||||
let window_target = EventProcessor::window_target(window_target);
|
let window_target = EventProcessor::window_target(window_target);
|
||||||
window_target.redraw_sender.send(wid).unwrap();
|
window_target.redraw_sender.send(wid);
|
||||||
} else {
|
} else {
|
||||||
match event {
|
match event {
|
||||||
Event::WindowEvent { window_id, event } => {
|
Event::WindowEvent { window_id, event } => {
|
||||||
|
@ -623,13 +616,13 @@ impl<T: 'static> EventLoop<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> AsFd for EventLoop<T> {
|
impl AsFd for EventLoop {
|
||||||
fn as_fd(&self) -> BorrowedFd<'_> {
|
fn as_fd(&self) -> BorrowedFd<'_> {
|
||||||
self.event_loop.as_fd()
|
self.event_loop.as_fd()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> AsRawFd for EventLoop<T> {
|
impl AsRawFd for EventLoop {
|
||||||
fn as_raw_fd(&self) -> RawFd {
|
fn as_raw_fd(&self) -> RawFd {
|
||||||
self.event_loop.as_raw_fd()
|
self.event_loop.as_raw_fd()
|
||||||
}
|
}
|
||||||
|
@ -729,9 +722,9 @@ impl ActiveEventLoop {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: 'static> EventLoopProxy<T> {
|
impl EventLoopProxy {
|
||||||
pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed<T>> {
|
pub fn wake_up(&self) {
|
||||||
self.user_sender.send(event).map_err(|e| EventLoopClosed(e.0))
|
self.ping.ping();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -815,6 +808,17 @@ impl Drop for Window {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct EventLoopProxy {
|
||||||
|
ping: Ping,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EventLoopProxy {
|
||||||
|
fn new(ping: Ping) -> Self {
|
||||||
|
Self { ping }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Generic sum error type for X11 errors.
|
/// Generic sum error type for X11 errors.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum X11Error {
|
pub enum X11Error {
|
||||||
|
|
|
@ -876,11 +876,11 @@ impl UnownedWindow {
|
||||||
|
|
||||||
/// Refresh the API for the given monitor.
|
/// Refresh the API for the given monitor.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(super) fn refresh_dpi_for_monitor<T: 'static>(
|
pub(super) fn refresh_dpi_for_monitor(
|
||||||
&self,
|
&self,
|
||||||
new_monitor: &X11MonitorHandle,
|
new_monitor: &X11MonitorHandle,
|
||||||
maybe_prev_scale_factor: Option<f64>,
|
maybe_prev_scale_factor: Option<f64>,
|
||||||
mut callback: impl FnMut(Event<T>),
|
mut callback: impl FnMut(Event),
|
||||||
) {
|
) {
|
||||||
// Check if the self is on this monitor
|
// Check if the self is on this monitor
|
||||||
let monitor = self.shared_state_lock().last_monitor.clone();
|
let monitor = self.shared_state_lock().last_monitor.clone();
|
||||||
|
@ -1805,9 +1805,7 @@ impl UnownedWindow {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn request_activation_token(&self) -> Result<AsyncRequestSerial, NotSupportedError> {
|
pub fn request_activation_token(&self) -> Result<AsyncRequestSerial, NotSupportedError> {
|
||||||
let serial = AsyncRequestSerial::get();
|
let serial = AsyncRequestSerial::get();
|
||||||
self.activation_sender
|
self.activation_sender.send((self.id(), serial));
|
||||||
.send((self.id(), serial))
|
|
||||||
.expect("activation token channel should never be closed");
|
|
||||||
Ok(serial)
|
Ok(serial)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1818,7 +1816,7 @@ impl UnownedWindow {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn request_redraw(&self) {
|
pub fn request_redraw(&self) {
|
||||||
self.redraw_sender.send(WindowId(self.xwindow as _)).unwrap();
|
self.redraw_sender.send(WindowId(self.xwindow as _));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
use std::cell::{Cell, RefCell};
|
use std::cell::{Cell, RefCell};
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::rc::Weak;
|
use std::rc::Weak;
|
||||||
|
use std::sync::atomic::{AtomicBool, Ordering as AtomicOrdering};
|
||||||
|
use std::sync::Arc;
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
|
|
||||||
use objc2::rc::Retained;
|
use objc2::rc::Retained;
|
||||||
|
@ -24,6 +26,7 @@ pub(super) struct AppState {
|
||||||
default_menu: bool,
|
default_menu: bool,
|
||||||
activate_ignoring_other_apps: bool,
|
activate_ignoring_other_apps: bool,
|
||||||
run_loop: RunLoop,
|
run_loop: RunLoop,
|
||||||
|
proxy_wake_up: Arc<AtomicBool>,
|
||||||
event_handler: EventHandler,
|
event_handler: EventHandler,
|
||||||
stop_on_launch: Cell<bool>,
|
stop_on_launch: Cell<bool>,
|
||||||
stop_before_wait: Cell<bool>,
|
stop_before_wait: Cell<bool>,
|
||||||
|
@ -77,11 +80,13 @@ impl ApplicationDelegate {
|
||||||
pub(super) fn new(
|
pub(super) fn new(
|
||||||
mtm: MainThreadMarker,
|
mtm: MainThreadMarker,
|
||||||
activation_policy: NSApplicationActivationPolicy,
|
activation_policy: NSApplicationActivationPolicy,
|
||||||
|
proxy_wake_up: Arc<AtomicBool>,
|
||||||
default_menu: bool,
|
default_menu: bool,
|
||||||
activate_ignoring_other_apps: bool,
|
activate_ignoring_other_apps: bool,
|
||||||
) -> Retained<Self> {
|
) -> Retained<Self> {
|
||||||
let this = mtm.alloc().set_ivars(AppState {
|
let this = mtm.alloc().set_ivars(AppState {
|
||||||
activation_policy,
|
activation_policy,
|
||||||
|
proxy_wake_up,
|
||||||
default_menu,
|
default_menu,
|
||||||
activate_ignoring_other_apps,
|
activate_ignoring_other_apps,
|
||||||
run_loop: RunLoop::main(mtm),
|
run_loop: RunLoop::main(mtm),
|
||||||
|
@ -168,7 +173,7 @@ impl ApplicationDelegate {
|
||||||
/// of the given closure.
|
/// of the given closure.
|
||||||
pub fn set_event_handler<R>(
|
pub fn set_event_handler<R>(
|
||||||
&self,
|
&self,
|
||||||
handler: &mut dyn ApplicationHandler<HandlePendingUserEvents>,
|
handler: &mut dyn ApplicationHandler,
|
||||||
closure: impl FnOnce() -> R,
|
closure: impl FnOnce() -> R,
|
||||||
) -> R {
|
) -> R {
|
||||||
self.ivars().event_handler.set(handler, closure)
|
self.ivars().event_handler.set(handler, closure)
|
||||||
|
@ -275,8 +280,7 @@ impl ApplicationDelegate {
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
pub fn maybe_queue_with_handler(
|
pub fn maybe_queue_with_handler(
|
||||||
&self,
|
&self,
|
||||||
callback: impl FnOnce(&mut dyn ApplicationHandler<HandlePendingUserEvents>, &RootActiveEventLoop)
|
callback: impl FnOnce(&mut dyn ApplicationHandler, &RootActiveEventLoop) + 'static,
|
||||||
+ 'static,
|
|
||||||
) {
|
) {
|
||||||
// Most programmer actions in AppKit (e.g. change window fullscreen, set focused, etc.)
|
// Most programmer actions in AppKit (e.g. change window fullscreen, set focused, etc.)
|
||||||
// result in an event being queued, and applied at a later point.
|
// result in an event being queued, and applied at a later point.
|
||||||
|
@ -296,11 +300,9 @@ impl ApplicationDelegate {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn with_handler<
|
fn with_handler(
|
||||||
F: FnOnce(&mut dyn ApplicationHandler<HandlePendingUserEvents>, &RootActiveEventLoop),
|
|
||||||
>(
|
|
||||||
&self,
|
&self,
|
||||||
callback: F,
|
callback: impl FnOnce(&mut dyn ApplicationHandler, &RootActiveEventLoop),
|
||||||
) {
|
) {
|
||||||
let event_loop = ActiveEventLoop::new_root(self.retain());
|
let event_loop = ActiveEventLoop::new_root(self.retain());
|
||||||
self.ivars().event_handler.handle(callback, &event_loop);
|
self.ivars().event_handler.handle(callback, &event_loop);
|
||||||
|
@ -361,7 +363,9 @@ impl ApplicationDelegate {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.with_handler(|app, event_loop| app.user_event(event_loop, HandlePendingUserEvents));
|
if self.ivars().proxy_wake_up.swap(false, AtomicOrdering::Relaxed) {
|
||||||
|
self.with_handler(|app, event_loop| app.proxy_wake_up(event_loop));
|
||||||
|
}
|
||||||
|
|
||||||
let redraw = mem::take(&mut *self.ivars().pending_redraw.borrow_mut());
|
let redraw = mem::take(&mut *self.ivars().pending_redraw.borrow_mut());
|
||||||
for window_id in redraw {
|
for window_id in redraw {
|
||||||
|
@ -393,9 +397,6 @@ impl ApplicationDelegate {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub(crate) struct HandlePendingUserEvents;
|
|
||||||
|
|
||||||
/// Returns the minimum `Option<Instant>`, taking into account that `None`
|
/// Returns the minimum `Option<Instant>`, taking into account that `None`
|
||||||
/// equates to an infinite timeout, not a zero timeout (so can't just use
|
/// equates to an infinite timeout, not a zero timeout (so can't just use
|
||||||
/// `Option::min`)
|
/// `Option::min`)
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::{fmt, mem};
|
use std::{fmt, mem};
|
||||||
|
|
||||||
use super::app_state::HandlePendingUserEvents;
|
|
||||||
use crate::application::ApplicationHandler;
|
use crate::application::ApplicationHandler;
|
||||||
use crate::event_loop::ActiveEventLoop as RootActiveEventLoop;
|
use crate::event_loop::ActiveEventLoop as RootActiveEventLoop;
|
||||||
|
|
||||||
|
@ -11,7 +10,7 @@ pub(crate) struct EventHandler {
|
||||||
/// - Not registered by the event loop (None).
|
/// - Not registered by the event loop (None).
|
||||||
/// - Present (Some(handler)).
|
/// - Present (Some(handler)).
|
||||||
/// - Currently executing the handler / in use (RefCell borrowed).
|
/// - Currently executing the handler / in use (RefCell borrowed).
|
||||||
inner: RefCell<Option<&'static mut dyn ApplicationHandler<HandlePendingUserEvents>>>,
|
inner: RefCell<Option<&'static mut dyn ApplicationHandler>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for EventHandler {
|
impl fmt::Debug for EventHandler {
|
||||||
|
@ -37,7 +36,7 @@ impl EventHandler {
|
||||||
/// from within the closure.
|
/// from within the closure.
|
||||||
pub(crate) fn set<'handler, R>(
|
pub(crate) fn set<'handler, R>(
|
||||||
&self,
|
&self,
|
||||||
app: &'handler mut dyn ApplicationHandler<HandlePendingUserEvents>,
|
app: &'handler mut dyn ApplicationHandler,
|
||||||
closure: impl FnOnce() -> R,
|
closure: impl FnOnce() -> R,
|
||||||
) -> R {
|
) -> R {
|
||||||
// SAFETY: We extend the lifetime of the handler here so that we can
|
// SAFETY: We extend the lifetime of the handler here so that we can
|
||||||
|
@ -48,8 +47,8 @@ impl EventHandler {
|
||||||
// extended beyond `'handler`.
|
// extended beyond `'handler`.
|
||||||
let handler = unsafe {
|
let handler = unsafe {
|
||||||
mem::transmute::<
|
mem::transmute::<
|
||||||
&'handler mut dyn ApplicationHandler<HandlePendingUserEvents>,
|
&'handler mut dyn ApplicationHandler,
|
||||||
&'static mut dyn ApplicationHandler<HandlePendingUserEvents>,
|
&'static mut dyn ApplicationHandler,
|
||||||
>(app)
|
>(app)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -109,11 +108,9 @@ impl EventHandler {
|
||||||
matches!(self.inner.try_borrow().as_deref(), Ok(Some(_)))
|
matches!(self.inner.try_borrow().as_deref(), Ok(Some(_)))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn handle<
|
pub(crate) fn handle(
|
||||||
F: FnOnce(&mut dyn ApplicationHandler<HandlePendingUserEvents>, &RootActiveEventLoop),
|
|
||||||
>(
|
|
||||||
&self,
|
&self,
|
||||||
callback: F,
|
callback: impl FnOnce(&mut dyn ApplicationHandler, &RootActiveEventLoop),
|
||||||
event_loop: &RootActiveEventLoop,
|
event_loop: &RootActiveEventLoop,
|
||||||
) {
|
) {
|
||||||
match self.inner.try_borrow_mut().as_deref_mut() {
|
match self.inner.try_borrow_mut().as_deref_mut() {
|
||||||
|
|
|
@ -6,7 +6,8 @@ use std::os::raw::c_void;
|
||||||
use std::panic::{catch_unwind, resume_unwind, RefUnwindSafe, UnwindSafe};
|
use std::panic::{catch_unwind, resume_unwind, RefUnwindSafe, UnwindSafe};
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
use std::rc::{Rc, Weak};
|
use std::rc::{Rc, Weak};
|
||||||
use std::sync::mpsc;
|
use std::sync::atomic::{AtomicBool, Ordering as AtomicOrdering};
|
||||||
|
use std::sync::Arc;
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
use core_foundation::base::{CFIndex, CFRelease};
|
use core_foundation::base::{CFIndex, CFRelease};
|
||||||
|
@ -21,15 +22,13 @@ use objc2_app_kit::{NSApplication, NSApplicationActivationPolicy, NSWindow};
|
||||||
use objc2_foundation::{MainThreadMarker, NSObjectProtocol};
|
use objc2_foundation::{MainThreadMarker, NSObjectProtocol};
|
||||||
|
|
||||||
use super::app::WinitApplication;
|
use super::app::WinitApplication;
|
||||||
use super::app_state::{ApplicationDelegate, HandlePendingUserEvents};
|
use super::app_state::ApplicationDelegate;
|
||||||
use super::event::dummy_event;
|
use super::event::dummy_event;
|
||||||
use super::monitor::{self, MonitorHandle};
|
use super::monitor::{self, MonitorHandle};
|
||||||
use super::observer::setup_control_flow_observers;
|
use super::observer::setup_control_flow_observers;
|
||||||
use crate::application::ApplicationHandler;
|
use crate::application::ApplicationHandler;
|
||||||
use crate::error::EventLoopError;
|
use crate::error::EventLoopError;
|
||||||
use crate::event_loop::{
|
use crate::event_loop::{ActiveEventLoop as RootWindowTarget, ControlFlow, DeviceEvents};
|
||||||
ActiveEventLoop as RootWindowTarget, ControlFlow, DeviceEvents, EventLoopClosed,
|
|
||||||
};
|
|
||||||
use crate::platform::macos::ActivationPolicy;
|
use crate::platform::macos::ActivationPolicy;
|
||||||
use crate::platform::pump_events::PumpStatus;
|
use crate::platform::pump_events::PumpStatus;
|
||||||
use crate::platform_impl::platform::cursor::CustomCursor;
|
use crate::platform_impl::platform::cursor::CustomCursor;
|
||||||
|
@ -155,82 +154,7 @@ impl ActiveEventLoop {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Temporary helper, will be removed in https://github.com/rust-windowing/winit/pull/3694
|
pub struct EventLoop {
|
||||||
struct MapUserEvent<T, A> {
|
|
||||||
app: A,
|
|
||||||
receiver: Rc<mpsc::Receiver<T>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<A: ApplicationHandler<T>, T: 'static> ApplicationHandler<HandlePendingUserEvents>
|
|
||||||
for MapUserEvent<T, A>
|
|
||||||
{
|
|
||||||
#[inline]
|
|
||||||
fn new_events(
|
|
||||||
&mut self,
|
|
||||||
event_loop: &crate::event_loop::ActiveEventLoop,
|
|
||||||
cause: crate::event::StartCause,
|
|
||||||
) {
|
|
||||||
self.app.new_events(event_loop, cause);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn resumed(&mut self, event_loop: &crate::event_loop::ActiveEventLoop) {
|
|
||||||
self.app.resumed(event_loop);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn user_event(
|
|
||||||
&mut self,
|
|
||||||
event_loop: &crate::event_loop::ActiveEventLoop,
|
|
||||||
_event: HandlePendingUserEvents,
|
|
||||||
) {
|
|
||||||
for event in self.receiver.try_iter() {
|
|
||||||
self.app.user_event(event_loop, event);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn window_event(
|
|
||||||
&mut self,
|
|
||||||
event_loop: &crate::event_loop::ActiveEventLoop,
|
|
||||||
window_id: crate::window::WindowId,
|
|
||||||
event: crate::event::WindowEvent,
|
|
||||||
) {
|
|
||||||
self.app.window_event(event_loop, window_id, event);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn device_event(
|
|
||||||
&mut self,
|
|
||||||
event_loop: &crate::event_loop::ActiveEventLoop,
|
|
||||||
device_id: crate::event::DeviceId,
|
|
||||||
event: crate::event::DeviceEvent,
|
|
||||||
) {
|
|
||||||
self.app.device_event(event_loop, device_id, event);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn about_to_wait(&mut self, event_loop: &crate::event_loop::ActiveEventLoop) {
|
|
||||||
self.app.about_to_wait(event_loop);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn suspended(&mut self, event_loop: &crate::event_loop::ActiveEventLoop) {
|
|
||||||
self.app.suspended(event_loop);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn exiting(&mut self, event_loop: &crate::event_loop::ActiveEventLoop) {
|
|
||||||
self.app.exiting(event_loop);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn memory_warning(&mut self, event_loop: &crate::event_loop::ActiveEventLoop) {
|
|
||||||
self.app.memory_warning(event_loop);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct EventLoop<T: 'static> {
|
|
||||||
/// Store a reference to the application for convenience.
|
/// Store a reference to the application for convenience.
|
||||||
///
|
///
|
||||||
/// We intentionally don't store `WinitApplication` since we want to have
|
/// We intentionally don't store `WinitApplication` since we want to have
|
||||||
|
@ -242,9 +166,7 @@ pub struct EventLoop<T: 'static> {
|
||||||
/// keep it around here as well.
|
/// keep it around here as well.
|
||||||
delegate: Retained<ApplicationDelegate>,
|
delegate: Retained<ApplicationDelegate>,
|
||||||
|
|
||||||
// Event sender and receiver, used for EventLoopProxy.
|
proxy_wake_up: Arc<AtomicBool>,
|
||||||
sender: mpsc::Sender<T>,
|
|
||||||
receiver: Rc<mpsc::Receiver<T>>,
|
|
||||||
|
|
||||||
window_target: RootWindowTarget,
|
window_target: RootWindowTarget,
|
||||||
panic_info: Rc<PanicInfo>,
|
panic_info: Rc<PanicInfo>,
|
||||||
|
@ -267,7 +189,7 @@ impl Default for PlatformSpecificEventLoopAttributes {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> EventLoop<T> {
|
impl EventLoop {
|
||||||
pub(crate) fn new(
|
pub(crate) fn new(
|
||||||
attributes: &PlatformSpecificEventLoopAttributes,
|
attributes: &PlatformSpecificEventLoopAttributes,
|
||||||
) -> Result<Self, EventLoopError> {
|
) -> Result<Self, EventLoopError> {
|
||||||
|
@ -289,9 +211,13 @@ impl<T> EventLoop<T> {
|
||||||
ActivationPolicy::Accessory => NSApplicationActivationPolicy::Accessory,
|
ActivationPolicy::Accessory => NSApplicationActivationPolicy::Accessory,
|
||||||
ActivationPolicy::Prohibited => NSApplicationActivationPolicy::Prohibited,
|
ActivationPolicy::Prohibited => NSApplicationActivationPolicy::Prohibited,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let proxy_wake_up = Arc::new(AtomicBool::new(false));
|
||||||
|
|
||||||
let delegate = ApplicationDelegate::new(
|
let delegate = ApplicationDelegate::new(
|
||||||
mtm,
|
mtm,
|
||||||
activation_policy,
|
activation_policy,
|
||||||
|
proxy_wake_up.clone(),
|
||||||
attributes.default_menu,
|
attributes.default_menu,
|
||||||
attributes.activate_ignoring_other_apps,
|
attributes.activate_ignoring_other_apps,
|
||||||
);
|
);
|
||||||
|
@ -303,16 +229,14 @@ impl<T> EventLoop<T> {
|
||||||
let panic_info: Rc<PanicInfo> = Default::default();
|
let panic_info: Rc<PanicInfo> = Default::default();
|
||||||
setup_control_flow_observers(mtm, Rc::downgrade(&panic_info));
|
setup_control_flow_observers(mtm, Rc::downgrade(&panic_info));
|
||||||
|
|
||||||
let (sender, receiver) = mpsc::channel();
|
|
||||||
Ok(EventLoop {
|
Ok(EventLoop {
|
||||||
app,
|
app,
|
||||||
delegate: delegate.clone(),
|
delegate: delegate.clone(),
|
||||||
sender,
|
|
||||||
receiver: Rc::new(receiver),
|
|
||||||
window_target: RootWindowTarget {
|
window_target: RootWindowTarget {
|
||||||
p: ActiveEventLoop { delegate, mtm },
|
p: ActiveEventLoop { delegate, mtm },
|
||||||
_marker: PhantomData,
|
_marker: PhantomData,
|
||||||
},
|
},
|
||||||
|
proxy_wake_up,
|
||||||
panic_info,
|
panic_info,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -321,7 +245,7 @@ impl<T> EventLoop<T> {
|
||||||
&self.window_target
|
&self.window_target
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_app<A: ApplicationHandler<T>>(mut self, app: &mut A) -> Result<(), EventLoopError> {
|
pub fn run_app<A: ApplicationHandler>(mut self, app: &mut A) -> Result<(), EventLoopError> {
|
||||||
self.run_app_on_demand(app)
|
self.run_app_on_demand(app)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -329,13 +253,11 @@ impl<T> EventLoop<T> {
|
||||||
// `pump_events` elegantly (we just ask to run the loop for a "short" amount of
|
// `pump_events` elegantly (we just ask to run the loop for a "short" amount of
|
||||||
// time and so a layered implementation would end up using a lot of CPU due to
|
// time and so a layered implementation would end up using a lot of CPU due to
|
||||||
// redundant wake ups.
|
// redundant wake ups.
|
||||||
pub fn run_app_on_demand<A: ApplicationHandler<T>>(
|
pub fn run_app_on_demand<A: ApplicationHandler>(
|
||||||
&mut self,
|
&mut self,
|
||||||
app: &mut A,
|
app: &mut A,
|
||||||
) -> Result<(), EventLoopError> {
|
) -> Result<(), EventLoopError> {
|
||||||
let mut handler = MapUserEvent { app, receiver: self.receiver.clone() };
|
self.delegate.set_event_handler(app, || {
|
||||||
|
|
||||||
self.delegate.set_event_handler(&mut handler, || {
|
|
||||||
autoreleasepool(|_| {
|
autoreleasepool(|_| {
|
||||||
// clear / normalize pump_events state
|
// clear / normalize pump_events state
|
||||||
self.delegate.set_wait_timeout(None);
|
self.delegate.set_wait_timeout(None);
|
||||||
|
@ -368,14 +290,12 @@ impl<T> EventLoop<T> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pump_app_events<A: ApplicationHandler<T>>(
|
pub fn pump_app_events<A: ApplicationHandler>(
|
||||||
&mut self,
|
&mut self,
|
||||||
timeout: Option<Duration>,
|
timeout: Option<Duration>,
|
||||||
app: &mut A,
|
app: &mut A,
|
||||||
) -> PumpStatus {
|
) -> PumpStatus {
|
||||||
let mut handler = MapUserEvent { app, receiver: self.receiver.clone() };
|
self.delegate.set_event_handler(app, || {
|
||||||
|
|
||||||
self.delegate.set_event_handler(&mut handler, || {
|
|
||||||
autoreleasepool(|_| {
|
autoreleasepool(|_| {
|
||||||
// As a special case, if the application hasn't been launched yet then we at least
|
// As a special case, if the application hasn't been launched yet then we at least
|
||||||
// run the loop until it has fully launched.
|
// run the loop until it has fully launched.
|
||||||
|
@ -439,8 +359,8 @@ impl<T> EventLoop<T> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_proxy(&self) -> EventLoopProxy<T> {
|
pub fn create_proxy(&self) -> EventLoopProxy {
|
||||||
EventLoopProxy::new(self.sender.clone())
|
EventLoopProxy::new(self.proxy_wake_up.clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -498,15 +418,15 @@ pub fn stop_app_on_panic<F: FnOnce() -> R + UnwindSafe, R>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct EventLoopProxy<T> {
|
pub struct EventLoopProxy {
|
||||||
sender: mpsc::Sender<T>,
|
proxy_wake_up: Arc<AtomicBool>,
|
||||||
source: CFRunLoopSourceRef,
|
source: CFRunLoopSourceRef,
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<T: Send> Send for EventLoopProxy<T> {}
|
unsafe impl Send for EventLoopProxy {}
|
||||||
unsafe impl<T: Send> Sync for EventLoopProxy<T> {}
|
unsafe impl Sync for EventLoopProxy {}
|
||||||
|
|
||||||
impl<T> Drop for EventLoopProxy<T> {
|
impl Drop for EventLoopProxy {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
unsafe {
|
unsafe {
|
||||||
CFRelease(self.source as _);
|
CFRelease(self.source as _);
|
||||||
|
@ -514,14 +434,14 @@ impl<T> Drop for EventLoopProxy<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Clone for EventLoopProxy<T> {
|
impl Clone for EventLoopProxy {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
EventLoopProxy::new(self.sender.clone())
|
EventLoopProxy::new(self.proxy_wake_up.clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> EventLoopProxy<T> {
|
impl EventLoopProxy {
|
||||||
fn new(sender: mpsc::Sender<T>) -> Self {
|
fn new(proxy_wake_up: Arc<AtomicBool>) -> Self {
|
||||||
unsafe {
|
unsafe {
|
||||||
// just wake up the eventloop
|
// just wake up the eventloop
|
||||||
extern "C" fn event_loop_proxy_handler(_: *const c_void) {}
|
extern "C" fn event_loop_proxy_handler(_: *const c_void) {}
|
||||||
|
@ -545,18 +465,17 @@ impl<T> EventLoopProxy<T> {
|
||||||
CFRunLoopAddSource(rl, source, kCFRunLoopCommonModes);
|
CFRunLoopAddSource(rl, source, kCFRunLoopCommonModes);
|
||||||
CFRunLoopWakeUp(rl);
|
CFRunLoopWakeUp(rl);
|
||||||
|
|
||||||
EventLoopProxy { sender, source }
|
EventLoopProxy { proxy_wake_up, source }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed<T>> {
|
pub fn wake_up(&self) {
|
||||||
self.sender.send(event).map_err(|mpsc::SendError(x)| EventLoopClosed(x))?;
|
self.proxy_wake_up.store(true, AtomicOrdering::Relaxed);
|
||||||
unsafe {
|
unsafe {
|
||||||
// let the main thread know there's a new event
|
// let the main thread know there's a new event
|
||||||
CFRunLoopSourceSignal(self.source);
|
CFRunLoopSourceSignal(self.source);
|
||||||
let rl = CFRunLoopGetMain();
|
let rl = CFRunLoopGetMain();
|
||||||
CFRunLoopWakeUp(rl);
|
CFRunLoopWakeUp(rl);
|
||||||
}
|
}
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -272,16 +272,18 @@ impl EventState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct EventLoop<T> {
|
pub struct EventLoop {
|
||||||
windows: Vec<(Arc<RedoxSocket>, EventState)>,
|
windows: Vec<(Arc<RedoxSocket>, EventState)>,
|
||||||
window_target: event_loop::ActiveEventLoop,
|
window_target: event_loop::ActiveEventLoop,
|
||||||
user_events_sender: mpsc::Sender<T>,
|
user_events_sender: mpsc::SyncSender<()>,
|
||||||
user_events_receiver: mpsc::Receiver<T>,
|
user_events_receiver: mpsc::Receiver<()>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: 'static> EventLoop<T> {
|
impl EventLoop {
|
||||||
pub(crate) fn new(_: &PlatformSpecificEventLoopAttributes) -> Result<Self, EventLoopError> {
|
pub(crate) fn new(_: &PlatformSpecificEventLoopAttributes) -> Result<Self, EventLoopError> {
|
||||||
let (user_events_sender, user_events_receiver) = mpsc::channel();
|
// NOTE: Create a channel which can hold only one event to automatically _squash_ user
|
||||||
|
// events.
|
||||||
|
let (user_events_sender, user_events_receiver) = mpsc::sync_channel(1);
|
||||||
|
|
||||||
let event_socket = Arc::new(
|
let event_socket = Arc::new(
|
||||||
RedoxSocket::event()
|
RedoxSocket::event()
|
||||||
|
@ -323,7 +325,7 @@ impl<T: 'static> EventLoop<T> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_event<A: ApplicationHandler<T>>(
|
fn process_event<A: ApplicationHandler>(
|
||||||
window_id: WindowId,
|
window_id: WindowId,
|
||||||
event_option: EventOption,
|
event_option: EventOption,
|
||||||
event_state: &mut EventState,
|
event_state: &mut EventState,
|
||||||
|
@ -500,7 +502,7 @@ impl<T: 'static> EventLoop<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_app<A: ApplicationHandler<T>>(mut self, app: &mut A) -> Result<(), EventLoopError> {
|
pub fn run_app<A: ApplicationHandler>(mut self, app: &mut A) -> Result<(), EventLoopError> {
|
||||||
let mut start_cause = StartCause::Init;
|
let mut start_cause = StartCause::Init;
|
||||||
loop {
|
loop {
|
||||||
app.new_events(&self.window_target, start_cause);
|
app.new_events(&self.window_target, start_cause);
|
||||||
|
@ -594,8 +596,8 @@ impl<T: 'static> EventLoop<T> {
|
||||||
i += 1;
|
i += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
while let Ok(event) = self.user_events_receiver.try_recv() {
|
while self.user_events_receiver.try_recv().is_ok() {
|
||||||
app.user_event(&self.window_target, event);
|
app.proxy_wake_up(&self.window_target);
|
||||||
}
|
}
|
||||||
|
|
||||||
// To avoid deadlocks the redraws lock is not held during event processing.
|
// To avoid deadlocks the redraws lock is not held during event processing.
|
||||||
|
@ -683,7 +685,7 @@ impl<T: 'static> EventLoop<T> {
|
||||||
&self.window_target
|
&self.window_target
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_proxy(&self) -> EventLoopProxy<T> {
|
pub fn create_proxy(&self) -> EventLoopProxy {
|
||||||
EventLoopProxy {
|
EventLoopProxy {
|
||||||
user_events_sender: self.user_events_sender.clone(),
|
user_events_sender: self.user_events_sender.clone(),
|
||||||
wake_socket: self.window_target.p.wake_socket.clone(),
|
wake_socket: self.window_target.p.wake_socket.clone(),
|
||||||
|
@ -691,24 +693,22 @@ impl<T: 'static> EventLoop<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct EventLoopProxy<T: 'static> {
|
pub struct EventLoopProxy {
|
||||||
user_events_sender: mpsc::Sender<T>,
|
user_events_sender: mpsc::SyncSender<()>,
|
||||||
wake_socket: Arc<TimeSocket>,
|
wake_socket: Arc<TimeSocket>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> EventLoopProxy<T> {
|
impl EventLoopProxy {
|
||||||
pub fn send_event(&self, event: T) -> Result<(), event_loop::EventLoopClosed<T>> {
|
pub fn wake_up(&self) {
|
||||||
self.user_events_sender
|
// When we fail to send the event it means that we haven't woken up to read the previous
|
||||||
.send(event)
|
// event.
|
||||||
.map_err(|mpsc::SendError(x)| event_loop::EventLoopClosed(x))?;
|
if self.user_events_sender.try_send(()).is_ok() {
|
||||||
|
self.wake_socket.wake().unwrap();
|
||||||
self.wake_socket.wake().unwrap();
|
}
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Clone for EventLoopProxy<T> {
|
impl Clone for EventLoopProxy {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
Self {
|
Self {
|
||||||
user_events_sender: self.user_events_sender.clone(),
|
user_events_sender: self.user_events_sender.clone(),
|
||||||
|
@ -717,7 +717,7 @@ impl<T> Clone for EventLoopProxy<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Unpin for EventLoopProxy<T> {}
|
impl Unpin for EventLoopProxy {}
|
||||||
|
|
||||||
pub struct ActiveEventLoop {
|
pub struct ActiveEventLoop {
|
||||||
control_flow: Cell<ControlFlow>,
|
control_flow: Cell<ControlFlow>,
|
||||||
|
|
|
@ -1,19 +1,18 @@
|
||||||
use std::future;
|
use std::future;
|
||||||
use std::num::NonZeroUsize;
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::task::Poll;
|
use std::task::Poll;
|
||||||
|
|
||||||
use super::super::main_thread::MainThreadMarker;
|
use super::super::main_thread::MainThreadMarker;
|
||||||
use super::{AtomicWaker, Wrapper};
|
use super::{AtomicWaker, Wrapper};
|
||||||
|
|
||||||
pub struct WakerSpawner<T: 'static>(Wrapper<Handler<T>, Sender, NonZeroUsize>);
|
pub struct WakerSpawner<T: 'static>(Wrapper<Handler<T>, Sender, ()>);
|
||||||
|
|
||||||
pub struct Waker<T: 'static>(Wrapper<Handler<T>, Sender, NonZeroUsize>);
|
pub struct Waker<T: 'static>(Wrapper<Handler<T>, Sender, ()>);
|
||||||
|
|
||||||
struct Handler<T> {
|
struct Handler<T> {
|
||||||
value: T,
|
value: T,
|
||||||
handler: fn(&T, NonZeroUsize, bool),
|
handler: fn(&T, bool),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -21,13 +20,9 @@ struct Sender(Arc<Inner>);
|
||||||
|
|
||||||
impl<T> WakerSpawner<T> {
|
impl<T> WakerSpawner<T> {
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
pub fn new(
|
pub fn new(main_thread: MainThreadMarker, value: T, handler: fn(&T, bool)) -> Option<Self> {
|
||||||
main_thread: MainThreadMarker,
|
|
||||||
value: T,
|
|
||||||
handler: fn(&T, NonZeroUsize, bool),
|
|
||||||
) -> Option<Self> {
|
|
||||||
let inner = Arc::new(Inner {
|
let inner = Arc::new(Inner {
|
||||||
counter: AtomicUsize::new(0),
|
awoken: AtomicBool::new(false),
|
||||||
waker: AtomicWaker::new(),
|
waker: AtomicWaker::new(),
|
||||||
closed: AtomicBool::new(false),
|
closed: AtomicBool::new(false),
|
||||||
});
|
});
|
||||||
|
@ -39,49 +34,43 @@ impl<T> WakerSpawner<T> {
|
||||||
let wrapper = Wrapper::new(
|
let wrapper = Wrapper::new(
|
||||||
main_thread,
|
main_thread,
|
||||||
handler,
|
handler,
|
||||||
|handler, count| {
|
|handler, _| {
|
||||||
let handler = handler.borrow();
|
let handler = handler.borrow();
|
||||||
let handler = handler.as_ref().unwrap();
|
let handler = handler.as_ref().unwrap();
|
||||||
(handler.handler)(&handler.value, count, true);
|
(handler.handler)(&handler.value, true);
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
let inner = Arc::clone(&inner);
|
let inner = Arc::clone(&inner);
|
||||||
|
|
||||||
move |handler| async move {
|
move |handler| async move {
|
||||||
while let Some(count) = future::poll_fn(|cx| {
|
while future::poll_fn(|cx| {
|
||||||
let count = inner.counter.swap(0, Ordering::Relaxed);
|
if inner.awoken.swap(false, Ordering::Relaxed) {
|
||||||
|
Poll::Ready(true)
|
||||||
|
} else {
|
||||||
|
inner.waker.register(cx.waker());
|
||||||
|
|
||||||
match NonZeroUsize::new(count) {
|
if inner.awoken.swap(false, Ordering::Relaxed) {
|
||||||
Some(count) => Poll::Ready(Some(count)),
|
Poll::Ready(true)
|
||||||
None => {
|
} else {
|
||||||
inner.waker.register(cx.waker());
|
if inner.closed.load(Ordering::Relaxed) {
|
||||||
|
return Poll::Ready(false);
|
||||||
let count = inner.counter.swap(0, Ordering::Relaxed);
|
|
||||||
|
|
||||||
match NonZeroUsize::new(count) {
|
|
||||||
Some(count) => Poll::Ready(Some(count)),
|
|
||||||
None => {
|
|
||||||
if inner.closed.load(Ordering::Relaxed) {
|
|
||||||
return Poll::Ready(None);
|
|
||||||
}
|
|
||||||
|
|
||||||
Poll::Pending
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
},
|
|
||||||
|
Poll::Pending
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
let handler = handler.borrow();
|
let handler = handler.borrow();
|
||||||
let handler = handler.as_ref().unwrap();
|
let handler = handler.as_ref().unwrap();
|
||||||
(handler.handler)(&handler.value, count, false);
|
(handler.handler)(&handler.value, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
sender,
|
sender,
|
||||||
|inner, _| {
|
|inner, _| {
|
||||||
inner.0.counter.fetch_add(1, Ordering::Relaxed);
|
inner.0.awoken.store(true, Ordering::Relaxed);
|
||||||
inner.0.waker.wake();
|
inner.0.waker.wake();
|
||||||
},
|
},
|
||||||
)?;
|
)?;
|
||||||
|
@ -93,13 +82,13 @@ impl<T> WakerSpawner<T> {
|
||||||
Waker(self.0.clone())
|
Waker(self.0.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn fetch(&self) -> usize {
|
pub fn take(&self) -> bool {
|
||||||
debug_assert!(
|
debug_assert!(
|
||||||
MainThreadMarker::new().is_some(),
|
MainThreadMarker::new().is_some(),
|
||||||
"this should only be called from the main thread"
|
"this should only be called from the main thread"
|
||||||
);
|
);
|
||||||
|
|
||||||
self.0.with_sender_data(|inner| inner.0.counter.swap(0, Ordering::Relaxed))
|
self.0.with_sender_data(|inner| inner.0.awoken.swap(false, Ordering::Relaxed))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,7 +103,7 @@ impl<T> Drop for WakerSpawner<T> {
|
||||||
|
|
||||||
impl<T> Waker<T> {
|
impl<T> Waker<T> {
|
||||||
pub fn wake(&self) {
|
pub fn wake(&self) {
|
||||||
self.0.send(NonZeroUsize::MIN)
|
self.0.send(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,7 +114,7 @@ impl<T> Clone for Waker<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Inner {
|
struct Inner {
|
||||||
counter: AtomicUsize,
|
awoken: AtomicBool,
|
||||||
waker: AtomicWaker,
|
waker: AtomicWaker,
|
||||||
closed: AtomicBool,
|
closed: AtomicBool,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::sync::mpsc::{self, Receiver, Sender};
|
|
||||||
|
|
||||||
use crate::application::ApplicationHandler;
|
use crate::application::ApplicationHandler;
|
||||||
use crate::error::EventLoopError;
|
use crate::error::EventLoopError;
|
||||||
|
@ -17,36 +16,30 @@ mod window_target;
|
||||||
pub(crate) use proxy::EventLoopProxy;
|
pub(crate) use proxy::EventLoopProxy;
|
||||||
pub(crate) use window_target::{ActiveEventLoop, OwnedDisplayHandle};
|
pub(crate) use window_target::{ActiveEventLoop, OwnedDisplayHandle};
|
||||||
|
|
||||||
pub struct EventLoop<T: 'static> {
|
pub struct EventLoop {
|
||||||
elw: RootActiveEventLoop,
|
elw: RootActiveEventLoop,
|
||||||
user_event_sender: Sender<T>,
|
|
||||||
user_event_receiver: Receiver<T>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
#[derive(Default, Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
pub(crate) struct PlatformSpecificEventLoopAttributes {}
|
pub(crate) struct PlatformSpecificEventLoopAttributes {}
|
||||||
|
|
||||||
impl<T> EventLoop<T> {
|
impl EventLoop {
|
||||||
pub(crate) fn new(_: &PlatformSpecificEventLoopAttributes) -> Result<Self, EventLoopError> {
|
pub(crate) fn new(_: &PlatformSpecificEventLoopAttributes) -> Result<Self, EventLoopError> {
|
||||||
let (user_event_sender, user_event_receiver) = mpsc::channel();
|
|
||||||
let elw = RootActiveEventLoop { p: ActiveEventLoop::new(), _marker: PhantomData };
|
let elw = RootActiveEventLoop { p: ActiveEventLoop::new(), _marker: PhantomData };
|
||||||
Ok(EventLoop { elw, user_event_sender, user_event_receiver })
|
Ok(EventLoop { elw })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_app<A: ApplicationHandler<T>>(self, app: &mut A) -> ! {
|
pub fn run_app<A: ApplicationHandler>(self, app: &mut A) -> ! {
|
||||||
let target = RootActiveEventLoop { p: self.elw.p.clone(), _marker: PhantomData };
|
let target = RootActiveEventLoop { p: self.elw.p.clone(), _marker: PhantomData };
|
||||||
|
|
||||||
// SAFETY: Don't use `move` to make sure we leak the `event_handler` and `target`.
|
// SAFETY: Don't use `move` to make sure we leak the `event_handler` and `target`.
|
||||||
let handler: Box<dyn FnMut(Event<()>)> =
|
let handler: Box<dyn FnMut(Event)> = Box::new(|event| handle_event(app, &target, event));
|
||||||
Box::new(|event| handle_event(app, &target, &self.user_event_receiver, event));
|
|
||||||
|
|
||||||
// SAFETY: The `transmute` is necessary because `run()` requires `'static`. This is safe
|
// SAFETY: The `transmute` is necessary because `run()` requires `'static`. This is safe
|
||||||
// because this function will never return and all resources not cleaned up by the point we
|
// because this function will never return and all resources not cleaned up by the point we
|
||||||
// `throw` will leak, making this actually `'static`.
|
// `throw` will leak, making this actually `'static`.
|
||||||
let handler = unsafe {
|
let handler = unsafe {
|
||||||
std::mem::transmute::<Box<dyn FnMut(Event<()>)>, Box<dyn FnMut(Event<()>) + 'static>>(
|
std::mem::transmute::<Box<dyn FnMut(Event)>, Box<dyn FnMut(Event) + 'static>>(handler)
|
||||||
handler,
|
|
||||||
)
|
|
||||||
};
|
};
|
||||||
self.elw.p.run(handler, false);
|
self.elw.p.run(handler, false);
|
||||||
|
|
||||||
|
@ -59,19 +52,14 @@ impl<T> EventLoop<T> {
|
||||||
unreachable!();
|
unreachable!();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn spawn_app<A: ApplicationHandler<T> + 'static>(self, mut app: A) {
|
pub fn spawn_app<A: ApplicationHandler + 'static>(self, mut app: A) {
|
||||||
let target = RootActiveEventLoop { p: self.elw.p.clone(), _marker: PhantomData };
|
let target = RootActiveEventLoop { p: self.elw.p.clone(), _marker: PhantomData };
|
||||||
|
|
||||||
self.elw.p.run(
|
self.elw.p.run(Box::new(move |event| handle_event(&mut app, &target, event)), true);
|
||||||
Box::new(move |event| {
|
|
||||||
handle_event(&mut app, &target, &self.user_event_receiver, event)
|
|
||||||
}),
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_proxy(&self) -> EventLoopProxy<T> {
|
pub fn create_proxy(&self) -> EventLoopProxy {
|
||||||
EventLoopProxy::new(self.elw.p.waker(), self.user_event_sender.clone())
|
EventLoopProxy::new(self.elw.p.waker())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn window_target(&self) -> &RootActiveEventLoop {
|
pub fn window_target(&self) -> &RootActiveEventLoop {
|
||||||
|
@ -95,21 +83,12 @@ impl<T> EventLoop<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_event<T: 'static, A: ApplicationHandler<T>>(
|
fn handle_event<A: ApplicationHandler>(app: &mut A, target: &RootActiveEventLoop, event: Event) {
|
||||||
app: &mut A,
|
|
||||||
target: &RootActiveEventLoop,
|
|
||||||
user_event_receiver: &Receiver<T>,
|
|
||||||
event: Event<()>,
|
|
||||||
) {
|
|
||||||
match event {
|
match event {
|
||||||
Event::NewEvents(cause) => app.new_events(target, cause),
|
Event::NewEvents(cause) => app.new_events(target, cause),
|
||||||
Event::WindowEvent { window_id, event } => app.window_event(target, window_id, event),
|
Event::WindowEvent { window_id, event } => app.window_event(target, window_id, event),
|
||||||
Event::DeviceEvent { device_id, event } => app.device_event(target, device_id, event),
|
Event::DeviceEvent { device_id, event } => app.device_event(target, device_id, event),
|
||||||
Event::UserEvent(_) => {
|
Event::UserWakeUp => app.proxy_wake_up(target),
|
||||||
let event =
|
|
||||||
user_event_receiver.try_recv().expect("user event signaled but not received");
|
|
||||||
app.user_event(target, event);
|
|
||||||
},
|
|
||||||
Event::Suspended => app.suspended(target),
|
Event::Suspended => app.suspended(target),
|
||||||
Event::Resumed => app.resumed(target),
|
Event::Resumed => app.resumed(target),
|
||||||
Event::AboutToWait => app.about_to_wait(target),
|
Event::AboutToWait => app.about_to_wait(target),
|
||||||
|
|
|
@ -1,29 +1,19 @@
|
||||||
use std::rc::Weak;
|
use std::rc::Weak;
|
||||||
use std::sync::mpsc::{SendError, Sender};
|
|
||||||
|
|
||||||
use super::runner::Execution;
|
use super::runner::Execution;
|
||||||
use crate::event_loop::EventLoopClosed;
|
|
||||||
use crate::platform_impl::platform::r#async::Waker;
|
use crate::platform_impl::platform::r#async::Waker;
|
||||||
|
|
||||||
pub struct EventLoopProxy<T: 'static> {
|
#[derive(Clone)]
|
||||||
|
pub struct EventLoopProxy {
|
||||||
runner: Waker<Weak<Execution>>,
|
runner: Waker<Weak<Execution>>,
|
||||||
sender: Sender<T>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: 'static> EventLoopProxy<T> {
|
impl EventLoopProxy {
|
||||||
pub fn new(runner: Waker<Weak<Execution>>, sender: Sender<T>) -> Self {
|
pub fn new(runner: Waker<Weak<Execution>>) -> Self {
|
||||||
Self { runner, sender }
|
Self { runner }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed<T>> {
|
pub fn wake_up(&self) {
|
||||||
self.sender.send(event).map_err(|SendError(event)| EventLoopClosed(event))?;
|
|
||||||
self.runner.wake();
|
self.runner.wake();
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: 'static> Clone for EventLoopProxy<T> {
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
Self { runner: self.runner.clone(), sender: self.sender.clone() }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,6 @@ use js_sys::Function;
|
||||||
use std::cell::{Cell, RefCell};
|
use std::cell::{Cell, RefCell};
|
||||||
use std::collections::{HashSet, VecDeque};
|
use std::collections::{HashSet, VecDeque};
|
||||||
use std::iter;
|
use std::iter;
|
||||||
use std::num::NonZeroUsize;
|
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::rc::{Rc, Weak};
|
use std::rc::{Rc, Weak};
|
||||||
use wasm_bindgen::prelude::{wasm_bindgen, Closure};
|
use wasm_bindgen::prelude::{wasm_bindgen, Closure};
|
||||||
|
@ -28,7 +27,7 @@ use web_time::{Duration, Instant};
|
||||||
|
|
||||||
pub struct Shared(Rc<Execution>);
|
pub struct Shared(Rc<Execution>);
|
||||||
|
|
||||||
pub(super) type EventHandler = dyn FnMut(Event<()>);
|
pub(super) type EventHandler = dyn FnMut(Event);
|
||||||
|
|
||||||
impl Clone for Shared {
|
impl Clone for Shared {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
|
@ -137,13 +136,12 @@ impl Shared {
|
||||||
let document = window.document().expect("Failed to obtain document");
|
let document = window.document().expect("Failed to obtain document");
|
||||||
|
|
||||||
Shared(Rc::<Execution>::new_cyclic(|weak| {
|
Shared(Rc::<Execution>::new_cyclic(|weak| {
|
||||||
let proxy_spawner =
|
let proxy_spawner = WakerSpawner::new(main_thread, weak.clone(), |runner, local| {
|
||||||
WakerSpawner::new(main_thread, weak.clone(), |runner, count, local| {
|
if let Some(runner) = runner.upgrade() {
|
||||||
if let Some(runner) = runner.upgrade() {
|
Shared(runner).send_proxy_wake_up(local);
|
||||||
Shared(runner).send_user_events(count, local)
|
}
|
||||||
}
|
})
|
||||||
})
|
.expect("`EventLoop` has to be created in the main thread");
|
||||||
.expect("`EventLoop` has to be created in the main thread");
|
|
||||||
|
|
||||||
Execution {
|
Execution {
|
||||||
main_thread,
|
main_thread,
|
||||||
|
@ -203,7 +201,7 @@ impl Shared {
|
||||||
// Set the event callback to use for the event loop runner
|
// Set the event callback to use for the event loop runner
|
||||||
// This the event callback is a fairly thin layer over the user-provided callback that closes
|
// This the event callback is a fairly thin layer over the user-provided callback that closes
|
||||||
// over a RootActiveEventLoop reference
|
// over a RootActiveEventLoop reference
|
||||||
pub fn set_listener(&self, event_handler: Box<EventHandler>) {
|
pub(crate) fn set_listener(&self, event_handler: Box<EventHandler>) {
|
||||||
{
|
{
|
||||||
let mut runner = self.0.runner.borrow_mut();
|
let mut runner = self.0.runner.borrow_mut();
|
||||||
assert!(matches!(*runner, RunnerEnum::Pending));
|
assert!(matches!(*runner, RunnerEnum::Pending));
|
||||||
|
@ -466,11 +464,11 @@ impl Shared {
|
||||||
self.send_events(iter::once(event));
|
self.send_events(iter::once(event));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add a series of user events to the event loop runner
|
// Add a user event to the event loop runner.
|
||||||
//
|
//
|
||||||
// This will schedule the event loop to wake up instead of waking it up immediately if its not
|
// This will schedule the event loop to wake up instead of waking it up immediately if its not
|
||||||
// running.
|
// running.
|
||||||
pub(crate) fn send_user_events(&self, count: NonZeroUsize, local: bool) {
|
pub(crate) fn send_proxy_wake_up(&self, local: bool) {
|
||||||
// If the event loop is closed, it should discard any new events
|
// If the event loop is closed, it should discard any new events
|
||||||
if self.is_closed() {
|
if self.is_closed() {
|
||||||
return;
|
return;
|
||||||
|
@ -492,9 +490,7 @@ impl Shared {
|
||||||
let this = Rc::downgrade(&self.0);
|
let this = Rc::downgrade(&self.0);
|
||||||
move || {
|
move || {
|
||||||
if let Some(shared) = this.upgrade() {
|
if let Some(shared) = this.upgrade() {
|
||||||
Shared(shared).send_events(
|
Shared(shared).send_event(Event::UserWakeUp)
|
||||||
iter::repeat(Event::UserEvent(())).take(count.get()),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -505,7 +501,7 @@ impl Shared {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.send_events(iter::repeat(Event::UserEvent(())).take(count.get()))
|
self.send_event(Event::UserWakeUp);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add a series of events to the event loop runner
|
// Add a series of events to the event loop runner
|
||||||
|
@ -648,8 +644,10 @@ impl Shared {
|
||||||
|
|
||||||
// Pre-fetch `UserEvent`s to avoid having to wait until the next event loop cycle.
|
// Pre-fetch `UserEvent`s to avoid having to wait until the next event loop cycle.
|
||||||
events.extend(
|
events.extend(
|
||||||
iter::repeat(Event::UserEvent(()))
|
self.0
|
||||||
.take(self.0.proxy_spawner.fetch())
|
.proxy_spawner
|
||||||
|
.take()
|
||||||
|
.then_some(Event::UserWakeUp)
|
||||||
.map(EventWrapper::from),
|
.map(EventWrapper::from),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -737,7 +735,7 @@ impl Shared {
|
||||||
// * The `register_redraw_request` closure.
|
// * The `register_redraw_request` closure.
|
||||||
// * The `destroy_fn` closure.
|
// * The `destroy_fn` closure.
|
||||||
if self.0.event_loop_recreation.get() {
|
if self.0.event_loop_recreation.get() {
|
||||||
crate::event_loop::EventLoopBuilder::<()>::allow_event_loop_recreation();
|
crate::event_loop::EventLoopBuilder::allow_event_loop_recreation();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -817,12 +815,12 @@ impl Shared {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) enum EventWrapper {
|
pub(crate) enum EventWrapper {
|
||||||
Event(Event<()>),
|
Event(Event),
|
||||||
ScaleChange { canvas: Weak<RefCell<backend::Canvas>>, size: PhysicalSize<u32>, scale: f64 },
|
ScaleChange { canvas: Weak<RefCell<backend::Canvas>>, size: PhysicalSize<u32>, scale: f64 },
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Event<()>> for EventWrapper {
|
impl From<Event> for EventWrapper {
|
||||||
fn from(value: Event<()>) -> Self {
|
fn from(value: Event) -> Self {
|
||||||
Self::Event(value)
|
Self::Event(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,7 +55,11 @@ impl ActiveEventLoop {
|
||||||
Self { runner: runner::Shared::new(), modifiers: ModifiersShared::default() }
|
Self { runner: runner::Shared::new(), modifiers: ModifiersShared::default() }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run(&self, event_handler: Box<runner::EventHandler>, event_loop_recreation: bool) {
|
pub(crate) fn run(
|
||||||
|
&self,
|
||||||
|
event_handler: Box<runner::EventHandler>,
|
||||||
|
event_loop_recreation: bool,
|
||||||
|
) {
|
||||||
self.runner.event_loop_recreation(event_loop_recreation);
|
self.runner.event_loop_recreation(event_loop_recreation);
|
||||||
self.runner.set_listener(event_handler);
|
self.runner.set_listener(event_handler);
|
||||||
}
|
}
|
||||||
|
|
|
@ -483,7 +483,7 @@ impl Canvas {
|
||||||
pub(crate) fn handle_scale_change(
|
pub(crate) fn handle_scale_change(
|
||||||
&self,
|
&self,
|
||||||
runner: &super::super::event_loop::runner::Shared,
|
runner: &super::super::event_loop::runner::Shared,
|
||||||
event_handler: impl FnOnce(crate::event::Event<()>),
|
event_handler: impl FnOnce(crate::event::Event),
|
||||||
current_size: PhysicalSize<u32>,
|
current_size: PhysicalSize<u32>,
|
||||||
scale: f64,
|
scale: f64,
|
||||||
) {
|
) {
|
||||||
|
|
|
@ -25,7 +25,7 @@ pub struct FileDropHandlerData {
|
||||||
pub interface: IDropTarget,
|
pub interface: IDropTarget,
|
||||||
refcount: AtomicUsize,
|
refcount: AtomicUsize,
|
||||||
window: HWND,
|
window: HWND,
|
||||||
send_event: Box<dyn Fn(Event<()>)>,
|
send_event: Box<dyn Fn(Event)>,
|
||||||
cursor_effect: u32,
|
cursor_effect: u32,
|
||||||
hovered_is_valid: bool, /* If the currently hovered item is not valid there must not be any
|
hovered_is_valid: bool, /* If the currently hovered item is not valid there must not be any
|
||||||
* `HoveredFileCancelled` emitted */
|
* `HoveredFileCancelled` emitted */
|
||||||
|
@ -37,7 +37,7 @@ pub struct FileDropHandler {
|
||||||
|
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
impl FileDropHandler {
|
impl FileDropHandler {
|
||||||
pub fn new(window: HWND, send_event: Box<dyn Fn(Event<()>)>) -> FileDropHandler {
|
pub(crate) fn new(window: HWND, send_event: Box<dyn Fn(Event)>) -> FileDropHandler {
|
||||||
let data = Box::new(FileDropHandlerData {
|
let data = Box::new(FileDropHandlerData {
|
||||||
interface: IDropTarget { lpVtbl: &DROP_TARGET_VTBL as *const IDropTargetVtbl },
|
interface: IDropTarget { lpVtbl: &DROP_TARGET_VTBL as *const IDropTargetVtbl },
|
||||||
refcount: AtomicUsize::new(1),
|
refcount: AtomicUsize::new(1),
|
||||||
|
@ -211,7 +211,7 @@ impl FileDropHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FileDropHandlerData {
|
impl FileDropHandlerData {
|
||||||
fn send_event(&self, event: Event<()>) {
|
fn send_event(&self, event: Event) {
|
||||||
(self.send_event)(event);
|
(self.send_event)(event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,6 @@ use std::ffi::c_void;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::sync::atomic::{AtomicU32, Ordering};
|
use std::sync::atomic::{AtomicU32, Ordering};
|
||||||
use std::sync::mpsc::{self, Receiver, Sender};
|
|
||||||
use std::sync::{Arc, Mutex, MutexGuard};
|
use std::sync::{Arc, Mutex, MutexGuard};
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
use std::{mem, panic, ptr};
|
use std::{mem, panic, ptr};
|
||||||
|
@ -63,7 +62,7 @@ use crate::error::EventLoopError;
|
||||||
use crate::event::{
|
use crate::event::{
|
||||||
DeviceEvent, Event, Force, Ime, InnerSizeWriter, RawKeyEvent, Touch, TouchPhase, WindowEvent,
|
DeviceEvent, Event, Force, Ime, InnerSizeWriter, RawKeyEvent, Touch, TouchPhase, WindowEvent,
|
||||||
};
|
};
|
||||||
use crate::event_loop::{ActiveEventLoop as RootAEL, ControlFlow, DeviceEvents, EventLoopClosed};
|
use crate::event_loop::{ActiveEventLoop as RootAEL, ControlFlow, DeviceEvents};
|
||||||
use crate::keyboard::ModifiersState;
|
use crate::keyboard::ModifiersState;
|
||||||
use crate::platform::pump_events::PumpStatus;
|
use crate::platform::pump_events::PumpStatus;
|
||||||
use crate::platform_impl::platform::dark_mode::try_theme;
|
use crate::platform_impl::platform::dark_mode::try_theme;
|
||||||
|
@ -84,35 +83,14 @@ use crate::platform_impl::platform::{
|
||||||
use crate::window::{
|
use crate::window::{
|
||||||
CustomCursor as RootCustomCursor, CustomCursorSource, WindowId as RootWindowId,
|
CustomCursor as RootCustomCursor, CustomCursorSource, WindowId as RootWindowId,
|
||||||
};
|
};
|
||||||
use runner::{EventLoopRunner, EventLoopRunnerShared};
|
use runner::EventLoopRunner;
|
||||||
|
|
||||||
use super::window::set_skip_taskbar;
|
use super::window::set_skip_taskbar;
|
||||||
use super::SelectedCursor;
|
use super::SelectedCursor;
|
||||||
|
|
||||||
/// some backends like macos uses an uninhabited `Never` type,
|
|
||||||
/// on windows, `UserEvent`s are also dispatched through the
|
|
||||||
/// WNDPROC callback, and due to the re-entrant nature of the
|
|
||||||
/// callback, recursively delivered events must be queued in a
|
|
||||||
/// buffer, the current implementation put this queue in
|
|
||||||
/// `EventLoopRunner`, which is shared between the event pumping
|
|
||||||
/// loop and the callback. because it's hard to decide from the
|
|
||||||
/// outside whether a event needs to be buffered, I decided not
|
|
||||||
/// use `Event<Never>` for the shared runner state, but use unit
|
|
||||||
/// as a placeholder so user events can be buffered as usual,
|
|
||||||
/// the real `UserEvent` is pulled from the mpsc channel directly
|
|
||||||
/// when the placeholder event is delivered to the event handler
|
|
||||||
pub(crate) struct UserEventPlaceholder;
|
|
||||||
|
|
||||||
// here below, the generic `EventLoopRunnerShared<T>` is replaced with
|
|
||||||
// `EventLoopRunnerShared<UserEventPlaceholder>` so we can get rid
|
|
||||||
// of the generic parameter T in types which don't depend on T.
|
|
||||||
// this is the approach which requires minimum changes to current
|
|
||||||
// backend implementation. it should be considered transitional
|
|
||||||
// and should be refactored and cleaned up eventually, I hope.
|
|
||||||
|
|
||||||
pub(crate) struct WindowData {
|
pub(crate) struct WindowData {
|
||||||
pub window_state: Arc<Mutex<WindowState>>,
|
pub window_state: Arc<Mutex<WindowState>>,
|
||||||
pub event_loop_runner: EventLoopRunnerShared<UserEventPlaceholder>,
|
pub event_loop_runner: Rc<EventLoopRunner>,
|
||||||
pub key_event_builder: KeyEventBuilder,
|
pub key_event_builder: KeyEventBuilder,
|
||||||
pub _file_drop_handler: Option<FileDropHandler>,
|
pub _file_drop_handler: Option<FileDropHandler>,
|
||||||
pub userdata_removed: Cell<bool>,
|
pub userdata_removed: Cell<bool>,
|
||||||
|
@ -120,7 +98,7 @@ pub(crate) struct WindowData {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WindowData {
|
impl WindowData {
|
||||||
fn send_event(&self, event: Event<UserEventPlaceholder>) {
|
fn send_event(&self, event: Event) {
|
||||||
self.event_loop_runner.send_event(event);
|
self.event_loop_runner.send_event(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,11 +108,11 @@ impl WindowData {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ThreadMsgTargetData {
|
struct ThreadMsgTargetData {
|
||||||
event_loop_runner: EventLoopRunnerShared<UserEventPlaceholder>,
|
event_loop_runner: Rc<EventLoopRunner>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ThreadMsgTargetData {
|
impl ThreadMsgTargetData {
|
||||||
fn send_event(&self, event: Event<UserEventPlaceholder>) {
|
fn send_event(&self, event: Event) {
|
||||||
self.event_loop_runner.send_event(event);
|
self.event_loop_runner.send_event(event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -146,9 +124,7 @@ pub(crate) enum ProcResult {
|
||||||
Value(isize),
|
Value(isize),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct EventLoop<T: 'static> {
|
pub struct EventLoop {
|
||||||
user_event_sender: Sender<T>,
|
|
||||||
user_event_receiver: Receiver<T>,
|
|
||||||
window_target: RootAEL,
|
window_target: RootAEL,
|
||||||
msg_hook: Option<Box<dyn FnMut(*const c_void) -> bool + 'static>>,
|
msg_hook: Option<Box<dyn FnMut(*const c_void) -> bool + 'static>>,
|
||||||
}
|
}
|
||||||
|
@ -168,10 +144,10 @@ impl Default for PlatformSpecificEventLoopAttributes {
|
||||||
pub struct ActiveEventLoop {
|
pub struct ActiveEventLoop {
|
||||||
thread_id: u32,
|
thread_id: u32,
|
||||||
thread_msg_target: HWND,
|
thread_msg_target: HWND,
|
||||||
pub(crate) runner_shared: EventLoopRunnerShared<UserEventPlaceholder>,
|
pub(crate) runner_shared: Rc<EventLoopRunner>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: 'static> EventLoop<T> {
|
impl EventLoop {
|
||||||
pub(crate) fn new(
|
pub(crate) fn new(
|
||||||
attributes: &mut PlatformSpecificEventLoopAttributes,
|
attributes: &mut PlatformSpecificEventLoopAttributes,
|
||||||
) -> Result<Self, EventLoopError> {
|
) -> Result<Self, EventLoopError> {
|
||||||
|
@ -194,7 +170,6 @@ impl<T: 'static> EventLoop<T> {
|
||||||
|
|
||||||
let runner_shared = Rc::new(EventLoopRunner::new(thread_msg_target));
|
let runner_shared = Rc::new(EventLoopRunner::new(thread_msg_target));
|
||||||
|
|
||||||
let (user_event_sender, user_event_receiver) = mpsc::channel();
|
|
||||||
insert_event_target_window_data(thread_msg_target, runner_shared.clone());
|
insert_event_target_window_data(thread_msg_target, runner_shared.clone());
|
||||||
raw_input::register_all_mice_and_keyboards_for_raw_input(
|
raw_input::register_all_mice_and_keyboards_for_raw_input(
|
||||||
thread_msg_target,
|
thread_msg_target,
|
||||||
|
@ -202,8 +177,6 @@ impl<T: 'static> EventLoop<T> {
|
||||||
);
|
);
|
||||||
|
|
||||||
Ok(EventLoop {
|
Ok(EventLoop {
|
||||||
user_event_sender,
|
|
||||||
user_event_receiver,
|
|
||||||
window_target: RootAEL {
|
window_target: RootAEL {
|
||||||
p: ActiveEventLoop { thread_id, thread_msg_target, runner_shared },
|
p: ActiveEventLoop { thread_id, thread_msg_target, runner_shared },
|
||||||
_marker: PhantomData,
|
_marker: PhantomData,
|
||||||
|
@ -216,11 +189,11 @@ impl<T: 'static> EventLoop<T> {
|
||||||
&self.window_target
|
&self.window_target
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_app<A: ApplicationHandler<T>>(mut self, app: &mut A) -> Result<(), EventLoopError> {
|
pub fn run_app<A: ApplicationHandler>(mut self, app: &mut A) -> Result<(), EventLoopError> {
|
||||||
self.run_app_on_demand(app)
|
self.run_app_on_demand(app)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_app_on_demand<A: ApplicationHandler<T>>(
|
pub fn run_app_on_demand<A: ApplicationHandler>(
|
||||||
&mut self,
|
&mut self,
|
||||||
app: &mut A,
|
app: &mut A,
|
||||||
) -> Result<(), EventLoopError> {
|
) -> Result<(), EventLoopError> {
|
||||||
|
@ -228,38 +201,24 @@ impl<T: 'static> EventLoop<T> {
|
||||||
let runner = &self.window_target.p.runner_shared;
|
let runner = &self.window_target.p.runner_shared;
|
||||||
|
|
||||||
let event_loop_windows_ref = &self.window_target;
|
let event_loop_windows_ref = &self.window_target;
|
||||||
let user_event_receiver = &self.user_event_receiver;
|
|
||||||
// # Safety
|
// # Safety
|
||||||
// We make sure to call runner.clear_event_handler() before
|
// We make sure to call runner.clear_event_handler() before
|
||||||
// returning
|
// returning
|
||||||
unsafe {
|
unsafe {
|
||||||
runner.set_event_handler(move |event| {
|
runner.set_event_handler(move |event| match event {
|
||||||
match event {
|
Event::NewEvents(cause) => app.new_events(event_loop_windows_ref, cause),
|
||||||
Event::NewEvents(cause) => app.new_events(event_loop_windows_ref, cause),
|
Event::WindowEvent { window_id, event } => {
|
||||||
Event::WindowEvent { window_id, event } => {
|
app.window_event(event_loop_windows_ref, window_id, event)
|
||||||
app.window_event(event_loop_windows_ref, window_id, event)
|
},
|
||||||
},
|
Event::DeviceEvent { device_id, event } => {
|
||||||
Event::DeviceEvent { device_id, event } => {
|
app.device_event(event_loop_windows_ref, device_id, event)
|
||||||
app.device_event(event_loop_windows_ref, device_id, event)
|
},
|
||||||
},
|
Event::UserWakeUp => app.proxy_wake_up(event_loop_windows_ref),
|
||||||
// The shared `EventLoopRunner` is not parameterized
|
Event::Suspended => app.suspended(event_loop_windows_ref),
|
||||||
// `EventLoopProxy::send_event()` calls `PostMessage`
|
Event::Resumed => app.resumed(event_loop_windows_ref),
|
||||||
// to wakeup and dispatch a placeholder `UserEvent`,
|
Event::AboutToWait => app.about_to_wait(event_loop_windows_ref),
|
||||||
// when we received the placeholder event here, the
|
Event::LoopExiting => app.exiting(event_loop_windows_ref),
|
||||||
// real UserEvent(T) should already be put in the
|
Event::MemoryWarning => app.memory_warning(event_loop_windows_ref),
|
||||||
// mpsc channel and ready to be pulled
|
|
||||||
Event::UserEvent(_) => {
|
|
||||||
let event = user_event_receiver
|
|
||||||
.try_recv()
|
|
||||||
.expect("user event signaled but not received");
|
|
||||||
app.user_event(event_loop_windows_ref, event);
|
|
||||||
},
|
|
||||||
Event::Suspended => app.suspended(event_loop_windows_ref),
|
|
||||||
Event::Resumed => app.resumed(event_loop_windows_ref),
|
|
||||||
Event::AboutToWait => app.about_to_wait(event_loop_windows_ref),
|
|
||||||
Event::LoopExiting => app.exiting(event_loop_windows_ref),
|
|
||||||
Event::MemoryWarning => app.memory_warning(event_loop_windows_ref),
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -293,7 +252,7 @@ impl<T: 'static> EventLoop<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pump_app_events<A: ApplicationHandler<T>>(
|
pub fn pump_app_events<A: ApplicationHandler>(
|
||||||
&mut self,
|
&mut self,
|
||||||
timeout: Option<Duration>,
|
timeout: Option<Duration>,
|
||||||
app: &mut A,
|
app: &mut A,
|
||||||
|
@ -301,7 +260,7 @@ impl<T: 'static> EventLoop<T> {
|
||||||
{
|
{
|
||||||
let runner = &self.window_target.p.runner_shared;
|
let runner = &self.window_target.p.runner_shared;
|
||||||
let event_loop_windows_ref = &self.window_target;
|
let event_loop_windows_ref = &self.window_target;
|
||||||
let user_event_receiver = &self.user_event_receiver;
|
// let user_event_receiver = &self.user_event_receiver;
|
||||||
|
|
||||||
// # Safety
|
// # Safety
|
||||||
// We make sure to call runner.clear_event_handler() before
|
// We make sure to call runner.clear_event_handler() before
|
||||||
|
@ -311,33 +270,20 @@ impl<T: 'static> EventLoop<T> {
|
||||||
// to leave the runner in an unsound state with an associated
|
// to leave the runner in an unsound state with an associated
|
||||||
// event handler.
|
// event handler.
|
||||||
unsafe {
|
unsafe {
|
||||||
runner.set_event_handler(move |event| {
|
runner.set_event_handler(move |event| match event {
|
||||||
match event {
|
Event::NewEvents(cause) => app.new_events(event_loop_windows_ref, cause),
|
||||||
Event::NewEvents(cause) => app.new_events(event_loop_windows_ref, cause),
|
Event::WindowEvent { window_id, event } => {
|
||||||
Event::WindowEvent { window_id, event } => {
|
app.window_event(event_loop_windows_ref, window_id, event)
|
||||||
app.window_event(event_loop_windows_ref, window_id, event)
|
},
|
||||||
},
|
Event::DeviceEvent { device_id, event } => {
|
||||||
Event::DeviceEvent { device_id, event } => {
|
app.device_event(event_loop_windows_ref, device_id, event)
|
||||||
app.device_event(event_loop_windows_ref, device_id, event)
|
},
|
||||||
},
|
Event::UserWakeUp => app.proxy_wake_up(event_loop_windows_ref),
|
||||||
// The shared `EventLoopRunner` is not parameterized
|
Event::Suspended => app.suspended(event_loop_windows_ref),
|
||||||
// `EventLoopProxy::send_event()` calls `PostMessage`
|
Event::Resumed => app.resumed(event_loop_windows_ref),
|
||||||
// to wakeup and dispatch a placeholder `UserEvent`,
|
Event::AboutToWait => app.about_to_wait(event_loop_windows_ref),
|
||||||
// when we received the placeholder event here, the
|
Event::LoopExiting => app.exiting(event_loop_windows_ref),
|
||||||
// real UserEvent(T) should already be put in the
|
Event::MemoryWarning => app.memory_warning(event_loop_windows_ref),
|
||||||
// mpsc channel and ready to be pulled
|
|
||||||
Event::UserEvent(_) => {
|
|
||||||
let event = user_event_receiver
|
|
||||||
.try_recv()
|
|
||||||
.expect("user event signaled but not received");
|
|
||||||
app.user_event(event_loop_windows_ref, event);
|
|
||||||
},
|
|
||||||
Event::Suspended => app.suspended(event_loop_windows_ref),
|
|
||||||
Event::Resumed => app.resumed(event_loop_windows_ref),
|
|
||||||
Event::AboutToWait => app.about_to_wait(event_loop_windows_ref),
|
|
||||||
Event::LoopExiting => app.exiting(event_loop_windows_ref),
|
|
||||||
Event::MemoryWarning => app.memory_warning(event_loop_windows_ref),
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
runner.wakeup();
|
runner.wakeup();
|
||||||
|
@ -522,11 +468,8 @@ impl<T: 'static> EventLoop<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_proxy(&self) -> EventLoopProxy<T> {
|
pub fn create_proxy(&self) -> EventLoopProxy {
|
||||||
EventLoopProxy {
|
EventLoopProxy { target_window: self.window_target.p.thread_msg_target }
|
||||||
target_window: self.window_target.p.thread_msg_target,
|
|
||||||
event_send: self.user_event_sender.clone(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn exit_code(&self) -> Option<i32> {
|
fn exit_code(&self) -> Option<i32> {
|
||||||
|
@ -698,7 +641,7 @@ fn dur2timeout(dur: Duration) -> u32 {
|
||||||
.unwrap_or(INFINITE)
|
.unwrap_or(INFINITE)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Drop for EventLoop<T> {
|
impl Drop for EventLoop {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
unsafe {
|
unsafe {
|
||||||
DestroyWindow(self.window_target.p.thread_msg_target);
|
DestroyWindow(self.window_target.p.thread_msg_target);
|
||||||
|
@ -756,27 +699,16 @@ impl EventLoopThreadExecutor {
|
||||||
|
|
||||||
type ThreadExecFn = Box<Box<dyn FnMut()>>;
|
type ThreadExecFn = Box<Box<dyn FnMut()>>;
|
||||||
|
|
||||||
pub struct EventLoopProxy<T: 'static> {
|
#[derive(Clone)]
|
||||||
|
pub struct EventLoopProxy {
|
||||||
target_window: HWND,
|
target_window: HWND,
|
||||||
event_send: Sender<T>,
|
|
||||||
}
|
|
||||||
unsafe impl<T: Send + 'static> Send for EventLoopProxy<T> {}
|
|
||||||
|
|
||||||
impl<T: 'static> Clone for EventLoopProxy<T> {
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
Self { target_window: self.target_window, event_send: self.event_send.clone() }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: 'static> EventLoopProxy<T> {
|
unsafe impl Send for EventLoopProxy {}
|
||||||
pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed<T>> {
|
|
||||||
self.event_send
|
impl EventLoopProxy {
|
||||||
.send(event)
|
pub fn wake_up(&self) {
|
||||||
.map(|result| {
|
unsafe { PostMessageW(self.target_window, USER_EVENT_MSG_ID.get(), 0, 0) };
|
||||||
unsafe { PostMessageW(self.target_window, USER_EVENT_MSG_ID.get(), 0, 0) };
|
|
||||||
result
|
|
||||||
})
|
|
||||||
.map_err(|e| EventLoopClosed(e.0))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -908,7 +840,7 @@ fn create_event_target_window() -> HWND {
|
||||||
|
|
||||||
fn insert_event_target_window_data(
|
fn insert_event_target_window_data(
|
||||||
thread_msg_target: HWND,
|
thread_msg_target: HWND,
|
||||||
event_loop_runner: EventLoopRunnerShared<UserEventPlaceholder>,
|
event_loop_runner: Rc<EventLoopRunner>,
|
||||||
) {
|
) {
|
||||||
let userdata = ThreadMsgTargetData { event_loop_runner };
|
let userdata = ThreadMsgTargetData { event_loop_runner };
|
||||||
let input_ptr = Box::into_raw(Box::new(userdata));
|
let input_ptr = Box::into_raw(Box::new(userdata));
|
||||||
|
@ -2454,7 +2386,7 @@ unsafe extern "system" fn thread_event_target_callback(
|
||||||
// user event is still in the mpsc channel and will be pulled
|
// user event is still in the mpsc channel and will be pulled
|
||||||
// once the placeholder event is delivered to the wrapper
|
// once the placeholder event is delivered to the wrapper
|
||||||
// `event_handler`
|
// `event_handler`
|
||||||
userdata.send_event(Event::UserEvent(UserEventPlaceholder));
|
userdata.send_event(Event::UserWakeUp);
|
||||||
0
|
0
|
||||||
},
|
},
|
||||||
_ if msg == EXEC_MSG_ID.get() => {
|
_ if msg == EXEC_MSG_ID.get() => {
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use std::cell::{Cell, RefCell};
|
use std::cell::{Cell, RefCell};
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::rc::Rc;
|
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
use std::{mem, panic};
|
use std::{mem, panic};
|
||||||
|
@ -16,11 +15,9 @@ use crate::window::WindowId;
|
||||||
|
|
||||||
use super::ControlFlow;
|
use super::ControlFlow;
|
||||||
|
|
||||||
pub(crate) type EventLoopRunnerShared<T> = Rc<EventLoopRunner<T>>;
|
type EventHandler = Cell<Option<Box<dyn FnMut(Event)>>>;
|
||||||
|
|
||||||
type EventHandler<T> = Cell<Option<Box<dyn FnMut(Event<T>)>>>;
|
pub(crate) struct EventLoopRunner {
|
||||||
|
|
||||||
pub(crate) struct EventLoopRunner<T: 'static> {
|
|
||||||
// The event loop's win32 handles
|
// The event loop's win32 handles
|
||||||
pub(super) thread_msg_target: HWND,
|
pub(super) thread_msg_target: HWND,
|
||||||
|
|
||||||
|
@ -33,8 +30,8 @@ pub(crate) struct EventLoopRunner<T: 'static> {
|
||||||
exit: Cell<Option<i32>>,
|
exit: Cell<Option<i32>>,
|
||||||
runner_state: Cell<RunnerState>,
|
runner_state: Cell<RunnerState>,
|
||||||
last_events_cleared: Cell<Instant>,
|
last_events_cleared: Cell<Instant>,
|
||||||
event_handler: EventHandler<T>,
|
event_handler: EventHandler,
|
||||||
event_buffer: RefCell<VecDeque<BufferedEvent<T>>>,
|
event_buffer: RefCell<VecDeque<BufferedEvent>>,
|
||||||
|
|
||||||
panic_error: Cell<Option<PanicError>>,
|
panic_error: Cell<Option<PanicError>>,
|
||||||
}
|
}
|
||||||
|
@ -55,13 +52,13 @@ pub(crate) enum RunnerState {
|
||||||
Destroyed,
|
Destroyed,
|
||||||
}
|
}
|
||||||
|
|
||||||
enum BufferedEvent<T: 'static> {
|
enum BufferedEvent {
|
||||||
Event(Event<T>),
|
Event(Event),
|
||||||
ScaleFactorChanged(WindowId, f64, PhysicalSize<u32>),
|
ScaleFactorChanged(WindowId, f64, PhysicalSize<u32>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> EventLoopRunner<T> {
|
impl EventLoopRunner {
|
||||||
pub(crate) fn new(thread_msg_target: HWND) -> EventLoopRunner<T> {
|
pub(crate) fn new(thread_msg_target: HWND) -> EventLoopRunner {
|
||||||
EventLoopRunner {
|
EventLoopRunner {
|
||||||
thread_msg_target,
|
thread_msg_target,
|
||||||
interrupt_msg_dispatch: Cell::new(false),
|
interrupt_msg_dispatch: Cell::new(false),
|
||||||
|
@ -88,13 +85,12 @@ impl<T> EventLoopRunner<T> {
|
||||||
/// undefined behaviour.
|
/// undefined behaviour.
|
||||||
pub(crate) unsafe fn set_event_handler<F>(&self, f: F)
|
pub(crate) unsafe fn set_event_handler<F>(&self, f: F)
|
||||||
where
|
where
|
||||||
F: FnMut(Event<T>),
|
F: FnMut(Event),
|
||||||
{
|
{
|
||||||
// Erase closure lifetime.
|
// Erase closure lifetime.
|
||||||
// SAFETY: Caller upholds that the lifetime of the closure is upheld.
|
// SAFETY: Caller upholds that the lifetime of the closure is upheld.
|
||||||
let f = unsafe {
|
let f =
|
||||||
mem::transmute::<Box<dyn FnMut(Event<T>)>, Box<dyn FnMut(Event<T>)>>(Box::new(f))
|
unsafe { mem::transmute::<Box<dyn FnMut(Event)>, Box<dyn FnMut(Event)>>(Box::new(f)) };
|
||||||
};
|
|
||||||
let old_event_handler = self.event_handler.replace(Some(f));
|
let old_event_handler = self.event_handler.replace(Some(f));
|
||||||
assert!(old_event_handler.is_none());
|
assert!(old_event_handler.is_none());
|
||||||
}
|
}
|
||||||
|
@ -124,7 +120,7 @@ impl<T> EventLoopRunner<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// State retrieval functions.
|
/// State retrieval functions.
|
||||||
impl<T> EventLoopRunner<T> {
|
impl EventLoopRunner {
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
pub fn thread_msg_target(&self) -> HWND {
|
pub fn thread_msg_target(&self) -> HWND {
|
||||||
self.thread_msg_target
|
self.thread_msg_target
|
||||||
|
@ -166,7 +162,7 @@ impl<T> EventLoopRunner<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Misc. functions
|
/// Misc. functions
|
||||||
impl<T> EventLoopRunner<T> {
|
impl EventLoopRunner {
|
||||||
pub fn catch_unwind<R>(&self, f: impl FnOnce() -> R) -> Option<R> {
|
pub fn catch_unwind<R>(&self, f: impl FnOnce() -> R) -> Option<R> {
|
||||||
let panic_error = self.panic_error.take();
|
let panic_error = self.panic_error.take();
|
||||||
if panic_error.is_none() {
|
if panic_error.is_none() {
|
||||||
|
@ -196,7 +192,7 @@ impl<T> EventLoopRunner<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Event dispatch functions.
|
/// Event dispatch functions.
|
||||||
impl<T> EventLoopRunner<T> {
|
impl EventLoopRunner {
|
||||||
pub(crate) fn prepare_wait(&self) {
|
pub(crate) fn prepare_wait(&self) {
|
||||||
self.move_state_to(RunnerState::Idle);
|
self.move_state_to(RunnerState::Idle);
|
||||||
}
|
}
|
||||||
|
@ -205,7 +201,7 @@ impl<T> EventLoopRunner<T> {
|
||||||
self.move_state_to(RunnerState::HandlingMainEvents);
|
self.move_state_to(RunnerState::HandlingMainEvents);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn send_event(&self, event: Event<T>) {
|
pub(crate) fn send_event(&self, event: Event) {
|
||||||
if let Event::WindowEvent { event: WindowEvent::RedrawRequested, .. } = event {
|
if let Event::WindowEvent { event: WindowEvent::RedrawRequested, .. } = event {
|
||||||
self.call_event_handler(event);
|
self.call_event_handler(event);
|
||||||
// As a rule, to ensure that `pump_events` can't block an external event loop
|
// As a rule, to ensure that `pump_events` can't block an external event loop
|
||||||
|
@ -226,7 +222,7 @@ impl<T> EventLoopRunner<T> {
|
||||||
self.move_state_to(RunnerState::Destroyed);
|
self.move_state_to(RunnerState::Destroyed);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call_event_handler(&self, event: Event<T>) {
|
fn call_event_handler(&self, event: Event) {
|
||||||
self.catch_unwind(|| {
|
self.catch_unwind(|| {
|
||||||
let mut event_handler = self.event_handler.take().expect(
|
let mut event_handler = self.event_handler.take().expect(
|
||||||
"either event handler is re-entrant (likely), or no event handler is registered \
|
"either event handler is re-entrant (likely), or no event handler is registered \
|
||||||
|
@ -358,8 +354,8 @@ impl<T> EventLoopRunner<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> BufferedEvent<T> {
|
impl BufferedEvent {
|
||||||
pub fn from_event(event: Event<T>) -> BufferedEvent<T> {
|
pub fn from_event(event: Event) -> BufferedEvent {
|
||||||
match event {
|
match event {
|
||||||
Event::WindowEvent {
|
Event::WindowEvent {
|
||||||
event: WindowEvent::ScaleFactorChanged { scale_factor, inner_size_writer },
|
event: WindowEvent::ScaleFactorChanged { scale_factor, inner_size_writer },
|
||||||
|
@ -373,7 +369,7 @@ impl<T> BufferedEvent<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dispatch_event(self, dispatch: impl FnOnce(Event<T>)) {
|
pub fn dispatch_event(self, dispatch: impl FnOnce(Event)) {
|
||||||
match self {
|
match self {
|
||||||
Self::Event(event) => dispatch(event),
|
Self::Event(event) => dispatch(event),
|
||||||
Self::ScaleFactorChanged(window_id, scale_factor, new_inner_size) => {
|
Self::ScaleFactorChanged(window_id, scale_factor, new_inner_size) => {
|
||||||
|
|
|
@ -1186,11 +1186,7 @@ impl<'a> InitData<'a> {
|
||||||
let file_drop_runner = self.event_loop.runner_shared.clone();
|
let file_drop_runner = self.event_loop.runner_shared.clone();
|
||||||
let file_drop_handler = FileDropHandler::new(
|
let file_drop_handler = FileDropHandler::new(
|
||||||
win.window,
|
win.window,
|
||||||
Box::new(move |event| {
|
Box::new(move |event| file_drop_runner.send_event(event)),
|
||||||
if let Ok(e) = event.map_nonuser_event() {
|
|
||||||
file_drop_runner.send_event(e)
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
let handler_interface_ptr =
|
let handler_interface_ptr =
|
||||||
|
|
|
@ -3,16 +3,11 @@ fn needs_send<T: Send>() {}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn event_loop_proxy_send() {
|
fn event_loop_proxy_send() {
|
||||||
#[allow(dead_code)]
|
needs_send::<winit::event_loop::EventLoopProxy>();
|
||||||
fn is_send<T: 'static + Send>() {
|
|
||||||
// ensures that `winit::EventLoopProxy<T: Send>` implements `Send`
|
|
||||||
needs_send::<winit::event_loop::EventLoopProxy<T>>();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn window_send() {
|
fn window_send() {
|
||||||
// ensures that `winit::Window` implements `Send`
|
|
||||||
needs_send::<winit::window::Window>();
|
needs_send::<winit::window::Window>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,7 +18,6 @@ fn window_builder_send() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn ids_send() {
|
fn ids_send() {
|
||||||
// ensures that the various `..Id` types implement `Send`
|
|
||||||
needs_send::<winit::window::WindowId>();
|
needs_send::<winit::window::WindowId>();
|
||||||
needs_send::<winit::event::DeviceId>();
|
needs_send::<winit::event::DeviceId>();
|
||||||
needs_send::<winit::monitor::MonitorHandle>();
|
needs_send::<winit::monitor::MonitorHandle>();
|
||||||
|
|
|
@ -3,16 +3,11 @@ fn needs_sync<T: Sync>() {}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn event_loop_proxy_send() {
|
fn event_loop_proxy_send() {
|
||||||
#[allow(dead_code)]
|
needs_sync::<winit::event_loop::EventLoopProxy>();
|
||||||
fn is_send<T: 'static + Send>() {
|
|
||||||
// ensures that `winit::EventLoopProxy<T: Send>` implements `Sync`
|
|
||||||
needs_sync::<winit::event_loop::EventLoopProxy<T>>();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn window_sync() {
|
fn window_sync() {
|
||||||
// ensures that `winit::Window` implements `Sync`
|
|
||||||
needs_sync::<winit::window::Window>();
|
needs_sync::<winit::window::Window>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue