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.
This commit is contained in:
Jonathan Johnson 2023-07-04 07:42:33 -07:00
parent 8f49442f28
commit 13e0864bcd
No known key found for this signature in database
GPG key ID: A66D6A34D6620579
3 changed files with 419 additions and 240 deletions

View file

@ -15,30 +15,52 @@ use winit::error::OsError;
use winit::window::WindowId; use winit::window::WindowId;
use std::collections::HashMap; use std::collections::HashMap;
use std::marker::PhantomData;
use std::sync::{mpsc, Arc, Mutex, PoisonError}; use std::sync::{mpsc, Arc, Mutex, PoisonError};
use winit::event_loop::{ControlFlow, EventLoopBuilder, EventLoopProxy, EventLoopWindowTarget}; use winit::event_loop::{ControlFlow, EventLoopBuilder, EventLoopProxy, EventLoopWindowTarget};
use winit::{event::Event, event_loop::EventLoop}; use winit::{event::Event, event_loop::EventLoop};
use crate::private::{AppMessage, WindowEvent, WindowMessage}; use crate::private::{EventLoopMessage, WindowEvent, WindowMessage};
use crate::window::WindowAttributes; use crate::window::WindowAttributes;
/// An application that is not yet running. /// An application that is not yet running.
pub struct PendingApp { pub struct PendingApp<AppMessage>
event_loop: EventLoop<AppMessage>, where
running: App, AppMessage: Message,
{
event_loop: EventLoop<EventLoopMessage<AppMessage>>,
message_callback: BoxedEventCallback<AppMessage>,
running: App<AppMessage>,
} }
impl Default for PendingApp { type BoxedEventCallback<AppMessage> =
Box<dyn FnMut(AppMessage, &Windows<AppMessage>) -> <AppMessage as Message>::Response>;
impl Default for PendingApp<()> {
fn default() -> Self { fn default() -> Self {
Self::new() Self::new()
} }
} }
impl PendingApp { impl PendingApp<()> {
/// Returns a new app with no windows. If no windows are opened before the /// Returns a new app with no windows. If no windows are opened before the
/// app is run, the app will immediately close. /// app is run, the app will immediately close.
#[must_use] #[must_use]
pub fn new() -> Self { pub fn new() -> Self {
Self::new_with_event_callback(|_, _| {})
}
}
impl<AppMessage> PendingApp<AppMessage>
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>) -> AppMessage::Response + 'static,
) -> Self {
let event_loop = EventLoopBuilder::with_user_event().build(); let event_loop = EventLoopBuilder::with_user_event().build();
let proxy = event_loop.create_proxy(); let proxy = event_loop.create_proxy();
Self { Self {
@ -47,13 +69,14 @@ impl PendingApp {
proxy, proxy,
windows: Windows::default(), windows: Windows::default(),
}, },
message_callback: Box::new(event_callback),
} }
} }
/// Begins running the application. This function will never return. /// Begins running the application. This function will never return.
/// ///
/// Internally this runs the [`EventLoop`]. /// Internally this runs the [`EventLoop`].
pub fn run(self) -> ! { pub fn run(mut self) -> ! {
self.event_loop.run(move |event, target, control_flow| { self.event_loop.run(move |event, target, control_flow| {
*control_flow = ControlFlow::Wait; *control_flow = ControlFlow::Wait;
match event { match event {
@ -67,17 +90,17 @@ impl PendingApp {
self.running.windows.send(window_id, WindowMessage::Redraw); self.running.windows.send(window_id, WindowMessage::Redraw);
} }
Event::UserEvent(message) => match message { Event::UserEvent(message) => match message {
AppMessage::CloseWindow(window_id) => { EventLoopMessage::CloseWindow(window_id) => {
if self.running.windows.close(window_id) { if self.running.windows.close(window_id) {
*control_flow = ControlFlow::ExitWithCode(0); *control_flow = ControlFlow::ExitWithCode(0);
} }
} }
AppMessage::WindowPanic(window_id) => { EventLoopMessage::WindowPanic(window_id) => {
if self.running.windows.close(window_id) { if self.running.windows.close(window_id) {
*control_flow = ControlFlow::ExitWithCode(1); *control_flow = ControlFlow::ExitWithCode(1);
} }
} }
AppMessage::OpenWindow { EventLoopMessage::OpenWindow {
attrs, attrs,
sender, sender,
open_sender, open_sender,
@ -85,6 +108,13 @@ impl PendingApp {
let result = self.running.windows.open(target, attrs, sender); let result = self.running.windows.open(target, attrs, sender);
let _result = open_sender.send(result); 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::NewEvents(_)
| Event::DeviceEvent { .. } | Event::DeviceEvent { .. }
@ -99,19 +129,64 @@ impl PendingApp {
} }
/// A reference to a multi-window application. /// A reference to a multi-window application.
#[derive(Clone)] pub struct App<AppMessage>
pub struct App { where
proxy: EventLoopProxy<AppMessage>, AppMessage: Message,
windows: Windows, {
proxy: EventLoopProxy<EventLoopMessage<AppMessage>>,
windows: Windows<AppMessage>,
}
impl<AppMessage> Clone for App<AppMessage>
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. /// A type that has a handle to the application thread.
pub trait Application: private::ApplicationSealed {} pub trait Application<AppMessage>: private::ApplicationSealed<AppMessage>
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<AppMessage::Response>;
}
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 { impl Message for () {
fn app(&self) -> App { type Response = ();
}
impl<AppMessage> Application<AppMessage> for PendingApp<AppMessage>
where
AppMessage: Message,
{
fn send(&mut self, message: AppMessage) -> Option<<AppMessage as Message>::Response> {
Some((self.message_callback)(message, &self.running.windows))
}
}
impl<AppMessage> private::ApplicationSealed<AppMessage> for PendingApp<AppMessage>
where
AppMessage: Message,
{
fn app(&self) -> App<AppMessage> {
self.running.clone() self.running.clone()
} }
@ -127,13 +202,37 @@ impl private::ApplicationSealed for PendingApp {
} }
} }
#[derive(Default, Clone)] /// A collection of open windows.
struct Windows { pub struct Windows<AppMessage> {
data: Arc<Mutex<HashMap<WindowId, OpenWindow>>>, data: Arc<Mutex<HashMap<WindowId, OpenWindow>>>,
_message: PhantomData<AppMessage>,
} }
impl Windows { impl<AppMessage> Default for Windows<AppMessage> {
fn get(&self, id: WindowId) -> Option<Arc<winit::window::Window>> { fn default() -> Self {
Self {
data: Arc::default(),
_message: PhantomData,
}
}
}
impl<AppMessage> Clone for Windows<AppMessage> {
fn clone(&self) -> Self {
Self {
data: self.data.clone(),
_message: PhantomData,
}
}
}
impl<AppMessage> Windows<AppMessage>
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<Arc<winit::window::Window>> {
let windows = self.data.lock().map_or_else(PoisonError::into_inner, |g| g); let windows = self.data.lock().map_or_else(PoisonError::into_inner, |g| g);
windows.get(&id).map(|w| w.winit.clone()) windows.get(&id).map(|w| w.winit.clone())
} }
@ -141,7 +240,7 @@ impl Windows {
#[allow(unsafe_code)] #[allow(unsafe_code)]
fn open( fn open(
&self, &self,
target: &EventLoopWindowTarget<AppMessage>, target: &EventLoopWindowTarget<EventLoopMessage<AppMessage>>,
attrs: WindowAttributes, attrs: WindowAttributes,
sender: mpsc::SyncSender<WindowMessage>, sender: mpsc::SyncSender<WindowMessage>,
) -> Result<Arc<winit::window::Window>, OsError> { ) -> Result<Arc<winit::window::Window>, OsError> {
@ -198,7 +297,7 @@ impl Windows {
Ok(winit) 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); let mut data = self.data.lock().map_or_else(PoisonError::into_inner, |g| g);
if let Some(open_window) = data.get(&window) { if let Some(open_window) = data.get(&window) {
match open_window.sender.try_send(message) { 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); let mut data = self.data.lock().map_or_else(PoisonError::into_inner, |g| g);
data.remove(&window); data.remove(&window);
data.is_empty() data.is_empty()

View file

@ -10,10 +10,13 @@ use winit::event::{
use winit::window::{Theme, WindowId}; use winit::window::{Theme, WindowId};
use crate::window::WindowAttributes; use crate::window::WindowAttributes;
use crate::App; use crate::{App, Message};
pub trait ApplicationSealed { pub trait ApplicationSealed<AppMessage>
fn app(&self) -> App; where
AppMessage: Message,
{
fn app(&self) -> App<AppMessage>;
fn open( fn open(
&self, &self,
window: WindowAttributes, window: WindowAttributes,
@ -21,7 +24,10 @@ pub trait ApplicationSealed {
) -> Result<Option<Arc<winit::window::Window>>, OsError>; ) -> Result<Option<Arc<winit::window::Window>>, OsError>;
} }
pub enum AppMessage { pub enum EventLoopMessage<AppMessage>
where
AppMessage: Message,
{
OpenWindow { OpenWindow {
attrs: WindowAttributes, attrs: WindowAttributes,
sender: mpsc::SyncSender<WindowMessage>, sender: mpsc::SyncSender<WindowMessage>,
@ -29,6 +35,10 @@ pub enum AppMessage {
}, },
CloseWindow(WindowId), CloseWindow(WindowId),
WindowPanic(WindowId), WindowPanic(WindowId),
User {
message: AppMessage,
response_sender: mpsc::SyncSender<AppMessage::Response>,
},
} }
#[derive(Debug)] #[derive(Debug)]

View file

@ -15,12 +15,11 @@ use winit::event::{
use winit::window::{Fullscreen, Icon, Theme, WindowButtons, WindowId, WindowLevel}; use winit::window::{Fullscreen, Icon, Theme, WindowButtons, WindowId, WindowLevel};
use crate::private::{self, WindowEvent}; use crate::private::{self, WindowEvent};
use crate::{App, AppMessage, Application, PendingApp, WindowMessage}; use crate::{App, Application, EventLoopMessage, Message, PendingApp, WindowMessage, Windows};
/// A weak reference to a running window. /// A weak reference to a running window.
#[derive(Clone)] #[derive(Clone)]
pub struct Window { pub struct Window {
app: App,
id: WindowId, id: WindowId,
} }
@ -30,13 +29,6 @@ impl Window {
pub const fn id(&self) -> WindowId { pub const fn id(&self) -> WindowId {
self.id 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<Arc<winit::window::Window>> {
self.app.windows.get(self.id)
}
} }
/// A builder for a window. /// A builder for a window.
@ -46,17 +38,20 @@ impl Window {
/// supports the cross-platform interface. Support for additional /// supports the cross-platform interface. Support for additional
/// platform-specific settings may be possible as long as all types introduced /// platform-specific settings may be possible as long as all types introduced
/// are `Send`. /// are `Send`.
pub struct WindowBuilder<'a, Behavior, Application> pub struct WindowBuilder<'a, Behavior, Application, AppMessage>
where where
Behavior: self::WindowBehavior, Behavior: self::WindowBehavior<AppMessage>,
AppMessage: Message,
{ {
owner: &'a Application, owner: &'a Application,
context: Behavior::Context, context: Behavior::Context,
attributes: WindowAttributes, 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 where
Behavior: self::WindowBehavior, Behavior: self::WindowBehavior<AppMessage>,
AppMessage: Message,
{ {
type Target = WindowAttributes; 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 where
Behavior: self::WindowBehavior, Behavior: self::WindowBehavior<AppMessage>,
AppMessage: Message,
{ {
fn deref_mut(&mut self) -> &mut Self::Target { fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.attributes &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 where
Behavior: self::WindowBehavior, Behavior: self::WindowBehavior<AppMessage>,
Application: crate::Application, Application: crate::Application<AppMessage>,
AppMessage: Message,
{ {
pub(crate) fn new(owner: &'a Application, context: Behavior::Context) -> Self { pub(crate) fn new(owner: &'a Application, context: Behavior::Context) -> Self {
Self { Self {
@ -156,12 +154,10 @@ where
let Some(winit) = self.owner.open(self.attributes, sender)? else { let Some(winit) = self.owner.open(self.attributes, sender)? else {
return Ok(None) return Ok(None)
}; };
let window = Window { let window = Window { id: winit.id() };
id: winit.id(),
app: self.owner.app(),
};
let running_window = RunningWindow { let running_window = RunningWindow {
messages: receiver, messages: receiver,
responses: mpsc::sync_channel(1),
app: self.owner.app(), app: self.owner.app(),
occluded: winit.is_visible().unwrap_or(false), occluded: winit.is_visible().unwrap_or(false),
focused: winit.has_focus(), focused: winit.has_focus(),
@ -185,11 +181,18 @@ where
} }
/// A window that is running in its own thread. /// A window that is running in its own thread.
pub struct RunningWindow { pub struct RunningWindow<AppMessage>
where
AppMessage: Message,
{
window: Arc<winit::window::Window>, window: Arc<winit::window::Window>,
next_redraw_target: Option<RedrawTarget>, next_redraw_target: Option<RedrawTarget>,
messages: mpsc::Receiver<WindowMessage>, messages: mpsc::Receiver<WindowMessage>,
app: App, responses: (
mpsc::SyncSender<AppMessage::Response>,
mpsc::Receiver<AppMessage::Response>,
),
app: App<AppMessage>,
inner_size: PhysicalSize<u32>, inner_size: PhysicalSize<u32>,
location: PhysicalPosition<i32>, location: PhysicalPosition<i32>,
cursor_location: Option<PhysicalPosition<f64>>, cursor_location: Option<PhysicalPosition<f64>>,
@ -203,7 +206,10 @@ pub struct RunningWindow {
modifiers: ModifiersState, modifiers: ModifiersState,
} }
impl RunningWindow { impl<AppMessage> RunningWindow<AppMessage>
where
AppMessage: Message,
{
/// Returns a reference to the underlying window. /// Returns a reference to the underlying window.
#[must_use] #[must_use]
pub fn winit(&self) -> &winit::window::Window { pub fn winit(&self) -> &winit::window::Window {
@ -300,7 +306,7 @@ impl RunningWindow {
fn run_with<Behavior>(mut self, context: Behavior::Context) fn run_with<Behavior>(mut self, context: Behavior::Context)
where where
Behavior: self::WindowBehavior, Behavior: self::WindowBehavior<AppMessage>,
{ {
let proxy = self.app.proxy.clone(); let proxy = self.app.proxy.clone();
let window_id = self.window.id(); let window_id = self.window.id();
@ -318,16 +324,16 @@ impl RunningWindow {
// //
if let Err(panic) = possible_panic { 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) std::panic::resume_unwind(panic)
} else { } else {
let _result = proxy.send_event(AppMessage::CloseWindow(window_id)); let _result = proxy.send_event(EventLoopMessage::CloseWindow(window_id));
} }
} }
fn process_messages_until_redraw<Behavior>(&mut self, behavior: &mut Behavior) -> bool fn process_messages_until_redraw<Behavior>(&mut self, behavior: &mut Behavior) -> bool
where where
Behavior: self::WindowBehavior, Behavior: self::WindowBehavior<AppMessage>,
{ {
loop { loop {
let message = match TimeUntilRedraw::from(self.next_redraw_target) { 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 #[allow(clippy::too_many_lines)] // can't avoid the match
fn handle_message<Behavior>(&mut self, message: WindowMessage, behavior: &mut Behavior) -> bool fn handle_message<Behavior>(&mut self, message: WindowMessage, behavior: &mut Behavior) -> bool
where where
Behavior: self::WindowBehavior, Behavior: self::WindowBehavior<AppMessage>,
{ {
match message { match message {
WindowMessage::Redraw => { WindowMessage::Redraw => {
@ -559,10 +565,27 @@ impl RunningWindow {
} }
} }
impl Application for RunningWindow {} impl<AppMessage> Application<AppMessage> for RunningWindow<AppMessage>
where
AppMessage: Message,
{
fn send(&mut self, message: AppMessage) -> Option<<AppMessage as Message>::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 { impl<AppMessage> private::ApplicationSealed<AppMessage> for RunningWindow<AppMessage>
fn app(&self) -> App { where
AppMessage: Message,
{
fn app(&self) -> App<AppMessage> {
self.app.clone() self.app.clone()
} }
@ -575,7 +598,7 @@ impl private::ApplicationSealed for RunningWindow {
if self if self
.app .app
.proxy .proxy
.send_event(AppMessage::OpenWindow { .send_event(EventLoopMessage::OpenWindow {
attrs, attrs,
sender, sender,
open_sender, open_sender,
@ -623,7 +646,10 @@ enum TimeUntilRedraw {
/// consumers of the libraries. This trait provides functions for each of the /// 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 /// events a window may receive, enabling the type to react and update its
/// state. /// state.
pub trait WindowBehavior: UnwindSafe + Sized + 'static { pub trait WindowBehavior<AppMessage>: UnwindSafe + Sized + 'static
where
AppMessage: Message,
{
/// A type that is passed to [`initialize()`](Self::initialize). /// A type that is passed to [`initialize()`](Self::initialize).
/// ///
/// This allows providing data to the window from the thread that is opening /// 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 /// Returns a new window builder for this behavior. When the window is
/// initialized, a default [`Context`](Self::Context) will be passed. /// initialized, a default [`Context`](Self::Context) will be passed.
fn build<App>(app: &App) -> WindowBuilder<'_, Self, App> fn build<App>(app: &App) -> WindowBuilder<'_, Self, App, AppMessage>
where where
App: Application, App: Application<AppMessage>,
Self::Context: Default, Self::Context: Default,
{ {
Self::build_with(app, <Self::Context as Default>::default()) Self::build_with(app, <Self::Context as Default>::default())
@ -642,13 +668,53 @@ pub trait WindowBehavior: UnwindSafe + Sized + 'static {
/// Returns a new window builder for this behavior. When the window is /// Returns a new window builder for this behavior. When the window is
/// initialized, the provided context will be passed. /// initialized, the provided context will be passed.
fn build_with<App>(app: &App, context: Self::Context) -> WindowBuilder<'_, Self, App> fn build_with<App>(
app: &App,
context: Self::Context,
) -> WindowBuilder<'_, Self, App, AppMessage>
where where
App: Application, App: Application<AppMessage>,
{ {
WindowBuilder::new(app, context) 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>) -> 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>) -> 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 /// Opens a new window with a default instance of this behavior's
/// [`Context`](Self::Context). The events of the window will be processed /// [`Context`](Self::Context). The events of the window will be processed
/// in a thread spawned by this function. /// in a thread spawned by this function.
@ -661,7 +727,7 @@ pub trait WindowBehavior: UnwindSafe + Sized + 'static {
/// [`winit::window::WindowBuilder::build`]. /// [`winit::window::WindowBuilder::build`].
fn open<App>(app: &App) -> Result<Option<Window>, OsError> fn open<App>(app: &App) -> Result<Option<Window>, OsError>
where where
App: Application, App: Application<AppMessage>,
Self::Context: Default, Self::Context: Default,
{ {
Self::build(app).open() Self::build(app).open()
@ -679,11 +745,183 @@ pub trait WindowBehavior: UnwindSafe + Sized + 'static {
/// [`winit::window::WindowBuilder::build`]. /// [`winit::window::WindowBuilder::build`].
fn open_with<App>(app: &App, context: Self::Context) -> Result<Option<Window>, OsError> fn open_with<App>(app: &App, context: Self::Context) -> Result<Option<Window>, OsError>
where where
App: Application, App: Application<AppMessage>,
{ {
Self::build_with(app, context).open() 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<AppMessage>, context: Self::Context) -> Self;
/// Displays the contents of the window.
fn redraw(&mut self, window: &mut RunningWindow<AppMessage>);
/// 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<AppMessage>) -> 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<AppMessage>) {}
/// The window has been occluded or revealed. [`RunningWindow::occluded()`]
/// returns the current state.
#[allow(unused_variables)]
fn occlusion_changed(&mut self, window: &mut RunningWindow<AppMessage>) {}
/// 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<AppMessage>) {}
/// The window has been resized. [`RunningWindow::inner_size()`]
/// returns the current size.
#[allow(unused_variables)]
fn resized(&mut self, window: &mut RunningWindow<AppMessage>) {}
/// The window's theme has been updated. [`RunningWindow::theme()`]
/// returns the current theme.
#[allow(unused_variables)]
fn theme_changed(&mut self, window: &mut RunningWindow<AppMessage>) {}
/// A file has been dropped on the window.
#[allow(unused_variables)]
fn dropped_file(&mut self, window: &mut RunningWindow<AppMessage>, path: PathBuf) {}
/// A file is hovering over the window.
#[allow(unused_variables)]
fn hovered_file(&mut self, window: &mut RunningWindow<AppMessage>, path: PathBuf) {}
/// A file being overed has been cancelled.
#[allow(unused_variables)]
fn hovered_file_cancelled(&mut self, window: &mut RunningWindow<AppMessage>) {}
/// An input event has generated a character.
#[allow(unused_variables)]
fn received_character(&mut self, window: &mut RunningWindow<AppMessage>, char: char) {}
/// A keyboard event occurred while the window was focused.
#[allow(unused_variables)]
fn keyboard_input(
&mut self,
window: &mut RunningWindow<AppMessage>,
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<AppMessage>) {}
/// An international input even thas occurred for the window.
#[allow(unused_variables)]
fn ime(&mut self, window: &mut RunningWindow<AppMessage>, ime: Ime) {}
/// A cursor has moved over the window.
#[allow(unused_variables)]
fn cursor_moved(
&mut self,
window: &mut RunningWindow<AppMessage>,
device_id: DeviceId,
position: PhysicalPosition<f64>,
) {
}
/// A cursor has hovered over the window.
#[allow(unused_variables)]
fn cursor_entered(&mut self, window: &mut RunningWindow<AppMessage>, device_id: DeviceId) {}
/// A cursor is no longer hovering over the window.
#[allow(unused_variables)]
fn cursor_left(&mut self, window: &mut RunningWindow<AppMessage>, device_id: DeviceId) {}
/// An event from a mouse wheel.
#[allow(unused_variables)]
fn mouse_wheel(
&mut self,
window: &mut RunningWindow<AppMessage>,
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<AppMessage>,
device_id: DeviceId,
state: ElementState,
button: MouseButton,
) {
}
/// A pressure-sensitive touchpad was touched.
#[allow(unused_variables)]
fn touchpad_pressure(
&mut self,
window: &mut RunningWindow<AppMessage>,
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<AppMessage>,
device_id: DeviceId,
axis: AxisId,
value: f64,
) {
}
/// A touch event.
#[allow(unused_variables)]
fn touch(&mut self, window: &mut RunningWindow<AppMessage>, touch: Touch) {}
/// A touchpad-originated magnification gesture.
#[allow(unused_variables)]
fn touchpad_magnify(
&mut self,
window: &mut RunningWindow<AppMessage>,
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<AppMessage>, device_id: DeviceId) {}
/// A touchpad-originated rotation gesture.
#[allow(unused_variables)]
fn touchpad_rotate(
&mut self,
window: &mut RunningWindow<AppMessage>,
device_id: DeviceId,
delta: f32,
phase: TouchPhase,
) {
}
}
pub trait Run: WindowBehavior<()> {
/// Runs a window with a default instance of this behavior's /// Runs a window with a default instance of this behavior's
/// [`Context`](Self::Context). /// [`Context`](Self::Context).
/// ///
@ -707,174 +945,6 @@ pub trait WindowBehavior: UnwindSafe + Sized + 'static {
Self::open_with(&app, context).expect("error opening initial window"); Self::open_with(&app, context).expect("error opening initial window");
app.run() 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<f64>,
) {
}
/// 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<T> Run for T where T: WindowBehavior<()> {}