mirror of
https://github.com/rust-windowing/winit.git
synced 2026-06-26 22:53:15 -04:00
Implement new ControlFlow and associated events
This commit is contained in:
@@ -3,14 +3,14 @@ extern crate winit;
|
||||
use winit::{Event, EventLoop, ElementState, MouseCursor, WindowEvent, KeyboardInput, ControlFlow};
|
||||
|
||||
fn main() {
|
||||
let mut events_loop = EventLoop::new();
|
||||
let events_loop = EventLoop::new();
|
||||
|
||||
let window = winit::WindowBuilder::new().build(&events_loop).unwrap();
|
||||
window.set_title("A fantastic window!");
|
||||
|
||||
let mut cursor_idx = 0;
|
||||
|
||||
events_loop.run_forever(move |event, _: &EventLoop| {
|
||||
events_loop.run(move |event, _, control_flow| {
|
||||
match event {
|
||||
Event::WindowEvent { event: WindowEvent::KeyboardInput { input: KeyboardInput { state: ElementState::Pressed, .. }, .. }, .. } => {
|
||||
println!("Setting cursor to \"{:?}\"", CURSORS[cursor_idx]);
|
||||
@@ -22,11 +22,11 @@ fn main() {
|
||||
}
|
||||
},
|
||||
Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => {
|
||||
return ControlFlow::Break;
|
||||
*control_flow = ControlFlow::Exit;
|
||||
return;
|
||||
},
|
||||
_ => ()
|
||||
}
|
||||
ControlFlow::Continue
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,18 +1,19 @@
|
||||
extern crate winit;
|
||||
|
||||
fn main() {
|
||||
let mut events_loop = winit::EventLoop::new();
|
||||
let events_loop = winit::EventLoop::new();
|
||||
|
||||
let window = winit::WindowBuilder::new()
|
||||
.with_title("Super Cursor Grab'n'Hide Simulator 9000")
|
||||
.build(&events_loop)
|
||||
.unwrap();
|
||||
|
||||
events_loop.run_forever(move |event, _: &winit::EventLoop| {
|
||||
events_loop.run(move |event, _, control_flow| {
|
||||
*control_flow = winit::ControlFlow::Wait;
|
||||
if let winit::Event::WindowEvent { event, .. } = event {
|
||||
use winit::WindowEvent::*;
|
||||
match event {
|
||||
CloseRequested => return winit::ControlFlow::Break,
|
||||
CloseRequested => *control_flow = winit::ControlFlow::Exit,
|
||||
KeyboardInput {
|
||||
input: winit::KeyboardInput {
|
||||
state: winit::ElementState::Released,
|
||||
@@ -24,7 +25,7 @@ fn main() {
|
||||
} => {
|
||||
use winit::VirtualKeyCode::*;
|
||||
match key {
|
||||
Escape => return winit::ControlFlow::Break,
|
||||
Escape => *control_flow = winit::ControlFlow::Exit,
|
||||
G => window.grab_cursor(!modifiers.shift).unwrap(),
|
||||
H => window.hide_cursor(!modifiers.shift),
|
||||
_ => (),
|
||||
@@ -33,6 +34,5 @@ fn main() {
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
winit::ControlFlow::Continue
|
||||
});
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ use std::io::{self, Write};
|
||||
use winit::{ControlFlow, Event, WindowEvent};
|
||||
|
||||
fn main() {
|
||||
let mut events_loop = winit::EventLoop::new();
|
||||
let events_loop = winit::EventLoop::new();
|
||||
|
||||
// enumerating monitors
|
||||
let monitor = {
|
||||
@@ -35,12 +35,13 @@ fn main() {
|
||||
let mut is_maximized = false;
|
||||
let mut decorations = true;
|
||||
|
||||
events_loop.run_forever(move |event, _: &winit::EventLoop| {
|
||||
events_loop.run(move |event, _, control_flow| {
|
||||
println!("{:?}", event);
|
||||
*control_flow = ControlFlow::Wait;
|
||||
|
||||
match event {
|
||||
Event::WindowEvent { event, .. } => match event {
|
||||
WindowEvent::CloseRequested => return ControlFlow::Break,
|
||||
WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit,
|
||||
WindowEvent::KeyboardInput {
|
||||
input:
|
||||
winit::KeyboardInput {
|
||||
@@ -50,7 +51,7 @@ fn main() {
|
||||
},
|
||||
..
|
||||
} => match (virtual_code, state) {
|
||||
(winit::VirtualKeyCode::Escape, _) => return ControlFlow::Break,
|
||||
(winit::VirtualKeyCode::Escape, _) => *control_flow = ControlFlow::Exit,
|
||||
(winit::VirtualKeyCode::F, winit::ElementState::Pressed) => {
|
||||
is_fullscreen = !is_fullscreen;
|
||||
if !is_fullscreen {
|
||||
@@ -73,7 +74,5 @@ fn main() {
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
|
||||
ControlFlow::Continue
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
extern crate winit;
|
||||
|
||||
fn main() {
|
||||
let mut events_loop = winit::EventLoop::new();
|
||||
let events_loop = winit::EventLoop::new();
|
||||
|
||||
let _window = winit::WindowBuilder::new()
|
||||
.with_title("Your faithful window")
|
||||
@@ -10,7 +10,7 @@ fn main() {
|
||||
|
||||
let mut close_requested = false;
|
||||
|
||||
events_loop.run_forever(move |event, _: &winit::EventLoop| {
|
||||
events_loop.run(move |event, _, control_flow| {
|
||||
use winit::WindowEvent::*;
|
||||
use winit::ElementState::Released;
|
||||
use winit::VirtualKeyCode::{N, Y};
|
||||
@@ -53,7 +53,7 @@ fn main() {
|
||||
// event loop (i.e. if it's a multi-window application), you need to
|
||||
// drop the window. That closes it, and results in `Destroyed` being
|
||||
// sent.
|
||||
return winit::ControlFlow::Break;
|
||||
*control_flow = winit::ControlFlow::Exit;
|
||||
}
|
||||
}
|
||||
N => {
|
||||
@@ -69,6 +69,6 @@ fn main() {
|
||||
_ => (),
|
||||
}
|
||||
|
||||
winit::ControlFlow::Continue
|
||||
*control_flow = winit::ControlFlow::Wait;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ extern crate winit;
|
||||
use winit::dpi::LogicalSize;
|
||||
|
||||
fn main() {
|
||||
let mut events_loop = winit::EventLoop::new();
|
||||
let events_loop = winit::EventLoop::new();
|
||||
|
||||
let window = winit::WindowBuilder::new()
|
||||
.build(&events_loop)
|
||||
@@ -12,12 +12,13 @@ fn main() {
|
||||
window.set_min_dimensions(Some(LogicalSize::new(400.0, 200.0)));
|
||||
window.set_max_dimensions(Some(LogicalSize::new(800.0, 400.0)));
|
||||
|
||||
events_loop.run_forever(move |event, _: &winit::EventLoop| {
|
||||
events_loop.run(move |event, _, control_flow| {
|
||||
println!("{:?}", event);
|
||||
|
||||
match event {
|
||||
winit::Event::WindowEvent { event: winit::WindowEvent::CloseRequested, .. } => winit::ControlFlow::Break,
|
||||
_ => winit::ControlFlow::Continue,
|
||||
winit::Event::WindowEvent { event: winit::WindowEvent::CloseRequested, .. } =>
|
||||
*control_flow = winit::ControlFlow::Exit,
|
||||
_ => *control_flow = winit::ControlFlow::Wait,
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ extern crate winit;
|
||||
use std::collections::HashMap;
|
||||
|
||||
fn main() {
|
||||
let mut events_loop = winit::EventLoop::new();
|
||||
let events_loop = winit::EventLoop::new();
|
||||
|
||||
let mut windows = HashMap::new();
|
||||
for _ in 0..3 {
|
||||
@@ -11,7 +11,8 @@ fn main() {
|
||||
windows.insert(window.id(), window);
|
||||
}
|
||||
|
||||
events_loop.run_forever(move |event, events_loop: &winit::EventLoop| {
|
||||
events_loop.run(move |event, events_loop, control_flow| {
|
||||
*control_flow = winit::ControlFlow::Wait;
|
||||
match event {
|
||||
winit::Event::WindowEvent { event, window_id } => {
|
||||
match event {
|
||||
@@ -22,7 +23,7 @@ fn main() {
|
||||
windows.remove(&window_id);
|
||||
|
||||
if windows.is_empty() {
|
||||
return winit::ControlFlow::Break;
|
||||
*control_flow = winit::ControlFlow::Exit;
|
||||
}
|
||||
},
|
||||
winit::WindowEvent::KeyboardInput{..} => {
|
||||
@@ -34,6 +35,5 @@ fn main() {
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
winit::ControlFlow::Continue
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
extern crate winit;
|
||||
|
||||
fn main() {
|
||||
let mut events_loop = winit::EventLoop::new();
|
||||
let events_loop = winit::EventLoop::new();
|
||||
|
||||
let _window = winit::WindowBuilder::new()
|
||||
.with_title("A fantastic window!")
|
||||
@@ -18,12 +18,12 @@ fn main() {
|
||||
}
|
||||
});
|
||||
|
||||
events_loop.run_forever(move |event, _: &winit::EventLoop| {
|
||||
events_loop.run(move |event, _, control_flow| {
|
||||
println!("{:?}", event);
|
||||
match event {
|
||||
winit::Event::WindowEvent { event: winit::WindowEvent::CloseRequested, .. } =>
|
||||
winit::ControlFlow::Break,
|
||||
_ => winit::ControlFlow::Continue,
|
||||
*control_flow = winit::ControlFlow::Wait,
|
||||
_ => *control_flow = winit::ControlFlow::Wait,
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
extern crate winit;
|
||||
|
||||
fn main() {
|
||||
let mut events_loop = winit::EventLoop::new();
|
||||
let events_loop = winit::EventLoop::new();
|
||||
|
||||
let mut resizable = false;
|
||||
|
||||
@@ -12,10 +12,11 @@ fn main() {
|
||||
.build(&events_loop)
|
||||
.unwrap();
|
||||
|
||||
events_loop.run_forever(move |event, _: &winit::EventLoop| {
|
||||
events_loop.run(move |event, _, control_flow| {
|
||||
*control_flow = winit::ControlFlow::Wait;
|
||||
match event {
|
||||
winit::Event::WindowEvent { event, .. } => match event {
|
||||
winit::WindowEvent::CloseRequested => return winit::ControlFlow::Break,
|
||||
winit::WindowEvent::CloseRequested => *control_flow = winit::ControlFlow::Exit,
|
||||
winit::WindowEvent::KeyboardInput {
|
||||
input:
|
||||
winit::KeyboardInput {
|
||||
@@ -33,6 +34,5 @@ fn main() {
|
||||
},
|
||||
_ => (),
|
||||
};
|
||||
winit::ControlFlow::Continue
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
extern crate winit;
|
||||
|
||||
fn main() {
|
||||
let mut events_loop = winit::EventLoop::new();
|
||||
let events_loop = winit::EventLoop::new();
|
||||
|
||||
let window = winit::WindowBuilder::new().with_decorations(false)
|
||||
.with_transparency(true)
|
||||
@@ -9,12 +9,13 @@ fn main() {
|
||||
|
||||
window.set_title("A fantastic window!");
|
||||
|
||||
events_loop.run_forever(move |event, _: &winit::EventLoop| {
|
||||
events_loop.run(move |event, _, control_flow| {
|
||||
println!("{:?}", event);
|
||||
|
||||
match event {
|
||||
winit::Event::WindowEvent { event: winit::WindowEvent::CloseRequested, .. } => winit::ControlFlow::Break,
|
||||
_ => winit::ControlFlow::Continue,
|
||||
winit::Event::WindowEvent { event: winit::WindowEvent::CloseRequested, .. } =>
|
||||
*control_flow = winit::ControlFlow::Exit,
|
||||
_ => *control_flow = winit::ControlFlow::Wait,
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -8,15 +8,15 @@ fn main() {
|
||||
.build(&events_loop)
|
||||
.unwrap();
|
||||
|
||||
events_loop.run_forever(move |event, _: &winit::EventLoop| {
|
||||
events_loop.run(move |event, _, control_flow| {
|
||||
println!("{:?}", event);
|
||||
|
||||
match event {
|
||||
winit::Event::WindowEvent {
|
||||
event: winit::WindowEvent::CloseRequested,
|
||||
..
|
||||
} => winit::ControlFlow::Break,
|
||||
_ => winit::ControlFlow::Continue,
|
||||
} => *control_flow = winit::ControlFlow::Exit,
|
||||
_ => *control_flow = winit::ControlFlow::Wait,
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ fn main() {
|
||||
// feature enabled).
|
||||
let icon = Icon::from_path(path).expect("Failed to open icon");
|
||||
|
||||
let mut events_loop = winit::EventLoop::new();
|
||||
let events_loop = winit::EventLoop::new();
|
||||
|
||||
let window = winit::WindowBuilder::new()
|
||||
.with_title("An iconic window!")
|
||||
@@ -30,11 +30,12 @@ fn main() {
|
||||
.build(&events_loop)
|
||||
.unwrap();
|
||||
|
||||
events_loop.run_forever(move |event, _: &EventLoop| {
|
||||
events_loop.run(move |event, _, control_flow| {
|
||||
*control_flow = winit::ControlFlow::Wait;
|
||||
if let winit::Event::WindowEvent { event, .. } = event {
|
||||
use winit::WindowEvent::*;
|
||||
match event {
|
||||
CloseRequested => return winit::ControlFlow::Break,
|
||||
CloseRequested => *control_flow = winit::ControlFlow::Exit,
|
||||
DroppedFile(path) => {
|
||||
use image::GenericImageView;
|
||||
|
||||
@@ -81,7 +82,6 @@ fn main() {
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
winit::ControlFlow::Continue
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use std::time::{Duration, Instant};
|
||||
use std::path::PathBuf;
|
||||
|
||||
use {DeviceId, LogicalPosition, LogicalSize, WindowId};
|
||||
@@ -14,6 +15,15 @@ pub enum Event {
|
||||
event: DeviceEvent,
|
||||
},
|
||||
Awakened,
|
||||
/// Emitted when new events arrive from the OS to be processed.
|
||||
NewEvents(StartCause),
|
||||
/// Emitted when all of the event loop's events have been processed and control flow is about
|
||||
/// to be taken away from the program.
|
||||
EventsCleared,
|
||||
|
||||
/// Emitted when the event loop is being shut down. This is irreversable - if this event is
|
||||
/// emitted, it is guaranteed to be the last event emitted.
|
||||
LoopDestroyed,
|
||||
|
||||
/// The application has been suspended or resumed.
|
||||
///
|
||||
@@ -21,6 +31,31 @@ pub enum Event {
|
||||
Suspended(bool),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub enum StartCause {
|
||||
/// Sent if the time specified by `ControlFlow::WaitTimeout` has been elapsed. Contains the
|
||||
/// moment the timeout was requested and the requested duration of the timeout. The actual
|
||||
/// duration is guaranteed to be greater than or equal to the requested timeout.
|
||||
TimeoutExpired {
|
||||
start: Instant,
|
||||
requested_duration: Duration,
|
||||
},
|
||||
|
||||
/// Sent if the OS has new events to send to the window, after a wait was requested. Contains
|
||||
/// the moment the wait was requested, and if a wait timout was requested, its duration.
|
||||
WaitCancelled {
|
||||
start: Instant,
|
||||
requested_duration: Option<Duration>
|
||||
},
|
||||
|
||||
/// Sent if the event loop is being resumed after the loop's control flow was set to
|
||||
/// `ControlFlow::Poll`.
|
||||
Poll,
|
||||
|
||||
/// Sent once, immediately after `run` is called. Indicates that the loop was just initialized.
|
||||
Init
|
||||
}
|
||||
|
||||
/// Describes an event from a `Window`.
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum WindowEvent {
|
||||
|
||||
84
src/lib.rs
84
src/lib.rs
@@ -28,47 +28,21 @@
|
||||
//! The events generated by a window can be retreived from the `EventLoop` the window was created
|
||||
//! with.
|
||||
//!
|
||||
//! There are two ways to do so. The first is to call `events_loop.poll_events(...)`, which will
|
||||
//! retrieve all the events pending on the windows and immediately return after no new event is
|
||||
//! available. You usually want to use this method in application that render continuously on the
|
||||
//! screen, such as video games.
|
||||
//!
|
||||
//! ```no_run
|
||||
//! use winit::{Event, WindowEvent};
|
||||
//! use winit::dpi::LogicalSize;
|
||||
//! # use winit::EventLoop;
|
||||
//! # let mut events_loop = EventLoop::new();
|
||||
//!
|
||||
//! loop {
|
||||
//! events_loop.poll_events(|event| {
|
||||
//! match event {
|
||||
//! Event::WindowEvent {
|
||||
//! event: WindowEvent::Resized(LogicalSize { width, height }),
|
||||
//! ..
|
||||
//! } => {
|
||||
//! println!("The window was resized to {}x{}", width, height);
|
||||
//! },
|
||||
//! _ => ()
|
||||
//! }
|
||||
//! });
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! The second way is to call `events_loop.run_forever(...)`. As its name tells, it will run
|
||||
//! forever unless it is stopped by returning `ControlFlow::Break`.
|
||||
//! You do this by calling `events_loop.run(...)`. This function will run forever unless it is
|
||||
//! stopped by returning `ControlFlow::Exit`, at which point the entire program will terminate.
|
||||
//!
|
||||
//! ```no_run
|
||||
//! use winit::{ControlFlow, Event, WindowEvent};
|
||||
//! # use winit::EventLoop;
|
||||
//! # let mut events_loop = EventLoop::new();
|
||||
//! # let events_loop = EventLoop::new();
|
||||
//!
|
||||
//! events_loop.run_forever(move |event, _: &EventLoop| {
|
||||
//! events_loop.run(move |event, _, control_flow| {
|
||||
//! match event {
|
||||
//! Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => {
|
||||
//! println!("The close button was pressed; stopping");
|
||||
//! ControlFlow::Break
|
||||
//! *control_flow = ControlFlow::Exit
|
||||
//! },
|
||||
//! _ => ControlFlow::Continue,
|
||||
//! _ => *control_flow = ControlFlow::Wait,
|
||||
//! }
|
||||
//! });
|
||||
//! ```
|
||||
@@ -116,6 +90,7 @@ extern crate percent_encoding;
|
||||
#[cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd"))]
|
||||
extern crate smithay_client_toolkit as sctk;
|
||||
|
||||
use std::time::Duration;
|
||||
pub(crate) use dpi::*; // TODO: Actually change the imports throughout the codebase.
|
||||
pub use events::*;
|
||||
pub use window::{AvailableMonitorsIter, MonitorId};
|
||||
@@ -139,12 +114,12 @@ pub mod os;
|
||||
/// let mut events_loop = EventLoop::new();
|
||||
/// let window = Window::new(&events_loop).unwrap();
|
||||
///
|
||||
/// events_loop.run_forever(move |event, _: &EventLoop| {
|
||||
/// events_loop.run(move |event, _, control_flow| {
|
||||
/// match event {
|
||||
/// Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => {
|
||||
/// ControlFlow::Break
|
||||
/// *control_flow = ControlFlow::Exit
|
||||
/// },
|
||||
/// _ => ControlFlow::Continue,
|
||||
/// _ => *control_flow = ControlFlow::Wait,
|
||||
/// }
|
||||
/// });
|
||||
/// ```
|
||||
@@ -199,28 +174,29 @@ impl std::fmt::Debug for EventLoop {
|
||||
}
|
||||
}
|
||||
|
||||
pub trait EventHandler {
|
||||
fn handle_event(&mut self, event: Event, event_loop: &EventLoop) -> ControlFlow;
|
||||
}
|
||||
|
||||
impl<F> EventHandler for F
|
||||
where F: FnMut(Event, &EventLoop) -> ControlFlow
|
||||
{
|
||||
fn handle_event(&mut self, event: Event, event_loop: &EventLoop) -> ControlFlow {
|
||||
self(event, event_loop)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returned by the user callback given to the `EventLoop::run_forever` method.
|
||||
///
|
||||
/// Indicates whether the `run_forever` method should continue or complete.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
pub enum ControlFlow {
|
||||
/// Continue looping and waiting for events.
|
||||
Continue,
|
||||
/// Break from the event loop.
|
||||
Break,
|
||||
/// When the current loop iteration finishes, suspend the thread until another event arrives.
|
||||
Wait,
|
||||
/// When the current loop iteration finishes, suspend the thread until either another event
|
||||
/// arrives or the timeout expires.
|
||||
WaitTimeout(Duration),
|
||||
/// When the current loop iteration finishes, immediately begin a new iteration regardless of
|
||||
/// whether or not new events are available to process.
|
||||
Poll,
|
||||
/// Send a `LoopDestroyed` event and stop the event loop.
|
||||
Exit
|
||||
}
|
||||
|
||||
impl Default for ControlFlow {
|
||||
#[inline(always)]
|
||||
fn default() -> ControlFlow {
|
||||
ControlFlow::Poll
|
||||
}
|
||||
}
|
||||
|
||||
impl EventLoop {
|
||||
@@ -257,8 +233,10 @@ impl EventLoop {
|
||||
///
|
||||
/// Any values not passed to this function will *not* be dropped.
|
||||
#[inline]
|
||||
pub fn run_forever(self, event_handler: impl 'static + EventHandler) -> ! {
|
||||
self.events_loop.run_forever(event_handler)
|
||||
pub fn run<F>(self, event_handler: F) -> !
|
||||
where F: 'static + FnMut(Event, &EventLoop, &mut ControlFlow)
|
||||
{
|
||||
self.events_loop.run(event_handler)
|
||||
}
|
||||
|
||||
/// Creates an `EventLoopProxy` that can be used to wake up the `EventLoop` from another
|
||||
|
||||
@@ -19,6 +19,7 @@ use std::{mem, ptr};
|
||||
use std::cell::RefCell;
|
||||
use std::sync::Arc;
|
||||
use std::collections::VecDeque;
|
||||
use std::time::{Duration, Instant};
|
||||
use parking_lot::Mutex;
|
||||
|
||||
use winapi::ctypes::c_int;
|
||||
@@ -35,13 +36,12 @@ use winapi::shared::minwindef::{
|
||||
};
|
||||
use winapi::shared::windef::{HWND, POINT, RECT};
|
||||
use winapi::shared::windowsx;
|
||||
use winapi::um::{winuser, processthreadsapi, ole2, commctrl};
|
||||
use winapi::um::{winuser, winbase, processthreadsapi, ole2, commctrl};
|
||||
use winapi::um::winnt::{LONG, LPCSTR, SHORT};
|
||||
|
||||
use {
|
||||
ControlFlow,
|
||||
Event,
|
||||
EventHandler,
|
||||
EventLoopClosed,
|
||||
KeyboardInput,
|
||||
LogicalPosition,
|
||||
@@ -50,7 +50,7 @@ use {
|
||||
WindowEvent,
|
||||
WindowId as SuperWindowId,
|
||||
};
|
||||
use events::{DeviceEvent, Touch, TouchPhase};
|
||||
use events::{DeviceEvent, Touch, TouchPhase, StartCause};
|
||||
use platform::platform::{event, Cursor, WindowId, DEVICE_ID, wrap_device_id, util};
|
||||
use platform::platform::dpi::{
|
||||
become_dpi_aware,
|
||||
@@ -154,11 +154,16 @@ impl EventLoop {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run_forever(self, mut event_handler: impl 'static + EventHandler) -> ! {
|
||||
pub fn run<F>(self, mut event_handler: F) -> !
|
||||
where F: 'static + FnMut(Event, &::EventLoop, &mut ControlFlow)
|
||||
{
|
||||
let event_loop = ::EventLoop {
|
||||
events_loop: self,
|
||||
_marker: ::std::marker::PhantomData
|
||||
};
|
||||
let mut control_flow = ControlFlow::default();
|
||||
let mut timer_handle = 0;
|
||||
|
||||
unsafe {
|
||||
// Calling `PostThreadMessageA` on a thread that does not have an events queue yet
|
||||
// will fail. In order to avoid this situation, we call `IsGuiThread` to initialize
|
||||
@@ -168,44 +173,109 @@ impl EventLoop {
|
||||
let mut msg = mem::uninitialized();
|
||||
|
||||
'main: loop {
|
||||
if winuser::GetMessageW(&mut msg, ptr::null_mut(), 0, 0) == 0 {
|
||||
// Only happens if the message is `WM_QUIT`.
|
||||
debug_assert_eq!(msg.message, winuser::WM_QUIT);
|
||||
break 'main;
|
||||
}
|
||||
|
||||
match msg.message {
|
||||
x if x == *WAKEUP_MSG_ID => {
|
||||
if ControlFlow::Break == event_handler.handle_event(Event::Awakened, &event_loop) {
|
||||
macro_rules! call_event_handler {
|
||||
($event:expr) => {{
|
||||
event_handler($event, &event_loop, &mut control_flow);
|
||||
if ControlFlow::Exit == control_flow {
|
||||
break 'main;
|
||||
}
|
||||
},
|
||||
x if x == *EXEC_MSG_ID => {
|
||||
let mut function: Box<Box<FnMut()>> = Box::from_raw(msg.wParam as usize as *mut _);
|
||||
function()
|
||||
}
|
||||
_ => {
|
||||
// Calls `event_handler` below.
|
||||
winuser::TranslateMessage(&msg);
|
||||
winuser::DispatchMessageW(&msg);
|
||||
}
|
||||
}}
|
||||
}
|
||||
|
||||
loop {
|
||||
// For whatever reason doing this in a `whlie let` loop doesn't drop the `RefMut`,
|
||||
// so we have to do it like this.
|
||||
let event = match event_loop.events_loop.event_queue.borrow_mut().pop_front() {
|
||||
Some(event) => event,
|
||||
None => break
|
||||
};
|
||||
let mut has_message = true;
|
||||
let new_events_cause: StartCause;
|
||||
match control_flow {
|
||||
ControlFlow::Wait => {
|
||||
let wait_start = Instant::now();
|
||||
if winuser::GetMessageW(&mut msg, ptr::null_mut(), 0, 0) == 0 {
|
||||
// Only happens if the message is `WM_QUIT`.
|
||||
debug_assert_eq!(msg.message, winuser::WM_QUIT);
|
||||
break 'main;
|
||||
}
|
||||
new_events_cause =
|
||||
StartCause::WaitCancelled {
|
||||
start: wait_start,
|
||||
requested_duration: None
|
||||
};
|
||||
}
|
||||
ControlFlow::WaitTimeout(duration) => {
|
||||
let new_handle = winuser::SetTimer(ptr::null_mut(), timer_handle, dur2timeout(duration), None);
|
||||
if timer_handle == 0 {
|
||||
timer_handle = new_handle;
|
||||
}
|
||||
let wait_start = Instant::now();
|
||||
if winuser::GetMessageW(&mut msg, ptr::null_mut(), 0, 0) == 0 {
|
||||
// Only happens if the message is `WM_QUIT`.
|
||||
debug_assert_eq!(msg.message, winuser::WM_QUIT);
|
||||
break 'main;
|
||||
}
|
||||
if msg.message == winuser::WM_TIMER && msg.wParam == timer_handle {
|
||||
new_events_cause =
|
||||
StartCause::TimeoutExpired {
|
||||
start: wait_start,
|
||||
requested_duration: duration,
|
||||
};
|
||||
if 0 == winuser::PeekMessageW(&mut msg, ptr::null_mut(), 0, 0, 1) {
|
||||
has_message = false;
|
||||
}
|
||||
} else {
|
||||
new_events_cause =
|
||||
StartCause::WaitCancelled {
|
||||
start: wait_start,
|
||||
requested_duration: Some(duration)
|
||||
};
|
||||
}
|
||||
}
|
||||
ControlFlow::Poll => {
|
||||
if 0 == winuser::PeekMessageW(&mut msg, ptr::null_mut(), 0, 0, 1) {
|
||||
has_message = false;
|
||||
}
|
||||
new_events_cause = StartCause::Poll;
|
||||
}
|
||||
ControlFlow::Exit => break 'main
|
||||
}
|
||||
call_event_handler!(Event::NewEvents(new_events_cause));
|
||||
|
||||
if ControlFlow::Break == event_handler.handle_event(event, &event_loop) {
|
||||
break 'main;
|
||||
while has_message {
|
||||
match msg.message {
|
||||
x if x == *WAKEUP_MSG_ID => {
|
||||
call_event_handler!(Event::Awakened);
|
||||
},
|
||||
x if x == *EXEC_MSG_ID => {
|
||||
let mut function: Box<Box<FnMut()>> = Box::from_raw(msg.wParam as usize as *mut _);
|
||||
function()
|
||||
}
|
||||
_ => {
|
||||
// Calls `event_handler` below.
|
||||
winuser::TranslateMessage(&msg);
|
||||
winuser::DispatchMessageW(&msg);
|
||||
}
|
||||
}
|
||||
|
||||
loop {
|
||||
// For whatever reason doing this in a `whlie let` loop doesn't drop the `RefMut`,
|
||||
// so we have to do it like this.
|
||||
let event = match event_loop.events_loop.event_queue.borrow_mut().pop_front() {
|
||||
Some(event) => event,
|
||||
None => break
|
||||
};
|
||||
|
||||
call_event_handler!(event);
|
||||
}
|
||||
|
||||
if 0 == winuser::PeekMessageW(&mut msg, ptr::null_mut(), 0, 0, 1) {
|
||||
has_message = false;
|
||||
}
|
||||
}
|
||||
call_event_handler!(Event::EventsCleared);
|
||||
}
|
||||
|
||||
if timer_handle != 0 {
|
||||
winuser::KillTimer(ptr::null_mut(), timer_handle);
|
||||
}
|
||||
}
|
||||
|
||||
event_handler(Event::LoopDestroyed, &event_loop, &mut control_flow);
|
||||
drop(event_handler);
|
||||
::std::process::exit(0);
|
||||
}
|
||||
@@ -217,6 +287,28 @@ impl EventLoop {
|
||||
}
|
||||
}
|
||||
|
||||
// Implementation taken from https://github.com/rust-lang/rust/blob/db5476571d9b27c862b95c1e64764b0ac8980e23/src/libstd/sys/windows/mod.rs
|
||||
pub fn dur2timeout(dur: Duration) -> DWORD {
|
||||
// Note that a duration is a (u64, u32) (seconds, nanoseconds) pair, and the
|
||||
// timeouts in windows APIs are typically u32 milliseconds. To translate, we
|
||||
// have two pieces to take care of:
|
||||
//
|
||||
// * Nanosecond precision is rounded up
|
||||
// * Greater than u32::MAX milliseconds (50 days) is rounded up to INFINITE
|
||||
// (never time out).
|
||||
dur.as_secs().checked_mul(1000).and_then(|ms| {
|
||||
ms.checked_add((dur.subsec_nanos() as u64) / 1_000_000)
|
||||
}).and_then(|ms| {
|
||||
ms.checked_add(if dur.subsec_nanos() % 1_000_000 > 0 {1} else {0})
|
||||
}).map(|ms| {
|
||||
if ms > DWORD::max_value() as u64 {
|
||||
winbase::INFINITE
|
||||
} else {
|
||||
ms as DWORD
|
||||
}
|
||||
}).unwrap_or(winbase::INFINITE)
|
||||
}
|
||||
|
||||
impl Drop for EventLoop {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
|
||||
Reference in New Issue
Block a user