Merge pull request #2 from ModProg/winit-beta

winit 0.29
This commit is contained in:
Jonathan Johnson 2023-09-02 09:14:14 -07:00 committed by GitHub
commit 0503b3d466
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 546 additions and 263 deletions

654
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -5,5 +5,5 @@ edition = "2021"
[dependencies] [dependencies]
winit = "0.28.6" winit = "0.29.1-beta"
raw-window-handle = "0.5.1" raw-window-handle = "0.5.1"

View file

@ -2,6 +2,7 @@
#![warn(missing_docs, clippy::pedantic)] #![warn(missing_docs, clippy::pedantic)]
#![deny(unsafe_code)] #![deny(unsafe_code)]
#![allow(clippy::module_name_repetitions)] #![allow(clippy::module_name_repetitions)]
#![allow(clippy::missing_panics_doc)] // https://github.com/rust-lang/rust-clippy/issues/11436
mod private; mod private;
mod window; mod window;
@ -11,7 +12,7 @@ pub use winit;
use raw_window_handle::HasRawWindowHandle; use raw_window_handle::HasRawWindowHandle;
pub use window::{RunningWindow, Window, WindowAttributes, WindowBehavior, WindowBuilder}; pub use window::{RunningWindow, Window, WindowAttributes, WindowBehavior, WindowBuilder};
use winit::error::OsError; use winit::error::{EventLoopError, OsError};
use winit::window::WindowId; use winit::window::WindowId;
use std::collections::HashMap; use std::collections::HashMap;
@ -64,7 +65,9 @@ where
event_callback: impl FnMut(AppMessage, &Windows<AppMessage::Window>) -> AppMessage::Response event_callback: impl FnMut(AppMessage, &Windows<AppMessage::Window>) -> AppMessage::Response
+ 'static, + 'static,
) -> Self { ) -> Self {
let event_loop = EventLoopBuilder::with_user_event().build(); let event_loop = EventLoopBuilder::with_user_event()
.build()
.expect("should be able to create an EventLoop");
let proxy = event_loop.create_proxy(); let proxy = event_loop.create_proxy();
Self { Self {
event_loop, event_loop,
@ -76,10 +79,15 @@ where
} }
} }
/// Begins running the application. This function will never return. /// Begins running the application.
/// ///
/// Internally this runs the [`EventLoop`]. /// Internally this runs the [`EventLoop`].
pub fn run(mut self) -> ! { ///
/// # Errors
///
/// Returns an [`EventLoopError`] upon the loop exiting due to an error. See
/// [`EventLoop::run`] for more information.
pub fn run(mut self) -> Result<(), EventLoopError> {
self.event_loop.run(move |event, target, control_flow| { self.event_loop.run(move |event, target, control_flow| {
*control_flow = ControlFlow::Wait; *control_flow = ControlFlow::Wait;
match event { match event {
@ -123,11 +131,10 @@ where
| Event::DeviceEvent { .. } | Event::DeviceEvent { .. }
| Event::Suspended | Event::Suspended
| Event::Resumed | Event::Resumed
| Event::MainEventsCleared | Event::LoopExiting
| Event::RedrawEventsCleared | Event::AboutToWait => {}
| Event::LoopDestroyed => {}
} }
}); })
} }
} }

View file

