Windows: Use ApplicationHandler (#4141)
* Make ActiveEventLoop a thin wrapper over EventLoopRunner * Use ApplicationHandler instead of Event
This commit is contained in:
parent
8c3e69c08b
commit
e26b831f23
4 changed files with 391 additions and 567 deletions
|
|
@ -13,18 +13,17 @@ use windows_sys::Win32::System::Ole::{CF_HDROP, DROPEFFECT_COPY, DROPEFFECT_NONE
|
||||||
use windows_sys::Win32::UI::Shell::{DragFinish, DragQueryFileW, HDROP};
|
use windows_sys::Win32::UI::Shell::{DragFinish, DragQueryFileW, HDROP};
|
||||||
|
|
||||||
use crate::dpi::PhysicalPosition;
|
use crate::dpi::PhysicalPosition;
|
||||||
use crate::event::{Event, WindowEvent};
|
use crate::event::WindowEvent;
|
||||||
use crate::platform_impl::platform::definitions::{
|
use crate::platform_impl::platform::definitions::{
|
||||||
IDataObject, IDataObjectVtbl, IDropTarget, IDropTargetVtbl, IUnknown, IUnknownVtbl,
|
IDataObject, IDataObjectVtbl, IDropTarget, IDropTargetVtbl, IUnknown, IUnknownVtbl,
|
||||||
};
|
};
|
||||||
use crate::window::WindowId;
|
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct FileDropHandlerData {
|
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(WindowEvent)>,
|
||||||
cursor_effect: u32,
|
cursor_effect: u32,
|
||||||
valid: bool, /* If the currently hovered item is not valid there must not be any
|
valid: bool, /* If the currently hovered item is not valid there must not be any
|
||||||
* `DragLeft` emitted */
|
* `DragLeft` emitted */
|
||||||
|
|
@ -36,7 +35,7 @@ pub struct FileDropHandler {
|
||||||
|
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
impl FileDropHandler {
|
impl FileDropHandler {
|
||||||
pub(crate) fn new(window: HWND, send_event: Box<dyn Fn(Event)>) -> FileDropHandler {
|
pub(crate) fn new(window: HWND, send_event: Box<dyn Fn(WindowEvent)>) -> 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),
|
||||||
|
|
@ -92,10 +91,7 @@ impl FileDropHandler {
|
||||||
let hdrop = unsafe { Self::iterate_filenames(pDataObj, |path| paths.push(path)) };
|
let hdrop = unsafe { Self::iterate_filenames(pDataObj, |path| paths.push(path)) };
|
||||||
drop_handler.valid = hdrop.is_some();
|
drop_handler.valid = hdrop.is_some();
|
||||||
if drop_handler.valid {
|
if drop_handler.valid {
|
||||||
drop_handler.send_event(Event::WindowEvent {
|
(drop_handler.send_event)(WindowEvent::DragEntered { paths, position });
|
||||||
window_id: WindowId::from_raw(drop_handler.window as usize),
|
|
||||||
event: WindowEvent::DragEntered { paths, position },
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
drop_handler.cursor_effect =
|
drop_handler.cursor_effect =
|
||||||
if drop_handler.valid { DROPEFFECT_COPY } else { DROPEFFECT_NONE };
|
if drop_handler.valid { DROPEFFECT_COPY } else { DROPEFFECT_NONE };
|
||||||
|
|
@ -119,10 +115,7 @@ impl FileDropHandler {
|
||||||
ScreenToClient(drop_handler.window, &mut pt);
|
ScreenToClient(drop_handler.window, &mut pt);
|
||||||
}
|
}
|
||||||
let position = PhysicalPosition::new(pt.x as f64, pt.y as f64);
|
let position = PhysicalPosition::new(pt.x as f64, pt.y as f64);
|
||||||
drop_handler.send_event(Event::WindowEvent {
|
(drop_handler.send_event)(WindowEvent::DragMoved { position });
|
||||||
window_id: WindowId::from_raw(drop_handler.window as usize),
|
|
||||||
event: WindowEvent::DragMoved { position },
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
unsafe {
|
unsafe {
|
||||||
*pdwEffect = drop_handler.cursor_effect;
|
*pdwEffect = drop_handler.cursor_effect;
|
||||||
|
|
@ -134,10 +127,7 @@ impl FileDropHandler {
|
||||||
pub unsafe extern "system" fn DragLeave(this: *mut IDropTarget) -> HRESULT {
|
pub unsafe extern "system" fn DragLeave(this: *mut IDropTarget) -> HRESULT {
|
||||||
let drop_handler = unsafe { Self::from_interface(this) };
|
let drop_handler = unsafe { Self::from_interface(this) };
|
||||||
if drop_handler.valid {
|
if drop_handler.valid {
|
||||||
drop_handler.send_event(Event::WindowEvent {
|
(drop_handler.send_event)(WindowEvent::DragLeft { position: None });
|
||||||
window_id: WindowId::from_raw(drop_handler.window as usize),
|
|
||||||
event: WindowEvent::DragLeft { position: None },
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
S_OK
|
S_OK
|
||||||
|
|
@ -159,10 +149,7 @@ impl FileDropHandler {
|
||||||
let position = PhysicalPosition::new(pt.x as f64, pt.y as f64);
|
let position = PhysicalPosition::new(pt.x as f64, pt.y as f64);
|
||||||
let mut paths = Vec::new();
|
let mut paths = Vec::new();
|
||||||
let hdrop = unsafe { Self::iterate_filenames(pDataObj, |path| paths.push(path)) };
|
let hdrop = unsafe { Self::iterate_filenames(pDataObj, |path| paths.push(path)) };
|
||||||
drop_handler.send_event(Event::WindowEvent {
|
(drop_handler.send_event)(WindowEvent::DragDropped { paths, position });
|
||||||
window_id: WindowId::from_raw(drop_handler.window as usize),
|
|
||||||
event: WindowEvent::DragDropped { paths, position },
|
|
||||||
});
|
|
||||||
if let Some(hdrop) = hdrop {
|
if let Some(hdrop) = hdrop {
|
||||||
unsafe {
|
unsafe {
|
||||||
DragFinish(hdrop);
|
DragFinish(hdrop);
|
||||||
|
|
@ -232,12 +219,6 @@ impl FileDropHandler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FileDropHandlerData {
|
|
||||||
fn send_event(&self, event: Event) {
|
|
||||||
(self.send_event)(event);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Drop for FileDropHandler {
|
impl Drop for FileDropHandler {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,22 +1,27 @@
|
||||||
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};
|
||||||
|
|
||||||
use windows_sys::Win32::Foundation::HWND;
|
use windows_sys::Win32::Foundation::HWND;
|
||||||
|
|
||||||
use super::ControlFlow;
|
use super::{ActiveEventLoop, ControlFlow, EventLoopThreadExecutor};
|
||||||
|
use crate::application::ApplicationHandler;
|
||||||
use crate::dpi::PhysicalSize;
|
use crate::dpi::PhysicalSize;
|
||||||
use crate::event::{Event, StartCause, SurfaceSizeWriter, WindowEvent};
|
use crate::event::{DeviceEvent, DeviceId, StartCause, SurfaceSizeWriter, WindowEvent};
|
||||||
|
use crate::event_loop::ActiveEventLoop as RootActiveEventLoop;
|
||||||
use crate::platform_impl::platform::event_loop::{WindowData, GWL_USERDATA};
|
use crate::platform_impl::platform::event_loop::{WindowData, GWL_USERDATA};
|
||||||
use crate::platform_impl::platform::get_window_long;
|
use crate::platform_impl::platform::get_window_long;
|
||||||
use crate::window::WindowId;
|
use crate::window::WindowId;
|
||||||
|
|
||||||
type EventHandler = Cell<Option<Box<dyn FnMut(Event)>>>;
|
type EventHandler = Cell<Option<&'static mut (dyn ApplicationHandler + 'static)>>;
|
||||||
|
|
||||||
pub(crate) struct EventLoopRunner {
|
pub(crate) struct EventLoopRunner {
|
||||||
|
pub(super) thread_id: u32,
|
||||||
|
|
||||||
// The event loop's win32 handles
|
// The event loop's win32 handles
|
||||||
pub(super) thread_msg_target: HWND,
|
pub(super) thread_msg_target: HWND,
|
||||||
|
|
||||||
|
|
@ -29,8 +34,8 @@ pub(crate) struct EventLoopRunner {
|
||||||
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,
|
event_handler: Rc<EventHandler>,
|
||||||
event_buffer: RefCell<VecDeque<BufferedEvent>>,
|
event_buffer: RefCell<VecDeque<Event>>,
|
||||||
|
|
||||||
panic_error: Cell<Option<PanicError>>,
|
panic_error: Cell<Option<PanicError>>,
|
||||||
}
|
}
|
||||||
|
|
@ -51,14 +56,20 @@ pub(crate) enum RunnerState {
|
||||||
Destroyed,
|
Destroyed,
|
||||||
}
|
}
|
||||||
|
|
||||||
enum BufferedEvent {
|
#[derive(Debug, Clone)]
|
||||||
Event(Event),
|
pub(crate) enum Event {
|
||||||
ScaleFactorChanged(HWND, f64, PhysicalSize<u32>),
|
Device { device_id: DeviceId, event: DeviceEvent },
|
||||||
|
Window { window_id: WindowId, event: WindowEvent },
|
||||||
|
BufferedScaleFactorChanged(HWND, f64, PhysicalSize<u32>),
|
||||||
|
// FIXME(madsmtm): Coalesce these into a flag (or similar) instead of handling them as events.
|
||||||
|
// https://github.com/rust-windowing/winit/pull/3687
|
||||||
|
WakeUp,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EventLoopRunner {
|
impl EventLoopRunner {
|
||||||
pub(crate) fn new(thread_msg_target: HWND) -> EventLoopRunner {
|
pub(crate) fn new(thread_id: u32, thread_msg_target: HWND) -> Self {
|
||||||
EventLoopRunner {
|
Self {
|
||||||
|
thread_id,
|
||||||
thread_msg_target,
|
thread_msg_target,
|
||||||
interrupt_msg_dispatch: Cell::new(false),
|
interrupt_msg_dispatch: Cell::new(false),
|
||||||
runner_state: Cell::new(RunnerState::Uninitialized),
|
runner_state: Cell::new(RunnerState::Uninitialized),
|
||||||
|
|
@ -66,40 +77,50 @@ impl EventLoopRunner {
|
||||||
exit: Cell::new(None),
|
exit: Cell::new(None),
|
||||||
panic_error: Cell::new(None),
|
panic_error: Cell::new(None),
|
||||||
last_events_cleared: Cell::new(Instant::now()),
|
last_events_cleared: Cell::new(Instant::now()),
|
||||||
event_handler: Cell::new(None),
|
event_handler: Rc::new(Cell::new(None)),
|
||||||
event_buffer: RefCell::new(VecDeque::new()),
|
event_buffer: RefCell::new(VecDeque::new()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Associate the application's event handler with the runner
|
/// Associate the application's event handler with the runner.
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
/// This is ignoring the lifetime of the application handler (which may not
|
|
||||||
/// outlive the EventLoopRunner) and can lead to undefined behaviour if
|
|
||||||
/// the handler is not cleared before the end of real lifetime.
|
|
||||||
///
|
///
|
||||||
/// All public APIs that take an event handler (`run`, `run_on_demand`,
|
/// The returned type must not be leaked (as that would allow the application to be associated
|
||||||
/// `pump_events`) _must_ pair a call to `set_event_handler` with
|
/// with the runner for too long).
|
||||||
/// a call to `clear_event_handler` before returning to avoid
|
pub(crate) unsafe fn set_app<'app>(
|
||||||
/// undefined behaviour.
|
&self,
|
||||||
pub(crate) unsafe fn set_event_handler<F>(&self, f: F)
|
app: &'app mut (dyn ApplicationHandler + 'app),
|
||||||
where
|
) -> impl Drop + 'app {
|
||||||
F: FnMut(Event),
|
// Erase app lifetime, to allow storing on the event loop runner.
|
||||||
{
|
//
|
||||||
// Erase closure lifetime.
|
// SAFETY: Caller upholds that the lifetime of the closure is upheld, by not dropping the
|
||||||
// SAFETY: Caller upholds that the lifetime of the closure is upheld.
|
// return type which resets it.
|
||||||
let f =
|
let f = unsafe {
|
||||||
unsafe { mem::transmute::<Box<dyn FnMut(Event)>, Box<dyn FnMut(Event)>>(Box::new(f)) };
|
mem::transmute::<
|
||||||
let old_event_handler = self.event_handler.replace(Some(f));
|
&'app mut (dyn ApplicationHandler + 'app),
|
||||||
assert!(old_event_handler.is_none());
|
&'static mut (dyn ApplicationHandler + 'static),
|
||||||
}
|
>(app)
|
||||||
|
};
|
||||||
|
|
||||||
pub(crate) fn clear_event_handler(&self) {
|
let old_event_handler = self.event_handler.replace(Some(f));
|
||||||
self.event_handler.set(None);
|
|
||||||
|
assert!(old_event_handler.is_none());
|
||||||
|
|
||||||
|
struct Resetter(Rc<EventHandler>);
|
||||||
|
|
||||||
|
impl Drop for Resetter {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.0.set(None);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Resetter(self.event_handler.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn reset_runner(&self) {
|
pub(crate) fn reset_runner(&self) {
|
||||||
let EventLoopRunner {
|
let Self {
|
||||||
|
thread_id: _,
|
||||||
thread_msg_target: _,
|
thread_msg_target: _,
|
||||||
interrupt_msg_dispatch,
|
interrupt_msg_dispatch,
|
||||||
runner_state,
|
runner_state,
|
||||||
|
|
@ -188,21 +209,26 @@ impl EventLoopRunner {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub(crate) fn create_thread_executor(&self) -> EventLoopThreadExecutor {
|
||||||
|
EventLoopThreadExecutor { thread_id: self.thread_id, target_window: self.thread_msg_target }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Event dispatch functions.
|
/// Event dispatch functions.
|
||||||
impl EventLoopRunner {
|
impl EventLoopRunner {
|
||||||
pub(crate) fn prepare_wait(&self) {
|
pub(crate) fn prepare_wait(self: &Rc<Self>) {
|
||||||
self.move_state_to(RunnerState::Idle);
|
self.move_state_to(RunnerState::Idle);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn wakeup(&self) {
|
pub(crate) fn wakeup(self: &Rc<Self>) {
|
||||||
self.move_state_to(RunnerState::HandlingMainEvents);
|
self.move_state_to(RunnerState::HandlingMainEvents);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn send_event(&self, event: Event) {
|
pub(crate) fn send_event(self: &Rc<Self>, event: Event) {
|
||||||
if let Event::WindowEvent { event: WindowEvent::RedrawRequested, .. } = event {
|
if let Event::Window { event: WindowEvent::RedrawRequested, .. } = event {
|
||||||
self.call_event_handler(event);
|
self.call_event_handler(|app, event_loop| event.dispatch_event(app, event_loop));
|
||||||
// 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
|
||||||
// for too long, we always guarantee that `pump_events` will return control to
|
// for too long, we always guarantee that `pump_events` will return control to
|
||||||
// the external loop asap after a `RedrawRequested` event is dispatched.
|
// the external loop asap after a `RedrawRequested` event is dispatched.
|
||||||
|
|
@ -210,31 +236,34 @@ impl EventLoopRunner {
|
||||||
} else if self.should_buffer() {
|
} else if self.should_buffer() {
|
||||||
// If the runner is already borrowed, we're in the middle of an event loop invocation.
|
// If the runner is already borrowed, we're in the middle of an event loop invocation.
|
||||||
// Add the event to a buffer to be processed later.
|
// Add the event to a buffer to be processed later.
|
||||||
self.event_buffer.borrow_mut().push_back(BufferedEvent::from_event(event))
|
self.event_buffer.borrow_mut().push_back(event.buffer_scale_factor())
|
||||||
} else {
|
} else {
|
||||||
self.call_event_handler(event);
|
self.call_event_handler(|app, event_loop| event.dispatch_event(app, event_loop));
|
||||||
self.dispatch_buffered_events();
|
self.dispatch_buffered_events();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn loop_destroyed(&self) {
|
pub(crate) fn loop_destroyed(self: &Rc<Self>) {
|
||||||
self.move_state_to(RunnerState::Destroyed);
|
self.move_state_to(RunnerState::Destroyed);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call_event_handler(&self, event: Event) {
|
fn call_event_handler(
|
||||||
|
self: &Rc<Self>,
|
||||||
|
closure: impl FnOnce(&mut dyn ApplicationHandler, &dyn RootActiveEventLoop),
|
||||||
|
) {
|
||||||
self.catch_unwind(|| {
|
self.catch_unwind(|| {
|
||||||
let mut event_handler = self.event_handler.take().expect(
|
let 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 \
|
||||||
(very unlikely)",
|
(very unlikely)",
|
||||||
);
|
);
|
||||||
|
|
||||||
event_handler(event);
|
closure(event_handler, ActiveEventLoop::from_ref(self));
|
||||||
|
|
||||||
assert!(self.event_handler.replace(Some(event_handler)).is_none());
|
assert!(self.event_handler.replace(Some(event_handler)).is_none());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dispatch_buffered_events(&self) {
|
fn dispatch_buffered_events(self: &Rc<Self>) {
|
||||||
loop {
|
loop {
|
||||||
// We do this instead of using a `while let` loop because if we use a `while let`
|
// We do this instead of using a `while let` loop because if we use a `while let`
|
||||||
// loop the reference returned `borrow_mut()` doesn't get dropped until the end
|
// loop the reference returned `borrow_mut()` doesn't get dropped until the end
|
||||||
|
|
@ -242,7 +271,9 @@ impl EventLoopRunner {
|
||||||
// `process_event` will fail.
|
// `process_event` will fail.
|
||||||
let buffered_event_opt = self.event_buffer.borrow_mut().pop_front();
|
let buffered_event_opt = self.event_buffer.borrow_mut().pop_front();
|
||||||
match buffered_event_opt {
|
match buffered_event_opt {
|
||||||
Some(e) => e.dispatch_event(|e| self.call_event_handler(e)),
|
Some(e) => {
|
||||||
|
self.call_event_handler(|app, event_loop| e.dispatch_event(app, event_loop))
|
||||||
|
},
|
||||||
None => break,
|
None => break,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -272,7 +303,7 @@ impl EventLoopRunner {
|
||||||
/// state is a no-op. Even if the `new_runner_state` isn't the immediate next state in the
|
/// state is a no-op. Even if the `new_runner_state` isn't the immediate next state in the
|
||||||
/// runner state machine (e.g. `self.runner_state == HandlingMainEvents` and
|
/// runner state machine (e.g. `self.runner_state == HandlingMainEvents` and
|
||||||
/// `new_runner_state == Idle`), the intermediate state transitions will still be executed.
|
/// `new_runner_state == Idle`), the intermediate state transitions will still be executed.
|
||||||
fn move_state_to(&self, new_runner_state: RunnerState) {
|
fn move_state_to(self: &Rc<Self>, new_runner_state: RunnerState) {
|
||||||
use RunnerState::{Destroyed, HandlingMainEvents, Idle, Uninitialized};
|
use RunnerState::{Destroyed, HandlingMainEvents, Idle, Uninitialized};
|
||||||
|
|
||||||
match (self.runner_state.replace(new_runner_state), new_runner_state) {
|
match (self.runner_state.replace(new_runner_state), new_runner_state) {
|
||||||
|
|
@ -287,14 +318,14 @@ impl EventLoopRunner {
|
||||||
},
|
},
|
||||||
(Uninitialized, Idle) => {
|
(Uninitialized, Idle) => {
|
||||||
self.call_new_events(true);
|
self.call_new_events(true);
|
||||||
self.call_event_handler(Event::AboutToWait);
|
self.call_event_handler(|app, event_loop| app.about_to_wait(event_loop));
|
||||||
self.last_events_cleared.set(Instant::now());
|
self.last_events_cleared.set(Instant::now());
|
||||||
},
|
},
|
||||||
(Uninitialized, Destroyed) => {
|
(Uninitialized, Destroyed) => {
|
||||||
self.call_new_events(true);
|
self.call_new_events(true);
|
||||||
self.call_event_handler(Event::AboutToWait);
|
self.call_event_handler(|app, event_loop| app.about_to_wait(event_loop));
|
||||||
self.last_events_cleared.set(Instant::now());
|
self.last_events_cleared.set(Instant::now());
|
||||||
self.call_event_handler(Event::LoopExiting);
|
self.call_event_handler(|app, event_loop| app.exiting(event_loop));
|
||||||
},
|
},
|
||||||
(_, Uninitialized) => panic!("cannot move state to Uninitialized"),
|
(_, Uninitialized) => panic!("cannot move state to Uninitialized"),
|
||||||
|
|
||||||
|
|
@ -303,25 +334,25 @@ impl EventLoopRunner {
|
||||||
self.call_new_events(false);
|
self.call_new_events(false);
|
||||||
},
|
},
|
||||||
(Idle, Destroyed) => {
|
(Idle, Destroyed) => {
|
||||||
self.call_event_handler(Event::LoopExiting);
|
self.call_event_handler(|app, event_loop| app.exiting(event_loop));
|
||||||
},
|
},
|
||||||
|
|
||||||
(HandlingMainEvents, Idle) => {
|
(HandlingMainEvents, Idle) => {
|
||||||
// This is always the last event we dispatch before waiting for new events
|
// This is always the last event we dispatch before waiting for new events
|
||||||
self.call_event_handler(Event::AboutToWait);
|
self.call_event_handler(|app, event_loop| app.about_to_wait(event_loop));
|
||||||
self.last_events_cleared.set(Instant::now());
|
self.last_events_cleared.set(Instant::now());
|
||||||
},
|
},
|
||||||
(HandlingMainEvents, Destroyed) => {
|
(HandlingMainEvents, Destroyed) => {
|
||||||
self.call_event_handler(Event::AboutToWait);
|
self.call_event_handler(|app, event_loop| app.about_to_wait(event_loop));
|
||||||
self.last_events_cleared.set(Instant::now());
|
self.last_events_cleared.set(Instant::now());
|
||||||
self.call_event_handler(Event::LoopExiting);
|
self.call_event_handler(|app, event_loop| app.exiting(event_loop));
|
||||||
},
|
},
|
||||||
|
|
||||||
(Destroyed, _) => panic!("cannot move state from Destroyed"),
|
(Destroyed, _) => panic!("cannot move state from Destroyed"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call_new_events(&self, init: bool) {
|
fn call_new_events(self: &Rc<Self>, init: bool) {
|
||||||
let start_cause = match (init, self.control_flow(), self.exit.get()) {
|
let start_cause = match (init, self.control_flow(), self.exit.get()) {
|
||||||
(true, ..) => StartCause::Init,
|
(true, ..) => StartCause::Init,
|
||||||
(false, ControlFlow::Poll, None) => StartCause::Poll,
|
(false, ControlFlow::Poll, None) => StartCause::Poll,
|
||||||
|
|
@ -343,45 +374,55 @@ impl EventLoopRunner {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
self.call_event_handler(Event::NewEvents(start_cause));
|
self.call_event_handler(|app, event_loop| app.new_events(event_loop, start_cause));
|
||||||
// NB: For consistency all platforms must call `can_create_surfaces` even though Windows
|
// NB: For consistency all platforms must call `can_create_surfaces` even though Windows
|
||||||
// applications don't themselves have a formal surface destroy/create lifecycle.
|
// applications don't themselves have a formal surface destroy/create lifecycle.
|
||||||
if init {
|
if init {
|
||||||
self.call_event_handler(Event::CreateSurfaces);
|
self.call_event_handler(|app, event_loop| app.can_create_surfaces(event_loop));
|
||||||
}
|
}
|
||||||
self.dispatch_buffered_events();
|
self.dispatch_buffered_events();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BufferedEvent {
|
impl Event {
|
||||||
pub fn from_event(event: Event) -> BufferedEvent {
|
/// Mark ScaleFactorChanged as being buffered (which forces us to re-handle when the user set a
|
||||||
match event {
|
/// new size).
|
||||||
Event::WindowEvent {
|
pub fn buffer_scale_factor(self) -> Self {
|
||||||
|
match self {
|
||||||
|
Self::Window {
|
||||||
event: WindowEvent::ScaleFactorChanged { scale_factor, surface_size_writer },
|
event: WindowEvent::ScaleFactorChanged { scale_factor, surface_size_writer },
|
||||||
window_id,
|
window_id,
|
||||||
} => BufferedEvent::ScaleFactorChanged(
|
} => Event::BufferedScaleFactorChanged(
|
||||||
window_id.into_raw() as HWND,
|
window_id.into_raw() as HWND,
|
||||||
scale_factor,
|
scale_factor,
|
||||||
*surface_size_writer.new_surface_size.upgrade().unwrap().lock().unwrap(),
|
*surface_size_writer.new_surface_size.upgrade().unwrap().lock().unwrap(),
|
||||||
),
|
),
|
||||||
event => BufferedEvent::Event(event),
|
event => event,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dispatch_event(self, dispatch: impl FnOnce(Event)) {
|
pub fn dispatch_event(
|
||||||
|
self,
|
||||||
|
app: &mut dyn ApplicationHandler,
|
||||||
|
event_loop: &dyn RootActiveEventLoop,
|
||||||
|
) {
|
||||||
match self {
|
match self {
|
||||||
Self::Event(event) => dispatch(event),
|
Self::Window { window_id, event } => app.window_event(event_loop, window_id, event),
|
||||||
Self::ScaleFactorChanged(window, scale_factor, new_surface_size) => {
|
Self::Device { device_id, event } => {
|
||||||
|
app.device_event(event_loop, Some(device_id), event)
|
||||||
|
},
|
||||||
|
Self::BufferedScaleFactorChanged(window, scale_factor, new_surface_size) => {
|
||||||
let user_new_surface_size = Arc::new(Mutex::new(new_surface_size));
|
let user_new_surface_size = Arc::new(Mutex::new(new_surface_size));
|
||||||
dispatch(Event::WindowEvent {
|
app.window_event(
|
||||||
window_id: WindowId::from_raw(window as usize),
|
event_loop,
|
||||||
event: WindowEvent::ScaleFactorChanged {
|
WindowId::from_raw(window as usize),
|
||||||
|
WindowEvent::ScaleFactorChanged {
|
||||||
scale_factor,
|
scale_factor,
|
||||||
surface_size_writer: SurfaceSizeWriter::new(Arc::downgrade(
|
surface_size_writer: SurfaceSizeWriter::new(Arc::downgrade(
|
||||||
&user_new_surface_size,
|
&user_new_surface_size,
|
||||||
)),
|
)),
|
||||||
},
|
},
|
||||||
});
|
);
|
||||||
let surface_size = *user_new_surface_size.lock().unwrap();
|
let surface_size = *user_new_surface_size.lock().unwrap();
|
||||||
|
|
||||||
drop(user_new_surface_size);
|
drop(user_new_surface_size);
|
||||||
|
|
@ -395,6 +436,7 @@ impl BufferedEvent {
|
||||||
window_flags.set_size(window, surface_size);
|
window_flags.set_size(window, surface_size);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
Self::WakeUp => app.proxy_wake_up(event_loop),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::ffi::c_void;
|
use std::ffi::c_void;
|
||||||
use std::mem::{self, MaybeUninit};
|
use std::mem::{self, MaybeUninit};
|
||||||
|
use std::rc::Rc;
|
||||||
use std::sync::mpsc::channel;
|
use std::sync::mpsc::channel;
|
||||||
use std::sync::{Arc, Mutex, MutexGuard};
|
use std::sync::{Arc, Mutex, MutexGuard};
|
||||||
use std::{io, panic, ptr};
|
use std::{io, panic, ptr};
|
||||||
|
|
@ -59,7 +60,9 @@ use crate::platform_impl::platform::dpi::{
|
||||||
dpi_to_scale_factor, enable_non_client_dpi_scaling, hwnd_dpi,
|
dpi_to_scale_factor, enable_non_client_dpi_scaling, hwnd_dpi,
|
||||||
};
|
};
|
||||||
use crate::platform_impl::platform::drop_handler::FileDropHandler;
|
use crate::platform_impl::platform::drop_handler::FileDropHandler;
|
||||||
use crate::platform_impl::platform::event_loop::{self, ActiveEventLoop, DESTROY_MSG_ID};
|
use crate::platform_impl::platform::event_loop::{
|
||||||
|
self, ActiveEventLoop, Event, EventLoopRunner, DESTROY_MSG_ID,
|
||||||
|
};
|
||||||
use crate::platform_impl::platform::icon::{self, IconType};
|
use crate::platform_impl::platform::icon::{self, IconType};
|
||||||
use crate::platform_impl::platform::ime::ImeContext;
|
use crate::platform_impl::platform::ime::ImeContext;
|
||||||
use crate::platform_impl::platform::keyboard::KeyEventBuilder;
|
use crate::platform_impl::platform::keyboard::KeyEventBuilder;
|
||||||
|
|
@ -109,7 +112,7 @@ impl Window {
|
||||||
// First person to remove the need for cloning here gets a cookie!
|
// First person to remove the need for cloning here gets a cookie!
|
||||||
//
|
//
|
||||||
// done. you owe me -- ossi
|
// done. you owe me -- ossi
|
||||||
unsafe { init(w_attr, event_loop) }
|
unsafe { init(w_attr, &event_loop.0) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn window_state_lock(&self) -> MutexGuard<'_, WindowState> {
|
fn window_state_lock(&self) -> MutexGuard<'_, WindowState> {
|
||||||
|
|
@ -1082,7 +1085,7 @@ impl CoreWindow for Window {
|
||||||
|
|
||||||
pub(super) struct InitData<'a> {
|
pub(super) struct InitData<'a> {
|
||||||
// inputs
|
// inputs
|
||||||
pub event_loop: &'a ActiveEventLoop,
|
pub runner: &'a Rc<EventLoopRunner>,
|
||||||
pub attributes: WindowAttributes,
|
pub attributes: WindowAttributes,
|
||||||
pub window_flags: WindowFlags,
|
pub window_flags: WindowFlags,
|
||||||
// outputs
|
// outputs
|
||||||
|
|
@ -1128,7 +1131,7 @@ impl InitData<'_> {
|
||||||
Window {
|
Window {
|
||||||
window: SyncWindowHandle(window),
|
window: SyncWindowHandle(window),
|
||||||
window_state,
|
window_state,
|
||||||
thread_executor: self.event_loop.create_thread_executor(),
|
thread_executor: self.runner.create_thread_executor(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1147,10 +1150,13 @@ impl InitData<'_> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let file_drop_runner = self.event_loop.runner_shared.clone();
|
let file_drop_runner = self.runner.clone();
|
||||||
|
let window_id = win.id();
|
||||||
let file_drop_handler = FileDropHandler::new(
|
let file_drop_handler = FileDropHandler::new(
|
||||||
win.window.hwnd(),
|
win.window.hwnd(),
|
||||||
Box::new(move |event| file_drop_runner.send_event(event)),
|
Box::new(move |event| {
|
||||||
|
file_drop_runner.send_event(Event::Window { window_id, event })
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
let handler_interface_ptr =
|
let handler_interface_ptr =
|
||||||
|
|
@ -1164,7 +1170,7 @@ impl InitData<'_> {
|
||||||
|
|
||||||
event_loop::WindowData {
|
event_loop::WindowData {
|
||||||
window_state: win.window_state.clone(),
|
window_state: win.window_state.clone(),
|
||||||
event_loop_runner: self.event_loop.runner_shared.clone(),
|
event_loop_runner: self.runner.clone(),
|
||||||
key_event_builder: KeyEventBuilder::default(),
|
key_event_builder: KeyEventBuilder::default(),
|
||||||
_file_drop_handler: file_drop_handler,
|
_file_drop_handler: file_drop_handler,
|
||||||
userdata_removed: Cell::new(false),
|
userdata_removed: Cell::new(false),
|
||||||
|
|
@ -1176,7 +1182,7 @@ impl InitData<'_> {
|
||||||
// The user data will be registered for the window and can be accessed within the window event
|
// The user data will be registered for the window and can be accessed within the window event
|
||||||
// callback.
|
// callback.
|
||||||
pub unsafe fn on_nccreate(&mut self, window: HWND) -> Option<isize> {
|
pub unsafe fn on_nccreate(&mut self, window: HWND) -> Option<isize> {
|
||||||
let runner = self.event_loop.runner_shared.clone();
|
let runner = self.runner.clone();
|
||||||
let result = runner.catch_unwind(|| {
|
let result = runner.catch_unwind(|| {
|
||||||
let window = unsafe { self.create_window(window) };
|
let window = unsafe { self.create_window(window) };
|
||||||
let window_data = unsafe { self.create_window_data(&window) };
|
let window_data = unsafe { self.create_window_data(&window) };
|
||||||
|
|
@ -1268,7 +1274,7 @@ impl InitData<'_> {
|
||||||
}
|
}
|
||||||
unsafe fn init(
|
unsafe fn init(
|
||||||
attributes: WindowAttributes,
|
attributes: WindowAttributes,
|
||||||
event_loop: &ActiveEventLoop,
|
runner: &Rc<EventLoopRunner>,
|
||||||
) -> Result<Window, RequestError> {
|
) -> Result<Window, RequestError> {
|
||||||
let title = util::encode_wide(&attributes.title);
|
let title = util::encode_wide(&attributes.title);
|
||||||
|
|
||||||
|
|
@ -1322,7 +1328,7 @@ unsafe fn init(
|
||||||
let menu = attributes.platform_specific.menu;
|
let menu = attributes.platform_specific.menu;
|
||||||
let fullscreen = attributes.fullscreen.clone();
|
let fullscreen = attributes.fullscreen.clone();
|
||||||
let maximized = attributes.maximized;
|
let maximized = attributes.maximized;
|
||||||
let mut initdata = InitData { event_loop, attributes, window_flags, window: None };
|
let mut initdata = InitData { runner, attributes, window_flags, window: None };
|
||||||
|
|
||||||
let (style, ex_style) = window_flags.to_window_styles();
|
let (style, ex_style) = window_flags.to_window_styles();
|
||||||
let handle = unsafe {
|
let handle = unsafe {
|
||||||
|
|
@ -1343,7 +1349,7 @@ unsafe fn init(
|
||||||
};
|
};
|
||||||
|
|
||||||
// If the window creation in `InitData` panicked, then should resume panicking here
|
// If the window creation in `InitData` panicked, then should resume panicking here
|
||||||
if let Err(panic_error) = event_loop.runner_shared.take_panic_error() {
|
if let Err(panic_error) = runner.take_panic_error() {
|
||||||
panic::resume_unwind(panic_error)
|
panic::resume_unwind(panic_error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue