Skip to content

Commit 595a5db

Browse files
committed
Workaround issue with winit on windows not resuming the event loop.
1 parent a1114ca commit 595a5db

2 files changed

Lines changed: 190 additions & 2 deletions

File tree

winit/src/application.rs

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -463,12 +463,86 @@ async fn run_instance<A, E, C>(
463463

464464
if let Some(event) = conversion::window_event(
465465
window::Id::MAIN,
466-
window_event,
466+
window_event.clone(),
467467
state.scale_factor(),
468468
state.modifiers(),
469469
) {
470470
events.push(event);
471471
}
472+
473+
// HACK: This is to work around an issue with Winit not respecting the `ControlFlow` changes during resize events on windows.
474+
// Without this fix, commands registered while resizing will not be executed until the user finishes the operation.
475+
// See: https://github.com/rust-windowing/winit/issues/3272
476+
#[cfg(target_os = "windows")]
477+
if matches!(window_event, event::WindowEvent::Resized(_)) {
478+
if events.is_empty() && messages.is_empty() {
479+
continue;
480+
}
481+
482+
debug.event_processing_started();
483+
484+
let (interface_state, statuses) = user_interface.update(
485+
&events,
486+
state.cursor(),
487+
&mut renderer,
488+
&mut clipboard,
489+
&mut messages,
490+
);
491+
492+
debug.event_processing_finished();
493+
494+
for (event, status) in
495+
events.drain(..).zip(statuses.into_iter())
496+
{
497+
runtime.broadcast(event, status);
498+
}
499+
500+
if !messages.is_empty()
501+
|| matches!(
502+
interface_state,
503+
user_interface::State::Outdated
504+
)
505+
{
506+
let mut cache =
507+
ManuallyDrop::into_inner(user_interface)
508+
.into_cache();
509+
510+
// Update application
511+
update(
512+
&mut application,
513+
&mut compositor,
514+
&mut surface,
515+
&mut cache,
516+
&mut state,
517+
&mut renderer,
518+
&mut runtime,
519+
&mut clipboard,
520+
&mut should_exit,
521+
&mut proxy,
522+
&mut debug,
523+
&mut messages,
524+
&window,
525+
);
526+
527+
user_interface =
528+
ManuallyDrop::new(build_user_interface(
529+
&application,
530+
cache,
531+
&mut renderer,
532+
state.logical_size(),
533+
&mut debug,
534+
));
535+
536+
if should_exit {
537+
break;
538+
}
539+
}
540+
541+
if !redraw_pending {
542+
window.request_redraw();
543+
redraw_pending = true;
544+
}
545+
}
472546
}
473547
event::Event::AboutToWait => {
474548
if events.is_empty() && messages.is_empty() {

winit/src/multi_window.rs

Lines changed: 115 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -660,13 +660,127 @@ async fn run_instance<A, E, C>(
660660

661661
if let Some(event) = conversion::window_event(
662662
id,
663-
window_event,
663+
window_event.clone(),
664664
window.state.scale_factor(),
665665
window.state.modifiers(),
666666
) {
667667
events.push((Some(id), event));
668668
}
669669
}
670+
671+
// HACK: This is to work around an issue with Winit not respecting the `ControlFlow` changes during resize events on windows.
672+
// Without this fix, commands registered while resizing will not be executed until the user finishes the operation.
673+
// See: https://github.com/rust-windowing/winit/issues/3272
674+
#[cfg(target_os = "windows")]
675+
if matches!(
676+
window_event,
677+
event::WindowEvent::Resized(_)
678+
) {
679+
if events.is_empty() && messages.is_empty() {
680+
continue;
681+
}
682+
683+
debug.event_processing_started();
684+
let mut uis_stale = false;
685+
686+
for (id, window) in window_manager.iter_mut() {
687+
let mut window_events = vec![];
688+
689+
events.retain(|(window_id, event)| {
690+
if *window_id == Some(id)
691+
|| window_id.is_none()
692+
{
693+
window_events.push(event.clone());
694+
false
695+
} else {
696+
true
697+
}
698+
});
699+
700+
if window_events.is_empty()
701+
&& messages.is_empty()
702+
{
703+
continue;
704+
}
705+
706+
let (ui_state, statuses) = user_interfaces
707+
.get_mut(&id)
708+
.expect("Get user interface")
709+
.update(
710+
&window_events,
711+
window.state.cursor(),
712+
&mut window.renderer,
713+
&mut clipboard,
714+
&mut messages,
715+
);
716+
717+
window.raw.request_redraw();
718+
719+
if !uis_stale {
720+
uis_stale = matches!(
721+
ui_state,
722+
user_interface::State::Outdated
723+
);
724+
}
725+
726+
for (event, status) in window_events
727+
.into_iter()
728+
.zip(statuses.into_iter())
729+
{
730+
runtime.broadcast(event, status);
731+
}
732+
}
733+
734+
debug.event_processing_finished();
735+
736+
// TODO mw application update returns which window IDs to update
737+
if !messages.is_empty() || uis_stale {
738+
let mut cached_interfaces: HashMap<
739+
window::Id,
740+
user_interface::Cache,
741+
> = ManuallyDrop::into_inner(user_interfaces)
742+
.drain()
743+
.map(|(id, ui)| (id, ui.into_cache()))
744+
.collect();
745+
746+
// Update application
747+
update(
748+
&mut application,
749+
&mut compositor,
750+
&mut runtime,
751+
&mut clipboard,
752+
&mut control_sender,
753+
&mut proxy,
754+
&mut debug,
755+
&mut messages,
756+
&mut window_manager,
757+
&mut cached_interfaces,
758+
);
759+
760+
// we must synchronize all window states with application state after an
761+
// application update since we don't know what changed
762+
for (id, window) in window_manager.iter_mut() {
763+
window.state.synchronize(
764+
&application,
765+
id,
766+
&window.raw,
767+
);
768+
769+
// TODO once widgets can request to be redrawn, we can avoid always requesting a
770+
// redraw
771+
window.raw.request_redraw();
772+
}
773+
774+
// rebuild UIs with the synchronized states
775+
user_interfaces =
776+
ManuallyDrop::new(build_user_interfaces(
777+
&application,
778+
&mut debug,
779+
&mut window_manager,
780+
cached_interfaces,
781+
));
782+
}
783+
}
670784
}
671785
event::Event::AboutToWait => {
672786
if events.is_empty() && messages.is_empty() {

0 commit comments

Comments
 (0)