Skip to content

Commit d7c3ee7

Browse files
Osspialkosyak
authored and
kosyak
committed
Event Loop 2.0 API and Windows implementation (rust-windowing#638)
* Rename EventsLoop and associated types to EventLoop * Rename WindowEvent::Refresh to WindowEvent::Redraw * Remove second thread from win32 backend * Update run_forever to hijack thread * Replace windows Mutex with parking_lot Mutex * Implement new ControlFlow and associated events * Add StartCause::Init support, timer example * Add ability to send custom user events * Fully invert windows control flow so win32 calls into winit's callback * Add request_redraw * Rename platform to platform_impl * Rename os to platform, add Ext trait postfixes * Add platform::desktop module with EventLoopExt::run_return * Re-organize into module structure * Improve documentation * Small changes to examples * Improve docs for run and run_return * Change instances of "events_loop" to "event_loop" * Rename MonitorId to MonitorHandle * Add CHANGELOG entry * Improve WaitUntil timer precision * When SendEvent is called during event closure, buffer events * Fix resize lag when waiting in some situations * Update send test and errors that broke some examples/APIs * Improve clarity/fix typos in docs * Fix unreachable panic after setting ControlFlow to Poll during some RedrawRequested events. * Fix crash when running in release mode * Remove crossbeam dependency and make drop events work again * Remove serde implementations from ControlFlow * Fix 1.24.1 build * Fix freeze when setting decorations * Replace &EventLoop in callback with &EventLoopWindowTarget * Document and implement Debug for EventLoopWindowTarget * Fix some deadlocks that could occur when changing window state * Fix thread executor not executing closure when called from non-loop thread * Fix buffered events not getting dispatched * Fix crash with runner refcell not getting dropped * Address review feedback * Fix CHANGELOG typo * Catch panics in user callback
1 parent e5ab8e5 commit d7c3ee7

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

92 files changed

+3490
-1304
lines changed

CHANGELOG.md

+37-15
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,41 @@
11
# Unreleased
2-
3-
# Version 0.19.1 (2019-04-08)
4-
5-
- On Wayland, added a `get_wayland_display` function to `EventsLoopExt`.
6-
- On Windows, fix `CursorMoved(0, 0)` getting dispatched on window focus.
7-
- On macOS, fix command key event left and right reverse.
8-
- On FreeBSD, NetBSD, and OpenBSD, fix build of X11 backend.
9-
- On Windows, fix icon not showing up in corner of window.
10-
- On X11, change DPI scaling factor behavior. First, winit tries to read it from "Xft.dpi" XResource, and uses DPI calculation from xrandr dimensions as fallback behavior.
11-
12-
# Version 0.19.0 (2019-03-06)
13-
14-
- On X11, we will use the faster `XRRGetScreenResourcesCurrent` function instead of `XRRGetScreenResources` when available.
15-
- On macOS, fix keycodes being incorrect when using a non-US keyboard layout.
16-
- On Wayland, fix `with_title()` not setting the windows title
2+
- Changes below are considered **breaking**.
3+
- Change all occurrences of `EventsLoop` to `EventLoop`.
4+
- Previously flat API is now exposed through `event`, `event_loop`, `monitor`, and `window` modules.
5+
- `os` module changes:
6+
- Renamed to `platform`.
7+
- All traits now have platform-specific suffixes.
8+
- Exposes new `desktop` module on Windows, Mac, and Linux.
9+
- Changes to event loop types:
10+
- `EventLoopProxy::wakeup` has been removed in favor of `send_event`.
11+
- **Major:** New `run` method drives winit event loop.
12+
- Returns `!` to ensure API behaves identically across all supported platforms.
13+
- This allows `emscripten` implementation to work without lying about the API.
14+
- `ControlFlow`'s variants have been replaced with `Wait`, `WaitUntil(Instant)`, `Poll`, and `Exit`.
15+
- Is read after `EventsCleared` is processed.
16+
- `Wait` waits until new events are available.
17+
- `WaitUntil` waits until either new events are available or the provided time has been reached.
18+
- `Poll` instantly resumes the event loop.
19+
- `Exit` aborts the event loop.
20+
- Takes a closure that implements `'static + FnMut(Event<T>, &EventLoop<T>, &mut ControlFlow)`.
21+
- `&EventLoop<T>` is provided to allow new `Window`s to be created.
22+
- **Major:** `platform::desktop` module exposes `EventLoopExtDesktop` trait with `run_return` method.
23+
- Behaves identically to `run`, but returns control flow to the calling context and can take non-`'static` closures.
24+
- `EventLoop`'s `poll_events` and `run_forever` methods have been removed in favor of `run` and `run_return`.
25+
- Changes to events:
26+
- Remove `Event::Awakened` in favor of `Event::UserEvent(T)`.
27+
- Can be sent with `EventLoopProxy::send_event`.
28+
- Rename `WindowEvent::Refresh` to `WindowEvent::RedrawRequested`.
29+
- `RedrawRequested` can be sent by the user with the `Window::request_redraw` method.
30+
- `EventLoop`, `EventLoopProxy`, and `Event` are now generic over `T`, for use in `UserEvent`.
31+
- **Major:** Add `NewEvents(StartCause)`, `EventsCleared`, and `LoopDestroyed` variants to `Event`.
32+
- `NewEvents` is emitted when new events are ready to be processed by event loop.
33+
- `StartCause` describes why new events are available, with `ResumeTimeReached`, `Poll`, `WaitCancelled`, and `Init` (sent once at start of loop).
34+
- `EventsCleared` is emitted when all available events have been processed.
35+
- Can be used to perform logic that depends on all events being processed (e.g. an iteration of a game loop).
36+
- `LoopDestroyed` is emitted when the `run` or `run_return` method is about to exit.
37+
- Rename `MonitorId` to `MonitorHandle`.
38+
- Removed `serde` implementations from `ControlFlow`.
1739
- On Wayland, add `set_wayland_theme()` to control client decoration color theme
1840
- Added serde serialization to `os::unix::XWindowType`.
1941
- **Breaking:** `image` crate upgraded to 0.21. This is exposed as part of the `icon_loading` API.

Cargo.toml

+4
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ bitflags = "1"
4343
version = "0.3.6"
4444
features = [
4545
"combaseapi",
46+
"commctrl",
4647
"dwmapi",
4748
"errhandlingapi",
4849
"hidusage",
@@ -70,3 +71,6 @@ parking_lot = "0.7"
7071
percent-encoding = "1.0"
7172
gbm = { git = "https://github.com/kosyak/gbm.rs", default-features = false, features = ["drm-support", "import-egl", "gen"] }
7273
drm = { git = "https://github.com/kosyak/drm-rs", branch = "master" }
74+
75+
[target.'cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd", target_os = "windows"))'.dependencies.parking_lot]
76+
version = "0.7"

README.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,10 @@ another library.
3434
extern crate winit;
3535

3636
fn main() {
37-
let mut events_loop = winit::EventsLoop::new();
38-
let window = winit::Window::new(&events_loop).unwrap();
37+
let mut event_loop = winit::EventLoop::new();
38+
let window = winit::Window::new(&event_loop).unwrap();
3939

40-
events_loop.run_forever(|event| {
40+
event_loop.run(|event| {
4141
match event {
4242
winit::Event::WindowEvent {
4343
event: winit::WindowEvent::CloseRequested,

examples/cursor.rs

+26-10
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,48 @@
11
extern crate winit;
22

3-
use winit::{Event, ElementState, MouseCursor, WindowEvent, KeyboardInput, ControlFlow};
3+
use winit::window::{WindowBuilder, MouseCursor};
4+
use winit::event::{Event, WindowEvent, ElementState, KeyboardInput};
5+
use winit::event_loop::{EventLoop, ControlFlow};
46

57
fn main() {
6-
let mut events_loop = winit::EventsLoop::new();
8+
let event_loop = EventLoop::new();
79

8-
let window = winit::WindowBuilder::new().build(&events_loop).unwrap();
10+
let window = WindowBuilder::new().build(&event_loop).unwrap();
911
window.set_title("A fantastic window!");
1012

11-
let cursors = [MouseCursor::Default, MouseCursor::Crosshair, MouseCursor::Hand, MouseCursor::Arrow, MouseCursor::Move, MouseCursor::Text, MouseCursor::Wait, MouseCursor::Help, MouseCursor::Progress, MouseCursor::NotAllowed, MouseCursor::ContextMenu, MouseCursor::Cell, MouseCursor::VerticalText, MouseCursor::Alias, MouseCursor::Copy, MouseCursor::NoDrop, MouseCursor::Grab, MouseCursor::Grabbing, MouseCursor::AllScroll, MouseCursor::ZoomIn, MouseCursor::ZoomOut, MouseCursor::EResize, MouseCursor::NResize, MouseCursor::NeResize, MouseCursor::NwResize, MouseCursor::SResize, MouseCursor::SeResize, MouseCursor::SwResize, MouseCursor::WResize, MouseCursor::EwResize, MouseCursor::NsResize, MouseCursor::NeswResize, MouseCursor::NwseResize, MouseCursor::ColResize, MouseCursor::RowResize];
1213
let mut cursor_idx = 0;
1314

14-
events_loop.run_forever(|event| {
15+
event_loop.run(move |event, _, control_flow| {
1516
match event {
1617
Event::WindowEvent { event: WindowEvent::KeyboardInput { input: KeyboardInput { state: ElementState::Pressed, .. }, .. }, .. } => {
17-
println!("Setting cursor to \"{:?}\"", cursors[cursor_idx]);
18-
window.set_cursor(cursors[cursor_idx]);
19-
if cursor_idx < cursors.len() - 1 {
18+
println!("Setting cursor to \"{:?}\"", CURSORS[cursor_idx]);
19+
window.set_cursor(CURSORS[cursor_idx]);
20+
if cursor_idx < CURSORS.len() - 1 {
2021
cursor_idx += 1;
2122
} else {
2223
cursor_idx = 0;
2324
}
2425
},
2526
Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => {
26-
return ControlFlow::Break;
27+
*control_flow = ControlFlow::Exit;
28+
return;
2729
},
2830
_ => ()
2931
}
30-
ControlFlow::Continue
3132
});
3233
}
34+
35+
const CURSORS: &[MouseCursor] = &[
36+
MouseCursor::Default, MouseCursor::Crosshair, MouseCursor::Hand,
37+
MouseCursor::Arrow, MouseCursor::Move, MouseCursor::Text,
38+
MouseCursor::Wait, MouseCursor::Help, MouseCursor::Progress,
39+
MouseCursor::NotAllowed, MouseCursor::ContextMenu, MouseCursor::Cell,
40+
MouseCursor::VerticalText, MouseCursor::Alias, MouseCursor::Copy,
41+
MouseCursor::NoDrop, MouseCursor::Grab, MouseCursor::Grabbing,
42+
MouseCursor::AllScroll, MouseCursor::ZoomIn, MouseCursor::ZoomOut,
43+
MouseCursor::EResize, MouseCursor::NResize, MouseCursor::NeResize,
44+
MouseCursor::NwResize, MouseCursor::SResize, MouseCursor::SeResize,
45+
MouseCursor::SwResize, MouseCursor::WResize, MouseCursor::EwResize,
46+
MouseCursor::NsResize, MouseCursor::NeswResize, MouseCursor::NwseResize,
47+
MouseCursor::ColResize, MouseCursor::RowResize
48+
];

examples/cursor_grab.rs

+16-13
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,34 @@
11
extern crate winit;
22

3+
use winit::window::WindowBuilder;
4+
use winit::event::{Event, WindowEvent, ElementState, KeyboardInput};
5+
use winit::event_loop::{EventLoop, ControlFlow};
6+
37
fn main() {
4-
let mut events_loop = winit::EventsLoop::new();
8+
let event_loop = EventLoop::new();
59

6-
let window = winit::WindowBuilder::new()
10+
let window = WindowBuilder::new()
711
.with_title("Super Cursor Grab'n'Hide Simulator 9000")
8-
.build(&events_loop)
12+
.build(&event_loop)
913
.unwrap();
1014

11-
events_loop.run_forever(|event| {
12-
if let winit::Event::WindowEvent { event, .. } = event {
13-
use winit::WindowEvent::*;
15+
event_loop.run(move |event, _, control_flow| {
16+
*control_flow = ControlFlow::Wait;
17+
if let Event::WindowEvent { event, .. } = event {
1418
match event {
15-
CloseRequested => return winit::ControlFlow::Break,
16-
KeyboardInput {
17-
input: winit::KeyboardInput {
18-
state: winit::ElementState::Released,
19+
WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit,
20+
WindowEvent::KeyboardInput {
21+
input: KeyboardInput {
22+
state: ElementState::Released,
1923
virtual_keycode: Some(key),
2024
modifiers,
2125
..
2226
},
2327
..
2428
} => {
25-
use winit::VirtualKeyCode::*;
29+
use winit::event::VirtualKeyCode::*;
2630
match key {
27-
Escape => return winit::ControlFlow::Break,
31+
Escape => *control_flow = ControlFlow::Exit,
2832
G => window.grab_cursor(!modifiers.shift).unwrap(),
2933
H => window.hide_cursor(!modifiers.shift),
3034
_ => (),
@@ -33,6 +37,5 @@ fn main() {
3337
_ => (),
3438
}
3539
}
36-
winit::ControlFlow::Continue
3740
});
3841
}

examples/fullscreen.rs

+20-18
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
extern crate winit;
22

33
use std::io::{self, Write};
4-
use winit::{ControlFlow, Event, WindowEvent};
4+
use winit::monitor::MonitorHandle;
5+
use winit::window::WindowBuilder;
6+
use winit::event::{Event, WindowEvent, VirtualKeyCode, ElementState, KeyboardInput};
7+
use winit::event_loop::{EventLoop, ControlFlow};
58

69
fn main() {
7-
let mut events_loop = winit::EventsLoop::new();
10+
let event_loop = EventLoop::new();
811

912
#[cfg(target_os = "macos")]
1013
let mut macos_use_simple_fullscreen = false;
@@ -26,43 +29,44 @@ fn main() {
2629

2730
// Prompt for monitor when using native fullscreen
2831
if !macos_use_simple_fullscreen {
29-
Some(prompt_for_monitor(&events_loop))
32+
Some(prompt_for_monitor(&event_loop))
3033
} else {
3134
None
3235
}
3336
}
3437

3538
#[cfg(not(target_os = "macos"))]
36-
Some(prompt_for_monitor(&events_loop))
39+
Some(prompt_for_monitor(&event_loop))
3740
};
3841

3942
let mut is_fullscreen = monitor.is_some();
4043
let mut is_maximized = false;
4144
let mut decorations = true;
4245

43-
let window = winit::WindowBuilder::new()
46+
let window = WindowBuilder::new()
4447
.with_title("Hello world!")
4548
.with_fullscreen(monitor)
46-
.build(&events_loop)
49+
.build(&event_loop)
4750
.unwrap();
4851

49-
events_loop.run_forever(|event| {
52+
event_loop.run(move |event, _, control_flow| {
5053
println!("{:?}", event);
54+
*control_flow = ControlFlow::Wait;
5155

5256
match event {
5357
Event::WindowEvent { event, .. } => match event {
54-
WindowEvent::CloseRequested => return ControlFlow::Break,
58+
WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit,
5559
WindowEvent::KeyboardInput {
5660
input:
57-
winit::KeyboardInput {
61+
KeyboardInput {
5862
virtual_keycode: Some(virtual_code),
5963
state,
6064
..
6165
},
6266
..
6367
} => match (virtual_code, state) {
64-
(winit::VirtualKeyCode::Escape, _) => return ControlFlow::Break,
65-
(winit::VirtualKeyCode::F, winit::ElementState::Pressed) => {
68+
(VirtualKeyCode::Escape, _) => *control_flow = ControlFlow::Exit,
69+
(VirtualKeyCode::F, ElementState::Pressed) => {
6670
#[cfg(target_os = "macos")]
6771
{
6872
if macos_use_simple_fullscreen {
@@ -82,11 +86,11 @@ fn main() {
8286
window.set_fullscreen(Some(window.get_current_monitor()));
8387
}
8488
}
85-
(winit::VirtualKeyCode::M, winit::ElementState::Pressed) => {
89+
(VirtualKeyCode::M, ElementState::Pressed) => {
8690
is_maximized = !is_maximized;
8791
window.set_maximized(is_maximized);
8892
}
89-
(winit::VirtualKeyCode::D, winit::ElementState::Pressed) => {
93+
(VirtualKeyCode::D, ElementState::Pressed) => {
9094
decorations = !decorations;
9195
window.set_decorations(decorations);
9296
}
@@ -96,14 +100,12 @@ fn main() {
96100
},
97101
_ => {}
98102
}
99-
100-
ControlFlow::Continue
101103
});
102104
}
103105

104106
// Enumerate monitors and prompt user to choose one
105-
fn prompt_for_monitor(events_loop: &winit::EventsLoop) -> winit::MonitorId {
106-
for (num, monitor) in events_loop.get_available_monitors().enumerate() {
107+
fn prompt_for_monitor(event_loop: &EventLoop<()>) -> MonitorHandle {
108+
for (num, monitor) in event_loop.get_available_monitors().enumerate() {
107109
println!("Monitor #{}: {:?}", num, monitor.get_name());
108110
}
109111

@@ -113,7 +115,7 @@ fn prompt_for_monitor(events_loop: &winit::EventsLoop) -> winit::MonitorId {
113115
let mut num = String::new();
114116
io::stdin().read_line(&mut num).unwrap();
115117
let num = num.trim().parse().ok().expect("Please enter a number");
116-
let monitor = events_loop.get_available_monitors().nth(num).expect("Please enter a valid ID");
118+
let monitor = event_loop.get_available_monitors().nth(num).expect("Please enter a valid ID");
117119

118120
println!("Using {:?}", monitor.get_name());
119121

examples/handling_close.rs

+16-14
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,27 @@
11
extern crate winit;
22

3+
use winit::window::WindowBuilder;
4+
use winit::event::{Event, WindowEvent, KeyboardInput};
5+
use winit::event_loop::{EventLoop, ControlFlow};
6+
37
fn main() {
4-
let mut events_loop = winit::EventsLoop::new();
8+
let event_loop = EventLoop::new();
59

6-
let _window = winit::WindowBuilder::new()
10+
let _window = WindowBuilder::new()
711
.with_title("Your faithful window")
8-
.build(&events_loop)
12+
.build(&event_loop)
913
.unwrap();
1014

1115
let mut close_requested = false;
1216

13-
events_loop.run_forever(|event| {
14-
use winit::WindowEvent::*;
15-
use winit::ElementState::Released;
16-
use winit::VirtualKeyCode::{N, Y};
17+
event_loop.run(move |event, _, control_flow| {
18+
use winit::event::ElementState::Released;
19+
use winit::event::VirtualKeyCode::{N, Y};
20+
*control_flow = ControlFlow::Wait;
1721

1822
match event {
19-
winit::Event::WindowEvent { event, .. } => match event {
20-
CloseRequested => {
23+
Event::WindowEvent { event, .. } => match event {
24+
WindowEvent::CloseRequested => {
2125
// `CloseRequested` is sent when the close button on the window is pressed (or
2226
// through whatever other mechanisms the window manager provides for closing a
2327
// window). If you don't handle this event, the close button won't actually do
@@ -34,9 +38,9 @@ fn main() {
3438
// closing the window. How to close the window is detailed in the handler for
3539
// the Y key.
3640
}
37-
KeyboardInput {
41+
WindowEvent::KeyboardInput {
3842
input:
39-
winit::KeyboardInput {
43+
KeyboardInput {
4044
virtual_keycode: Some(virtual_code),
4145
state: Released,
4246
..
@@ -53,7 +57,7 @@ fn main() {
5357
// event loop (i.e. if it's a multi-window application), you need to
5458
// drop the window. That closes it, and results in `Destroyed` being
5559
// sent.
56-
return winit::ControlFlow::Break;
60+
*control_flow = ControlFlow::Exit;
5761
}
5862
}
5963
N => {
@@ -68,7 +72,5 @@ fn main() {
6872
},
6973
_ => (),
7074
}
71-
72-
winit::ControlFlow::Continue
7375
});
7476
}

0 commit comments

Comments
 (0)