Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Event Loop 2.0 API and Windows implementation #638

Merged
merged 41 commits into from
Feb 5, 2019
Merged
Show file tree
Hide file tree
Changes from 30 commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
529c085
Rename EventsLoop and associated types to EventLoop
Osspial Jul 13, 2018
64b8a9c
Rename WindowEvent::Refresh to WindowEvent::Redraw
Osspial Jul 13, 2018
2e83bac
Remove second thread from win32 backend
Osspial Jul 13, 2018
9feada2
Update run_forever to hijack thread
Osspial Jul 13, 2018
8b8a767
Replace windows Mutex with parking_lot Mutex
Osspial Jul 13, 2018
02f922f
Implement new ControlFlow and associated events
Osspial Aug 17, 2018
a0b2bb3
Add StartCause::Init support, timer example
Osspial Aug 17, 2018
2c607ff
Add ability to send custom user events
Osspial Aug 19, 2018
a0fef1a
Fully invert windows control flow so win32 calls into winit's callback
Osspial Aug 20, 2018
99c0f84
Add request_redraw
Osspial Aug 22, 2018
7df59c6
Rename platform to platform_impl
Osspial Aug 22, 2018
dad24d0
Rename os to platform, add Ext trait postfixes
Osspial Aug 22, 2018
f20fac9
Add platform::desktop module with EventLoopExt::run_return
Osspial Aug 23, 2018
4377680
Re-organize into module structure
Osspial Aug 23, 2018
42e8a0d
Improve documentation
Osspial Aug 23, 2018
fba41f7
Small changes to examples
Osspial Aug 23, 2018
0f34408
Improve docs for run and run_return
Osspial Aug 24, 2018
8d8d9b7
Change instances of "events_loop" to "event_loop"
Osspial Aug 24, 2018
deb7d37
Rename MonitorId to MonitorHandle
Osspial Aug 24, 2018
a654400
Add CHANGELOG entry
Osspial Aug 24, 2018
5337092
Improve WaitUntil timer precision
Osspial Aug 27, 2018
70722cc
When SendEvent is called during event closure, buffer events
Osspial Sep 6, 2018
bf7bfa8
Fix resize lag when waiting in some situations
Osspial Sep 6, 2018
8ed575f
Update send test and errors that broke some examples/APIs
Osspial Sep 9, 2018
5068ff4
Improve clarity/fix typos in docs
Osspial Sep 9, 2018
bb6ab1b
Fix unreachable panic after setting ControlFlow to Poll during some R…
Osspial Sep 9, 2018
8299eb2
Fix crash when running in release mode
Osspial Sep 14, 2018
92ac3d6
Remove crossbeam dependency and make drop events work again
Osspial Nov 9, 2018
5289d22
Remove serde implementations from ControlFlow
Osspial Nov 9, 2018
d9c3dac
Fix 1.24.1 build
Osspial Nov 10, 2018
9f36a7a
Fix freeze when setting decorations
Osspial Nov 15, 2018
fa46825
Replace &EventLoop in callback with &EventLoopWindowTarget
Osspial Nov 15, 2018
2a3cefd
Document and implement Debug for EventLoopWindowTarget
Osspial Nov 15, 2018
5a3a5e2
Fix some deadlocks that could occur when changing window state
Osspial Nov 16, 2018
2c18b80
Fix thread executor not executing closure when called from non-loop t…
Osspial Nov 18, 2018
54ce6a2
Fix buffered events not getting dispatched
Osspial Nov 19, 2018
8269ed2
Fix crash with runner refcell not getting dropped
Osspial Nov 20, 2018
48a2526
Address review feedback
Osspial Dec 21, 2018
b92d043
Fix CHANGELOG typo
Osspial Jan 1, 2019
9336755
Merge branch 'master' into events_loop_2.0
Osspial Feb 4, 2019
7cb081c
Catch panics in user callback
Osspial Feb 4, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,41 @@
# Unreleased
- Changes below are considered **breaking**.
- Change all occurrences of `EventsLoop` to `EventLoop`.
- Previously flat API is now exposed through `event`, `event_loop`, `monitor`, and `window` modules.
- `os` module changes:
- Renamed to `platform`.
- All traits now have platform-specific suffixes.
- Exposes new `desktop` module on Windows, Mac, and Linux.
- Changes to event loop types:
- `EventLoopProxy::wakeup` has been removed in favor of `send_event`.
- **Major:** New `run` method drives winit event loop.
- Returns `!` to ensure API behaves identically across all supported platforms.
- This allows `emscripten` implementation to work without lying about the API.
- `ControlFlow`'s variants have been replaced with `Wait`, `WaitUntil(Instant)`, `Poll`, and `Exit`.
- Is read after `EventsCleared` is processed.
- `Wait` waits until new events are available.
- `WaitUntil` waits until either new events are available or the provided time has been reached.
- `Poll` instantly resumes the event loop.
- `Exit` aborts the event loop.
- Takes a closure that implements `'static + FnMut(Event<T>, &EventLoop<T>, &mut ControlFlow)`.
- `&EventLoop<T>` is provided to allow new `Window`s to be created.
- **Major:** `platform::desktop` module exposes `EventLoopExtDesktop` trait with `run_return` method.
- Behaves identically to `run`, but returns control flow to the calling context can take non-`'static` closures.
- `EventLoop`'s `poll_events` and `run_forever` methods have been removed in favor of `run` and `run_return`.
- Changes to events:
- Remove `Event::Awakened` in favor of `Event::UserEvent(T)`.
- Can be sent with `EventLoopProxy::send_event`.
- Rename `WindowEvent::Refresh` to `WindowEvent::RedrawRequested`.
- `RedrawRequested` can be sent by the user with the `Window::request_redraw` method.
- `EventLoop`, `EventLoopProxy`, and `Event` are now generic over `T`, for use in `UserEvent`.
- **Major:** Add `NewEvents(StartCause)`, `EventsCleared`, and `LoopDestroyed` variants to `Event`.
- `NewEvents` is emitted when new events are ready to be processed by event loop.
- `StartCause` describes why new events are available, with `ResumeTimeReached`, `Poll`, `WaitCancelled`, and `Init` (sent once at start of loop).
- `EventsCleared` is emitted when all available events have been processed.
- Can be used to perform logic that depends on all events being processed (e.g. an iteration of a game loop).
- `LoopDestroyed` is emitted when the `run` or `run_return` method is about to exit.
- Rename `MonitorId` to `MonitorHandle`.
- Removed `serde` implementations from `ControlFlow`.

