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 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<AppMessage>,
running: App,
pub struct PendingApp<AppMessage>
where
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 {
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<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 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<AppMessage>,
windows: Windows,
pub struct App<AppMessage>
where
AppMessage: Message,
{
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.
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 {
fn app(&self) -> App {
impl Message for () {
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()
}
@ -127,13 +202,37 @@ impl private::ApplicationSealed for PendingApp {
}
}
#[derive(Default, Clone)]
struct Windows {
/// A collection of open windows.
pub struct Windows<AppMessage> {
data: Arc<Mutex<HashMap<WindowId, OpenWindow>>>,
_message: PhantomData<AppMessage>,
}
impl Windows {
fn get(&self, id: WindowId) -> Option<Arc<winit::window::Window>> {
impl<AppMessage> Default for Windows<AppMessage> {
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);
windows.get(&id).map(|w| w.winit.clone())
}
@ -141,7 +240,7 @@ impl Windows {
#[allow(unsafe_code)]
fn open(
&self,
target: &EventLoopWindowTarget<AppMessage>,
target: &EventLoopWindowTarget<EventLoopMessage<AppMessage>>,
attrs: WindowAttributes,
sender: mpsc::SyncSender<WindowMessage>,
) -> Result<Arc<winit::window::Window>, 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()

View file

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

View file

@ -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<Arc<winit::window::Window>> {
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>,
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>,
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>,
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<AppMessage>,
Application: crate::Application<AppMessage>,
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<AppMessage>
where
AppMessage: Message,
{
window: Arc<winit::window::Window>,
next_redraw_target: Option<RedrawTarget>,
messages: mpsc::Receiver<WindowMessage>,
app: App,
responses: (
mpsc::SyncSender<AppMessage::Response>,
mpsc::Receiver<AppMessage::Response>,
),
app: App<AppMessage>,
inner_size: PhysicalSize<u32>,
location: PhysicalPosition<i32>,
cursor_location: Option<PhysicalPosition<f64>>,
@ -203,7 +206,10 @@ pub struct RunningWindow {
modifiers: ModifiersState,
}
impl RunningWindow {
impl<AppMessage> RunningWindow<AppMessage>
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<Behavior>(mut self, context: Behavior::Context)
where
Behavior: self::WindowBehavior,
Behavior: self::WindowBehavior<AppMessage>,
{
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<Behavior>(&mut self, behavior: &mut Behavior) -> bool
where
Behavior: self::WindowBehavior,
Behavior: self::WindowBehavior<AppMessage>,
{
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<Behavior>(&mut self, message: WindowMessage, behavior: &mut Behavior) -> bool
where
Behavior: self::WindowBehavior,
Behavior: self::WindowBehavior<AppMessage>,
{
match message {
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 {
fn app(&self) -> App {
impl<AppMessage> private::ApplicationSealed<AppMessage> for RunningWindow<AppMessage>
where
AppMessage: Message,
{
fn app(&self) -> App<AppMessage> {
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<AppMessage>: 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: &App) -> WindowBuilder<'_, Self, App>
fn build<App>(app: &App) -> WindowBuilder<'_, Self, App, AppMessage>
where
App: Application,
App: Application<AppMessage>,
Self::Context: 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
/// 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
App: Application,
App: Application<AppMessage>,
{
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
/// [`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: &App) -> Result<Option<Window>, OsError>
where
App: Application,
App: Application<AppMessage>,
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: &App, context: Self::Context) -> Result<Option<Window>, OsError>
where
App: Application,
App: Application<AppMessage>,
{
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
/// [`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<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<()> {}