Compare commits

..

5 Commits

Author SHA1 Message Date
Mads Marquart
fbc6fdc30c Add initialization closure and drop on exit 2024-12-03 13:28:52 +01:00
Mads Marquart
164bf85b5b Windows: Add scancode conversions from Chromium sources (#4020) 2024-12-03 11:05:22 +01:00
Mads Marquart
cfa8f027cc AppKit/UIKit: Do not emit default state events upon window creation (#3912)
Do not emit redundant ScaleFactorChanged, SurfaceResized and Focused.
2024-12-02 23:10:33 +01:00
Mads Marquart
2e5db75101 Linux: Align scancode conversions with Firefox (#4021) 2024-12-02 13:38:37 +01:00
Mads Marquart
19e5bee3d1 chore: fix clippy lints 2024-12-02 14:51:26 +03:00
39 changed files with 489 additions and 541 deletions

View File

@@ -212,7 +212,6 @@ windows-sys = { version = "0.52.0", features = [
"Win32_Media",
"Win32_System_Com_StructuredStorage",
"Win32_System_Com",
"Win32_System_Diagnostics_ToolHelp",
"Win32_System_LibraryLoader",
"Win32_System_Ole",
"Win32_Security",

View File

@@ -13,26 +13,12 @@ fn main() -> Result<(), impl std::error::Error> {
#[path = "util/fill.rs"]
mod fill;
#[derive(Default)]
struct Application {
parent_window_id: Option<WindowId>,
parent_window_id: WindowId,
windows: HashMap<WindowId, Box<dyn Window>>,
}
impl ApplicationHandler for Application {
fn can_create_surfaces(&mut self, event_loop: &dyn ActiveEventLoop) {
let attributes = WindowAttributes::default()
.with_title("parent window")
.with_position(Position::Logical(LogicalPosition::new(0.0, 0.0)))
.with_surface_size(LogicalSize::new(640.0f32, 480.0f32));
let window = event_loop.create_window(attributes).unwrap();
println!("Parent window id: {:?})", window.id());
self.parent_window_id = Some(window.id());
self.windows.insert(window.id(), window);
}
fn window_event(
&mut self,
event_loop: &dyn ActiveEventLoop,
@@ -56,7 +42,7 @@ fn main() -> Result<(), impl std::error::Error> {
event: KeyEvent { state: ElementState::Pressed, .. },
..
} => {
let parent_window = self.windows.get(&self.parent_window_id.unwrap()).unwrap();
let parent_window = self.windows.get(&self.parent_window_id).unwrap();
let child_window = spawn_child_window(parent_window.as_ref(), event_loop);
let child_id = child_window.id();
println!("Child window created with id: {child_id:?}");
@@ -72,6 +58,20 @@ fn main() -> Result<(), impl std::error::Error> {
}
}
fn init(event_loop: &dyn ActiveEventLoop) -> Application {
let attributes = WindowAttributes::default()
.with_title("parent window")
.with_position(Position::Logical(LogicalPosition::new(0.0, 0.0)))
.with_surface_size(LogicalSize::new(640.0f32, 480.0f32));
let window = event_loop.create_window(attributes).unwrap();
println!("Parent window id: {:?})", window.id());
let parent_window_id = window.id();
let windows = HashMap::from([(window.id(), window)]);
Application { parent_window_id, windows }
}
fn spawn_child_window(
parent: &dyn Window,
event_loop: &dyn ActiveEventLoop,
@@ -89,7 +89,7 @@ fn main() -> Result<(), impl std::error::Error> {
}
let event_loop = EventLoop::new().unwrap();
event_loop.run_app(Application::default())
event_loop.run(init)
}
#[cfg(not(any(x11_platform, macos_platform, windows_platform)))]

View File

@@ -43,16 +43,31 @@ fn main() -> Result<(), impl std::error::Error> {
let event_loop = EventLoop::new().unwrap();
event_loop.run_app(ControlFlowDemo::default())
event_loop.run(ControlFlowDemo::new)
}
#[derive(Default)]
struct ControlFlowDemo {
mode: Mode,
request_redraw: bool,
wait_cancelled: bool,
close_requested: bool,
window: Option<Box<dyn Window>>,
window: Box<dyn Window>,
}
impl ControlFlowDemo {
fn new(event_loop: &dyn ActiveEventLoop) -> Self {
let window_attributes = WindowAttributes::default().with_title(
"Press 1, 2, 3 to change control flow mode. Press R to toggle redraw requests.",
);
let window = event_loop.create_window(window_attributes).unwrap();
Self {
mode: Mode::default(),
request_redraw: false,
wait_cancelled: false,
close_requested: false,
window,
}
}
}
impl ApplicationHandler for ControlFlowDemo {
@@ -65,13 +80,6 @@ impl ApplicationHandler for ControlFlowDemo {
}
}
fn can_create_surfaces(&mut self, event_loop: &dyn ActiveEventLoop) {
let window_attributes = WindowAttributes::default().with_title(
"Press 1, 2, 3 to change control flow mode. Press R to toggle redraw requests.",
);
self.window = Some(event_loop.create_window(window_attributes).unwrap());
}
fn window_event(
&mut self,
_event_loop: &dyn ActiveEventLoop,
@@ -112,9 +120,8 @@ impl ApplicationHandler for ControlFlowDemo {
_ => (),
},
WindowEvent::RedrawRequested => {
let window = self.window.as_ref().unwrap();
window.pre_present_notify();
fill::fill_window(window.as_ref());
self.window.pre_present_notify();
fill::fill_window(&*self.window);
},
_ => (),
}
@@ -122,7 +129,7 @@ impl ApplicationHandler for ControlFlowDemo {
fn about_to_wait(&mut self, event_loop: &dyn ActiveEventLoop) {
if self.request_redraw && !self.wait_cancelled && !self.close_requested {
self.window.as_ref().unwrap().request_redraw();
self.window.request_redraw();
}
match self.mode {

View File

@@ -8,7 +8,7 @@ fn main() -> std::process::ExitCode {
use std::time::Duration;
use winit::application::ApplicationHandler;
use winit::event::WindowEvent;
use winit::event::{StartCause, WindowEvent};
use winit::event_loop::{ActiveEventLoop, EventLoop};
use winit::platform::pump_events::{EventLoopExtPumpEvents, PumpStatus};
use winit::window::{Window, WindowAttributes, WindowId};
@@ -22,9 +22,12 @@ fn main() -> std::process::ExitCode {
}
impl ApplicationHandler for PumpDemo {
fn can_create_surfaces(&mut self, event_loop: &dyn ActiveEventLoop) {
let window_attributes = WindowAttributes::default().with_title("A fantastic window!");
self.window = Some(event_loop.create_window(window_attributes).unwrap());
fn new_events(&mut self, event_loop: &dyn ActiveEventLoop, cause: StartCause) {
if matches!(cause, StartCause::Init) && self.window.is_none() {
let window_attributes =
WindowAttributes::default().with_title("A fantastic window!");
self.window = Some(event_loop.create_window(window_attributes).unwrap());
}
}
fn window_event(

View File

@@ -21,14 +21,8 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
window: Option<Box<dyn Window>>,
}
impl ApplicationHandler for App {
fn about_to_wait(&mut self, _event_loop: &dyn ActiveEventLoop) {
if let Some(window) = self.window.as_ref() {
window.request_redraw();
}
}
fn can_create_surfaces(&mut self, event_loop: &dyn ActiveEventLoop) {
impl App {
fn init_window(&mut self, event_loop: &dyn ActiveEventLoop) {
let window_attributes = WindowAttributes::default()
.with_title("Fantastic window number one!")
.with_surface_size(winit::dpi::LogicalSize::new(128.0, 128.0));
@@ -36,6 +30,14 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
self.window_id = Some(window.id());
self.window = Some(window);
}
}
impl ApplicationHandler for App {
fn about_to_wait(&mut self, _event_loop: &dyn ActiveEventLoop) {
if let Some(window) = self.window.as_ref() {
window.request_redraw();
}
}
fn window_event(
&mut self,
@@ -81,14 +83,20 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut event_loop = EventLoop::new().unwrap();
let mut app = App { idx: 1, ..Default::default() };
event_loop.run_app_on_demand(&mut app)?;
event_loop.run_on_demand(|event_loop| {
app.init_window(event_loop);
&mut app
})?;
println!("--------------------------------------------------------- Finished first loop");
println!("--------------------------------------------------------- Waiting 5 seconds");
std::thread::sleep(Duration::from_secs(5));
app.idx += 1;
event_loop.run_app_on_demand(&mut app)?;
event_loop.run_on_demand(|event_loop| {
app.init_window(event_loop);
&mut app
})?;
println!("--------------------------------------------------------- Finished second loop");
Ok(())
}

View File

@@ -70,8 +70,7 @@ fn main() -> Result<(), Box<dyn Error>> {
});
}
let app = Application::new(&event_loop, receiver, sender);
Ok(event_loop.run_app(app)?)
Ok(event_loop.run(|event_loop| Application::new(event_loop, receiver, sender))?)
}
/// Application state and event handling.
@@ -88,21 +87,24 @@ struct Application {
///
/// With OpenGL it could be EGLDisplay.
#[cfg(not(android_platform))]
context: Option<Context<DisplayHandle<'static>>>,
context: Context<DisplayHandle<'static>>,
}
impl Application {
fn new(event_loop: &EventLoop, receiver: Receiver<Action>, sender: Sender<Action>) -> Self {
// SAFETY: we drop the context right before the event loop is stopped, thus making it safe.
fn new(
event_loop: &dyn ActiveEventLoop,
receiver: Receiver<Action>,
sender: Sender<Action>,
) -> Self {
// SAFETY: The context is stored in the application, which is dropped right before the event
// loop is stopped, thus making it safe.
#[cfg(not(android_platform))]
let context = Some(
Context::new(unsafe {
std::mem::transmute::<DisplayHandle<'_>, DisplayHandle<'static>>(
event_loop.display_handle().unwrap(),
)
})
.unwrap(),
);
let context = Context::new(unsafe {
std::mem::transmute::<DisplayHandle<'_>, DisplayHandle<'static>>(
event_loop.display_handle().unwrap(),
)
})
.unwrap();
// You'll have to choose an icon size at your own discretion. On X11, the desired size
// varies by WM, and on Windows, you still have to account for screen scaling. Here
@@ -120,7 +122,7 @@ impl Application {
.into_iter()
.collect();
Self {
let mut app = Self {
receiver,
sender,
#[cfg(not(android_platform))]
@@ -128,7 +130,16 @@ impl Application {
custom_cursors,
icon,
windows: Default::default(),
}
};
app.dump_monitors(event_loop);
// Create initial window.
app.create_window(event_loop, None).expect("failed to create initial window");
app.print_help();
app
}
fn create_window(
@@ -560,14 +571,12 @@ impl ApplicationHandler for Application {
info!("Device {device_id:?} event: {event:?}");
}
fn can_create_surfaces(&mut self, event_loop: &dyn ActiveEventLoop) {
info!("Ready to create surfaces");
self.dump_monitors(event_loop);
// Create initial window.
self.create_window(event_loop, None).expect("failed to create initial window");
self.print_help();
#[cfg(not(android_platform))]
fn can_create_surfaces(&mut self, _event_loop: &dyn ActiveEventLoop) {
for window in self.windows.values_mut() {
window.surface = Some(Surface::new(&self.context, Arc::clone(&window.window)).unwrap());
window.resize(window.window.surface_size());
}
}
fn about_to_wait(&mut self, event_loop: &dyn ActiveEventLoop) {
@@ -578,9 +587,10 @@ impl ApplicationHandler for Application {
}
#[cfg(not(android_platform))]
fn exiting(&mut self, _event_loop: &dyn ActiveEventLoop) {
// We must drop the context here.
self.context = None;
fn destroy_surfaces(&mut self, _event_loop: &dyn ActiveEventLoop) {
for window in self.windows.values_mut() {
window.surface = None;
}
}
#[cfg(target_os = "macos")]
@@ -607,9 +617,9 @@ struct WindowState {
ime: bool,
/// Render surface.
///
/// NOTE: This surface must be dropped before the `Window`.
/// `None` when not between `can_create_surfaces` and `destroy_surfaces`.
#[cfg(not(android_platform))]
surface: Surface<DisplayHandle<'static>, Arc<dyn Window>>,
surface: Option<Surface<DisplayHandle<'static>, Arc<dyn Window>>>,
/// The actual winit Window.
window: Arc<dyn Window>,
/// The window theme we're drawing with.
@@ -642,11 +652,6 @@ impl WindowState {
fn new(app: &Application, window: Box<dyn Window>) -> Result<Self, Box<dyn Error>> {
let window: Arc<dyn Window> = Arc::from(window);
// SAFETY: the surface is dropped before the `window` which provided it with handle, thus
// it doesn't outlive it.
#[cfg(not(android_platform))]
let surface = Surface::new(app.context.as_ref().unwrap(), Arc::clone(&window))?;
let theme = window.theme().unwrap_or(Theme::Dark);
info!("Theme: {theme:?}");
let named_idx = 0;
@@ -656,15 +661,14 @@ impl WindowState {
let ime = true;
window.set_ime_allowed(ime);
let size = window.surface_size();
let mut state = Self {
Ok(Self {
#[cfg(macos_platform)]
option_as_alt: window.option_as_alt(),
custom_idx: app.custom_cursors.as_ref().map(Vec::len).unwrap_or(1) - 1,
cursor_grab: CursorGrabMode::None,
named_idx,
#[cfg(not(android_platform))]
surface,
surface: None,
window,
theme,
ime,
@@ -675,10 +679,7 @@ impl WindowState {
rotated: Default::default(),
panned: Default::default(),
zoom: Default::default(),
};
state.resize(size);
Ok(state)
})
}
pub fn toggle_ime(&mut self) {
@@ -852,7 +853,11 @@ impl WindowState {
(Some(width), Some(height)) => (width, height),
_ => return,
};
self.surface.resize(width, height).expect("failed to resize inner buffer");
self.surface
.as_mut()
.unwrap()
.resize(width, height)
.expect("failed to resize inner buffer");
}
self.window.request_redraw();
}
@@ -945,7 +950,7 @@ impl WindowState {
return Ok(());
}
let mut buffer = self.surface.buffer_mut()?;
let mut buffer = self.surface.as_mut().unwrap().buffer_mut()?;
// Draw a different color inside the safe area
let surface_size = self.window.surface_size();

View File

@@ -13,39 +13,28 @@ fn main() -> Result<(), Box<dyn Error>> {
mod fill;
pub struct XEmbedDemo {
parent_window_id: u32,
window: Option<Box<dyn Window>>,
window: Box<dyn Window>,
}
impl ApplicationHandler for XEmbedDemo {
fn can_create_surfaces(&mut self, event_loop: &dyn ActiveEventLoop) {
let window_attributes = WindowAttributes::default()
.with_title("An embedded window!")
.with_surface_size(winit::dpi::LogicalSize::new(128.0, 128.0))
.with_embed_parent_window(self.parent_window_id);
self.window = Some(event_loop.create_window(window_attributes).unwrap());
}
fn window_event(
&mut self,
event_loop: &dyn ActiveEventLoop,
_window_id: WindowId,
event: WindowEvent,
) {
let window = self.window.as_ref().unwrap();
match event {
WindowEvent::CloseRequested => event_loop.exit(),
WindowEvent::RedrawRequested => {
window.pre_present_notify();
fill::fill_window(window.as_ref());
self.window.pre_present_notify();
fill::fill_window(&*self.window);
},
_ => (),
}
}
fn about_to_wait(&mut self, _event_loop: &dyn ActiveEventLoop) {
self.window.as_ref().unwrap().request_redraw();
self.window.request_redraw();
}
}
@@ -58,7 +47,15 @@ fn main() -> Result<(), Box<dyn Error>> {
tracing_subscriber::fmt::init();
let event_loop = EventLoop::new()?;
Ok(event_loop.run_app(XEmbedDemo { parent_window_id, window: None })?)
Ok(event_loop.run(|event_loop| {
let window_attributes = WindowAttributes::default()
.with_title("An embedded window!")
.with_surface_size(winit::dpi::LogicalSize::new(128.0, 128.0))
.with_embed_parent_window(parent_window_id);
let window = event_loop.create_window(window_attributes).unwrap();
XEmbedDemo { window }
})?)
}
#[cfg(not(x11_platform))]

View File

@@ -7,6 +7,8 @@ use crate::platform::macos::ApplicationHandlerExtMacOS;
use crate::window::WindowId;
/// The handler of the application events.
///
/// This is [dropped][std::ops::Drop] when the event loop is being shut down.
pub trait ApplicationHandler {
/// Emitted when new events arrive from the OS to be processed.
///
@@ -101,7 +103,9 @@ pub trait ApplicationHandler {
///
/// [`can_create_surfaces()`]: Self::can_create_surfaces()
/// [`destroy_surfaces()`]: Self::destroy_surfaces()
fn can_create_surfaces(&mut self, event_loop: &dyn ActiveEventLoop);
fn can_create_surfaces(&mut self, event_loop: &dyn ActiveEventLoop) {
let _ = event_loop;
}
/// Called after a wake up is requested using [`EventLoopProxy::wake_up()`].
///
@@ -142,8 +146,6 @@ pub trait ApplicationHandler {
/// # ) {
/// # }
/// #
/// # fn can_create_surfaces(&mut self, _event_loop: &dyn ActiveEventLoop) {}
/// #
/// fn proxy_wake_up(&mut self, _event_loop: &dyn ActiveEventLoop) {
/// // Iterate current events, since wake-ups may have been merged.
/// //
@@ -162,8 +164,6 @@ pub trait ApplicationHandler {
///
/// let (sender, receiver) = mpsc::channel();
///
/// let mut app = MyApp { receiver };
///
/// // Send an event in a loop
/// let proxy = event_loop.create_proxy();
/// let background_thread = thread::spawn(move || {
@@ -182,9 +182,8 @@ pub trait ApplicationHandler {
/// }
/// });
///
/// event_loop.run_app(&mut app)?;
/// event_loop.run(|_event_loop| MyApp { receiver })?;
///
/// drop(app);
/// background_thread.join().unwrap();
///
/// Ok(())
@@ -286,13 +285,13 @@ pub trait ApplicationHandler {
/// with the [`onStop`] lifecycle event which typically results in the surface to be destroyed
/// after the app becomes invisible.
///
/// Applications that need to run on Android should assume their [`NativeWindow`] has been
/// destroyed, which indirectly invalidates any existing render surfaces that may have been
/// created outside of Winit (such as an `EGLSurface`, [`VkSurfaceKHR`] or [`wgpu::Surface`]).
/// Applications that need to run on Android must be able to handle their underlying
/// [`SurfaceView`] being destroyed, which in turn indirectly invalidates any existing
/// render surfaces that may have been created outside of Winit (such as an `EGLSurface`,
/// [`VkSurfaceKHR`] or [`wgpu::Surface`]).
///
/// When receiving [`destroy_surfaces()`] Android applications should drop all render surfaces
/// before the event callback completes, which may be re-created when the application next
/// receives [`can_create_surfaces()`].
/// This means that in this method, you must drop all render surfaces before the event callback
/// completes, and only re-create them in or after [`can_create_surfaces()`] is next recieved.
///
/// [`NativeWindow`]: https://developer.android.com/ndk/reference/group/a-native-window
/// [`Surface`]: https://developer.android.com/reference/android/view/Surface
@@ -310,14 +309,6 @@ pub trait ApplicationHandler {
let _ = event_loop;
}
/// Emitted when the event loop is being shut down.
///
/// This is irreversible - if this method is called, it is guaranteed that the event loop
/// will exit right after.
fn exiting(&mut self, event_loop: &dyn ActiveEventLoop) {
let _ = event_loop;
}
/// Emitted when the application has received a memory warning.
///
/// ## Platform-specific
@@ -413,11 +404,6 @@ impl<A: ?Sized + ApplicationHandler> ApplicationHandler for &mut A {
(**self).destroy_surfaces(event_loop);
}
#[inline]
fn exiting(&mut self, event_loop: &dyn ActiveEventLoop) {
(**self).exiting(event_loop);
}
#[inline]
fn memory_warning(&mut self, event_loop: &dyn ActiveEventLoop) {
(**self).memory_warning(event_loop);
@@ -487,11 +473,6 @@ impl<A: ?Sized + ApplicationHandler> ApplicationHandler for Box<A> {
(**self).destroy_surfaces(event_loop);
}
#[inline]
fn exiting(&mut self, event_loop: &dyn ActiveEventLoop) {
(**self).exiting(event_loop);
}
#[inline]
fn memory_warning(&mut self, event_loop: &dyn ActiveEventLoop) {
(**self).memory_warning(event_loop);

View File

@@ -75,6 +75,8 @@ changelog entry.
variables to test the respective modifiers of window creation.
- Added `Window::surface_position`, which is the position of the surface inside the window.
- Added `Window::safe_area`, which describes the area of the surface that is unobstructed.
- On X11 and Wayland, improved scancode conversions for more obscure key codes.
- On Windows, improved scancode conversions for more obscure key codes.
### Changed
@@ -160,6 +162,8 @@ changelog entry.
- In the same spirit rename `DeviceEvent::MouseMotion` to `PointerMotion`.
- Remove `Force::Calibrated::altitude_angle`.
- On X11, use bottom-right corner for IME hotspot in `Window::set_ime_cursor_area`.
- On macOS and iOS, no longer emit `ScaleFactorChanged` upon window creation.
- On macOS, no longer emit `Focused` upon window creation.
### Removed

View File

@@ -1,39 +1,4 @@
//! The event enums and assorted supporting types.
//!
//! These are sent to the closure given to [`EventLoop::run_app(...)`], where they get
//! processed and used to modify the program state. For more details, see the root-level
//! documentation.
//!
//! Some of these events represent different "parts" of a traditional event-handling loop. You could
//! approximate the basic ordering loop of [`EventLoop::run_app(...)`] like this:
//!
//! ```rust,ignore
//! let mut start_cause = StartCause::Init;
//!
//! while !elwt.exiting() {
//! app.new_events(event_loop, start_cause);
//!
//! for event in (window events, user events, device events) {
//! // This will pick the right method on the application based on the event.
//! app.handle_event(event_loop, event);
//! }
//!
//! for window_id in (redraw windows) {
//! app.window_event(event_loop, window_id, RedrawRequested);
//! }
//!
//! app.about_to_wait(event_loop);
//! start_cause = wait_if_necessary();
//! }
//!
//! app.exiting(event_loop);
//! ```
//!
//! This leaves out timing details like [`ControlFlow::WaitUntil`] but hopefully
//! describes what happens in what order.
//!
//! [`EventLoop::run_app(...)`]: crate::event_loop::EventLoop::run_app
//! [`ControlFlow::WaitUntil`]: crate::event_loop::ControlFlow::WaitUntil
use std::path::PathBuf;
use std::sync::{Mutex, Weak};
#[cfg(not(web_platform))]
@@ -85,11 +50,6 @@ pub(crate) enum Event {
/// [`ApplicationHandler::suspended()`]: crate::application::ApplicationHandler::suspended()
Suspended,
/// See [`ApplicationHandler::can_create_surfaces()`] for details.
///
/// [`ApplicationHandler::can_create_surfaces()`]: crate::application::ApplicationHandler::can_create_surfaces()
CreateSurfaces,
/// See [`ApplicationHandler::resumed()`] for details.
///
/// [`ApplicationHandler::resumed()`]: crate::application::ApplicationHandler::resumed()
@@ -100,11 +60,6 @@ pub(crate) enum Event {
/// [`ApplicationHandler::about_to_wait()`]: crate::application::ApplicationHandler::about_to_wait()
AboutToWait,
/// See [`ApplicationHandler::exiting()`] for details.
///
/// [`ApplicationHandler::exiting()`]: crate::application::ApplicationHandler::exiting()
LoopExiting,
/// See [`ApplicationHandler::memory_warning()`] for details.
///
/// [`ApplicationHandler::memory_warning()`]: crate::application::ApplicationHandler::memory_warning()
@@ -153,6 +108,9 @@ pub enum WindowEvent {
/// Contains the new dimensions of the surface (can also be retrieved with
/// [`Window::surface_size`]).
///
/// This event will not necessarily be emitted upon window creation, query
/// [`Window::surface_size`] if you need to determine the surface's initial size.
///
/// [`Window::surface_size`]: crate::window::Window::surface_size
SurfaceResized(PhysicalSize<u32>),
@@ -193,6 +151,9 @@ pub enum WindowEvent {
/// The window gained or lost focus.
///
/// The parameter is true if the window has gained focus, and false if it has lost focus.
///
/// Windows are unfocused upon creation, but will usually be focused by the system soon
/// afterwards.
Focused(bool),
/// An event from the keyboard has been received.
@@ -420,7 +381,12 @@ pub enum WindowEvent {
/// To update the window size, use the provided [`SurfaceSizeWriter`] handle. By default, the
/// window is resized to the value suggested by the OS, but it can be changed to any value.
///
/// This event will not necessarily be emitted upon window creation, query
/// [`Window::scale_factor`] if you need to determine the window's initial scale factor.
///
/// For more information about DPI in general, see the [`dpi`] crate.
///
/// [`Window::scale_factor`]: crate::window::Window::scale_factor
ScaleFactorChanged {
scale_factor: f64,
/// Handle to update surface size during scale changes.
@@ -1184,7 +1150,6 @@ mod tests {
let wid = WindowId::from_raw(0);
x(NewEvents(event::StartCause::Init));
x(AboutToWait);
x(LoopExiting);
x(Suspended);
x(Resumed);

View File

@@ -195,10 +195,48 @@ impl EventLoop {
}
impl EventLoop {
/// Run the application with the event loop on the calling thread.
/// Run the event loop on the current thread.
///
/// You pass in a closure that returns your application state. This closure has access to the
/// currently running event loop, allowing you to initialize your windows and surfaces in here.
///
/// See the [`set_control_flow()`] docs on how to change the event loop's behavior.
///
/// ## Event loop flow
///
/// This function internally handles the different parts of a traditional event-handling loop.
/// You could imagine this method being implemented like this:
///
/// ```rust,ignore
/// // Initialize.
/// let mut app = init_closure(event_loop);
/// let mut start_cause = StartCause::Init;
///
/// // Run loop.
/// while !elwt.exiting() {
/// // Wake up.
/// app.new_events(event_loop, start_cause);
///
/// // Handle events by the user.
/// for (device_id, event) in incoming_device_events {
/// app.device_event(event_loop, device_id, event);
/// }
/// for (window_id, event) in incoming_window_events {
/// app.window_event(event_loop, window_id, event);
/// }
///
/// // Done handling events, wait until we're woken up again.
/// app.about_to_wait(event_loop);
/// start_cause = wait_if_necessary();
/// }
///
/// // Finished running, drop application state.
/// drop(app);
/// ```
///
/// This is of course a very coarse-grained overview, and leaves out timing details like
/// [`ControlFlow::WaitUntil`] and life-cycle methods like [`ApplicationHandler::resumed`].
///
/// ## Platform-specific
///
/// - **iOS:** Will never return to the caller and so values not passed to this function will
@@ -213,7 +251,7 @@ impl EventLoop {
doc = " [`EventLoopExtWeb::spawn_app()`][crate::platform::web::EventLoopExtWeb::spawn_app()]"
)]
#[cfg_attr(not(any(web_platform, docsrs)), doc = " `EventLoopExtWeb::spawn_app()`")]
/// [^1] instead of [`run_app()`] to avoid the need for the Javascript exception trick, and to
/// [^1] instead of [`run()`] to avoid the need for the Javascript exception trick, and to
/// make it clearer that the event loop runs asynchronously (via the browser's own,
/// internal, event loop) and doesn't block the current thread of execution like it does
/// on other platforms.
@@ -223,11 +261,20 @@ impl EventLoop {
/// [^1]: `spawn_app()` is only available on the Web platform.
///
/// [`set_control_flow()`]: ActiveEventLoop::set_control_flow()
/// [`run_app()`]: Self::run_app()
/// [`run()`]: Self::run()
#[inline]
#[cfg(not(all(web_platform, target_feature = "exception-handling")))]
pub fn run<A: ApplicationHandler>(
self,
init_closure: impl FnOnce(&dyn ActiveEventLoop) -> A,
) -> Result<(), EventLoopError> {
self.event_loop.run(init_closure)
}
/// Run the event loop with the given application state.
#[deprecated = "less flexible version of `run`"]
pub fn run_app<A: ApplicationHandler>(self, app: A) -> Result<(), EventLoopError> {
self.event_loop.run_app(app)
self.run(|_event_loop| app)
}
/// Creates an [`EventLoopProxy`] that can be used to dispatch user events
@@ -392,9 +439,7 @@ pub trait ActiveEventLoop: AsAny {
/// Gets the current [`ControlFlow`].
fn control_flow(&self) -> ControlFlow;
/// This exits the event loop.
///
/// See [`exiting`][crate::application::ApplicationHandler::exiting].
/// This stops the event loop.
fn exit(&self);
/// Returns if the [`EventLoop`] is about to stop.

View File

@@ -1,24 +1,14 @@
//! Winit is a cross-platform window creation and event loop management library.
//!
//! # Building windows
//!
//! Before you can create a [`Window`], you first need to build an [`EventLoop`]. This is done with
//! the [`EventLoop::new()`] function.
//!
//! ```no_run
//! use winit::event_loop::EventLoop;
//!
//! # // Intentionally use `fn main` for clarity
//! fn main() {
//! let event_loop = EventLoop::new().unwrap();
//! // ...
//! }
//! ```
//!
//! Then you create a [`Window`] with [`create_window`].
//!
//! # Event handling
//!
//! Basically all of the functionality that Winit exposes requires an [`ActiveEventLoop`], which you
//! can get access to by running an [`EventLoop`] using [`EventLoop::new()`] and
//! [`EventLoop::run()`].
//!
//! Once it's running, you can create your [`Window`]s with [`ActiveEventLoop::create_window()`] by
//! passing in the desired [`WindowAttributes`].
//!
//! Once a [`Window`] has been created, it will generate different *events*. A [`Window`] object can
//! generate [`WindowEvent`]s when certain input events occur, such as a cursor moving over the
//! window or a key getting pressed while the window is focused. Devices can generate
@@ -26,9 +16,10 @@
//! Some user activity, like mouse movement, can generate both a [`WindowEvent`] *and* a
//! [`DeviceEvent`].
//!
//! You can retrieve events by calling [`EventLoop::run_app()`]. This function will
//! dispatch events for every [`Window`] that was created with that particular [`EventLoop`], and
//! will run until [`exit()`] is used, at which point [`exiting()`] is called.
//! You retrieve by implementing [`ApplicationHandler`] for a new type, which will be the state of
//! your application. The methods in this trait will continuously receive events until
//! [`ActiveEventLoop::exit()`] is used, at which point your application state will be dropped, and
//! the application shuts down.
//!
//! Winit no longer uses a `EventLoop::poll_events() -> impl Iterator<Event>`-based event loop
//! model, since that can't be implemented properly on some platforms (e.g Web, iOS) and works
@@ -49,19 +40,20 @@
//! use winit::application::ApplicationHandler;
//! use winit::event::WindowEvent;
//! use winit::event_loop::{ActiveEventLoop, ControlFlow, EventLoop};
//! use winit::window::{Window, WindowId, WindowAttributes};
//! use winit::window::{Window, WindowId};
//!
//! #[derive(Default)]
//! struct App {
//! window: Option<Box<dyn Window>>,
//! window: Box<dyn Window>,
//! }
//!
//! impl ApplicationHandler for App {
//! fn can_create_surfaces(&mut self, event_loop: &dyn ActiveEventLoop) {
//! self.window = Some(event_loop.create_window(WindowAttributes::default()).unwrap());
//! }
//!
//! fn window_event(&mut self, event_loop: &dyn ActiveEventLoop, id: WindowId, event: WindowEvent) {
//! fn window_event(
//! &mut self,
//! event_loop: &dyn ActiveEventLoop,
//! id: WindowId,
//! event: WindowEvent,
//! ) {
//! // Called by `EventLoop::run` when a new event happens on the window.
//! match event {
//! WindowEvent::CloseRequested => {
//! println!("The close button was pressed; stopping");
@@ -81,16 +73,19 @@
//! // You only need to call this if you've determined that you need to redraw in
//! // applications which do not always need to. Applications that redraw continuously
//! // can render here instead.
//! self.window.as_ref().unwrap().request_redraw();
//! }
//! self.window.request_redraw();
//! },
//! _ => (),
//! }
//! }
//! }
//!
//! # // Intentionally use `fn main` for clarity
//! fn main() {
//! let event_loop = EventLoop::new().unwrap();
//! fn main() -> Result<(), Box<dyn std::error::Error>> {
//! // Create a new event loop.
//! let event_loop = EventLoop::new()?;
//!
//! // Configure settings before launching.
//!
//! // ControlFlow::Poll continuously runs the event loop, even if the OS hasn't
//! // dispatched any events. This is ideal for games and similar applications.
@@ -101,8 +96,21 @@
//! // input, and uses significantly less power/CPU time than ControlFlow::Poll.
//! event_loop.set_control_flow(ControlFlow::Wait);
//!
//! let mut app = App::default();
//! event_loop.run_app(&mut app);
//! // Launch and begin running our event loop.
//! event_loop.run(|event_loop| {
//! // The event loop has launched, and we can initialize our UI state in this closure.
//!
//! // Create a simple window with default attributes.
//! let window = event_loop
//! .create_window(Window::default_attributes())
//! .expect("failed creating window");
//!
//! // Give our newly created application state to Winit, which will, when necessary, call
//! // the `ApplicationHandler` methods configured above.
//! App { window }
//! })?;
//!
//! Ok(())
//! }
//! ```
//!
@@ -250,20 +258,21 @@
//! |32-bit ARM Android |`arm-linux-androideabi` |Android |
//! |64-bit SPARC Linux with glibc |`sparc64-unknown-linux-gnu` |X11, Wayland |
//!
//! [`ActiveEventLoop`]: event_loop::ActiveEventLoop
//! [`EventLoop`]: event_loop::EventLoop
//! [`EventLoop::new()`]: event_loop::EventLoop::new
//! [`EventLoop::run_app()`]: event_loop::EventLoop::run_app
//! [`exit()`]: event_loop::ActiveEventLoop::exit
//! [`EventLoop::run()`]: event_loop::EventLoop::run
//! [`ActiveEventLoop::exit()`]: event_loop::ActiveEventLoop::exit
//! [`Window`]: window::Window
//! [`WindowId`]: window::WindowId
//! [`WindowAttributes`]: window::WindowAttributes
//! [window_new]: window::Window::new
//! [`create_window`]: event_loop::ActiveEventLoop::create_window
//! [`ActiveEventLoop::create_window()`]: event_loop::ActiveEventLoop::create_window
//! [`Window::id()`]: window::Window::id
//! [`WindowEvent`]: event::WindowEvent
//! [`DeviceEvent`]: event::DeviceEvent
//! [`ApplicationHandler`]: application::ApplicationHandler
//! [`Event::UserEvent`]: event::Event::UserEvent
//! [`exiting()`]: crate::application::ApplicationHandler::exiting
//! [`raw_window_handle`]: ./window/struct.Window.html#method.raw_window_handle
//! [`raw_display_handle`]: ./window/struct.Window.html#method.raw_display_handle
//! [^1]: `EventLoopExtPumpEvents::pump_app_events()` is only available on Windows, macOS, Android, X11 and Wayland.

View File

@@ -65,7 +65,7 @@
//! let app = NSApplication::sharedApplication(mtm);
//! app.setDelegate(Some(ProtocolObject::from_ref(&*delegate)));
//!
//! // event_loop.run_app(&mut my_app);
//! // event_loop.run(|event_loop| { ... })?;
//! Ok(())
//! }
//! ```

View File

@@ -1,16 +1,14 @@
use crate::application::ApplicationHandler;
use crate::error::EventLoopError;
use crate::event_loop::EventLoop;
use crate::event_loop::{ActiveEventLoop, EventLoop};
#[cfg(doc)]
use crate::{
event_loop::ActiveEventLoop, platform::pump_events::EventLoopExtPumpEvents, window::Window,
};
use crate::{platform::pump_events::EventLoopExtPumpEvents, window::Window};
/// Additional methods on [`EventLoop`] to return control flow to the caller.
pub trait EventLoopExtRunOnDemand {
/// Run the application with the event loop on the calling thread.
///
/// Unlike [`EventLoop::run_app`], this function accepts non-`'static` (i.e. non-`move`)
/// Unlike [`EventLoop::run`], this function accepts non-`'static` (i.e. non-`move`)
/// closures and it is possible to return control back to the caller without
/// consuming the `EventLoop` (by using [`exit()`]) and
/// so the event loop can be re-run after it has exit.
@@ -23,7 +21,7 @@ pub trait EventLoopExtRunOnDemand {
/// to while maintaining the full state of your application. (If you need something like this
/// you can look at the [`EventLoopExtPumpEvents::pump_app_events()`] API)
///
/// Each time `run_app_on_demand` is called the startup sequence of `init`, followed by
/// Each time `run_on_demand` is called the startup sequence of `init`, followed by
/// `resume` is being preserved.
///
/// See the [`set_control_flow()`] docs on how to change the event loop's behavior.
@@ -40,7 +38,7 @@ pub trait EventLoopExtRunOnDemand {
/// [^1] more than once instead).
/// - No [`Window`] state can be carried between separate runs of the event loop.
///
/// You are strongly encouraged to use [`EventLoop::run_app()`] for portability, unless you
/// You are strongly encouraged to use [`EventLoop::run()`] for portability, unless you
/// specifically need the ability to re-run a single event loop more than once
///
/// # Supported Platforms
@@ -60,12 +58,18 @@ pub trait EventLoopExtRunOnDemand {
///
/// [`exit()`]: ActiveEventLoop::exit()
/// [`set_control_flow()`]: ActiveEventLoop::set_control_flow()
fn run_app_on_demand<A: ApplicationHandler>(&mut self, app: A) -> Result<(), EventLoopError>;
fn run_on_demand<A: ApplicationHandler>(
&mut self,
init_closure: impl FnOnce(&dyn ActiveEventLoop) -> A,
) -> Result<(), EventLoopError>;
}
impl EventLoopExtRunOnDemand for EventLoop {
fn run_app_on_demand<A: ApplicationHandler>(&mut self, app: A) -> Result<(), EventLoopError> {
self.event_loop.run_app_on_demand(app)
fn run_on_demand<A: ApplicationHandler>(
&mut self,
init_closure: impl FnOnce(&dyn ActiveEventLoop) -> A,
) -> Result<(), EventLoopError> {
self.event_loop.run_on_demand(init_closure)
}
}

View File

@@ -190,10 +190,10 @@ pub trait EventLoopExtWeb {
/// Initializes the winit event loop.
///
/// Unlike
#[cfg_attr(all(web_platform, target_feature = "exception-handling"), doc = "`run_app()`")]
#[cfg_attr(all(web_platform, target_feature = "exception-handling"), doc = "`run()`")]
#[cfg_attr(
not(all(web_platform, target_feature = "exception-handling")),
doc = "[`run_app()`]"
doc = "[`run()`]"
)]
/// [^1], this returns immediately, and doesn't throw an exception in order to
/// satisfy its [`!`] return type.
@@ -206,9 +206,9 @@ pub trait EventLoopExtWeb {
///
#[cfg_attr(
not(all(web_platform, target_feature = "exception-handling")),
doc = "[`run_app()`]: EventLoop::run_app()"
doc = "[`run()`]: EventLoop::run()"
)]
/// [^1]: `run_app()` is _not_ available on Wasm when the target supports `exception-handling`.
/// [^1]: `run()` is _not_ available on Wasm when the target supports `exception-handling`.
fn spawn_app<A: ApplicationHandler + 'static>(self, app: A);
/// Sets the strategy for [`ControlFlow::Poll`].

View File

@@ -496,15 +496,21 @@ impl EventLoop {
input_status
}
pub fn run_app<A: ApplicationHandler>(mut self, app: A) -> Result<(), EventLoopError> {
self.run_app_on_demand(app)
pub fn run<A: ApplicationHandler>(
mut self,
init_closure: impl FnOnce(&dyn RootActiveEventLoop) -> A,
) -> Result<(), EventLoopError> {
self.run_on_demand(init_closure)
}
pub fn run_app_on_demand<A: ApplicationHandler>(
pub fn run_on_demand<A: ApplicationHandler>(
&mut self,
mut app: A,
init_closure: impl FnOnce(&dyn RootActiveEventLoop) -> A,
) -> Result<(), EventLoopError> {
self.window_target.clear_exit();
let mut app = init_closure(&self.window_target);
loop {
match self.pump_app_events(None, &mut app) {
PumpStatus::Exit(0) => {
@@ -546,8 +552,6 @@ impl EventLoop {
if self.exiting() {
self.loop_running = false;
app.exiting(&self.window_target);
PumpStatus::Exit(0)
} else {
PumpStatus::Continue

View File

@@ -9,12 +9,12 @@ use objc2_app_kit::{NSApplication, NSApplicationActivationPolicy, NSRunningAppli
use objc2_foundation::{MainThreadMarker, NSNotification};
use super::super::event_handler::EventHandler;
use super::event_loop::{stop_app_immediately, ActiveEventLoop, EventLoopProxy, PanicInfo};
use super::event_loop::{stop_app_immediately, EventLoopProxy, PanicInfo};
use super::menu;
use super::observer::{EventLoopWaker, RunLoop};
use crate::application::ApplicationHandler;
use crate::event::{StartCause, WindowEvent};
use crate::event_loop::ControlFlow;
use crate::event_loop::{ActiveEventLoop, ControlFlow};
use crate::window::WindowId;
#[derive(Debug)]
@@ -163,17 +163,25 @@ impl AppState {
pub fn will_terminate(self: &Rc<Self>, _notification: &NSNotification) {
trace_scope!("NSApplicationWillTerminateNotification");
// TODO: Notify every window that it will be destroyed, like done in iOS?
self.with_handler(|app, event_loop| {
app.exiting(event_loop);
});
self.internal_exit();
}
/// Place the event handler in the application state for the duration
/// of the given closure.
pub fn set_event_handler<R>(
pub fn set_init_closure<A: ApplicationHandler, R>(
&self,
handler: &mut dyn ApplicationHandler,
init_closure: impl FnOnce(&dyn ActiveEventLoop) -> A,
closure: impl FnOnce() -> R,
) -> R {
self.event_handler.set(handler, closure)
let init_closure = Box::new(
|active_event_loop: &'_ dyn ActiveEventLoop| -> Box<dyn ApplicationHandler + '_> {
Box::new(init_closure(active_event_loop))
},
);
self.event_handler.set(init_closure, closure)
}
pub fn event_loop_proxy(&self) -> &Arc<EventLoopProxy> {
@@ -208,10 +216,6 @@ impl AppState {
/// NOTE: that if the `NSApplication` has been launched then that state is preserved,
/// and we won't need to re-launch the app if subsequent EventLoops are run.
pub fn internal_exit(self: &Rc<Self>) {
self.with_handler(|app, event_loop| {
app.exiting(event_loop);
});
self.set_is_running(false);
self.set_stop_on_redraw(false);
self.set_stop_before_wait(false);

View File

@@ -274,20 +274,23 @@ impl EventLoop {
&self.window_target
}
pub fn run_app<A: ApplicationHandler>(mut self, app: A) -> Result<(), EventLoopError> {
self.run_app_on_demand(app)
pub fn run<A: ApplicationHandler>(
mut self,
init_closure: impl FnOnce(&dyn RootActiveEventLoop) -> A,
) -> Result<(), EventLoopError> {
self.run_on_demand(init_closure)
}
// NB: we don't base this on `pump_events` because for `MacOs` we can't support
// `pump_events` elegantly (we just ask to run the loop for a "short" amount of
// time and so a layered implementation would end up using a lot of CPU due to
// redundant wake ups.
pub fn run_app_on_demand<A: ApplicationHandler>(
pub fn run_on_demand<A: ApplicationHandler>(
&mut self,
mut app: A,
init_closure: impl FnOnce(&dyn RootActiveEventLoop) -> A,
) -> Result<(), EventLoopError> {
self.app_state.clear_exit();
self.app_state.set_event_handler(&mut app, || {
self.app_state.set_init_closure(init_closure, || {
autoreleasepool(|_| {
// clear / normalize pump_events state
self.app_state.set_wait_timeout(None);

View File

@@ -399,7 +399,7 @@ declare_class!(
unsafe { &*string }.to_string()
};
let is_control = string.chars().next().map_or(false, |c| c.is_control());
let is_control = string.chars().next().is_some_and(|c| c.is_control());
// Commit only if we have marked text.
if unsafe { self.hasMarkedText() } && self.is_ime_enabled() && !is_control {

View File

@@ -765,12 +765,6 @@ impl WindowDelegate {
});
let delegate: Retained<WindowDelegate> = unsafe { msg_send_id![super(delegate), init] };
if scale_factor != 1.0 {
let delegate = delegate.clone();
RunLoop::main(mtm).queue_closure(move || {
delegate.handle_scale_factor_changed(scale_factor);
});
}
window.setDelegate(Some(ProtocolObject::from_ref(&*delegate)));
// Listen for theme change event.
@@ -801,10 +795,6 @@ impl WindowDelegate {
delegate.set_cursor(attrs.cursor);
// XXX Send `Focused(false)` right after creating the window delegate, so we won't
// obscure the real focused events on the startup.
delegate.queue_event(WindowEvent::Focused(false));
// Set fullscreen mode after we setup everything
delegate.set_fullscreen(attrs.fullscreen.map(Into::into));

View File

@@ -1,33 +1,55 @@
use std::cell::RefCell;
use std::cell::Cell;
use std::{fmt, mem};
use crate::application::ApplicationHandler;
use crate::event_loop::ActiveEventLoop;
/// A helper type for storing a reference to `ApplicationHandler`, allowing interior mutable access
/// to it within the execution of a closure.
#[derive(Default)]
pub(crate) struct EventHandler {
/// This can be in the following states:
/// - Not registered by the event loop (None).
/// - Present (Some(handler)).
/// - Currently executing the handler / in use (RefCell borrowed).
inner: RefCell<Option<&'static mut dyn ApplicationHandler>>,
state: Cell<State>,
}
type InitClosure<'handler> =
Box<dyn FnOnce(&dyn ActiveEventLoop) -> Box<dyn ApplicationHandler + 'handler> + 'handler>;
#[derive(Default)]
enum State {
/// Not registered by the event loop.
#[default]
NotRegistered,
/// The event is registered by the event loop.
Registered(InitClosure<'static>),
/// The application has been initialized, and we're ready to handle events.
Ready(Box<dyn ApplicationHandler + 'static>),
/// Currently executing the handler.
CurrentlyExecuting,
/// The application has been terminated.
Terminated,
// TODO: Invalid state?
}
impl fmt::Debug for EventHandler {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let state = match self.inner.try_borrow().as_deref() {
Ok(Some(_)) => "<available>",
Ok(None) => "<not set>",
Err(_) => "<in use>",
let state = self.state.replace(State::CurrentlyExecuting);
// NOTE: We're very careful not to panic inside the "critial" section here.
let string = match &state {
State::NotRegistered => "<not registered>",
State::Registered(_) => "<registered>",
State::Ready(_) => "<ready>",
State::CurrentlyExecuting => "<currently executing>",
State::Terminated => "<terminated>",
};
f.debug_struct("EventHandler").field("state", &state).finish_non_exhaustive()
self.state.set(state);
f.debug_struct("EventHandler").field("state", &string).finish_non_exhaustive()
}
}
impl EventHandler {
pub(crate) fn new() -> Self {
Self { inner: RefCell::new(None) }
pub(crate) const fn new() -> Self {
Self { state: Cell::new(State::NotRegistered) }
}
/// Set the event loop handler for the duration of the given closure.
@@ -37,7 +59,7 @@ impl EventHandler {
/// from within the closure.
pub(crate) fn set<'handler, R>(
&self,
app: &'handler mut dyn ApplicationHandler,
init_closure: InitClosure<'handler>,
closure: impl FnOnce() -> R,
) -> R {
// SAFETY: We extend the lifetime of the handler here so that we can
@@ -46,14 +68,9 @@ impl EventHandler {
// This is sound, since we make sure to unset the handler again at the
// end of this function, and as such the lifetime isn't actually
// extended beyond `'handler`.
let handler = unsafe {
mem::transmute::<
&'handler mut dyn ApplicationHandler,
&'static mut dyn ApplicationHandler,
>(app)
};
let handler = unsafe { mem::transmute::<InitClosure<'handler>, InitClosure<'static>>(app) };
match self.inner.try_borrow_mut().as_deref_mut() {
match self.state.try_borrow_mut().as_deref_mut() {
Ok(Some(_)) => {
unreachable!("tried to set handler while another was already set");
},
@@ -69,7 +86,7 @@ impl EventHandler {
impl Drop for ClearOnDrop<'_> {
fn drop(&mut self) {
match self.0.inner.try_borrow_mut().as_deref_mut() {
match self.0.state.try_borrow_mut().as_deref_mut() {
Ok(data @ Some(_)) => {
*data = None;
},
@@ -101,6 +118,10 @@ impl EventHandler {
// soundness.
}
fn init(&self) {}
fn terminate(&self) {}
#[cfg(target_os = "macos")]
pub(crate) fn in_use(&self) -> bool {
self.inner.try_borrow().is_err()
@@ -120,7 +141,7 @@ impl EventHandler {
//
// If the handler unwinds, the `RefMut` will ensure that the
// handler is no longer borrowed.
callback(*user_app);
callback(user_app);
},
Ok(None) => {
// `NSApplication`, our app state and this handler are all

View File

@@ -517,30 +517,6 @@ impl Window {
let window = WinitUIWindow::new(mtm, &window_attributes, frame, &view_controller);
window.makeKeyAndVisible();
// Like the Windows and macOS backends, we send a `ScaleFactorChanged` and `SurfaceResized`
// event on window creation if the DPI factor != 1.0
let scale_factor = view.contentScaleFactor();
let scale_factor = scale_factor as f64;
if scale_factor != 1.0 {
let frame = view.frame();
let size =
LogicalSize { width: frame.size.width as f64, height: frame.size.height as f64 };
app_state::handle_nonuser_events(
mtm,
std::iter::once(EventWrapper::ScaleFactorChanged(app_state::ScaleFactorChanged {
window: window.clone(),
scale_factor,
suggested_size: size.to_physical(scale_factor),
}))
.chain(std::iter::once(EventWrapper::StaticEvent(
Event::WindowEvent {
window_id: window.id(),
event: WindowEvent::SurfaceResized(size.to_physical(scale_factor)),
},
))),
);
}
let inner = Inner { window, view_controller, view, gl_or_metal_backed };
Ok(Window { inner: MainThreadBound::new(inner, mtm) })
}

View File

@@ -35,6 +35,9 @@ pub fn scancode_to_physicalkey(scancode: u32) -> PhysicalKey {
// are defined by the Linux kernel. If Winit programs end up being run on other Unix-likes,
// I can only hope they agree on what the keycodes mean.
//
// The mapping here is heavily influenced by Firefox' source:
// https://searchfox.org/mozilla-central/rev/c597e9c789ad36af84a0370d395be066b7dc94f4/widget/NativeKeyToDOMCodeName.h
//
// Some of the keycodes are likely superfluous for our purposes, and some are ones which are
// difficult to test the correctness of, or discover the purpose of. Because of this, they've
// either been commented out here, or not included at all.
@@ -166,23 +169,23 @@ pub fn scancode_to_physicalkey(scancode: u32) -> PhysicalKey {
125 => KeyCode::SuperLeft,
126 => KeyCode::SuperRight,
127 => KeyCode::ContextMenu,
// 128 => KeyCode::STOP,
// 129 => KeyCode::AGAIN,
// 130 => KeyCode::PROPS,
// 131 => KeyCode::UNDO,
// 132 => KeyCode::FRONT,
// 133 => KeyCode::COPY,
// 134 => KeyCode::OPEN,
// 135 => KeyCode::PASTE,
// 136 => KeyCode::FIND,
// 137 => KeyCode::CUT,
// 138 => KeyCode::HELP,
128 => KeyCode::BrowserStop,
129 => KeyCode::Again,
130 => KeyCode::Props,
131 => KeyCode::Undo,
132 => KeyCode::Select, // FRONT
133 => KeyCode::Copy,
134 => KeyCode::Open,
135 => KeyCode::Paste,
136 => KeyCode::Find,
137 => KeyCode::Cut,
138 => KeyCode::Help,
// 139 => KeyCode::MENU,
// 140 => KeyCode::CALC,
140 => KeyCode::LaunchApp2, // CALC
// 141 => KeyCode::SETUP,
// 142 => KeyCode::SLEEP,
// 143 => KeyCode::WAKEUP,
// 144 => KeyCode::FILE,
143 => KeyCode::WakeUp,
144 => KeyCode::LaunchApp1, // FILE
// 145 => KeyCode::SENDFILE,
// 146 => KeyCode::DELETEFILE,
// 147 => KeyCode::XFER,
@@ -193,13 +196,13 @@ pub fn scancode_to_physicalkey(scancode: u32) -> PhysicalKey {
// 152 => KeyCode::COFFEE,
// 153 => KeyCode::ROTATE_DISPLAY,
// 154 => KeyCode::CYCLEWINDOWS,
// 155 => KeyCode::MAIL,
// 156 => KeyCode::BOOKMARKS,
155 => KeyCode::LaunchMail,
156 => KeyCode::BrowserFavorites, // BOOKMARKS
// 157 => KeyCode::COMPUTER,
// 158 => KeyCode::BACK,
// 159 => KeyCode::FORWARD,
158 => KeyCode::BrowserBack,
159 => KeyCode::BrowserForward,
// 160 => KeyCode::CLOSECD,
// 161 => KeyCode::EJECTCD,
161 => KeyCode::Eject, // EJECTCD
// 162 => KeyCode::EJECTCLOSECD,
163 => KeyCode::MediaTrackNext,
164 => KeyCode::MediaPlayPause,
@@ -209,9 +212,9 @@ pub fn scancode_to_physicalkey(scancode: u32) -> PhysicalKey {
// 168 => KeyCode::REWIND,
// 169 => KeyCode::PHONE,
// 170 => KeyCode::ISO,
// 171 => KeyCode::CONFIG,
// 172 => KeyCode::HOMEPAGE,
// 173 => KeyCode::REFRESH,
171 => KeyCode::MediaSelect, // CONFIG
172 => KeyCode::BrowserHome,
173 => KeyCode::BrowserRefresh,
// 174 => KeyCode::EXIT,
// 175 => KeyCode::MOVE,
// 176 => KeyCode::EDIT,
@@ -250,7 +253,7 @@ pub fn scancode_to_physicalkey(scancode: u32) -> PhysicalKey {
// 214 => KeyCode::QUESTION,
// 215 => KeyCode::EMAIL,
// 216 => KeyCode::CHAT,
// 217 => KeyCode::SEARCH,
217 => KeyCode::BrowserSearch,
// 218 => KeyCode::CONNECT,
// 219 => KeyCode::FINANCE,
// 220 => KeyCode::SPORT,
@@ -419,10 +422,32 @@ pub fn physicalkey_to_scancode(key: PhysicalKey) -> Option<u32> {
KeyCode::SuperLeft => Some(125),
KeyCode::SuperRight => Some(126),
KeyCode::ContextMenu => Some(127),
KeyCode::BrowserStop => Some(128),
KeyCode::Again => Some(129),
KeyCode::Props => Some(130),
KeyCode::Undo => Some(131),
KeyCode::Select => Some(132),
KeyCode::Copy => Some(133),
KeyCode::Open => Some(134),
KeyCode::Paste => Some(135),
KeyCode::Find => Some(136),
KeyCode::Cut => Some(137),
KeyCode::Help => Some(138),
KeyCode::LaunchApp2 => Some(140),
KeyCode::WakeUp => Some(143),
KeyCode::LaunchApp1 => Some(144),
KeyCode::LaunchMail => Some(155),
KeyCode::BrowserFavorites => Some(156),
KeyCode::BrowserBack => Some(158),
KeyCode::BrowserForward => Some(159),
KeyCode::Eject => Some(161),
KeyCode::MediaTrackNext => Some(163),
KeyCode::MediaPlayPause => Some(164),
KeyCode::MediaTrackPrevious => Some(165),
KeyCode::MediaStop => Some(166),
KeyCode::MediaSelect => Some(171),
KeyCode::BrowserHome => Some(172),
KeyCode::BrowserRefresh => Some(173),
KeyCode::F13 => Some(183),
KeyCode::F14 => Some(184),
KeyCode::F15 => Some(185),
@@ -435,6 +460,7 @@ pub fn physicalkey_to_scancode(key: PhysicalKey) -> Option<u32> {
KeyCode::F22 => Some(192),
KeyCode::F23 => Some(193),
KeyCode::F24 => Some(194),
KeyCode::BrowserSearch => Some(217),
_ => None,
}
}

View File

@@ -183,7 +183,7 @@ pub struct KeyContext<'a> {
scratch_buffer: &'a mut Vec<u8>,
}
impl<'a> KeyContext<'a> {
impl KeyContext<'_> {
pub fn process_key_event(
&mut self,
keycode: u32,

View File

@@ -360,15 +360,18 @@ impl EventLoop {
}
}
pub fn run_app<A: ApplicationHandler>(self, app: A) -> Result<(), EventLoopError> {
x11_or_wayland!(match self; EventLoop(evlp) => evlp.run_app(app))
pub fn run<A: ApplicationHandler>(
self,
init_closure: impl FnOnce(&dyn ActiveEventLoop) -> A,
) -> Result<(), EventLoopError> {
x11_or_wayland!(match self; EventLoop(evlp) => evlp.run(init_closure))
}
pub fn run_app_on_demand<A: ApplicationHandler>(
pub fn run_on_demand<A: ApplicationHandler>(
&mut self,
app: A,
init_closure: impl FnOnce(&dyn ActiveEventLoop) -> A,
) -> Result<(), EventLoopError> {
x11_or_wayland!(match self; EventLoop(evlp) => evlp.run_app_on_demand(app))
x11_or_wayland!(match self; EventLoop(evlp) => evlp.run_on_demand(init_closure))
}
pub fn pump_app_events<A: ApplicationHandler>(

View File

@@ -146,15 +146,21 @@ impl EventLoop {
Ok(event_loop)
}
pub fn run_app<A: ApplicationHandler>(mut self, app: A) -> Result<(), EventLoopError> {
self.run_app_on_demand(app)
pub fn run<A: ApplicationHandler>(
mut self,
init_closure: impl FnOnce(&dyn RootActiveEventLoop) -> A,
) -> Result<(), EventLoopError> {
self.run_on_demand(init_closure)
}
pub fn run_app_on_demand<A: ApplicationHandler>(
pub fn run_on_demand<A: ApplicationHandler>(
&mut self,
mut app: A,
init_closure: impl FnOnce(&dyn RootActiveEventLoop) -> A,
) -> Result<(), EventLoopError> {
self.active_event_loop.clear_exit();
let mut app = init_closure(&self.active_event_loop);
let exit = loop {
match self.pump_app_events(None, &mut app) {
PumpStatus::Exit(0) => {
@@ -198,8 +204,6 @@ impl EventLoop {
if let Some(code) = self.exit_code() {
self.loop_running = false;
app.exiting(&self.active_event_loop);
PumpStatus::Exit(code)
} else {
PumpStatus::Continue

View File

@@ -27,10 +27,7 @@ use sctk::seat::pointer::{
use sctk::seat::SeatState;
use crate::dpi::{LogicalPosition, PhysicalPosition};
use crate::event::{
ElementState, MouseButton, MouseScrollDelta, PointerKind, PointerSource, TouchPhase,
WindowEvent,
};
use crate::event::{ElementState, MouseButton, MouseScrollDelta, PointerSource, PointerKind, TouchPhase, WindowEvent};
use crate::platform_impl::wayland::state::WinitState;
use crate::platform_impl::wayland::{self, WindowId};

View File

@@ -165,7 +165,7 @@ fn push_display(buffer: &mut Vec<u8>, display: &impl std::fmt::Display) {
buffer: &'a mut Vec<u8>,
}
impl<'a> std::fmt::Write for Writer<'a> {
impl std::fmt::Write for Writer<'_> {
fn write_str(&mut self, s: &str) -> std::fmt::Result {
self.buffer.extend_from_slice(s.as_bytes());
Ok(())

View File

@@ -373,15 +373,21 @@ impl EventLoop {
&self.event_processor.target
}
pub fn run_app<A: ApplicationHandler>(mut self, app: A) -> Result<(), EventLoopError> {
self.run_app_on_demand(app)
pub fn run<A: ApplicationHandler>(
mut self,
init_closure: impl FnOnce(&dyn RootActiveEventLoop) -> A,
) -> Result<(), EventLoopError> {
self.run_on_demand(init_closure)
}
pub fn run_app_on_demand<A: ApplicationHandler>(
pub fn run_on_demand<A: ApplicationHandler>(
&mut self,
mut app: A,
init_closure: impl FnOnce(&dyn RootActiveEventLoop) -> A,
) -> Result<(), EventLoopError> {
self.event_processor.target.clear_exit();
let mut app = init_closure(&self.event_processor.target);
let exit = loop {
match self.pump_app_events(None, &mut app) {
PumpStatus::Exit(0) => {
@@ -429,8 +435,6 @@ impl EventLoop {
if let Some(code) = self.exit_code() {
self.loop_running = false;
app.exiting(self.window_target());
PumpStatus::Exit(code)
} else {
PumpStatus::Continue
@@ -762,14 +766,14 @@ impl<'a> DeviceInfo<'a> {
}
}
impl<'a> Drop for DeviceInfo<'a> {
impl Drop for DeviceInfo<'_> {
fn drop(&mut self) {
assert!(!self.info.is_null());
unsafe { (self.xconn.xinput2.XIFreeDeviceInfo)(self.info as *mut _) };
}
}
impl<'a> Deref for DeviceInfo<'a> {
impl Deref for DeviceInfo<'_> {
type Target = [ffi::XIDeviceInfo];
fn deref(&self) -> &Self::Target {
@@ -954,7 +958,7 @@ trait CookieResultExt {
fn expect_then_ignore_error(self, msg: &str);
}
impl<'a, E: fmt::Debug> CookieResultExt for Result<VoidCookie<'a>, E> {
impl<E: fmt::Debug> CookieResultExt for Result<VoidCookie<'_>, E> {
fn expect_then_ignore_error(self, msg: &str) {
self.expect(msg).ignore_error()
}

View File

@@ -280,7 +280,7 @@ impl XConnection {
let info = self
.xcb_connection()
.extension_information(randr::X11_EXTENSION_NAME)?
.ok_or_else(|| X11Error::MissingExtension(randr::X11_EXTENSION_NAME))?;
.ok_or(X11Error::MissingExtension(randr::X11_EXTENSION_NAME))?;
// Select input data.
let event_mask =

View File

@@ -19,7 +19,7 @@ impl<'a, T> XSmartPointer<'a, T> {
}
}
impl<'a, T> Deref for XSmartPointer<'a, T> {
impl<T> Deref for XSmartPointer<'_, T> {
type Target = T;
fn deref(&self) -> &T {
@@ -27,13 +27,13 @@ impl<'a, T> Deref for XSmartPointer<'a, T> {
}
}
impl<'a, T> DerefMut for XSmartPointer<'a, T> {
impl<T> DerefMut for XSmartPointer<'_, T> {
fn deref_mut(&mut self) -> &mut T {
unsafe { &mut *self.ptr }
}
}
impl<'a, T> Drop for XSmartPointer<'a, T> {
impl<T> Drop for XSmartPointer<'_, T> {
fn drop(&mut self) {
unsafe {
(self.xconn.xlib.XFree)(self.ptr as *mut _);

View File

@@ -483,7 +483,11 @@ impl EventLoop {
}
}
pub fn run_app<A: ApplicationHandler>(mut self, mut app: A) -> Result<(), EventLoopError> {
pub fn run<A: ApplicationHandler>(
mut self,
init_closure: impl FnOnce(&dyn RootActiveEventLoop) -> A,
) -> Result<(), EventLoopError> {
let mut app = init_closure(&self.window_target);
let mut start_cause = StartCause::Init;
loop {
app.new_events(&self.window_target, start_cause);
@@ -654,8 +658,6 @@ impl EventLoop {
}
}
app.exiting(&self.window_target);
Ok(())
}

View File

@@ -125,7 +125,7 @@ impl<'a> WindowProperties<'a> {
}
}
impl<'a> fmt::Display for WindowProperties<'a> {
impl fmt::Display for WindowProperties<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,

View File

@@ -96,7 +96,6 @@ fn handle_event<A: ApplicationHandler>(app: &mut A, target: &ActiveEventLoop, ev
Event::Resumed => app.resumed(target),
Event::CreateSurfaces => app.can_create_surfaces(target),
Event::AboutToWait => app.about_to_wait(target),
Event::LoopExiting => app.exiting(target),
Event::MemoryWarning => app.memory_warning(target),
}
}

View File

@@ -609,7 +609,7 @@ impl Shared {
self.apply_control_flow();
// We don't call `handle_loop_destroyed` here because we don't need to
// perform cleanup when the Web browser is going to destroy the page.
self.handle_event(Event::LoopExiting);
todo!("drop the application handler");
}
// handle_event takes in events and either queues them or applies a callback
@@ -713,7 +713,7 @@ impl Shared {
}
fn handle_loop_destroyed(&self) {
self.handle_event(Event::LoopExiting);
todo!("drop the application handler");
let all_canvases = std::mem::take(&mut *self.0.all_canvases.borrow_mut());
*self.0.page_transition_event_handle.borrow_mut() = None;
*self.0.on_mouse_move.borrow_mut() = None;

View File

@@ -20,12 +20,10 @@ use windows_sys::Win32::Graphics::Gdi::{
GetMonitorInfoW, MonitorFromRect, MonitorFromWindow, RedrawWindow, ScreenToClient,
ValidateRect, MONITORINFO, MONITOR_DEFAULTTONULL, RDW_INTERNALPAINT, SC_SCREENSAVE,
};
use windows_sys::Win32::System::Diagnostics::ToolHelp as toolhelp;
use windows_sys::Win32::System::Ole::RevokeDragDrop;
use windows_sys::Win32::System::Threading::{
CreateWaitableTimerExW, GetCurrentProcessId, GetCurrentThreadId, GetThreadTimes, OpenThread,
SetWaitableTimer, CREATE_WAITABLE_TIMER_HIGH_RESOLUTION, INFINITE, THREAD_QUERY_INFORMATION,
TIMER_ALL_ACCESS,
CreateWaitableTimerExW, GetCurrentThreadId, SetWaitableTimer,
CREATE_WAITABLE_TIMER_HIGH_RESOLUTION, INFINITE, TIMER_ALL_ACCESS,
};
use windows_sys::Win32::UI::Controls::{HOVER_DEFAULT, WM_MOUSELEAVE};
use windows_sys::Win32::UI::Input::Ime::{GCS_COMPSTR, GCS_RESULTSTR, ISC_SHOWUICOMPOSITIONWINDOW};
@@ -222,15 +220,21 @@ impl EventLoop {
&self.window_target
}
pub fn run_app<A: ApplicationHandler>(mut self, app: A) -> Result<(), EventLoopError> {
self.run_app_on_demand(app)
pub fn run<A: ApplicationHandler>(
mut self,
init_closure: impl FnOnce(&dyn RootActiveEventLoop) -> A,
) -> Result<(), EventLoopError> {
self.run_on_demand(init_closure)
}
pub fn run_app_on_demand<A: ApplicationHandler>(
pub fn run_on_demand<A: ApplicationHandler>(
&mut self,
mut app: A,
init_closure: impl FnOnce(&dyn RootActiveEventLoop) -> A,
) -> Result<(), EventLoopError> {
self.window_target.clear_exit();
let mut app = init_closure(&self.window_target);
{
let runner = &self.window_target.runner_shared;
@@ -252,7 +256,6 @@ impl EventLoop {
Event::Resumed => app.resumed(event_loop_windows_ref),
Event::CreateSurfaces => app.can_create_surfaces(event_loop_windows_ref),
Event::AboutToWait => app.about_to_wait(event_loop_windows_ref),
Event::LoopExiting => app.exiting(event_loop_windows_ref),
Event::MemoryWarning => app.memory_warning(event_loop_windows_ref),
});
}
@@ -319,7 +322,6 @@ impl EventLoop {
Event::Resumed => app.resumed(event_loop_windows_ref),
Event::CreateSurfaces => app.can_create_surfaces(event_loop_windows_ref),
Event::AboutToWait => app.about_to_wait(event_loop_windows_ref),
Event::LoopExiting => app.exiting(event_loop_windows_ref),
Event::MemoryWarning => app.memory_warning(event_loop_windows_ref),
});
@@ -350,8 +352,10 @@ impl EventLoop {
PumpStatus::Continue
};
// We wait until we've checked for an exit status before clearing the
// application callback, in case we need to dispatch a LoopExiting event
// We wait until we've checked for an exit status before clearing the application callback,
// in case any of the methods above ends up triggering an event.
//
// This drops the user's `ApplicationHandler`.
//
// # Safety
// This pairs up with our call to `runner.set_event_handler` and ensures
@@ -544,37 +548,6 @@ impl rwh_06::HasDisplayHandle for OwnedDisplayHandle {
}
}
/// Get the main thread ID.
fn main_thread_id() -> u32 {
main_thread_id_via_snapshot().unwrap_or_else(main_thread_id_via_crt)
}
/// Get the main thread ID via the snapshot feature.
fn main_thread_id_via_snapshot() -> Option<u32> {
// Get the current process ID.
let process_id = unsafe { GetCurrentProcessId() };
// Take a snapshot of the process.
let snapshot = match ToolhelpSnapshot::new(process_id) {
Ok(snapshot) => snapshot,
Err(err) => {
tracing::error!("failed to take snapshot of process: {err}");
return None;
},
};
// Filter to threads owned by this process.
let threads = snapshot.filter(|ti| ti.process_id == process_id);
// Get the time that the thread was created.
let threadtimes = threads
.filter_map(|ti| ti.thread_time().map(move |time| (ti, time)))
.filter(|(_, time)| *time != 0);
// Identify the thread with the earliest time, since that must be the thread that called main().
threadtimes.min_by_key(|(_, time)| *time).map(|(ti, _)| ti.thread_id)
}
/// Returns the id of the main thread.
///
/// Windows has no real API to check if the current executing thread is the "main thread", unlike
@@ -593,14 +566,10 @@ fn main_thread_id_via_snapshot() -> Option<u32> {
///
/// Full details of CRT initialization can be found here:
/// <https://docs.microsoft.com/en-us/cpp/c-runtime-library/crt-initialization?view=msvc-160>
///
/// notgull addendum: The above comment is a lie, we can get the total list of threads in the
/// process and figure out which thread came first. We try to use that strategy first, and use this
/// strategy as a fallback.
fn main_thread_id_via_crt() -> u32 {
fn main_thread_id() -> u32 {
static mut MAIN_THREAD_ID: u32 = 0;
/// Function pointer used in CRT initialization section to set the above static field's value.
// Function pointer used in CRT initialization section to set the above static field's value.
// Mark as used so this is not removable.
#[used]
@@ -620,110 +589,6 @@ fn main_thread_id_via_crt() -> u32 {
unsafe { MAIN_THREAD_ID }
}
/// A screenshot from the toolhelp tool.
struct ToolhelpSnapshot {
/// The handle to the snapshot.
handle: OwnedHandle,
/// Are we returning the first thread entry?
first_entry: bool,
}
impl ToolhelpSnapshot {
/// Take a screenshot of the provided process.
fn new(process_id: u32) -> Result<Self, EventLoopError> {
// Take a snapshot.
let handle =
unsafe { toolhelp::CreateToolhelp32Snapshot(toolhelp::TH32CS_SNAPTHREAD, process_id) };
if handle == 0 {
return Err(EventLoopError::Os(os_error!("failed to get toolhelp snapshot")));
}
Ok(Self { handle: unsafe { OwnedHandle::from_raw_handle(handle as _) }, first_entry: true })
}
}
impl Iterator for ToolhelpSnapshot {
type Item = ThreadEntry;
fn next(&mut self) -> Option<Self::Item> {
let mut slot = mem::MaybeUninit::uninit();
// Write the size to the slot.
unsafe {
let slot: *mut toolhelp::THREADENTRY32 = slot.as_mut_ptr();
let size = ptr::addr_of_mut!((*slot).dwSize);
size.write(mem::size_of::<toolhelp::THREADENTRY32>() as _);
}
let result = if self.first_entry {
self.first_entry = false;
unsafe { toolhelp::Thread32First(self.handle.as_raw_handle() as _, slot.as_mut_ptr()) }
} else {
unsafe { toolhelp::Thread32Next(self.handle.as_raw_handle() as _, slot.as_mut_ptr()) }
};
if result != 0 {
let thread_entry = unsafe { slot.assume_init() };
Some(ThreadEntry {
thread_id: thread_entry.th32ThreadID,
process_id: thread_entry.th32OwnerProcessID,
})
} else {
None
}
}
}
#[derive(Copy, Clone)]
struct ThreadEntry {
/// The thread ID.
thread_id: u32,
/// The owner process ID.
process_id: u32,
}
impl ThreadEntry {
/// Get the time this thread was created.
fn thread_time(self) -> Option<u64> {
// Open a thread id.
let thread_handle = unsafe {
let handle = OpenThread(THREAD_QUERY_INFORMATION, 1, self.thread_id);
if handle == 0 {
return None;
}
OwnedHandle::from_raw_handle(handle as _)
};
// Get the time this thread was opened.
let file_time = unsafe {
let mut file_time = [mem::MaybeUninit::uninit(); 4];
let result = GetThreadTimes(
thread_handle.as_raw_handle() as _,
file_time[0].as_mut_ptr(),
file_time[1].as_mut_ptr(),
file_time[2].as_mut_ptr(),
file_time[3].as_mut_ptr(),
);
if result == 0 {
return None;
}
file_time[0].assume_init()
};
Some(
((file_time.dwHighDateTime as u64) << 32)
| ((file_time.dwLowDateTime as u64) & 0xffffffff),
)
}
}
/// Returns the minimum `Option<Duration>`, taking into account that `None`
/// equates to an infinite timeout, not a zero timeout (so can't just use
/// `Option::min`)

View File

@@ -248,9 +248,8 @@ impl EventLoopRunner {
}
}
/// Dispatch control flow events (`NewEvents`, `AboutToWait`, and
/// `LoopExiting`) as necessary to bring the internal `RunnerState` to the
/// new runner state.
/// Dispatch control flow events (`new_events`, `about_to_wait`) as necessary to bring the
/// internal `RunnerState` to the new runner state.
///
/// The state transitions are defined as follows:
///
@@ -294,7 +293,6 @@ impl EventLoopRunner {
self.call_new_events(true);
self.call_event_handler(Event::AboutToWait);
self.last_events_cleared.set(Instant::now());
self.call_event_handler(Event::LoopExiting);
},
(_, Uninitialized) => panic!("cannot move state to Uninitialized"),
@@ -302,9 +300,7 @@ impl EventLoopRunner {
(Idle, HandlingMainEvents) => {
self.call_new_events(false);
},
(Idle, Destroyed) => {
self.call_event_handler(Event::LoopExiting);
},
(Idle, Destroyed) => {},
(HandlingMainEvents, Idle) => {
// This is always the last event we dispatch before waiting for new events
@@ -314,7 +310,6 @@ impl EventLoopRunner {
(HandlingMainEvents, Destroyed) => {
self.call_event_handler(Event::AboutToWait);
self.last_events_cleared.set(Instant::now());
self.call_event_handler(Event::LoopExiting);
},
(Destroyed, _) => panic!("cannot move state from Destroyed"),

View File

@@ -1079,6 +1079,20 @@ pub(crate) fn physicalkey_to_scancode(physical_key: PhysicalKey) -> Option<u32>
KeyCode::AudioVolumeDown => Some(0xe02e),
KeyCode::AudioVolumeMute => Some(0xe020),
KeyCode::AudioVolumeUp => Some(0xe030),
// Extra from Chromium sources:
// https://chromium.googlesource.com/chromium/src.git/+/3e1a26c44c024d97dc9a4c09bbc6a2365398ca2c/ui/events/keycodes/dom/dom_code_data.inc
KeyCode::Lang4 => Some(0x0077),
KeyCode::Lang3 => Some(0x0078),
KeyCode::Undo => Some(0xe008),
KeyCode::Paste => Some(0xe00a),
KeyCode::Cut => Some(0xe017),
KeyCode::Copy => Some(0xe018),
KeyCode::Eject => Some(0xe02c),
KeyCode::Help => Some(0xe03b),
KeyCode::Sleep => Some(0xe05f),
KeyCode::WakeUp => Some(0xe063),
_ => None,
}
}
@@ -1238,6 +1252,20 @@ pub(crate) fn scancode_to_physicalkey(scancode: u32) -> PhysicalKey {
0xe02e => KeyCode::AudioVolumeDown,
0xe020 => KeyCode::AudioVolumeMute,
0xe030 => KeyCode::AudioVolumeUp,
// Extra from Chromium sources:
// https://chromium.googlesource.com/chromium/src.git/+/3e1a26c44c024d97dc9a4c09bbc6a2365398ca2c/ui/events/keycodes/dom/dom_code_data.inc
0x0077 => KeyCode::Lang4,
0x0078 => KeyCode::Lang3,
0xe008 => KeyCode::Undo,
0xe00a => KeyCode::Paste,
0xe017 => KeyCode::Cut,
0xe018 => KeyCode::Copy,
0xe02c => KeyCode::Eject,
0xe03b => KeyCode::Help,
0xe05f => KeyCode::Sleep,
0xe063 => KeyCode::WakeUp,
_ => return PhysicalKey::Unidentified(NativeKeyCode::Windows(scancode as u16)),
})
}

View File

@@ -1071,7 +1071,7 @@ pub(super) struct InitData<'a> {
pub window: Option<Window>,
}
impl<'a> InitData<'a> {
impl InitData<'_> {
unsafe fn create_window(&self, window: HWND) -> Window {
// Register for touch events if applicable
{