Add initialization closure and drop on exit

This commit is contained in:
Mads Marquart
2024-12-03 12:17:58 +01:00
parent 164bf85b5b
commit fbc6fdc30c
25 changed files with 380 additions and 322 deletions

View File

@@ -13,26 +13,12 @@ fn main() -> Result<(), impl std::error::Error> {
#[path = "util/fill.rs"]
mod fill;
#[derive(Default)]
struct Application {
parent_window_id: Option<WindowId>,
parent_window_id: WindowId,
windows: HashMap<WindowId, Box<dyn Window>>,
}
impl ApplicationHandler for Application {
fn can_create_surfaces(&mut self, event_loop: &dyn ActiveEventLoop) {
let attributes = WindowAttributes::default()
.with_title("parent window")
.with_position(Position::Logical(LogicalPosition::new(0.0, 0.0)))
.with_surface_size(LogicalSize::new(640.0f32, 480.0f32));
let window = event_loop.create_window(attributes).unwrap();
println!("Parent window id: {:?})", window.id());
self.parent_window_id = Some(window.id());
self.windows.insert(window.id(), window);
}
fn window_event(
&mut self,
event_loop: &dyn ActiveEventLoop,
@@ -56,7 +42,7 @@ fn main() -> Result<(), impl std::error::Error> {
event: KeyEvent { state: ElementState::Pressed, .. },
..
} => {
let parent_window = self.windows.get(&self.parent_window_id.unwrap()).unwrap();
let parent_window = self.windows.get(&self.parent_window_id).unwrap();
let child_window = spawn_child_window(parent_window.as_ref(), event_loop);
let child_id = child_window.id();
println!("Child window created with id: {child_id:?}");
@@ -72,6 +58,20 @@ fn main() -> Result<(), impl std::error::Error> {
}
}
fn init(event_loop: &dyn ActiveEventLoop) -> Application {
let attributes = WindowAttributes::default()
.with_title("parent window")
.with_position(Position::Logical(LogicalPosition::new(0.0, 0.0)))
.with_surface_size(LogicalSize::new(640.0f32, 480.0f32));
let window = event_loop.create_window(attributes).unwrap();
println!("Parent window id: {:?})", window.id());
let parent_window_id = window.id();
let windows = HashMap::from([(window.id(), window)]);
Application { parent_window_id, windows }
}
fn spawn_child_window(
parent: &dyn Window,
event_loop: &dyn ActiveEventLoop,
@@ -89,7 +89,7 @@ fn main() -> Result<(), impl std::error::Error> {
}
let event_loop = EventLoop::new().unwrap();
event_loop.run_app(Application::default())
event_loop.run(init)
}
#[cfg(not(any(x11_platform, macos_platform, windows_platform)))]

View File

@@ -43,16 +43,31 @@ fn main() -> Result<(), impl std::error::Error> {
let event_loop = EventLoop::new().unwrap();
event_loop.run_app(ControlFlowDemo::default())
event_loop.run(ControlFlowDemo::new)
}
#[derive(Default)]
struct ControlFlowDemo {
mode: Mode,
request_redraw: bool,
wait_cancelled: bool,
close_requested: bool,
window: Option<Box<dyn Window>>,
window: Box<dyn Window>,
}
impl ControlFlowDemo {
fn new(event_loop: &dyn ActiveEventLoop) -> Self {
let window_attributes = WindowAttributes::default().with_title(
"Press 1, 2, 3 to change control flow mode. Press R to toggle redraw requests.",
);
let window = event_loop.create_window(window_attributes).unwrap();
Self {
mode: Mode::default(),
request_redraw: false,
wait_cancelled: false,
close_requested: false,
window,
}
}
}
impl ApplicationHandler for ControlFlowDemo {
@@ -65,13 +80,6 @@ impl ApplicationHandler for ControlFlowDemo {
}
}
fn can_create_surfaces(&mut self, event_loop: &dyn ActiveEventLoop) {
let window_attributes = WindowAttributes::default().with_title(
"Press 1, 2, 3 to change control flow mode. Press R to toggle redraw requests.",
);
self.window = Some(event_loop.create_window(window_attributes).unwrap());
}
fn window_event(
&mut self,
_event_loop: &dyn ActiveEventLoop,
@@ -112,9 +120,8 @@ impl ApplicationHandler for ControlFlowDemo {
_ => (),
},
WindowEvent::RedrawRequested => {
let window = self.window.as_ref().unwrap();
window.pre_present_notify();
fill::fill_window(window.as_ref());
self.window.pre_present_notify();
fill::fill_window(&*self.window);
},
_ => (),
}
@@ -122,7 +129,7 @@ impl ApplicationHandler for ControlFlowDemo {
fn about_to_wait(&mut self, event_loop: &dyn ActiveEventLoop) {
if self.request_redraw && !self.wait_cancelled && !self.close_requested {
self.window.as_ref().unwrap().request_redraw();
self.window.request_redraw();
}
match self.mode {

View File

@@ -8,7 +8,7 @@ fn main() -> std::process::ExitCode {
use std::time::Duration;
use winit::application::ApplicationHandler;
use winit::event::WindowEvent;
use winit::event::{StartCause, WindowEvent};
use winit::event_loop::{ActiveEventLoop, EventLoop};
use winit::platform::pump_events::{EventLoopExtPumpEvents, PumpStatus};
use winit::window::{Window, WindowAttributes, WindowId};
@@ -22,9 +22,12 @@ fn main() -> std::process::ExitCode {
}
impl ApplicationHandler for PumpDemo {
fn can_create_surfaces(&mut self, event_loop: &dyn ActiveEventLoop) {
let window_attributes = WindowAttributes::default().with_title("A fantastic window!");
self.window = Some(event_loop.create_window(window_attributes).unwrap());
fn new_events(&mut self, event_loop: &dyn ActiveEventLoop, cause: StartCause) {
if matches!(cause, StartCause::Init) && self.window.is_none() {
let window_attributes =
WindowAttributes::default().with_title("A fantastic window!");
self.window = Some(event_loop.create_window(window_attributes).unwrap());
}
}
fn window_event(

View File

@@ -21,14 +21,8 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
window: Option<Box<dyn Window>>,
}
impl ApplicationHandler for App {
fn about_to_wait(&mut self, _event_loop: &dyn ActiveEventLoop) {
if let Some(window) = self.window.as_ref() {
window.request_redraw();
}
}
fn can_create_surfaces(&mut self, event_loop: &dyn ActiveEventLoop) {
impl App {
fn init_window(&mut self, event_loop: &dyn ActiveEventLoop) {
let window_attributes = WindowAttributes::default()
.with_title("Fantastic window number one!")
.with_surface_size(winit::dpi::LogicalSize::new(128.0, 128.0));
@@ -36,6 +30,14 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
self.window_id = Some(window.id());
self.window = Some(window);
}
}
impl ApplicationHandler for App {
fn about_to_wait(&mut self, _event_loop: &dyn ActiveEventLoop) {
if let Some(window) = self.window.as_ref() {
window.request_redraw();
}
}
fn window_event(
&mut self,
@@ -81,14 +83,20 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut event_loop = EventLoop::new().unwrap();
let mut app = App { idx: 1, ..Default::default() };
event_loop.run_app_on_demand(&mut app)?;
event_loop.run_on_demand(|event_loop| {
app.init_window(event_loop);
&mut app
})?;
println!("--------------------------------------------------------- Finished first loop");
println!("--------------------------------------------------------- Waiting 5 seconds");
std::thread::sleep(Duration::from_secs(5));
app.idx += 1;
event_loop.run_app_on_demand(&mut app)?;
event_loop.run_on_demand(|event_loop| {
app.init_window(event_loop);
&mut app
})?;
println!("--------------------------------------------------------- Finished second loop");
Ok(())
}

View File

@@ -70,8 +70,7 @@ fn main() -> Result<(), Box<dyn Error>> {
});
}
let app = Application::new(&event_loop, receiver, sender);
Ok(event_loop.run_app(app)?)
Ok(event_loop.run(|event_loop| Application::new(event_loop, receiver, sender))?)
}
/// Application state and event handling.
@@ -88,21 +87,24 @@ struct Application {
///
/// With OpenGL it could be EGLDisplay.
#[cfg(not(android_platform))]
context: Option<Context<DisplayHandle<'static>>>,
context: Context<DisplayHandle<'static>>,
}
impl Application {
fn new(event_loop: &EventLoop, receiver: Receiver<Action>, sender: Sender<Action>) -> Self {
// SAFETY: we drop the context right before the event loop is stopped, thus making it safe.
fn new(
event_loop: &dyn ActiveEventLoop,
receiver: Receiver<Action>,
sender: Sender<Action>,
) -> Self {
// SAFETY: The context is stored in the application, which is dropped right before the event
// loop is stopped, thus making it safe.
#[cfg(not(android_platform))]
let context = Some(
Context::new(unsafe {
std::mem::transmute::<DisplayHandle<'_>, DisplayHandle<'static>>(
event_loop.display_handle().unwrap(),
)
})
.unwrap(),
);
let context = Context::new(unsafe {
std::mem::transmute::<DisplayHandle<'_>, DisplayHandle<'static>>(
event_loop.display_handle().unwrap(),
)
})
.unwrap();
// You'll have to choose an icon size at your own discretion. On X11, the desired size
// varies by WM, and on Windows, you still have to account for screen scaling. Here
@@ -120,7 +122,7 @@ impl Application {
.into_iter()
.collect();
Self {
let mut app = Self {
receiver,
sender,
#[cfg(not(android_platform))]
@@ -128,7 +130,16 @@ impl Application {
custom_cursors,
icon,
windows: Default::default(),
}
};
app.dump_monitors(event_loop);
// Create initial window.
app.create_window(event_loop, None).expect("failed to create initial window");
app.print_help();
app
}
fn create_window(
@@ -560,14 +571,12 @@ impl ApplicationHandler for Application {
info!("Device {device_id:?} event: {event:?}");
}
fn can_create_surfaces(&mut self, event_loop: &dyn ActiveEventLoop) {
info!("Ready to create surfaces");
self.dump_monitors(event_loop);
// Create initial window.
self.create_window(event_loop, None).expect("failed to create initial window");
self.print_help();
#[cfg(not(android_platform))]
fn can_create_surfaces(&mut self, _event_loop: &dyn ActiveEventLoop) {
for window in self.windows.values_mut() {
window.surface = Some(Surface::new(&self.context, Arc::clone(&window.window)).unwrap());
window.resize(window.window.surface_size());
}
}
fn about_to_wait(&mut self, event_loop: &dyn ActiveEventLoop) {
@@ -578,9 +587,10 @@ impl ApplicationHandler for Application {
}
#[cfg(not(android_platform))]
fn exiting(&mut self, _event_loop: &dyn ActiveEventLoop) {
// We must drop the context here.
self.context = None;
fn destroy_surfaces(&mut self, _event_loop: &dyn ActiveEventLoop) {
for window in self.windows.values_mut() {
window.surface = None;
}
}
#[cfg(target_os = "macos")]
@@ -607,9 +617,9 @@ struct WindowState {
ime: bool,
/// Render surface.
///
/// NOTE: This surface must be dropped before the `Window`.
/// `None` when not between `can_create_surfaces` and `destroy_surfaces`.
#[cfg(not(android_platform))]
surface: Surface<DisplayHandle<'static>, Arc<dyn Window>>,
surface: Option<Surface<DisplayHandle<'static>, Arc<dyn Window>>>,
/// The actual winit Window.
window: Arc<dyn Window>,
/// The window theme we're drawing with.
@@ -642,11 +652,6 @@ impl WindowState {
fn new(app: &Application, window: Box<dyn Window>) -> Result<Self, Box<dyn Error>> {
let window: Arc<dyn Window> = Arc::from(window);
// SAFETY: the surface is dropped before the `window` which provided it with handle, thus
// it doesn't outlive it.
#[cfg(not(android_platform))]
let surface = Surface::new(app.context.as_ref().unwrap(), Arc::clone(&window))?;
let theme = window.theme().unwrap_or(Theme::Dark);
info!("Theme: {theme:?}");
let named_idx = 0;
@@ -656,15 +661,14 @@ impl WindowState {
let ime = true;
window.set_ime_allowed(ime);
let size = window.surface_size();
let mut state = Self {
Ok(Self {
#[cfg(macos_platform)]
option_as_alt: window.option_as_alt(),
custom_idx: app.custom_cursors.as_ref().map(Vec::len).unwrap_or(1) - 1,
cursor_grab: CursorGrabMode::None,
named_idx,
#[cfg(not(android_platform))]
surface,
surface: None,
window,
theme,
ime,
@@ -675,10 +679,7 @@ impl WindowState {
rotated: Default::default(),
panned: Default::default(),
zoom: Default::default(),
};
state.resize(size);
Ok(state)
})
}
pub fn toggle_ime(&mut self) {
@@ -852,7 +853,11 @@ impl WindowState {
(Some(width), Some(height)) => (width, height),
_ => return,
};
self.surface.resize(width, height).expect("failed to resize inner buffer");
self.surface
.as_mut()
.unwrap()
.resize(width, height)
.expect("failed to resize inner buffer");
}
self.window.request_redraw();
}
@@ -945,7 +950,7 @@ impl WindowState {
return Ok(());
}
let mut buffer = self.surface.buffer_mut()?;
let mut buffer = self.surface.as_mut().unwrap().buffer_mut()?;
// Draw a different color inside the safe area
let surface_size = self.window.surface_size();

View File

@@ -13,39 +13,28 @@ fn main() -> Result<(), Box<dyn Error>> {
mod fill;
pub struct XEmbedDemo {
parent_window_id: u32,
window: Option<Box<dyn Window>>,
window: Box<dyn Window>,
}
impl ApplicationHandler for XEmbedDemo {
fn can_create_surfaces(&mut self, event_loop: &dyn ActiveEventLoop) {
let window_attributes = WindowAttributes::default()
.with_title("An embedded window!")
.with_surface_size(winit::dpi::LogicalSize::new(128.0, 128.0))
.with_embed_parent_window(self.parent_window_id);
self.window = Some(event_loop.create_window(window_attributes).unwrap());
}
fn window_event(
&mut self,
event_loop: &dyn ActiveEventLoop,
_window_id: WindowId,
event: WindowEvent,
) {
let window = self.window.as_ref().unwrap();
match event {
WindowEvent::CloseRequested => event_loop.exit(),
WindowEvent::RedrawRequested => {
window.pre_present_notify();
fill::fill_window(window.as_ref());
self.window.pre_present_notify();
fill::fill_window(&*self.window);
},
_ => (),
}
}
fn about_to_wait(&mut self, _event_loop: &dyn ActiveEventLoop) {
self.window.as_ref().unwrap().request_redraw();
self.window.request_redraw();
}
}
@@ -58,7 +47,15 @@ fn main() -> Result<(), Box<dyn Error>> {
tracing_subscriber::fmt::init();
let event_loop = EventLoop::new()?;
Ok(event_loop.run_app(XEmbedDemo { parent_window_id, window: None })?)
Ok(event_loop.run(|event_loop| {
let window_attributes = WindowAttributes::default()
.with_title("An embedded window!")
.with_surface_size(winit::dpi::LogicalSize::new(128.0, 128.0))
.with_embed_parent_window(parent_window_id);
let window = event_loop.create_window(window_attributes).unwrap();
XEmbedDemo { window }
})?)
}
#[cfg(not(x11_platform))]