winit 0.30

This commit is contained in:
Jonathan Johnson 2024-05-01 11:29:26 -07:00
parent 657493a81d
commit 6048148efd
No known key found for this signature in database
GPG key ID: A66D6A34D6620579
6 changed files with 581 additions and 467 deletions

View file

@ -13,12 +13,26 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
This crate will maintain feature flags that allow picking whatever versions
winit is exposing. As of writing this note, the choices are `rwh_05` and
`rwh_06`. `rwh_05` was the feature that was activated in v0.2.0.
- `winit` has been updated to 0.30.0.
- `Window::id` now returns `Option<WindowId>`, as a window may be opened before
the event loop has been started.
- `WindowBehavior::build`, `WindowBehavior::build_with`, `WindowBehavior::open`,
and `WindowBehavior::open_with` now require exclusive references to the
application.
- These gesture events have been renamed to match `winit`'s updated nomenclature:
- `WindowBehavior::touchpad_magnify` -> `WindowBehavior::pinch_gesture`
- `WindowBehavior::smart_magnify` -> `WindowBehavior::double_tap_gesture`
### Changed
- All `&Appplication` bounds now are `?Sized`, enabling `&dyn Application`
parameters.
### Added
- `AsApplication` now provides `as_application_mut`.
- `WindowBeahvior::pan_gesture` is a new event provided by `winit`.
## v0.2.0 (2023-12-27)
### Breaking Changes

618
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -20,4 +20,4 @@ rwh_05 = ["winit/rwh_05"]
[dependencies]
winit = { version = "0.29.3", default-features = false }
winit = { version = "0.30.0", default-features = false }

View file