# Version 0.18.0 (2018-11-07)

Expand Down
5 changes: 4 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ core-graphics = "0.17.3"
version = "0.3.6"
features = [
"combaseapi",
"commctrl",
"dwmapi",
"errhandlingapi",
"hidusage",
Expand All @@ -62,5 +63,7 @@ features = [
wayland-client = { version = "0.21", features = [ "dlopen", "egl", "cursor"] }
smithay-client-toolkit = "0.4"
x11-dl = "2.18.3"
parking_lot = "0.6"
percent-encoding = "1.0"

[target.'cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd", target_os = "windows"))'.dependencies.parking_lot]
version = "0.6"
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@ another library.
extern crate winit;

fn main() {
let mut events_loop = winit::EventsLoop::new();
let window = winit::Window::new(&events_loop).unwrap();
let mut event_loop = winit::EventLoop::new();
let window = winit::Window::new(&event_loop).unwrap();

events_loop.run_forever(|event| {
event_loop.run(|event| {
match event {
winit::Event::WindowEvent {
event: winit::WindowEvent::CloseRequested,
Expand Down
36 changes: 26 additions & 10 deletions examples/cursor.rs
Original file line number Diff line number Diff line change
@@ -1,32 +1,48 @@
extern crate winit;

use winit::{Event, ElementState, MouseCursor, WindowEvent, KeyboardInput, ControlFlow};
use winit::window::{WindowBuilder, MouseCursor};
use winit::event::{Event, WindowEvent, ElementState, KeyboardInput};
use winit::event_loop::{EventLoop, ControlFlow};

fn main() {
let mut events_loop = winit::EventsLoop::new();
let event_loop = EventLoop::new();

let window = winit::WindowBuilder::new().build(&events_loop).unwrap();
let window = WindowBuilder::new().build(&event_loop).unwrap();
window.set_title("A fantastic window!");

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];
let mut cursor_idx = 0;

events_loop.run_forever(|event| {
event_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]);
window.set_cursor(cursors[cursor_idx]);
if cursor_idx < cursors.len() - 1 {
println!("Setting cursor to \"{:?}\"", CURSORS[cursor_idx]);
window.set_cursor(CURSORS[cursor_idx]);
if cursor_idx < CURSORS.len() - 1 {
cursor_idx += 1;
} else {
cursor_idx = 0;
}
},
Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => {
return ControlFlow::Break;
*control_flow = ControlFlow::Exit;
return;
},
_ => ()
}
ControlFlow::Continue
});
}

const CURSORS: &[MouseCursor] = &[
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
];
29 changes: 16 additions & 13 deletions examples/cursor_grab.rs
Original file line number Diff line number Diff line change
@@ -1,30 +1,34 @@
extern crate winit;

use winit::window::WindowBuilder;
use winit::event::{Event, WindowEvent, ElementState, KeyboardInput};
use winit::event_loop::{EventLoop, ControlFlow};

fn main() {
let mut events_loop = winit::EventsLoop::new();
let event_loop = EventLoop::new();

let window = winit::WindowBuilder::new()
let window = WindowBuilder::new()
.with_title("Super Cursor Grab'n'Hide Simulator 9000")
.build(&events_loop)
.build(&event_loop)
.unwrap();

events_loop.run_forever(|event| {
if let winit::Event::WindowEvent { event, .. } = event {
use winit::WindowEvent::*;
event_loop.run(move |event, _, control_flow| {
*control_flow = ControlFlow::Wait;
if let Event::WindowEvent { event, .. } = event {
match event {
CloseRequested => return winit::ControlFlow::Break,
KeyboardInput {
input: winit::KeyboardInput {
state: winit::ElementState::Released,
WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit,
WindowEvent::KeyboardInput {
input: KeyboardInput {
state: ElementState::Released,
virtual_keycode: Some(key),
modifiers,
..
},
..
} => {
use winit::VirtualKeyCode::*;
use winit::event::VirtualKeyCode::*;
match key {
Escape => return winit::ControlFlow::Break,
Escape => *control_flow = ControlFlow::Exit,
G => window.grab_cursor(!modifiers.shift).unwrap(),
H => window.hide_cursor(!modifiers.shift),
_ => (),
Expand All @@ -33,6 +37,5 @@ fn main() {
_ => (),
}
}
winit::ControlFlow::Continue
});
}
31 changes: 16 additions & 15 deletions examples/fullscreen.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
extern crate winit;

use std::io::{self, Write};
use winit::{ControlFlow, Event, WindowEvent};
use winit::window::WindowBuilder;
use winit::event::{Event, WindowEvent, VirtualKeyCode, ElementState, KeyboardInput};
use winit::event_loop::{EventLoop, ControlFlow};

fn main() {
let mut events_loop = winit::EventsLoop::new();
let event_loop = EventLoop::new();

// enumerating monitors
let monitor = {
for (num, monitor) in events_loop.get_available_monitors().enumerate() {
for (num, monitor) in event_loop.get_available_monitors().enumerate() {
println!("Monitor #{}: {:?}", num, monitor.get_name());
}

Expand All @@ -18,52 +20,53 @@ fn main() {
let mut num = String::new();
io::stdin().read_line(&mut num).unwrap();
let num = num.trim().parse().ok().expect("Please enter a number");
let monitor = events_loop.get_available_monitors().nth(num).expect("Please enter a valid ID");
let monitor = event_loop.get_available_monitors().nth(num).expect("Please enter a valid ID");

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

monitor
};

let window = winit::WindowBuilder::new()
let window = WindowBuilder::new()
.with_title("Hello world!")
.with_fullscreen(Some(monitor))
.build(&events_loop)
.build(&event_loop)
.unwrap();

let mut is_fullscreen = true;
let mut is_maximized = false;
let mut decorations = true;

events_loop.run_forever(|event| {
event_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 {
KeyboardInput {
virtual_keycode: Some(virtual_code),
state,
..
},
..
} => match (virtual_code, state) {
(winit::VirtualKeyCode::Escape, _) => return ControlFlow::Break,
(winit::VirtualKeyCode::F, winit::ElementState::Pressed) => {
(VirtualKeyCode::Escape, _) => *control_flow = ControlFlow::Exit,
(VirtualKeyCode::F, ElementState::Pressed) => {
is_fullscreen = !is_fullscreen;
if !is_fullscreen {
window.set_fullscreen(None);
} else {
window.set_fullscreen(Some(window.get_current_monitor()));
}
}
(winit::VirtualKeyCode::M, winit::ElementState::Pressed) => {
(VirtualKeyCode::M, ElementState::Pressed) => {
is_maximized = !is_maximized;
window.set_maximized(is_maximized);
}
(winit::VirtualKeyCode::D, winit::ElementState::Pressed) => {
(VirtualKeyCode::D, ElementState::Pressed) => {
decorations = !decorations;
window.set_decorations(decorations);
}
Expand All @@ -73,7 +76,5 @@ fn main() {
},
_ => {}
}

ControlFlow::Continue
});
}
30 changes: 16 additions & 14 deletions examples/handling_close.rs
Original file line number Diff line number Diff line change
@@ -1,23 +1,27 @@
extern crate winit;

use winit::window::WindowBuilder;
use winit::event::{Event, WindowEvent, KeyboardInput};
use winit::event_loop::{EventLoop, ControlFlow};

fn main() {
let mut events_loop = winit::EventsLoop::new();
let event_loop = EventLoop::new();

let _window = winit::WindowBuilder::new()
let _window = WindowBuilder::new()
.with_title("Your faithful window")
.build(&events_loop)
.build(&event_loop)
.unwrap();

let mut close_requested = false;

events_loop.run_forever(|event| {
use winit::WindowEvent::*;
use winit::ElementState::Released;
use winit::VirtualKeyCode::{N, Y};
event_loop.run(move |event, _, control_flow| {
use winit::event::ElementState::Released;
use winit::event::VirtualKeyCode::{N, Y};
*control_flow = ControlFlow::Wait;

match event {
winit::Event::WindowEvent { event, .. } => match event {
CloseRequested => {
Event::WindowEvent { event, .. } => match event {
WindowEvent::CloseRequested => {
// `CloseRequested` is sent when the close button on the window is pressed (or
// through whatever other mechanisms the window manager provides for closing a
// window). If you don't handle this event, the close button won't actually do
Expand All @@ -34,9 +38,9 @@ fn main() {
// closing the window. How to close the window is detailed in the handler for
// the Y key.
}
KeyboardInput {
WindowEvent::KeyboardInput {
input:
winit::KeyboardInput {
KeyboardInput {
virtual_keycode: Some(virtual_code),
state: Released,
..
Expand All @@ -53,7 +57,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 = ControlFlow::Exit;
}
}
N => {
Expand All @@ -68,7 +72,5 @@ fn main() {
},
_ => (),
}

winit::ControlFlow::Continue
});
}
16 changes: 10 additions & 6 deletions examples/min_max_size.rs
Original file line number Diff line number Diff line change
@@ -1,23 +1,27 @@
extern crate winit;

use winit::dpi::LogicalSize;
use winit::window::WindowBuilder;
use winit::event::{Event, WindowEvent};
use winit::event_loop::{EventLoop, ControlFlow};

fn main() {
let mut events_loop = winit::EventsLoop::new();
let event_loop = EventLoop::new();

let window = winit::WindowBuilder::new()
.build(&events_loop)
let window = WindowBuilder::new()
.build(&event_loop)
.unwrap();

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(|event| {
event_loop.run(move |event, _, control_flow| {
println!("{:?}", event);

match event {
winit::Event::WindowEvent { event: winit::WindowEvent::CloseRequested, .. } => winit::ControlFlow::Break,
_ => winit::ControlFlow::Continue,
Event::WindowEvent { event: WindowEvent::CloseRequested, .. } =>
*control_flow = ControlFlow::Exit,
_ => *control_flow = ControlFlow::Wait,
}
});
}
6 changes: 4 additions & 2 deletions examples/monitor_list.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
extern crate winit;
use winit::event_loop::EventLoop;
use winit::window::WindowBuilder;

fn main() {
let event_loop = winit::EventsLoop::new();
let window = winit::WindowBuilder::new().build(&event_loop).unwrap();
let event_loop = EventLoop::new();
let window = WindowBuilder::new().build(&event_loop).unwrap();
println!("{:#?}\nPrimary: {:#?}", window.get_available_monitors(), window.get_primary_monitor());
}
Loading