mirror of
https://github.com/rust-windowing/winit.git
synced 2026-06-26 22:53:15 -04:00
Compare commits
5 Commits
notgull/wi
...
madsmtm/in
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fbc6fdc30c | ||
|
|
164bf85b5b | ||
|
|
cfa8f027cc | ||
|
|
2e5db75101 | ||
|
|
19e5bee3d1 |
@@ -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",
|
||||
|
||||
@@ -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)))]
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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(())
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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))]
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
57
src/event.rs
57
src/event.rs
@@ -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);
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
85
src/lib.rs
85
src/lib.rs
@@ -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.
|
||||
|
||||
@@ -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(())
|
||||
//! }
|
||||
//! ```
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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`].
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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));
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) })
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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>(
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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};
|
||||
|
||||
@@ -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(())
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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 _);
|
||||
|
||||
@@ -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(())
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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`)
|
||||
|
||||
@@ -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"),
|
||||
|
||||
@@ -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)),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user