@ -11,13 +11,12 @@ use std::collections::HashMap;
use std::process::exit;
use std::sync::{mpsc, Arc, Mutex, PoisonError};
use private::{OpenedWindow, WindowSpawner};
pub use window::{RunningWindow, Window, WindowAttributes, WindowBehavior, WindowBuilder};
pub use winit;
use winit::application::ApplicationHandler;
use winit::error::{EventLoopError, OsError};
use winit::event::Event;
use winit::event_loop::{
ControlFlow, EventLoop, EventLoopBuilder, EventLoopProxy, EventLoopWindowTarget,
};
use winit::event_loop::{ActiveEventLoop, ControlFlow, EventLoop, EventLoopProxy};
use winit::window::WindowId;
use crate::private::{EventLoopMessage, WindowEvent, WindowMessage};
@ -30,6 +29,16 @@ where
event_loop: EventLoop<EventLoopMessage<AppMessage>>,
message_callback: BoxedEventCallback<AppMessage>,
running: App<AppMessage>,
pending_windows: Vec<PendingWindow<AppMessage>>,
}
struct PendingWindow<AppMessage>
where
AppMessage: Message,
{
window: WindowAttributes,
sender: Arc<mpsc::SyncSender<WindowMessage<AppMessage::Window>>>,
spawner: WindowSpawner,
}
type BoxedEventCallback<AppMessage> = Box<
@ -65,7 +74,7 @@ where
event_callback: impl FnMut(AppMessage, &Windows<AppMessage::Window>) -> AppMessage::Response
+ 'static,
) -> Self {
let event_loop = EventLoopBuilder::with_user_event()
let event_loop = EventLoop::with_user_event()
.build()
.expect("should be able to create an EventLoop");
let proxy = event_loop.create_proxy();
@ -76,6 +85,7 @@ where
windows: Windows::default(),
},
message_callback: Box::new(event_callback),
pending_windows: Vec::new(),
}
}
@ -87,55 +97,99 @@ where
///
/// Returns an [`EventLoopError`] upon the loop exiting due to an error. See
/// [`EventLoop::run`] for more information.
pub fn run(mut self) -> Result<(), EventLoopError> {
self.event_loop.run(move |event, target| {
target.set_control_flow(ControlFlow::Wait);
match event {
Event::WindowEvent { window_id, event } => {
let event = WindowEvent::from(event);
self.running
.windows
.send(window_id, WindowMessage::Event(event));
}
Event::UserEvent(message) => match message {
EventLoopMessage::CloseWindow(window_id) => {
if self.running.windows.close(window_id) {
exit(0)
}
}
EventLoopMessage::WindowPanic(window_id) => {
if self.running.windows.close(window_id) {
exit(1)
}
}
EventLoopMessage::OpenWindow {
attrs,
sender,
open_sender,
} => {
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::MemoryWarning
| Event::DeviceEvent { .. }
| Event::Suspended
| Event::Resumed
| Event::LoopExiting
| Event::AboutToWait => {}
}
pub fn run(self) -> Result<(), EventLoopError> {
let Self {
event_loop,
message_callback,
running,
pending_windows,
} = self;
event_loop.run_app(&mut RunningApp::<AppMessage> {
message_callback,
running,
pending_windows,
})
}
}
struct RunningApp<AppMessage>
where
AppMessage: Message,
{
message_callback: BoxedEventCallback<AppMessage>,
running: App<AppMessage>,
pending_windows: Vec<PendingWindow<AppMessage>>,
}
impl<AppMessage> ApplicationHandler<EventLoopMessage<AppMessage>> for RunningApp<AppMessage>
where
AppMessage: Message,
{
fn resumed(&mut self, event_loop: &ActiveEventLoop) {
event_loop.set_control_flow(ControlFlow::Wait);
for PendingWindow {
window,
sender,
spawner,
} in self.pending_windows.drain(..)
{
// TODO how to handle open failure errors for pending windows?
let window = self
.running
.windows
.open(event_loop, window, sender)
.expect("error spawning initial window");
spawner(window);
}
}
fn window_event(
&mut self,
_event_loop: &ActiveEventLoop,
window_id: WindowId,
event: winit::event::WindowEvent,
) {
let event = WindowEvent::from(event);
self.running
.windows
.send(window_id, WindowMessage::Event(event));
}
fn user_event(&mut self, event_loop: &ActiveEventLoop, message: EventLoopMessage<AppMessage>) {
match message {
EventLoopMessage::CloseWindow(window_id) => {
if self.running.windows.close(window_id) {
exit(0)
}
}
EventLoopMessage::WindowPanic(window_id) => {
if self.running.windows.close(window_id) {
exit(1)
}
}
EventLoopMessage::OpenWindow {
attrs,
sender,
open_sender,
spawner,
} => {
let result = self.running.windows.open(event_loop, attrs, sender);
if let Ok(open) = &result {
spawner(open.clone());
}
let _result = open_sender.send(result);
}
EventLoopMessage::User {
message,
response_sender,
} => {
let _result =
response_sender.send((self.message_callback)(message, &self.running.windows));
}
}
}
}
/// A reference to a multi-window application.
pub struct App<AppMessage>
where
@ -180,6 +234,11 @@ pub trait AsApplication<AppMessage> {
fn as_application(&self) -> &dyn Application<AppMessage>
where
AppMessage: Message;
/// Returns this type's application.
fn as_application_mut(&mut self) -> &mut dyn Application<AppMessage>
where
AppMessage: Message;
}
impl<T, AppMessage> AsApplication<AppMessage> for T
@ -193,6 +252,13 @@ where
{
self
}
fn as_application_mut(&mut self) -> &mut dyn Application<AppMessage>
where
AppMessage: Message,
{
self
}
}
/// A message with an associated response type.
@ -226,14 +292,17 @@ where
AppMessage: Message,
{
fn open(
&self,
&mut self,
window: WindowAttributes,
sender: Arc<mpsc::SyncSender<WindowMessage<AppMessage::Window>>>,
) -> Result<Option<Arc<winit::window::Window>>, OsError> {
self.running
.windows
.open(&self.event_loop, window, sender)
.map(Some)
spawner: WindowSpawner,
) -> Result<Option<OpenedWindow>, OsError> {
self.pending_windows.push(PendingWindow {
window,
sender,
spawner,
});
Ok(None)
}
}
@ -262,10 +331,11 @@ where
AppMessage: Message,
{
fn open(
&self,
&mut self,
attrs: WindowAttributes,
sender: Arc<mpsc::SyncSender<WindowMessage<AppMessage::Window>>>,
) -> Result<Option<Arc<winit::window::Window>>, OsError> {
spawner: WindowSpawner,
) -> Result<Option<OpenedWindow>, OsError> {
let (open_sender, open_receiver) = mpsc::sync_channel(1);
if self
.proxy
@ -273,6 +343,7 @@ where
attrs,
sender,
open_sender,
spawner,
})
.is_err()
{
@ -305,24 +376,21 @@ impl<Message> Clone for Windows<Message> {
}
impl<Message> Windows<Message> {
/// Gets an instance of the winit window for the given window id, if it is
/// still open.
/// Gets an instance of the winit window for the given window id, if it has
/// been opened and 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())
windows.get(&id).and_then(|w| w.winit.winit())
}
#[allow(unsafe_code)]
fn open<AppMessage>(
fn open(
&self,
target: &EventLoopWindowTarget<EventLoopMessage<AppMessage>>,
target: &ActiveEventLoop,
attrs: WindowAttributes,
sender: Arc<mpsc::SyncSender<WindowMessage<Message>>>,
) -> Result<Arc<winit::window::Window>, OsError>
where
AppMessage: crate::Message<Window = Message>,
{
let mut builder = winit::window::WindowBuilder::new()
) -> Result<OpenedWindow, OsError> {
let mut builder = winit::window::WindowAttributes::default()
.with_active(attrs.active)
.with_resizable(attrs.resizable)
.with_enabled_buttons(attrs.enabled_buttons)
@ -370,10 +438,12 @@ impl<Message> Windows<Message> {
if let Some(resize_increments) = attrs.resize_increments {
builder = builder.with_resize_increments(resize_increments);
}
let winit = Arc::new(builder.build(target)?);
let winit = Arc::new(target.create_window(builder)?);
let id = winit.id();
let winit = OpenedWindow(Arc::new(Mutex::new(Some(winit))));
let mut windows = self.data.lock().map_or_else(PoisonError::into_inner, |g| g);
windows.insert(
winit.id(),
id,
OpenWindow {
winit: winit.clone(),
sender,
@ -406,6 +476,6 @@ impl<Message> Windows<Message> {
}
struct OpenWindow<User> {
winit: Arc<winit::window::Window>,
winit: OpenedWindow,
sender: Arc<mpsc::SyncSender<WindowMessage<User>>>,
}

View file

@ -1,5 +1,5 @@
use std::path::PathBuf;
use std::sync::{mpsc, Arc};
use std::sync::{mpsc, Arc, Mutex, PoisonError};
use winit::dpi::{PhysicalPosition, PhysicalSize};
use winit::error::OsError;
@ -13,15 +13,30 @@ use winit::window::{ActivationToken, Theme, WindowId};
use crate::window::WindowAttributes;
use crate::Message;
pub type WindowSpawner = Box<dyn FnOnce(OpenedWindow) + Send + 'static>;
pub trait ApplicationSealed<AppMessage>
where
AppMessage: Message,
{
fn open(
&self,
&mut self,
window: WindowAttributes,
sender: Arc<mpsc::SyncSender<WindowMessage<AppMessage::Window>>>,
) -> Result<Option<Arc<winit::window::Window>>, OsError>;
spawner: WindowSpawner,
) -> Result<Option<OpenedWindow>, OsError>;
}
#[derive(Clone, Debug)]
pub struct OpenedWindow(pub(crate) Arc<Mutex<Option<Arc<winit::window::Window>>>>);
impl OpenedWindow {
pub fn winit(&self) -> Option<Arc<winit::window::Window>> {
self.0
.lock()
.map_or_else(PoisonError::into_inner, |g| g)
.clone()
}
}
pub enum EventLoopMessage<AppMessage>
@ -31,7 +46,8 @@ where
OpenWindow {
attrs: WindowAttributes,
sender: Arc<mpsc::SyncSender<WindowMessage<AppMessage::Window>>>,
open_sender: mpsc::SyncSender<Result<Arc<winit::window::Window>, OsError>>,
open_sender: mpsc::SyncSender<Result<OpenedWindow, OsError>>,
spawner: WindowSpawner,
},
CloseWindow(WindowId),
WindowPanic(WindowId),
@ -219,15 +235,20 @@ pub enum WindowEvent {
/// - **iOS / Android / Web / Wayland / Windows:** Unsupported.
Occluded(bool),
TouchpadMagnify {
PinchGesture {
device_id: DeviceId,
delta: f64,
phase: TouchPhase,
},
SmartMagnify {
PanGesture {
device_id: DeviceId,
delta: PhysicalPosition<f32>,
phase: TouchPhase,
},
DoubleTapGesture {
device_id: DeviceId,
},
TouchpadRotate {
RotationGesture {
device_id: DeviceId,
delta: f32,
phase: TouchPhase,
@ -329,23 +350,30 @@ impl From<winit::event::WindowEvent> for WindowEvent {
},
winit::event::WindowEvent::ThemeChanged(theme) => Self::ThemeChanged(theme),
winit::event::WindowEvent::Occluded(occluded) => Self::Occluded(occluded),
winit::event::WindowEvent::TouchpadMagnify {
winit::event::WindowEvent::PinchGesture {
device_id,
delta,
phase,
} => Self::TouchpadMagnify {
} => Self::PinchGesture {
device_id,
delta,
phase,
},
winit::event::WindowEvent::SmartMagnify { device_id } => {
Self::SmartMagnify { device_id }
winit::event::WindowEvent::PanGesture { device_id, delta, phase } => {
Self::PanGesture {
device_id,
delta,
phase,
}
}
winit::event::WindowEvent::TouchpadRotate {
winit::event::WindowEvent::DoubleTapGesture { device_id } => {
Self::DoubleTapGesture { device_id }
}
winit::event::WindowEvent::RotationGesture {
device_id,
delta,
phase,
} => Self::TouchpadRotate {
} => Self::RotationGesture {
device_id,
delta,
phase,

View file

@ -2,7 +2,7 @@ use std::collections::HashSet;
use std::ops::{Deref, DerefMut};
use std::panic::AssertUnwindSafe;
use std::path::PathBuf;
use std::sync::{mpsc, Arc, Weak};
use std::sync::{mpsc, Arc, PoisonError, Weak};
use std::thread;
use std::time::{Duration, Instant};
@ -15,7 +15,7 @@ use winit::event::{
use winit::keyboard::PhysicalKey;
use winit::window::{Fullscreen, Icon, Theme, WindowButtons, WindowId, WindowLevel};
use crate::private::{self, WindowEvent};
use crate::private::{self, OpenedWindow, WindowEvent, WindowSpawner};
use crate::{
App, Application, AsApplication, EventLoopMessage, Message, PendingApp, WindowMessage, Windows,
};
@ -23,15 +23,20 @@ use crate::{
/// A weak reference to a running window.
#[derive(Debug, Clone)]
pub struct Window<Message> {
id: WindowId,
opened: OpenedWindow,
sender: Weak<mpsc::SyncSender<WindowMessage<Message>>>,
}
impl<Message> Window<Message> {
/// Returns the winit id of the window.
#[must_use]
pub const fn id(&self) -> WindowId {
self.id
pub fn id(&self) -> Option<WindowId> {
self.opened
.0
.lock()
.map_or_else(PoisonError::into_inner, |g| g)
.as_ref()
.map(|w| w.id())
}
/// Sends a message to the window.
@ -68,7 +73,7 @@ where
AppMessage: Message,
Application: ?Sized,
{
owner: &'a Application,
owner: &'a mut Application,
context: Behavior::Context,
attributes: WindowAttributes,
}
@ -156,7 +161,7 @@ pub struct WindowAttributes {
impl Default for WindowAttributes {
fn default() -> Self {
let defaults = winit::window::WindowAttributes::default();
let fullscreen = defaults.fullscreen().cloned();
let fullscreen = defaults.fullscreen.clone();
Self {
inner_size: defaults.inner_size,
min_inner_size: defaults.min_inner_size,
@ -187,7 +192,7 @@ where
Application: crate::AsApplication<AppMessage> + ?Sized,
AppMessage: Message,
{
pub(crate) fn new(owner: &'a Application, context: Behavior::Context) -> Self {
pub(crate) fn new(owner: &'a mut Application, context: Behavior::Context) -> Self {
Self {
owner,
context,
@ -212,37 +217,45 @@ where
// by always using try_send.
let (sender, receiver) = mpsc::sync_channel(65536);
let sender = Arc::new(sender);
let Some(winit) = self
.owner
.as_application()
.open(self.attributes, sender.clone())?
let app = self.owner.as_application().app();
let Some(winit) = self.owner.as_application_mut().open(
self.attributes,
sender.clone(),
Box::new({
let sender = sender.clone();
move |opened| {
let winit = opened.winit().expect("just opened");
let running_window = RunningWindow {
messages: (sender, receiver),
responses: mpsc::sync_channel(1),
app,
occluded: winit.is_visible().unwrap_or(false),
focused: winit.has_focus(),
inner_size: winit.inner_size(),
position: winit.inner_position().unwrap_or_default(),
scale: winit.scale_factor(),
theme: winit.theme().unwrap_or(Theme::Dark),
window: winit,
opened,
next_redraw_target: None,
close: false,
modifiers: Modifiers::default(),
cursor_position: None,
mouse_buttons: HashSet::default(),
keys: HashSet::default(),
};
thread::spawn(move || running_window.run_with::<Behavior>(self.context));
}
}),
)?
else {
return Ok(None);
};
let window = Window {
id: winit.id(),
opened: winit.clone(),
sender: Arc::downgrade(&sender),
};
let running_window = RunningWindow {
messages: (sender, receiver),
responses: mpsc::sync_channel(1),
app: self.owner.as_application().app(),
occluded: winit.is_visible().unwrap_or(false),
focused: winit.has_focus(),
inner_size: winit.inner_size(),
position: winit.inner_position().unwrap_or_default(),
scale: winit.scale_factor(),
theme: winit.theme().unwrap_or(Theme::Dark),
window: winit,
next_redraw_target: None,
close: false,
modifiers: Modifiers::default(),
cursor_position: None,
mouse_buttons: HashSet::default(),
keys: HashSet::default(),
};
thread::spawn(move || running_window.run_with::<Behavior>(self.context));
Ok(Some(window))
}
@ -257,6 +270,7 @@ where
AppMessage: Message,
{
window: Arc<winit::window::Window>,
opened: OpenedWindow,
next_redraw_target: Option<RedrawTarget>,
messages: SyncArcChannel<WindowMessage<AppMessage::Window>>,
responses: SyncChannel<AppMessage::Response>,
@ -288,7 +302,7 @@ where
#[must_use]
pub fn handle(&self) -> Window<AppMessage::Window> {
Window {
id: self.window.id(),
opened: self.opened.clone(),
sender: Arc::downgrade(&self.messages.0),
}
}
@ -625,24 +639,31 @@ where
WindowEvent::Touch(touch) => {
behavior.touch(self, touch);
}
WindowEvent::TouchpadMagnify {
WindowEvent::PinchGesture {
device_id,
delta,
phase,
} => {
behavior.touchpad_magnify(self, device_id, delta, phase);
behavior.pinch_gesture(self, device_id, delta, phase);
}
WindowEvent::SmartMagnify { device_id } => {
behavior.smart_magnify(self, device_id);
WindowEvent::PanGesture {
device_id,
delta,
phase,
} => {
behavior.pan_gesture(self, device_id, delta, phase);
}
WindowEvent::TouchpadRotate {
WindowEvent::DoubleTapGesture { device_id } => {
behavior.double_tap_gesture(self, device_id);
}
WindowEvent::RotationGesture {
device_id,
delta,
phase,
} => {
behavior.touchpad_rotate(self, device_id, delta, phase);
}
WindowEvent::ActivationTokenDone { .. } => todo!(),
WindowEvent::ActivationTokenDone { .. } => {}
},
}
@ -707,10 +728,11 @@ where
AppMessage: Message,
{
fn open(
&self,
&mut self,
attrs: WindowAttributes,
sender: Arc<mpsc::SyncSender<WindowMessage<AppMessage::Window>>>,
) -> Result<Option<Arc<winit::window::Window>>, OsError> {
spawner: WindowSpawner,
) -> Result<Option<OpenedWindow>, OsError> {
let (open_sender, open_receiver) = mpsc::sync_channel(1);
if self
.app
@ -719,6 +741,7 @@ where
attrs,
sender,
open_sender,
spawner,
})
.is_ok()
{
@ -774,7 +797,7 @@ where
type Context: Send;
/// 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, AppMessage>
fn build<App>(app: &mut App) -> WindowBuilder<'_, Self, App, AppMessage>
where
App: AsApplication<AppMessage> + ?Sized,
Self::Context: Default,
@ -785,7 +808,7 @@ where
/// 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,
app: &mut App,
context: Self::Context,
) -> WindowBuilder<'_, Self, App, AppMessage>
where
@ -815,8 +838,8 @@ where
where
Self::Context: Default,
{
let app = PendingApp::new_with_event_callback(app_callback);
Self::open(&app).expect("error opening initial window");
let mut app = PendingApp::new_with_event_callback(app_callback);
Self::open(&mut app).expect("error opening initial window");
app.run()
}
@ -838,8 +861,8 @@ where
app_callback: impl FnMut(AppMessage, &Windows<AppMessage::Window>) -> AppMessage::Response
+ 'static,
) -> Result<(), EventLoopError> {
let app = PendingApp::new_with_event_callback(app_callback);
Self::open_with(&app, context).expect("error opening initial window");
let mut app = PendingApp::new_with_event_callback(app_callback);
Self::open_with(&mut app, context).expect("error opening initial window");
app.run()
}
@ -853,7 +876,7 @@ where
///
/// The only errors this funciton can return arise from
/// [`winit::window::WindowBuilder::build`].
fn open<App>(app: &App) -> Result<Option<Window<AppMessage::Window>>, OsError>
fn open<App>(app: &mut App) -> Result<Option<Window<AppMessage::Window>>, OsError>
where
App: AsApplication<AppMessage> + ?Sized,
Self::Context: Default,
@ -872,7 +895,7 @@ where
/// The only errors this funciton can return arise from
/// [`winit::window::WindowBuilder::build`].
fn open_with<App>(
app: &App,
app: &mut App,
context: Self::Context,
) -> Result<Option<Window<AppMessage::Window>>, OsError>
where
@ -1025,9 +1048,9 @@ where
#[allow(unused_variables)]
fn touch(&mut self, window: &mut RunningWindow<AppMessage>, touch: Touch) {}
/// A touchpad-originated magnification gesture.
/// A magnification gesture.
#[allow(unused_variables)]
fn touchpad_magnify(
fn pinch_gesture(
&mut self,
window: &mut RunningWindow<AppMessage>,
device_id: DeviceId,
@ -1036,9 +1059,20 @@ where
) {
}
/// A pan/scroll gesture.
#[allow(unused_variables)]
fn pan_gesture(
&mut self,
window: &mut RunningWindow<AppMessage>,
device_id: DeviceId,
delta: PhysicalPosition<f32>,
phase: TouchPhase,
) {
}
/// A request to smart-magnify the window.
#[allow(unused_variables)]
fn smart_magnify(&mut self, window: &mut RunningWindow<AppMessage>, device_id: DeviceId) {}
fn double_tap_gesture(&mut self, window: &mut RunningWindow<AppMessage>, device_id: DeviceId) {}
/// A touchpad-originated rotation gesture.
#[allow(unused_variables)]
@ -1066,8 +1100,8 @@ pub trait Run: WindowBehavior<()> {
where
Self::Context: Default,
{
let app = PendingApp::new();
Self::open(&app).expect("error opening initial window");
let mut app = PendingApp::new();
Self::open(&mut app).expect("error opening initial window");
app.run()
}
@ -1076,8 +1110,8 @@ pub trait Run: WindowBehavior<()> {
/// This function is shorthand for creating a [`PendingApp`], opening this
/// window inside of it, and running the pending app.
fn run_with(context: Self::Context) -> Result<(), EventLoopError> {
let app = PendingApp::new();
Self::open_with(&app, context).expect("error opening initial window");
let mut app = PendingApp::new();
Self::open_with(&mut app, context).expect("error opening initial window");
app.run()
}
}