mirror of
https://github.com/rust-windowing/winit.git
synced 2026-06-28 07:33:14 -04:00
Add initialization closure and drop on exit
This commit is contained in:
@@ -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)))]
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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(())
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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))]
|
||||
|
||||
Reference in New Issue
Block a user