Implement widget redraw support in iced_glutin

This commit is contained in:
Héctor Ramón Jiménez 2023-01-12 03:11:08 +01:00
parent 7354f68b3c
commit a980024bbf
No known key found for this signature in database
GPG key ID: 140CC052C94F138E

View file

@ -12,10 +12,11 @@ use iced_winit::futures;
use iced_winit::futures::channel::mpsc; use iced_winit::futures::channel::mpsc;
use iced_winit::renderer; use iced_winit::renderer;
use iced_winit::user_interface; use iced_winit::user_interface;
use iced_winit::{Clipboard, Command, Debug, Proxy, Settings}; use iced_winit::{Clipboard, Command, Debug, Event, Proxy, Settings};
use glutin::window::Window; use glutin::window::Window;
use std::mem::ManuallyDrop; use std::mem::ManuallyDrop;
use std::time::Instant;
#[cfg(feature = "tracing")] #[cfg(feature = "tracing")]
use tracing::{info_span, instrument::Instrument}; use tracing::{info_span, instrument::Instrument};
@ -131,7 +132,8 @@ where
})? })?
}; };
let (mut sender, receiver) = mpsc::unbounded(); let (mut event_sender, event_receiver) = mpsc::unbounded();
let (control_sender, mut control_receiver) = mpsc::unbounded();
let mut instance = Box::pin({ let mut instance = Box::pin({
let run_instance = run_instance::<A, E, C>( let run_instance = run_instance::<A, E, C>(
@ -141,7 +143,8 @@ where
runtime, runtime,
proxy, proxy,
debug, debug,
receiver, event_receiver,
control_sender,
context, context,
init_command, init_command,
settings.exit_on_close_request, settings.exit_on_close_request,
@ -179,14 +182,20 @@ where
}; };
if let Some(event) = event { if let Some(event) = event {
sender.start_send(event).expect("Send event"); event_sender.start_send(event).expect("Send event");
let poll = instance.as_mut().poll(&mut context); let poll = instance.as_mut().poll(&mut context);
*control_flow = match poll { match poll {
task::Poll::Pending => ControlFlow::Wait, task::Poll::Pending => {
task::Poll::Ready(_) => ControlFlow::Exit, if let Ok(Some(flow)) = control_receiver.try_next() {
}; *control_flow = flow;
}
}
task::Poll::Ready(_) => {
*control_flow = ControlFlow::Exit;
}
}
} }
}); });
@ -200,7 +209,10 @@ async fn run_instance<A, E, C>(
mut runtime: Runtime<E, Proxy<A::Message>, A::Message>, mut runtime: Runtime<E, Proxy<A::Message>, A::Message>,
mut proxy: glutin::event_loop::EventLoopProxy<A::Message>, mut proxy: glutin::event_loop::EventLoopProxy<A::Message>,
mut debug: Debug, mut debug: Debug,
mut receiver: mpsc::UnboundedReceiver<glutin::event::Event<'_, A::Message>>, mut event_receiver: mpsc::UnboundedReceiver<
glutin::event::Event<'_, A::Message>,
>,
mut control_sender: mpsc::UnboundedSender<glutin::event_loop::ControlFlow>,
mut context: glutin::ContextWrapper<glutin::PossiblyCurrent, Window>, mut context: glutin::ContextWrapper<glutin::PossiblyCurrent, Window>,
init_command: Command<A::Message>, init_command: Command<A::Message>,
exit_on_close_request: bool, exit_on_close_request: bool,
@ -211,6 +223,7 @@ async fn run_instance<A, E, C>(
<A::Renderer as iced_native::Renderer>::Theme: StyleSheet, <A::Renderer as iced_native::Renderer>::Theme: StyleSheet,
{ {
use glutin::event; use glutin::event;
use glutin::event_loop::ControlFlow;
use iced_winit::futures::stream::StreamExt; use iced_winit::futures::stream::StreamExt;
let mut clipboard = Clipboard::connect(context.window()); let mut clipboard = Clipboard::connect(context.window());
@ -247,13 +260,21 @@ async fn run_instance<A, E, C>(
let mut mouse_interaction = mouse::Interaction::default(); let mut mouse_interaction = mouse::Interaction::default();
let mut events = Vec::new(); let mut events = Vec::new();
let mut messages = Vec::new(); let mut messages = Vec::new();
let mut redraw_pending = false;
debug.startup_finished(); debug.startup_finished();
while let Some(event) = receiver.next().await { while let Some(event) = event_receiver.next().await {
match event { match event {
event::Event::NewEvents(start_cause) => {
redraw_pending = matches!(
start_cause,
event::StartCause::Init
| event::StartCause::ResumeTimeReached { .. }
);
}
event::Event::MainEventsCleared => { event::Event::MainEventsCleared => {
if events.is_empty() && messages.is_empty() { if !redraw_pending && events.is_empty() && messages.is_empty() {
continue; continue;
} }
@ -315,6 +336,24 @@ async fn run_instance<A, E, C>(
} }
} }
// TODO: Avoid redrawing all the time by forcing widgets to
// request redraws on state changes
//
// Then, we can use the `interface_state` here to decide whether
// if a redraw is needed right away, or simply wait until a
// specific time.
let redraw_event = Event::Window(
crate::window::Event::RedrawRequested(Instant::now()),
);
let (interface_state, _) = user_interface.update(
&[redraw_event.clone()],
state.cursor_position(),
&mut renderer,
&mut clipboard,
&mut messages,
);
debug.draw_started(); debug.draw_started();
let new_mouse_interaction = user_interface.draw( let new_mouse_interaction = user_interface.draw(
&mut renderer, &mut renderer,
@ -335,6 +374,17 @@ async fn run_instance<A, E, C>(
} }
context.window().request_redraw(); context.window().request_redraw();
runtime
.broadcast((redraw_event, crate::event::Status::Ignored));
let _ = control_sender.start_send(match interface_state {
user_interface::State::Updated {
redraw_requested_at: Some(at),
} => ControlFlow::WaitUntil(at),
_ => ControlFlow::Wait,
});
redraw_pending = false;
} }
event::Event::PlatformSpecific(event::PlatformSpecific::MacOS( event::Event::PlatformSpecific(event::PlatformSpecific::MacOS(
event::MacOS::ReceivedUrl(url), event::MacOS::ReceivedUrl(url),