From 13e0864bcd12d6fcfddc7ba4655f9e3be6542d7a Mon Sep 17 00:00:00 2001 From: Jonathan Johnson Date: Tue, 4 Jul 2023 07:42:33 -0700 Subject: [PATCH] Added ability for windows to call the main loop When I ran the new Kludgine on my mac last night, I was surprised to discover it didn't work. It turns out create_surface needs to be called on the main thread on Metal. This commit adds a way to provide a callback that can be remotely called through the EventLoopProxy. This allows Kludgine to send a CreateSurfaceRequest to the main event loop and receive a wgpu::Surface back. --- src/lib.rs | 149 ++++++++++++--- src/private.rs | 18 +- src/window.rs | 492 ++++++++++++++++++++++++++++--------------------- 3 files changed, 419 insertions(+), 240 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 017f52c..c0d3fc1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,30 +15,52 @@ use winit::error::OsError; use winit::window::WindowId; use std::collections::HashMap; +use std::marker::PhantomData; use std::sync::{mpsc, Arc, Mutex, PoisonError}; use winit::event_loop::{ControlFlow, EventLoopBuilder, EventLoopProxy, EventLoopWindowTarget}; use winit::{event::Event, event_loop::EventLoop}; -use crate::private::{AppMessage, WindowEvent, WindowMessage}; +use crate::private::{EventLoopMessage, WindowEvent, WindowMessage}; use crate::window::WindowAttributes; /// An application that is not yet running. -pub struct PendingApp { - event_loop: EventLoop, - running: App, +pub struct PendingApp +where + AppMessage: Message, +{ + event_loop: EventLoop>, + message_callback: BoxedEventCallback, + running: App, } -impl Default for PendingApp { +type BoxedEventCallback = + Box) -> ::Response>; + +impl Default for PendingApp<()> { fn default() -> Self { Self::new() } } -impl PendingApp { +impl PendingApp<()> { /// Returns a new app with no windows. If no windows are opened before the /// app is run, the app will immediately close. #[must_use] pub fn new() -> Self { + Self::new_with_event_callback(|_, _| {}) + } +} + +impl PendingApp +where + AppMessage: Message, +{ + /// Returns a new app with no windows. If no windows are opened before the + /// app is run, the app will immediately close. + #[must_use] + pub fn new_with_event_callback( + event_callback: impl FnMut(AppMessage, &Windows) -> AppMessage::Response + 'static, + ) -> Self { let event_loop = EventLoopBuilder::with_user_event().build(); let proxy = event_loop.create_proxy(); Self { @@ -47,13 +69,14 @@ impl PendingApp { proxy, windows: Windows::default(), }, + message_callback: Box::new(event_callback), } } /// Begins running the application. This function will never return. /// /// Internally this runs the [`EventLoop`]. - pub fn run(self) -> ! { + pub fn run(mut self) -> ! { self.event_loop.run(move |event, target, control_flow| { *control_flow = ControlFlow::Wait; match event { @@ -67,17 +90,17 @@ impl PendingApp { self.running.windows.send(window_id, WindowMessage::Redraw); } Event::UserEvent(message) => match message { - AppMessage::CloseWindow(window_id) => { + EventLoopMessage::CloseWindow(window_id) => { if self.running.windows.close(window_id) { *control_flow = ControlFlow::ExitWithCode(0); } } - AppMessage::WindowPanic(window_id) => { + EventLoopMessage::WindowPanic(window_id) => { if self.running.windows.close(window_id) { *control_flow = ControlFlow::ExitWithCode(1); } } - AppMessage::OpenWindow { + EventLoopMessage::OpenWindow { attrs, sender, open_sender, @@ -85,6 +108,13 @@ impl PendingApp { let result = self.running.windows.open(target, attrs, sender); let _result = open_sender.send(result); } + EventLoopMessage::User { + message, + response_sender, + } => { + let _result = response_sender + .send((self.message_callback)(message, &self.running.windows)); + } }, Event::NewEvents(_) | Event::DeviceEvent { .. } @@ -99,19 +129,64 @@ impl PendingApp { } /// A reference to a multi-window application. -#[derive(Clone)] -pub struct App { - proxy: EventLoopProxy, - windows: Windows, +pub struct App +where + AppMessage: Message, +{ + proxy: EventLoopProxy>, + windows: Windows, +} + +impl Clone for App +where + AppMessage: Message, +{ + fn clone(&self) -> Self { + Self { + proxy: self.proxy.clone(), + windows: self.windows.clone(), + } + } } /// A type that has a handle to the application thread. -pub trait Application: private::ApplicationSealed {} +pub trait Application: private::ApplicationSealed +where + AppMessage: Message, +{ + /// Sends an app message to the main event loop to be handled by the + /// callback provided when the app was created. + /// + /// This function will return None if the main event loop is no longer + /// running. Otherwise, this function will block until the result of the + /// callback has been received. + fn send(&mut self, message: AppMessage) -> Option; +} -impl Application for PendingApp {} +/// A message with an associated response type. +pub trait Message: Send + 'static { + /// The type returned when responding to this message. + type Response: Send; +} -impl private::ApplicationSealed for PendingApp { - fn app(&self) -> App { +impl Message for () { + type Response = (); +} + +impl Application for PendingApp +where + AppMessage: Message, +{ + fn send(&mut self, message: AppMessage) -> Option<::Response> { + Some((self.message_callback)(message, &self.running.windows)) + } +} + +impl private::ApplicationSealed for PendingApp +where + AppMessage: Message, +{ + fn app(&self) -> App { self.running.clone() } @@ -127,13 +202,37 @@ impl private::ApplicationSealed for PendingApp { } } -#[derive(Default, Clone)] -struct Windows { +/// A collection of open windows. +pub struct Windows { data: Arc>>, + _message: PhantomData, } -impl Windows { - fn get(&self, id: WindowId) -> Option> { +impl Default for Windows { + fn default() -> Self { + Self { + data: Arc::default(), + _message: PhantomData, + } + } +} + +impl Clone for Windows { + fn clone(&self) -> Self { + Self { + data: self.data.clone(), + _message: PhantomData, + } + } +} + +impl Windows +where + AppMessage: Message, +{ + /// Gets an instance of the winit window for the given window id, if it is + /// still open. + pub fn get(&self, id: WindowId) -> Option> { let windows = self.data.lock().map_or_else(PoisonError::into_inner, |g| g); windows.get(&id).map(|w| w.winit.clone()) } @@ -141,7 +240,7 @@ impl Windows { #[allow(unsafe_code)] fn open( &self, - target: &EventLoopWindowTarget, + target: &EventLoopWindowTarget>, attrs: WindowAttributes, sender: mpsc::SyncSender, ) -> Result, OsError> { @@ -198,7 +297,7 @@ impl Windows { Ok(winit) } - pub fn send(&self, window: WindowId, message: WindowMessage) { + fn send(&self, window: WindowId, message: WindowMessage) { let mut data = self.data.lock().map_or_else(PoisonError::into_inner, |g| g); if let Some(open_window) = data.get(&window) { match open_window.sender.try_send(message) { @@ -214,7 +313,7 @@ impl Windows { } } - pub fn close(&self, window: WindowId) -> bool { + fn close(&self, window: WindowId) -> bool { let mut data = self.data.lock().map_or_else(PoisonError::into_inner, |g| g); data.remove(&window); data.is_empty() diff --git a/src/private.rs b/src/private.rs index c55989f..92b4748 100644 --- a/src/private.rs +++ b/src/private.rs @@ -10,10 +10,13 @@ use winit::event::{ use winit::window::{Theme, WindowId}; use crate::window::WindowAttributes; -use crate::App; +use crate::{App, Message}; -pub trait ApplicationSealed { - fn app(&self) -> App; +pub trait ApplicationSealed +where + AppMessage: Message, +{ + fn app(&self) -> App; fn open( &self, window: WindowAttributes, @@ -21,7 +24,10 @@ pub trait ApplicationSealed { ) -> Result>, OsError>; } -pub enum AppMessage { +pub enum EventLoopMessage +where + AppMessage: Message, +{ OpenWindow { attrs: WindowAttributes, sender: mpsc::SyncSender, @@ -29,6 +35,10 @@ pub enum AppMessage { }, CloseWindow(WindowId), WindowPanic(WindowId), + User { + message: AppMessage, + response_sender: mpsc::SyncSender, + }, } #[derive(Debug)] diff --git a/src/window.rs b/src/window.rs index a756df8..7b746ea 100644 --- a/src/window.rs +++ b/src/window.rs @@ -15,12 +15,11 @@ use winit::event::{ use winit::window::{Fullscreen, Icon, Theme, WindowButtons, WindowId, WindowLevel}; use crate::private::{self, WindowEvent}; -use crate::{App, AppMessage, Application, PendingApp, WindowMessage}; +use crate::{App, Application, EventLoopMessage, Message, PendingApp, WindowMessage, Windows}; /// A weak reference to a running window. #[derive(Clone)] pub struct Window { - app: App, id: WindowId, } @@ -30,13 +29,6 @@ impl Window { pub const fn id(&self) -> WindowId { self.id } - - /// Returns a clone of the winit [`Window`](winit::window::Window) if the - /// window is still open. - #[must_use] - pub fn winit(&self) -> Option> { - self.app.windows.get(self.id) - } } /// A builder for a window. @@ -46,17 +38,20 @@ impl Window { /// supports the cross-platform interface. Support for additional /// platform-specific settings may be possible as long as all types introduced /// are `Send`. -pub struct WindowBuilder<'a, Behavior, Application> +pub struct WindowBuilder<'a, Behavior, Application, AppMessage> where - Behavior: self::WindowBehavior, + Behavior: self::WindowBehavior, + AppMessage: Message, { owner: &'a Application, context: Behavior::Context, attributes: WindowAttributes, } -impl<'a, Behavior, Application> Deref for WindowBuilder<'a, Behavior, Application> +impl<'a, Behavior, Application, AppMessage> Deref + for WindowBuilder<'a, Behavior, Application, AppMessage> where - Behavior: self::WindowBehavior, + Behavior: self::WindowBehavior, + AppMessage: Message, { type Target = WindowAttributes; @@ -65,9 +60,11 @@ where } } -impl<'a, Behavior, Application> DerefMut for WindowBuilder<'a, Behavior, Application> +impl<'a, Behavior, Application, AppMessage> DerefMut + for WindowBuilder<'a, Behavior, Application, AppMessage> where - Behavior: self::WindowBehavior, + Behavior: self::WindowBehavior, + AppMessage: Message, { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.attributes @@ -124,10 +121,11 @@ impl Default for WindowAttributes { } } -impl<'a, Behavior, Application> WindowBuilder<'a, Behavior, Application> +impl<'a, Behavior, Application, AppMessage> WindowBuilder<'a, Behavior, Application, AppMessage> where - Behavior: self::WindowBehavior, - Application: crate::Application, + Behavior: self::WindowBehavior, + Application: crate::Application, + AppMessage: Message, { pub(crate) fn new(owner: &'a Application, context: Behavior::Context) -> Self { Self { @@ -156,12 +154,10 @@ where let Some(winit) = self.owner.open(self.attributes, sender)? else { return Ok(None) }; - let window = Window { - id: winit.id(), - app: self.owner.app(), - }; + let window = Window { id: winit.id() }; let running_window = RunningWindow { messages: receiver, + responses: mpsc::sync_channel(1), app: self.owner.app(), occluded: winit.is_visible().unwrap_or(false), focused: winit.has_focus(), @@ -185,11 +181,18 @@ where } /// A window that is running in its own thread. -pub struct RunningWindow { +pub struct RunningWindow +where + AppMessage: Message, +{ window: Arc, next_redraw_target: Option, messages: mpsc::Receiver, - app: App, + responses: ( + mpsc::SyncSender, + mpsc::Receiver, + ), + app: App, inner_size: PhysicalSize, location: PhysicalPosition, cursor_location: Option>, @@ -203,7 +206,10 @@ pub struct RunningWindow { modifiers: ModifiersState, } -impl RunningWindow { +impl RunningWindow +where + AppMessage: Message, +{ /// Returns a reference to the underlying window. #[must_use] pub fn winit(&self) -> &winit::window::Window { @@ -300,7 +306,7 @@ impl RunningWindow { fn run_with(mut self, context: Behavior::Context) where - Behavior: self::WindowBehavior, + Behavior: self::WindowBehavior, { let proxy = self.app.proxy.clone(); let window_id = self.window.id(); @@ -318,16 +324,16 @@ impl RunningWindow { // if let Err(panic) = possible_panic { - let _result = proxy.send_event(AppMessage::WindowPanic(window_id)); + let _result = proxy.send_event(EventLoopMessage::WindowPanic(window_id)); std::panic::resume_unwind(panic) } else { - let _result = proxy.send_event(AppMessage::CloseWindow(window_id)); + let _result = proxy.send_event(EventLoopMessage::CloseWindow(window_id)); } } fn process_messages_until_redraw(&mut self, behavior: &mut Behavior) -> bool where - Behavior: self::WindowBehavior, + Behavior: self::WindowBehavior, { loop { let message = match TimeUntilRedraw::from(self.next_redraw_target) { @@ -364,7 +370,7 @@ impl RunningWindow { #[allow(clippy::too_many_lines)] // can't avoid the match fn handle_message(&mut self, message: WindowMessage, behavior: &mut Behavior) -> bool where - Behavior: self::WindowBehavior, + Behavior: self::WindowBehavior, { match message { WindowMessage::Redraw => { @@ -559,10 +565,27 @@ impl RunningWindow { } } -impl Application for RunningWindow {} +impl Application for RunningWindow +where + AppMessage: Message, +{ + fn send(&mut self, message: AppMessage) -> Option<::Response> { + self.app + .proxy + .send_event(EventLoopMessage::User { + message, + response_sender: self.responses.0.clone(), + }) + .ok()?; + self.responses.1.recv().ok() + } +} -impl private::ApplicationSealed for RunningWindow { - fn app(&self) -> App { +impl private::ApplicationSealed for RunningWindow +where + AppMessage: Message, +{ + fn app(&self) -> App { self.app.clone() } @@ -575,7 +598,7 @@ impl private::ApplicationSealed for RunningWindow { if self .app .proxy - .send_event(AppMessage::OpenWindow { + .send_event(EventLoopMessage::OpenWindow { attrs, sender, open_sender, @@ -623,7 +646,10 @@ enum TimeUntilRedraw { /// consumers of the libraries. This trait provides functions for each of the /// events a window may receive, enabling the type to react and update its /// state. -pub trait WindowBehavior: UnwindSafe + Sized + 'static { +pub trait WindowBehavior: UnwindSafe + Sized + 'static +where + AppMessage: Message, +{ /// A type that is passed to [`initialize()`](Self::initialize). /// /// This allows providing data to the window from the thread that is opening @@ -632,9 +658,9 @@ pub trait WindowBehavior: UnwindSafe + Sized + 'static { /// Returns a new window builder for this behavior. When the window is /// initialized, a default [`Context`](Self::Context) will be passed. - fn build(app: &App) -> WindowBuilder<'_, Self, App> + fn build(app: &App) -> WindowBuilder<'_, Self, App, AppMessage> where - App: Application, + App: Application, Self::Context: Default, { Self::build_with(app, ::default()) @@ -642,13 +668,53 @@ pub trait WindowBehavior: UnwindSafe + Sized + 'static { /// Returns a new window builder for this behavior. When the window is /// initialized, the provided context will be passed. - fn build_with(app: &App, context: Self::Context) -> WindowBuilder<'_, Self, App> + fn build_with( + app: &App, + context: Self::Context, + ) -> WindowBuilder<'_, Self, App, AppMessage> where - App: Application, + App: Application, { WindowBuilder::new(app, context) } + /// Runs a window with a default instance of this behavior's + /// [`Context`](Self::Context). + /// + /// This function is shorthand for creating a [`PendingApp`], opening this + /// window inside of it, and running the pending app. + /// + /// Messages can be sent to the application's main thread using + /// [`Application::send`]. Each time a message is received by the main event + /// loop, `app_callback` will be invoked. + fn run_with_event_callback( + app_callback: impl FnMut(AppMessage, &Windows) -> AppMessage::Response + 'static, + ) -> ! + where + Self::Context: Default, + { + let app = PendingApp::new_with_event_callback(app_callback); + Self::open(&app).expect("error opening initial window"); + app.run() + } + + /// Runs a window with the provided [`Context`](Self::Context). + /// + /// This function is shorthand for creating a [`PendingApp`], opening this + /// window inside of it, and running the pending app. + /// + /// Messages can be sent to the application's main thread using + /// [`Application::send`]. Each time a message is received by the main event + /// loop, `app_callback` will be invoked. + fn run_with_context_and_event_callback( + context: Self::Context, + app_callback: impl FnMut(AppMessage, &Windows) -> AppMessage::Response + 'static, + ) -> ! { + let app = PendingApp::new_with_event_callback(app_callback); + Self::open_with(&app, context).expect("error opening initial window"); + app.run() + } + /// Opens a new window with a default instance of this behavior's /// [`Context`](Self::Context). The events of the window will be processed /// in a thread spawned by this function. @@ -661,7 +727,7 @@ pub trait WindowBehavior: UnwindSafe + Sized + 'static { /// [`winit::window::WindowBuilder::build`]. fn open(app: &App) -> Result, OsError> where - App: Application, + App: Application, Self::Context: Default, { Self::build(app).open() @@ -679,11 +745,183 @@ pub trait WindowBehavior: UnwindSafe + Sized + 'static { /// [`winit::window::WindowBuilder::build`]. fn open_with(app: &App, context: Self::Context) -> Result, OsError> where - App: Application, + App: Application, { Self::build_with(app, context).open() } + /// Returns a new instance of this behavior after initializing itself with + /// the window and context. + fn initialize(window: &mut RunningWindow, context: Self::Context) -> Self; + + /// Displays the contents of the window. + fn redraw(&mut self, window: &mut RunningWindow); + + /// The window has been requested to be closed. This can happen as a result + /// of the user clicking the close button. + /// + /// If the window should be closed, return true. To prevent closing the + /// window, return false. + #[allow(unused_variables)] + fn close_requested(&mut self, window: &mut RunningWindow) -> bool { + true + } + + /// The window has gained or lost keyboard focus. + /// [`RunningWindow::focused()`] returns the current state. + #[allow(unused_variables)] + fn focus_changed(&mut self, window: &mut RunningWindow) {} + + /// The window has been occluded or revealed. [`RunningWindow::occluded()`] + /// returns the current state. + #[allow(unused_variables)] + fn occlusion_changed(&mut self, window: &mut RunningWindow) {} + + /// The window's scale factor has changed. [`RunningWindow::scale()`] + /// returns the current scale. + #[allow(unused_variables)] + fn scale_factor_changed(&mut self, window: &mut RunningWindow) {} + + /// The window has been resized. [`RunningWindow::inner_size()`] + /// returns the current size. + #[allow(unused_variables)] + fn resized(&mut self, window: &mut RunningWindow) {} + + /// The window's theme has been updated. [`RunningWindow::theme()`] + /// returns the current theme. + #[allow(unused_variables)] + fn theme_changed(&mut self, window: &mut RunningWindow) {} + + /// A file has been dropped on the window. + #[allow(unused_variables)] + fn dropped_file(&mut self, window: &mut RunningWindow, path: PathBuf) {} + + /// A file is hovering over the window. + #[allow(unused_variables)] + fn hovered_file(&mut self, window: &mut RunningWindow, path: PathBuf) {} + + /// A file being overed has been cancelled. + #[allow(unused_variables)] + fn hovered_file_cancelled(&mut self, window: &mut RunningWindow) {} + + /// An input event has generated a character. + #[allow(unused_variables)] + fn received_character(&mut self, window: &mut RunningWindow, char: char) {} + + /// A keyboard event occurred while the window was focused. + #[allow(unused_variables)] + fn keyboard_input( + &mut self, + window: &mut RunningWindow, + device_id: DeviceId, + input: KeyboardInput, + is_synthetic: bool, + ) { + } + + /// The keyboard modifier keys have changed. [`RunningWindow::modifiers()`] + /// returns the current modifier keys state. + #[allow(unused_variables)] + fn modifiers_changed(&mut self, window: &mut RunningWindow) {} + + /// An international input even thas occurred for the window. + #[allow(unused_variables)] + fn ime(&mut self, window: &mut RunningWindow, ime: Ime) {} + + /// A cursor has moved over the window. + #[allow(unused_variables)] + fn cursor_moved( + &mut self, + window: &mut RunningWindow, + device_id: DeviceId, + position: PhysicalPosition, + ) { + } + + /// A cursor has hovered over the window. + #[allow(unused_variables)] + fn cursor_entered(&mut self, window: &mut RunningWindow, device_id: DeviceId) {} + + /// A cursor is no longer hovering over the window. + #[allow(unused_variables)] + fn cursor_left(&mut self, window: &mut RunningWindow, device_id: DeviceId) {} + + /// An event from a mouse wheel. + #[allow(unused_variables)] + fn mouse_wheel( + &mut self, + window: &mut RunningWindow, + device_id: DeviceId, + delta: MouseScrollDelta, + phase: TouchPhase, + ) { + } + + /// A mouse button was pressed or released. + #[allow(unused_variables)] + fn mouse_input( + &mut self, + window: &mut RunningWindow, + device_id: DeviceId, + state: ElementState, + button: MouseButton, + ) { + } + + /// A pressure-sensitive touchpad was touched. + #[allow(unused_variables)] + fn touchpad_pressure( + &mut self, + window: &mut RunningWindow, + device_id: DeviceId, + pressure: f32, + stage: i64, + ) { + } + + /// A multi-axis input device has registered motion. + #[allow(unused_variables)] + fn axis_motion( + &mut self, + window: &mut RunningWindow, + device_id: DeviceId, + axis: AxisId, + value: f64, + ) { + } + + /// A touch event. + #[allow(unused_variables)] + fn touch(&mut self, window: &mut RunningWindow, touch: Touch) {} + + /// A touchpad-originated magnification gesture. + #[allow(unused_variables)] + fn touchpad_magnify( + &mut self, + window: &mut RunningWindow, + device_id: DeviceId, + delta: f64, + phase: TouchPhase, + ) { + } + + /// A request to smart-magnify the window. + #[allow(unused_variables)] + fn smart_magnify(&mut self, window: &mut RunningWindow, device_id: DeviceId) {} + + /// A touchpad-originated rotation gesture. + #[allow(unused_variables)] + fn touchpad_rotate( + &mut self, + window: &mut RunningWindow, + device_id: DeviceId, + delta: f32, + phase: TouchPhase, + ) { + } +} + +pub trait Run: WindowBehavior<()> { /// Runs a window with a default instance of this behavior's /// [`Context`](Self::Context). /// @@ -707,174 +945,6 @@ pub trait WindowBehavior: UnwindSafe + Sized + 'static { Self::open_with(&app, context).expect("error opening initial window"); app.run() } - - /// Returns a new instance of this behavior after initializing itself with - /// the window and context. - fn initialize(window: &mut RunningWindow, context: Self::Context) -> Self; - - /// Displays the contents of the window. - fn redraw(&mut self, window: &mut RunningWindow); - - /// The window has been requested to be closed. This can happen as a result - /// of the user clicking the close button. - /// - /// If the window should be closed, return true. To prevent closing the - /// window, return false. - #[allow(unused_variables)] - fn close_requested(&mut self, window: &mut RunningWindow) -> bool { - true - } - - /// The window has gained or lost keyboard focus. - /// [`RunningWindow::focused()`] returns the current state. - #[allow(unused_variables)] - fn focus_changed(&mut self, window: &mut RunningWindow) {} - - /// The window has been occluded or revealed. [`RunningWindow::occluded()`] - /// returns the current state. - #[allow(unused_variables)] - fn occlusion_changed(&mut self, window: &mut RunningWindow) {} - - /// The window's scale factor has changed. [`RunningWindow::scale()`] - /// returns the current scale. - #[allow(unused_variables)] - fn scale_factor_changed(&mut self, window: &mut RunningWindow) {} - - /// The window has been resized. [`RunningWindow::inner_size()`] - /// returns the current size. - #[allow(unused_variables)] - fn resized(&mut self, window: &mut RunningWindow) {} - - /// The window's theme has been updated. [`RunningWindow::theme()`] - /// returns the current theme. - #[allow(unused_variables)] - fn theme_changed(&mut self, window: &mut RunningWindow) {} - - /// A file has been dropped on the window. - #[allow(unused_variables)] - fn dropped_file(&mut self, window: &mut RunningWindow, path: PathBuf) {} - - /// A file is hovering over the window. - #[allow(unused_variables)] - fn hovered_file(&mut self, window: &mut RunningWindow, path: PathBuf) {} - - /// A file being overed has been cancelled. - #[allow(unused_variables)] - fn hovered_file_cancelled(&mut self, window: &mut RunningWindow) {} - - /// An input event has generated a character. - #[allow(unused_variables)] - fn received_character(&mut self, window: &mut RunningWindow, char: char) {} - - /// A keyboard event occurred while the window was focused. - #[allow(unused_variables)] - fn keyboard_input( - &mut self, - window: &mut RunningWindow, - device_id: DeviceId, - input: KeyboardInput, - is_synthetic: bool, - ) { - } - - /// The keyboard modifier keys have changed. [`RunningWindow::modifiers()`] - /// returns the current modifier keys state. - #[allow(unused_variables)] - fn modifiers_changed(&mut self, window: &mut RunningWindow) {} - - /// An international input even thas occurred for the window. - #[allow(unused_variables)] - fn ime(&mut self, window: &mut RunningWindow, ime: Ime) {} - - /// A cursor has moved over the window. - #[allow(unused_variables)] - fn cursor_moved( - &mut self, - window: &mut RunningWindow, - device_id: DeviceId, - position: PhysicalPosition, - ) { - } - - /// A cursor has hovered over the window. - #[allow(unused_variables)] - fn cursor_entered(&mut self, window: &mut RunningWindow, device_id: DeviceId) {} - - /// A cursor is no longer hovering over the window. - #[allow(unused_variables)] - fn cursor_left(&mut self, window: &mut RunningWindow, device_id: DeviceId) {} - - /// An event from a mouse wheel. - #[allow(unused_variables)] - fn mouse_wheel( - &mut self, - window: &mut RunningWindow, - device_id: DeviceId, - delta: MouseScrollDelta, - phase: TouchPhase, - ) { - } - - /// A mouse button was pressed or released. - #[allow(unused_variables)] - fn mouse_input( - &mut self, - window: &mut RunningWindow, - device_id: DeviceId, - state: ElementState, - button: MouseButton, - ) { - } - - /// A pressure-sensitive touchpad was touched. - #[allow(unused_variables)] - fn touchpad_pressure( - &mut self, - window: &mut RunningWindow, - device_id: DeviceId, - pressure: f32, - stage: i64, - ) { - } - - /// A multi-axis input device has registered motion. - #[allow(unused_variables)] - fn axis_motion( - &mut self, - window: &mut RunningWindow, - device_id: DeviceId, - axis: AxisId, - value: f64, - ) { - } - - /// A touch event. - #[allow(unused_variables)] - fn touch(&mut self, window: &mut RunningWindow, touch: Touch) {} - - /// A touchpad-originated magnification gesture. - #[allow(unused_variables)] - fn touchpad_magnify( - &mut self, - window: &mut RunningWindow, - device_id: DeviceId, - delta: f64, - phase: TouchPhase, - ) { - } - - /// A request to smart-magnify the window. - #[allow(unused_variables)] - fn smart_magnify(&mut self, window: &mut RunningWindow, device_id: DeviceId) {} - - /// A touchpad-originated rotation gesture. - #[allow(unused_variables)] - fn touchpad_rotate( - &mut self, - window: &mut RunningWindow, - device_id: DeviceId, - delta: f32, - phase: TouchPhase, - ) { - } } + +impl Run for T where T: WindowBehavior<()> {}