Skip to content

Commit 74effdd

Browse files
committed
examples: Implement proper Event::Resumed semantics
On Android the backing buffer (`NativeWindow`) disappears when the application is not focussed and/or the screen is locked. Winit handles this by requiring apps to create their `raw_window_handle()` consumers _after_ `Event::Resumed` and to clean it up _before_ returning from `Event::Suspended`. For consistency Winit also sends `Resumed` on all other platforms during init.
1 parent 0264cba commit 74effdd

File tree

8 files changed

+189
-108
lines changed

8 files changed

+189
-108
lines changed

README.md

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -75,21 +75,27 @@ mod winit_app;
7575
fn main() {
7676
let event_loop = EventLoop::new().unwrap();
7777
78-
let mut app = winit_app::WinitAppBuilder::with_init(|elwt| {
79-
let window = {
80-
let window = elwt.create_window(Window::default_attributes());
81-
Rc::new(window.unwrap())
82-
};
83-
let context = softbuffer::Context::new(window.clone()).unwrap();
84-
let surface = softbuffer::Surface::new(&context, window.clone()).unwrap();
85-
86-
(window, surface)
87-
}).with_event_handler(|state, event, elwt| {
88-
let (window, surface) = state;
78+
let mut app = winit_app::WinitAppBuilder::with_init(
79+
|elwt| {
80+
let window = {
81+
let window = elwt.create_window(Window::default_attributes());
82+
Rc::new(window.unwrap())
83+
};
84+
let context = softbuffer::Context::new(window.clone()).unwrap();
85+
86+
(window, context)
87+
},
88+
|_elwt, (window, context)| softbuffer::Surface::new(context, window.clone()).unwrap(),
89+
)
90+
.with_event_handler(|(window, _context), surface, event, elwt| {
8991
elwt.set_control_flow(ControlFlow::Wait);
9092
9193
match event {
9294
Event::WindowEvent { window_id, event: WindowEvent::RedrawRequested } if window_id == window.id() => {
95+
let Some(surface) = surface else {
96+
eprintln!("RedrawRequested fired before Resumed or after Suspended");
97+
return;
98+
};
9399
let (width, height) = {
94100
let size = window.inner_size();
95101
(size.width, size.height)

examples/animation.rs

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,19 +14,23 @@ fn main() {
1414
let event_loop = EventLoop::new().unwrap();
1515
let start = Instant::now();
1616

17-
let app = winit_app::WinitAppBuilder::with_init(|event_loop| {
18-
let window = winit_app::make_window(event_loop, |w| w);
17+
let app = winit_app::WinitAppBuilder::with_init(
18+
|event_loop| {
19+
let window = winit_app::make_window(event_loop, |w| w);
1920

20-
let context = softbuffer::Context::new(window.clone()).unwrap();
21-
let surface = softbuffer::Surface::new(&context, window.clone()).unwrap();
21+
let context = softbuffer::Context::new(window.clone()).unwrap();
2222

23-
let old_size = (0, 0);
24-
let frames = pre_render_frames(0, 0);
23+
let old_size = (0, 0);
24+
let frames = pre_render_frames(0, 0);
2525

26-
(window, surface, old_size, frames)
27-
})
28-
.with_event_handler(move |state, event, elwt| {
29-
let (window, surface, old_size, frames) = state;
26+
(window, context, old_size, frames)
27+
},
28+
|_elwft, (window, context, _old_size, _frames)| {
29+
softbuffer::Surface::new(context, window.clone()).unwrap()
30+
},
31+
)
32+
.with_event_handler(move |state, surface, event, elwt| {
33+
let (window, _context, old_size, frames) = state;
3034

3135
elwt.set_control_flow(ControlFlow::Poll);
3236

@@ -35,6 +39,10 @@ fn main() {
3539
window_id,
3640
event: WindowEvent::RedrawRequested,
3741
} if window_id == window.id() => {
42+
let Some(surface) = surface else {
43+
eprintln!("RedrawRequested fired before Resumed or after Suspended");
44+
return;
45+
};
3846
if let (Some(width), Some(height)) = {
3947
let size = window.inner_size();
4048
(NonZeroU32::new(size.width), NonZeroU32::new(size.height))

examples/fruit.rs

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,25 +14,31 @@ fn main() {
1414

1515
let event_loop = EventLoop::new().unwrap();
1616

17-
let app = winit_app::WinitAppBuilder::with_init(move |elwt| {
18-
let window = winit_app::make_window(elwt, |w| {
19-
w.with_inner_size(winit::dpi::PhysicalSize::new(width, height))
20-
});
17+
let app = winit_app::WinitAppBuilder::with_init(
18+
move |elwt| {
19+
let window = winit_app::make_window(elwt, |w| {
20+
w.with_inner_size(winit::dpi::PhysicalSize::new(width, height))
21+
});
2122

22-
let context = softbuffer::Context::new(window.clone()).unwrap();
23-
let surface = softbuffer::Surface::new(&context, window.clone()).unwrap();
23+
let context = softbuffer::Context::new(window.clone()).unwrap();
2424

25-
(window, surface)
26-
})
27-
.with_event_handler(move |state, event, elwt| {
28-
let (window, surface) = state;
25+
(window, context)
26+
},
27+
|_elwt, (window, context)| softbuffer::Surface::new(context, window.clone()).unwrap(),
28+
)
29+
.with_event_handler(move |state, surface, event, elwt| {
30+
let (window, _context) = state;
2931
elwt.set_control_flow(ControlFlow::Wait);
3032

3133
match event {
3234
Event::WindowEvent {
3335
window_id,
3436
event: WindowEvent::RedrawRequested,
3537
} if window_id == window.id() => {
38+
let Some(surface) = surface else {
39+
eprintln!("RedrawRequested fired before Resumed or after Suspended");
40+
return;
41+
};
3642
surface
3743
.resize(
3844
NonZeroU32::new(fruit.width()).unwrap(),

examples/rectangle.rs

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -25,20 +25,24 @@ fn redraw(buffer: &mut [u32], width: usize, height: usize, flag: bool) {
2525
fn main() {
2626
let event_loop = EventLoop::new().unwrap();
2727

28-
let app = winit_app::WinitAppBuilder::with_init(|elwt| {
29-
let window = winit_app::make_window(elwt, |w| {
30-
w.with_title("Press space to show/hide a rectangle")
31-
});
28+
let app = winit_app::WinitAppBuilder::with_init(
29+
|elwt| {
30+
let window = winit_app::make_window(elwt, |w| {
31+
w.with_title("Press space to show/hide a rectangle")
32+
});
3233

33-
let context = softbuffer::Context::new(window.clone()).unwrap();
34-
let surface = softbuffer::Surface::new(&context, window.clone()).unwrap();
34+
let context = softbuffer::Context::new(window.clone()).unwrap();
3535

36-
let flag = false;
36+
let flag = false;
3737

38-
(window, surface, flag)
39-
})
40-
.with_event_handler(|state, event, elwt| {
41-
let (window, surface, flag) = state;
38+
(window, context, flag)
39+
},
40+
|_elwt, (window, context, _flag)| {
41+
softbuffer::Surface::new(context, window.clone()).unwrap()
42+
},
43+
)
44+
.with_event_handler(|state, surface, event, elwt| {
45+
let (window, _context, flag) = state;
4246

4347
elwt.set_control_flow(ControlFlow::Wait);
4448

@@ -47,6 +51,10 @@ fn main() {
4751
window_id,
4852
event: WindowEvent::RedrawRequested,
4953
} if window_id == window.id() => {
54+
let Some(surface) = surface else {
55+
eprintln!("RedrawRequested fired before Resumed or after Suspended");
56+
return;
57+
};
5058
// Grab the window's client area dimensions
5159
if let (Some(width), Some(height)) = {
5260
let size = window.inner_size();

examples/utils/winit_app.rs

Lines changed: 50 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -31,76 +31,94 @@ pub(crate) fn make_window(
3131
}
3232

3333
/// Easily constructable winit application.
34-
pub(crate) struct WinitApp<T, Init, Handler> {
35-
/// Closure to initialize state.
34+
pub(crate) struct WinitApp<T, S, Init, InitSurface, Handler> {
35+
/// Closure to initialize `state`.
3636
init: Init,
3737

38+
/// Closure to initialize `surface_state`.
39+
init_surface: InitSurface,
40+
3841
/// Closure to run on window events.
3942
event: Handler,
4043

4144
/// Contained state.
4245
state: Option<T>,
46+
47+
/// Contained surface state.
48+
surface_state: Option<S>,
4349
}
4450

4551
/// Builder that makes it so we don't have to name `T`.
46-
pub(crate) struct WinitAppBuilder<T, Init> {
47-
/// Closure to initialize state.
52+
pub(crate) struct WinitAppBuilder<T, S, Init, InitSurface> {
53+
/// Closure to initialize `state`.
4854
init: Init,
4955

56+
/// Closure to initialize `surface_state`.
57+
init_surface: InitSurface,
58+
5059
/// Eat the type parameter.
51-
_marker: PhantomData<Option<T>>,
60+
_marker: PhantomData<(Option<T>, Option<S>)>,
5261
}
5362

54-
impl<T, Init> WinitAppBuilder<T, Init>
63+
impl<T, S, Init, InitSurface> WinitAppBuilder<T, S, Init, InitSurface>
5564
where
5665
Init: FnMut(&ActiveEventLoop) -> T,
66+
InitSurface: FnMut(&ActiveEventLoop, &mut T) -> S,
5767
{
5868
/// Create with an "init" closure.
59-
pub(crate) fn with_init(init: Init) -> Self {
69+
pub(crate) fn with_init(init: Init, init_surface: InitSurface) -> Self {
6070
Self {
6171
init,
72+
init_surface,
6273
_marker: PhantomData,
6374
}
6475
}
6576

6677
/// Build a new application.
67-
pub(crate) fn with_event_handler<F>(self, handler: F) -> WinitApp<T, Init, F>
78+
pub(crate) fn with_event_handler<F>(self, handler: F) -> WinitApp<T, S, Init, InitSurface, F>
6879
where
69-
F: FnMut(&mut T, Event<()>, &ActiveEventLoop),
80+
F: FnMut(&mut T, Option<&mut S>, Event<()>, &ActiveEventLoop),
7081
{
71-
WinitApp::new(self.init, handler)
82+
WinitApp::new(self.init, self.init_surface, handler)
7283
}
7384
}
7485

75-
impl<T, Init, Handler> WinitApp<T, Init, Handler>
86+
impl<T, S, Init, InitSurface, Handler> WinitApp<T, S, Init, InitSurface, Handler>
7687
where
7788
Init: FnMut(&ActiveEventLoop) -> T,
78-
Handler: FnMut(&mut T, Event<()>, &ActiveEventLoop),
89+
InitSurface: FnMut(&ActiveEventLoop, &mut T) -> S,
90+
Handler: FnMut(&mut T, Option<&mut S>, Event<()>, &ActiveEventLoop),
7991
{
8092
/// Create a new application.
81-
pub(crate) fn new(init: Init, event: Handler) -> Self {
93+
pub(crate) fn new(init: Init, init_surface: InitSurface, event: Handler) -> Self {
8294
Self {
8395
init,
96+
init_surface,
8497
event,
8598
state: None,
99+
surface_state: None,
86100
}
87101
}
88102
}
89103

90-
impl<T, Init, Handler> ApplicationHandler for WinitApp<T, Init, Handler>
104+
impl<T, S, Init, InitSurface, Handler> ApplicationHandler
105+
for WinitApp<T, S, Init, InitSurface, Handler>
91106
where
92107
Init: FnMut(&ActiveEventLoop) -> T,
93-
Handler: FnMut(&mut T, Event<()>, &ActiveEventLoop),
108+
InitSurface: FnMut(&ActiveEventLoop, &mut T) -> S,
109+
Handler: FnMut(&mut T, Option<&mut S>, Event<()>, &ActiveEventLoop),
94110
{
95111
fn resumed(&mut self, el: &ActiveEventLoop) {
96112
debug_assert!(self.state.is_none());
97-
self.state = Some((self.init)(el));
113+
let mut state = (self.init)(el);
114+
self.surface_state = Some((self.init_surface)(el, &mut state));
115+
self.state = Some(state);
98116
}
99117

100118
fn suspended(&mut self, _event_loop: &ActiveEventLoop) {
101-
let state = self.state.take();
102-
debug_assert!(state.is_some());
103-
drop(state);
119+
let surface_state = self.surface_state.take();
120+
debug_assert!(surface_state.is_some());
121+
drop(surface_state);
104122
}
105123

106124
fn window_event(
@@ -110,12 +128,23 @@ where
110128
event: WindowEvent,
111129
) {
112130
let state = self.state.as_mut().unwrap();
113-
(self.event)(state, Event::WindowEvent { window_id, event }, event_loop);
131+
let surface_state = self.surface_state.as_mut();
132+
(self.event)(
133+
state,
134+
surface_state,
135+
Event::WindowEvent { window_id, event },
136+
event_loop,
137+
);
114138
}
115139

116140
fn about_to_wait(&mut self, event_loop: &ActiveEventLoop) {
117141
if let Some(state) = self.state.as_mut() {
118-
(self.event)(state, Event::AboutToWait, event_loop);
142+
(self.event)(
143+
state,
144+
self.surface_state.as_mut(),
145+
Event::AboutToWait,
146+
event_loop,
147+
);
119148
}
120149
}
121150
}

examples/winit.rs

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,23 +9,28 @@ mod winit_app;
99
fn main() {
1010
let event_loop = EventLoop::new().unwrap();
1111

12-
let app = winit_app::WinitAppBuilder::with_init(|elwt| {
13-
let window = winit_app::make_window(elwt, |w| w);
12+
let app = winit_app::WinitAppBuilder::with_init(
13+
|elwt| {
14+
let window = winit_app::make_window(elwt, |w| w);
1415

15-
let context = softbuffer::Context::new(window.clone()).unwrap();
16-
let surface = softbuffer::Surface::new(&context, window.clone()).unwrap();
16+
let context = softbuffer::Context::new(window.clone()).unwrap();
1717

18-
(window, surface)
19-
})
20-
.with_event_handler(|state, event, elwt| {
21-
let (window, surface) = state;
18+
(window, context)
19+
},
20+
|_elwt, (window, context)| softbuffer::Surface::new(context, window.clone()).unwrap(),
21+
)
22+
.with_event_handler(|(window, _context), surface, event, elwt| {
2223
elwt.set_control_flow(ControlFlow::Wait);
2324

2425
match event {
2526
Event::WindowEvent {
2627
window_id,
2728
event: WindowEvent::RedrawRequested,
2829
} if window_id == window.id() => {
30+
let Some(surface) = surface else {
31+
eprintln!("RedrawRequested fired before Resumed or after Suspended");
32+
return;
33+
};
2934
if let (Some(width), Some(height)) = {
3035
let size = window.inner_size();
3136
(NonZeroU32::new(size.width), NonZeroU32::new(size.height))

0 commit comments

Comments
 (0)