@ -4,10 +4,11 @@ use std::sync::{mpsc, Arc};
use winit::dpi::{PhysicalPosition, PhysicalSize}; use winit::dpi::{PhysicalPosition, PhysicalSize};
use winit::error::OsError; use winit::error::OsError;
use winit::event::{ use winit::event::{
AxisId, DeviceId, ElementState, Ime, KeyboardInput, ModifiersState, MouseButton, AxisId, DeviceId, ElementState, Ime, KeyEvent, Modifiers, MouseButton, MouseScrollDelta, Touch,
MouseScrollDelta, Touch, TouchPhase, TouchPhase,
}; };
use winit::window::{Theme, WindowId}; use winit::event_loop::AsyncRequestSerial;
use winit::window::{ActivationToken, Theme, WindowId};
use crate::window::WindowAttributes; use crate::window::WindowAttributes;
use crate::Message; use crate::Message;
@ -96,7 +97,7 @@ pub enum WindowEvent {
/// An event from the keyboard has been received. /// An event from the keyboard has been received.
KeyboardInput { KeyboardInput {
device_id: DeviceId, device_id: DeviceId,
input: KeyboardInput, event: KeyEvent,
/// If `true`, the event was generated synthetically by winit /// If `true`, the event was generated synthetically by winit
/// in one of the following circumstances: /// in one of the following circumstances:
/// ///
@ -115,7 +116,7 @@ pub enum WindowEvent {
/// ///
/// - **Web:** This API is currently unimplemented on the web. This isn't by design - it's an /// - **Web:** This API is currently unimplemented on the web. This isn't by design - it's an
/// issue, and it should get fixed - but it's the current state of the API. /// issue, and it should get fixed - but it's the current state of the API.
ModifiersChanged(ModifiersState), ModifiersChanged(Modifiers),
/// An event from an input method. /// An event from an input method.
/// ///
@ -196,7 +197,6 @@ pub enum WindowEvent {
/// For more information about DPI in general, see the [`dpi`](crate::dpi) module. /// For more information about DPI in general, see the [`dpi`](crate::dpi) module.
ScaleFactorChanged { ScaleFactorChanged {
scale_factor: f64, scale_factor: f64,
new_inner_size: PhysicalSize<u32>,
}, },
/// The system window theme has changed. /// The system window theme has changed.
@ -231,11 +231,18 @@ pub enum WindowEvent {
delta: f32, delta: f32,
phase: TouchPhase, phase: TouchPhase,
}, },
/// The activation token was delivered back and now could be used.
///
/// Delivered in response to [`request_activation_token`].
ActivationTokenDone {
serial: AsyncRequestSerial,
token: ActivationToken,
},
} }
impl<'a> From<winit::event::WindowEvent<'a>> for WindowEvent { impl From<winit::event::WindowEvent> for WindowEvent {
#[allow(clippy::too_many_lines)] // it's a match statement #[allow(clippy::too_many_lines)] // it's a match statement
fn from(event: winit::event::WindowEvent<'a>) -> Self { fn from(event: winit::event::WindowEvent) -> Self {
match event { match event {
winit::event::WindowEvent::Resized(size) => Self::Resized(size), winit::event::WindowEvent::Resized(size) => Self::Resized(size),
winit::event::WindowEvent::Moved(pos) => Self::Moved(pos), winit::event::WindowEvent::Moved(pos) => Self::Moved(pos),
@ -244,15 +251,14 @@ impl<'a> From<winit::event::WindowEvent<'a>> for WindowEvent {
winit::event::WindowEvent::DroppedFile(path) => Self::DroppedFile(path), winit::event::WindowEvent::DroppedFile(path) => Self::DroppedFile(path),
winit::event::WindowEvent::HoveredFile(path) => Self::HoveredFile(path), winit::event::WindowEvent::HoveredFile(path) => Self::HoveredFile(path),
winit::event::WindowEvent::HoveredFileCancelled => Self::HoveredFileCancelled, winit::event::WindowEvent::HoveredFileCancelled => Self::HoveredFileCancelled,
winit::event::WindowEvent::ReceivedCharacter(ch) => Self::ReceivedCharacter(ch),
winit::event::WindowEvent::Focused(focused) => Self::Focused(focused), winit::event::WindowEvent::Focused(focused) => Self::Focused(focused),
winit::event::WindowEvent::KeyboardInput { winit::event::WindowEvent::KeyboardInput {
device_id, device_id,
input, event,
is_synthetic, is_synthetic,
} => Self::KeyboardInput { } => Self::KeyboardInput {
device_id, device_id,
input, event,
is_synthetic, is_synthetic,
}, },
@ -313,10 +319,11 @@ impl<'a> From<winit::event::WindowEvent<'a>> for WindowEvent {
winit::event::WindowEvent::Touch(touch) => Self::Touch(touch), winit::event::WindowEvent::Touch(touch) => Self::Touch(touch),
winit::event::WindowEvent::ScaleFactorChanged { winit::event::WindowEvent::ScaleFactorChanged {
scale_factor, scale_factor,
new_inner_size, .. // TODO use the suggested size from the writer <https://github.com/rust-windowing/winit/issues/3080>
} => Self::ScaleFactorChanged { } => {
scale_factor, Self::ScaleFactorChanged {
new_inner_size: *new_inner_size, scale_factor,
}
}, },
winit::event::WindowEvent::ThemeChanged(theme) => Self::ThemeChanged(theme), winit::event::WindowEvent::ThemeChanged(theme) => Self::ThemeChanged(theme),
winit::event::WindowEvent::Occluded(occluded) => Self::Occluded(occluded), winit::event::WindowEvent::Occluded(occluded) => Self::Occluded(occluded),
@ -341,6 +348,9 @@ impl<'a> From<winit::event::WindowEvent<'a>> for WindowEvent {
delta, delta,
phase, phase,
}, },
winit::event::WindowEvent::ActivationTokenDone { serial, token } => {
Self::ActivationTokenDone { serial, token }
}
} }
} }
} }

View file

@ -7,11 +7,12 @@ use std::thread;
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
use winit::dpi::{PhysicalPosition, PhysicalSize, Position, Size}; use winit::dpi::{PhysicalPosition, PhysicalSize, Position, Size};
use winit::error::OsError; use winit::error::{EventLoopError, OsError};
use winit::event::{ use winit::event::{
AxisId, DeviceId, ElementState, Ime, KeyboardInput, ModifiersState, MouseButton, AxisId, DeviceId, ElementState, Ime, KeyEvent, Modifiers, MouseButton, MouseScrollDelta, Touch,
MouseScrollDelta, Touch, TouchPhase, VirtualKeyCode, TouchPhase,
}; };
use winit::keyboard::KeyCode;
use winit::window::{Fullscreen, Icon, Theme, WindowButtons, WindowId, WindowLevel}; use winit::window::{Fullscreen, Icon, Theme, WindowButtons, WindowId, WindowLevel};
use crate::private::{self, WindowEvent}; use crate::private::{self, WindowEvent};
@ -215,7 +216,7 @@ where
window: winit, window: winit,
next_redraw_target: None, next_redraw_target: None,
close: false, close: false,
modifiers: ModifiersState::default(), modifiers: Modifiers::default(),
cursor_position: None, cursor_position: None,
mouse_buttons: HashSet::default(), mouse_buttons: HashSet::default(),
keys: HashSet::default(), keys: HashSet::default(),
@ -243,13 +244,13 @@ where
position: PhysicalPosition<i32>, position: PhysicalPosition<i32>,
cursor_position: Option<PhysicalPosition<f64>>, cursor_position: Option<PhysicalPosition<f64>>,
mouse_buttons: HashSet<MouseButton>, mouse_buttons: HashSet<MouseButton>,
keys: HashSet<VirtualKeyCode>, keys: HashSet<KeyCode>,
scale: f64, scale: f64,
close: bool, close: bool,
occluded: bool, occluded: bool,
focused: bool, focused: bool,
theme: Theme, theme: Theme,
modifiers: ModifiersState, modifiers: Modifiers,
} }
impl<AppMessage> RunningWindow<AppMessage> impl<AppMessage> RunningWindow<AppMessage>
@ -328,7 +329,9 @@ where
/// Sets the inner size of the window, in pixels. /// Sets the inner size of the window, in pixels.
pub fn set_inner_size(&self, new_size: PhysicalSize<u32>) { pub fn set_inner_size(&self, new_size: PhysicalSize<u32>) {
self.window.set_inner_size(new_size); // TODO not sure if this is reasonable
self.window.set_min_inner_size(Some(new_size));
self.window.set_max_inner_size(Some(new_size));
} }
/// Returns the current locpositionation of the window, in pixels. /// Returns the current locpositionation of the window, in pixels.
@ -376,7 +379,7 @@ where
/// Returns the current state of the keyboard modifier keys. /// Returns the current state of the keyboard modifier keys.
#[must_use] #[must_use]
pub const fn modifiers(&self) -> ModifiersState { pub const fn modifiers(&self) -> Modifiers {
self.modifiers self.modifiers
} }
@ -471,13 +474,27 @@ where
self.occluded = occluded; self.occluded = occluded;
behavior.occlusion_changed(self); behavior.occlusion_changed(self);
} }
WindowEvent::ScaleFactorChanged { WindowEvent::ScaleFactorChanged { scale_factor } => {
scale_factor, let factor_changed = scale_factor - self.scale;
new_inner_size, let new_inner_size = if factor_changed.abs() >= f64::EPSILON {
} => { // TODO use the suggested size from the writer <https://github.com/rust-windowing/winit/issues/3080>
PhysicalSize {
width: self.inner_size.width
+ lossy_f64_to_u32(
((f64::from(self.inner_size.width)) * factor_changed).round(),
),
height: self.inner_size.height
+ lossy_f64_to_u32(
(f64::from(self.inner_size.height) * factor_changed).round(),
),
}
} else {
self.inner_size
};
// Ensure both values are updated before any behavior // Ensure both values are updated before any behavior
// callbacks are invoked. // callbacks are invoked.
self.scale = scale_factor; self.scale = scale_factor;
// TODO not sure how to implement now
let inner_size_changed = self.inner_size != new_inner_size; let inner_size_changed = self.inner_size != new_inner_size;
self.inner_size = new_inner_size; self.inner_size = new_inner_size;
behavior.scale_factor_changed(self); behavior.scale_factor_changed(self);
@ -515,20 +532,18 @@ where
} }
WindowEvent::KeyboardInput { WindowEvent::KeyboardInput {
device_id, device_id,
input, event,
is_synthetic, is_synthetic,
} => { } => {
if let Some(keycode) = input.virtual_keycode { match event.state {
match input.state { ElementState::Pressed => {
ElementState::Pressed => { self.keys.insert(event.physical_key);
self.keys.insert(keycode); }
} ElementState::Released => {
ElementState::Released => { self.keys.remove(&event.physical_key);
self.keys.remove(&keycode);
}
} }
} }
behavior.keyboard_input(self, device_id, input, is_synthetic); behavior.keyboard_input(self, device_id, event, is_synthetic);
} }
WindowEvent::ModifiersChanged(modifiers) => { WindowEvent::ModifiersChanged(modifiers) => {
self.modifiers = modifiers; self.modifiers = modifiers;
@ -607,6 +622,7 @@ where
} => { } => {
behavior.touchpad_rotate(self, device_id, delta, phase); behavior.touchpad_rotate(self, device_id, delta, phase);
} }
WindowEvent::ActivationTokenDone { .. } => todo!(),
}, },
} }
@ -622,13 +638,13 @@ where
/// Returns an iterator of the currently pressed keys. /// Returns an iterator of the currently pressed keys.
/// ///
/// This iterator does not guarantee any specific order. /// This iterator does not guarantee any specific order.
pub fn pressed_keys(&self) -> impl Iterator<Item = VirtualKeyCode> + '_ { pub fn pressed_keys(&self) -> impl Iterator<Item = KeyCode> + '_ {
self.keys.iter().copied() self.keys.iter().copied()
} }
/// Returns true if the given key code is currently pressed. /// Returns true if the given key code is currently pressed.
#[must_use] #[must_use]
pub fn key_pressed(&self, keycode: &VirtualKeyCode) -> bool { pub fn key_pressed(&self, keycode: &KeyCode) -> bool {
self.keys.contains(keycode) self.keys.contains(keycode)
} }
@ -646,6 +662,12 @@ where
} }
} }
/// Performs `f64 as u32` but avoids clippy's lints.
#[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
fn lossy_f64_to_u32(value: f64) -> u32 {
value as u32
}
impl<AppMessage> Application<AppMessage> for RunningWindow<AppMessage> impl<AppMessage> Application<AppMessage> for RunningWindow<AppMessage>
where where
AppMessage: Message, AppMessage: Message,
@ -768,10 +790,15 @@ where
/// Messages can be sent to the application's main thread using /// Messages can be sent to the application's main thread using
/// [`Application::send`]. Each time a message is received by the main event /// [`Application::send`]. Each time a message is received by the main event
/// loop, `app_callback` will be invoked. /// loop, `app_callback` will be invoked.
///
/// # Errors
///
/// Returns an [`EventLoopError`] upon the loop exiting due to an error. See
/// [`EventLoop::run`] for more information.
fn run_with_event_callback( fn run_with_event_callback(
app_callback: impl FnMut(AppMessage, &Windows<AppMessage::Window>) -> AppMessage::Response app_callback: impl FnMut(AppMessage, &Windows<AppMessage::Window>) -> AppMessage::Response
+ 'static, + 'static,
) -> ! ) -> Result<(), EventLoopError>
where where
Self::Context: Default, Self::Context: Default,
{ {
@ -788,11 +815,16 @@ where
/// Messages can be sent to the application's main thread using /// Messages can be sent to the application's main thread using
/// [`Application::send`]. Each time a message is received by the main event /// [`Application::send`]. Each time a message is received by the main event
/// loop, `app_callback` will be invoked. /// loop, `app_callback` will be invoked.
///
/// # Errors
///
/// Returns an [`EventLoopError`] upon the loop exiting due to an error. See
/// [`EventLoop::run`] for more information.
fn run_with_context_and_event_callback( fn run_with_context_and_event_callback(
context: Self::Context, context: Self::Context,
app_callback: impl FnMut(AppMessage, &Windows<AppMessage::Window>) -> AppMessage::Response app_callback: impl FnMut(AppMessage, &Windows<AppMessage::Window>) -> AppMessage::Response
+ 'static, + 'static,
) -> ! { ) -> Result<(), EventLoopError> {
let app = PendingApp::new_with_event_callback(app_callback); let app = PendingApp::new_with_event_callback(app_callback);
Self::open_with(&app, context).expect("error opening initial window"); Self::open_with(&app, context).expect("error opening initial window");
app.run() app.run()
@ -900,7 +932,7 @@ where
&mut self, &mut self,
window: &mut RunningWindow<AppMessage>, window: &mut RunningWindow<AppMessage>,
device_id: DeviceId, device_id: DeviceId,
input: KeyboardInput, event: KeyEvent,
is_synthetic: bool, is_synthetic: bool,
) { ) {
} }
@ -1017,7 +1049,7 @@ pub trait Run: WindowBehavior<()> {
/// ///
/// This function is shorthand for creating a [`PendingApp`], opening this /// This function is shorthand for creating a [`PendingApp`], opening this
/// window inside of it, and running the pending app. /// window inside of it, and running the pending app.
fn run() -> ! fn run() -> Result<(), EventLoopError>
where where
Self::Context: Default, Self::Context: Default,
{ {
@ -1030,7 +1062,7 @@ pub trait Run: WindowBehavior<()> {
/// ///
/// This function is shorthand for creating a [`PendingApp`], opening this /// This function is shorthand for creating a [`PendingApp`], opening this
/// window inside of it, and running the pending app. /// window inside of it, and running the pending app.
fn run_with(context: Self::Context) -> ! { fn run_with(context: Self::Context) -> Result<(), EventLoopError> {
let app = PendingApp::new(); let app = PendingApp::new();
Self::open_with(&app, context).expect("error opening initial window"); Self::open_with(&app, context).expect("error opening initial window");
app.run() app.run()