From 5c33ce18ed8b12db9a6ba138112804761d26fddb Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Tue, 22 Oct 2024 00:13:42 +0200 Subject: Draft `reactive-rendering` feature for `button` --- winit/src/program.rs | 95 +++++++++++++++++++++++++++++++++------------- winit/src/program/state.rs | 5 ++- 2 files changed, 73 insertions(+), 27 deletions(-) (limited to 'winit/src') diff --git a/winit/src/program.rs b/winit/src/program.rs index 8d1eec3a..2ac7ad0d 100644 --- a/winit/src/program.rs +++ b/winit/src/program.rs @@ -691,6 +691,7 @@ async fn run_instance( let mut ui_caches = FxHashMap::default(); let mut user_interfaces = ManuallyDrop::new(FxHashMap::default()); let mut clipboard = Clipboard::unconnected(); + let mut redraw_queue = Vec::new(); debug.startup_finished(); @@ -758,14 +759,30 @@ async fn run_instance( } Event::EventLoopAwakened(event) => { match event { - event::Event::NewEvents( - event::StartCause::Init - | event::StartCause::ResumeTimeReached { .. }, - ) => { + event::Event::NewEvents(event::StartCause::Init) => { for (_id, window) in window_manager.iter_mut() { window.raw.request_redraw(); } } + event::Event::NewEvents( + event::StartCause::ResumeTimeReached { .. }, + ) => { + let now = Instant::now(); + + while let Some((target, id)) = + redraw_queue.last().copied() + { + if target > now { + break; + } + + let _ = redraw_queue.pop(); + + if let Some(window) = window_manager.get_mut(id) { + window.raw.request_redraw(); + } + } + } event::Event::PlatformSpecific( event::PlatformSpecific::MacOS( event::MacOS::ReceivedUrl(url), @@ -857,23 +874,19 @@ async fn run_instance( status: core::event::Status::Ignored, }); - let _ = control_sender.start_send(Control::ChangeFlow( - match ui_state { - user_interface::State::Updated { - redraw_request: Some(redraw_request), - } => match redraw_request { - window::RedrawRequest::NextFrame => { - window.raw.request_redraw(); - - ControlFlow::Wait - } - window::RedrawRequest::At(at) => { - ControlFlow::WaitUntil(at) - } - }, - _ => ControlFlow::Wait, - }, - )); + if let user_interface::State::Updated { + redraw_request: Some(redraw_request), + } = ui_state + { + match redraw_request { + window::RedrawRequest::NextFrame => { + window.raw.request_redraw(); + } + window::RedrawRequest::At(at) => { + redraw_queue.push((at, id)); + } + } + } let physical_size = window.state.physical_size(); @@ -1065,13 +1078,25 @@ async fn run_instance( &mut messages, ); + #[cfg(not(feature = "reactive-rendering"))] window.raw.request_redraw(); - if !uis_stale { - uis_stale = matches!( - ui_state, - user_interface::State::Outdated - ); + match ui_state { + #[cfg(feature = "reactive-rendering")] + user_interface::State::Updated { + redraw_request: Some(redraw_request), + } => match redraw_request { + window::RedrawRequest::NextFrame => { + window.raw.request_redraw(); + } + window::RedrawRequest::At(at) => { + redraw_queue.push((at, id)); + } + }, + user_interface::State::Outdated => { + uis_stale = true; + } + user_interface::State::Updated { .. } => {} } for (event, status) in window_events @@ -1139,6 +1164,24 @@ async fn run_instance( actions = 0; } } + + if !redraw_queue.is_empty() { + redraw_queue.sort_by( + |(target_a, _), (target_b, _)| { + target_a.cmp(target_b).reverse() + }, + ); + + let (target, _id) = redraw_queue + .last() + .copied() + .expect("Redraw queue is not empty"); + + let _ = + control_sender.start_send(Control::ChangeFlow( + ControlFlow::WaitUntil(target), + )); + } } _ => {} } diff --git a/winit/src/program/state.rs b/winit/src/program/state.rs index a7fa2788..b8a58960 100644 --- a/winit/src/program/state.rs +++ b/winit/src/program/state.rs @@ -190,7 +190,10 @@ where .. }, .. - } => _debug.toggle(), + } => { + _debug.toggle(); + window.request_redraw(); + } _ => {} } } -- cgit From 97bcca04002d9d7c4812e178d30fb12358fad72c Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Tue, 22 Oct 2024 00:25:30 +0200 Subject: Remove `TODO` about reactive rendering in `iced_winit` --- winit/src/program.rs | 5 ----- 1 file changed, 5 deletions(-) (limited to 'winit/src') diff --git a/winit/src/program.rs b/winit/src/program.rs index 2ac7ad0d..f15e5be5 100644 --- a/winit/src/program.rs +++ b/winit/src/program.rs @@ -824,11 +824,6 @@ async fn run_instance( continue; }; - // 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 if a redraw - // is needed right away, or simply wait until a specific time. let redraw_event = core::Event::Window( window::Event::RedrawRequested(Instant::now()), ); -- cgit From 3ba7c71e3ffb651fde753bcf63bb604c16d4bcc2 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Tue, 22 Oct 2024 00:45:36 +0200 Subject: Implement `reactive-rendering` for `slider` --- winit/src/program.rs | 2 ++ 1 file changed, 2 insertions(+) (limited to 'winit/src') diff --git a/winit/src/program.rs b/winit/src/program.rs index f15e5be5..579038af 100644 --- a/winit/src/program.rs +++ b/winit/src/program.rs @@ -1161,6 +1161,8 @@ async fn run_instance( } if !redraw_queue.is_empty() { + // The queue should be fairly short, so we can + // simply sort all of the time. redraw_queue.sort_by( |(target_a, _), (target_b, _)| { target_a.cmp(target_b).reverse() -- cgit From 52490397d64f187d55f51dc5883e3ba6c0da57a6 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Tue, 22 Oct 2024 02:50:46 +0200 Subject: Implement `reactive-rendering` for `text_input` ... and fix the redraw queue logic in `iced_winit`. --- winit/src/program.rs | 48 ++++++++++++++----------------------- winit/src/program/window_manager.rs | 16 +++++++++++++ 2 files changed, 34 insertions(+), 30 deletions(-) (limited to 'winit/src') diff --git a/winit/src/program.rs b/winit/src/program.rs index 579038af..a6729fa0 100644 --- a/winit/src/program.rs +++ b/winit/src/program.rs @@ -691,7 +691,6 @@ async fn run_instance( let mut ui_caches = FxHashMap::default(); let mut user_interfaces = ManuallyDrop::new(FxHashMap::default()); let mut clipboard = Clipboard::unconnected(); - let mut redraw_queue = Vec::new(); debug.startup_finished(); @@ -769,17 +768,12 @@ async fn run_instance( ) => { let now = Instant::now(); - while let Some((target, id)) = - redraw_queue.last().copied() - { - if target > now { - break; - } - - let _ = redraw_queue.pop(); - - if let Some(window) = window_manager.get_mut(id) { - window.raw.request_redraw(); + for (_id, window) in window_manager.iter_mut() { + if let Some(redraw_at) = window.redraw_at { + if redraw_at <= now { + window.raw.request_redraw(); + window.redraw_at = None; + } } } } @@ -878,7 +872,7 @@ async fn run_instance( window.raw.request_redraw(); } window::RedrawRequest::At(at) => { - redraw_queue.push((at, id)); + window.redraw_at = Some(at); } } } @@ -1039,7 +1033,10 @@ async fn run_instance( } } event::Event::AboutToWait => { - if events.is_empty() && messages.is_empty() { + if events.is_empty() + && messages.is_empty() + && window_manager.is_idle() + { continue; } @@ -1085,7 +1082,7 @@ async fn run_instance( window.raw.request_redraw(); } window::RedrawRequest::At(at) => { - redraw_queue.push((at, id)); + window.redraw_at = Some(at); } }, user_interface::State::Outdated => { @@ -1160,24 +1157,15 @@ async fn run_instance( } } - if !redraw_queue.is_empty() { - // The queue should be fairly short, so we can - // simply sort all of the time. - redraw_queue.sort_by( - |(target_a, _), (target_b, _)| { - target_a.cmp(target_b).reverse() - }, - ); - - let (target, _id) = redraw_queue - .last() - .copied() - .expect("Redraw queue is not empty"); - + if let Some(redraw_at) = window_manager.redraw_at() { let _ = control_sender.start_send(Control::ChangeFlow( - ControlFlow::WaitUntil(target), + ControlFlow::WaitUntil(redraw_at), )); + } else { + let _ = control_sender.start_send( + Control::ChangeFlow(ControlFlow::Wait), + ); } } _ => {} diff --git a/winit/src/program/window_manager.rs b/winit/src/program/window_manager.rs index 3d22e155..7c00a84b 100644 --- a/winit/src/program/window_manager.rs +++ b/winit/src/program/window_manager.rs @@ -1,4 +1,5 @@ use crate::core::mouse; +use crate::core::time::Instant; use crate::core::window::Id; use crate::core::{Point, Size}; use crate::graphics::Compositor; @@ -62,6 +63,7 @@ where surface, renderer, mouse_interaction: mouse::Interaction::None, + redraw_at: None, }, ); @@ -74,6 +76,19 @@ where self.entries.is_empty() } + pub fn is_idle(&self) -> bool { + self.entries + .values() + .any(|window| window.redraw_at.is_some()) + } + + pub fn redraw_at(&self) -> Option { + self.entries + .values() + .filter_map(|window| window.redraw_at) + .min() + } + pub fn first(&self) -> Option<&Window> { self.entries.first_key_value().map(|(_id, window)| window) } @@ -138,6 +153,7 @@ where pub mouse_interaction: mouse::Interaction, pub surface: C::Surface, pub renderer: P::Renderer, + pub redraw_at: Option, } impl Window -- cgit From 0691e617f31aab92cb5ddc4698f841357f4c14ec Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Tue, 22 Oct 2024 02:53:30 +0200 Subject: Fix `WindowManager::is_idle` in `iced_winit` --- winit/src/program/window_manager.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'winit/src') diff --git a/winit/src/program/window_manager.rs b/winit/src/program/window_manager.rs index 7c00a84b..10a973fe 100644 --- a/winit/src/program/window_manager.rs +++ b/winit/src/program/window_manager.rs @@ -79,7 +79,7 @@ where pub fn is_idle(&self) -> bool { self.entries .values() - .any(|window| window.redraw_at.is_some()) + .all(|window| window.redraw_at.is_none()) } pub fn redraw_at(&self) -> Option { -- cgit From 7908b6eba91b91c61f7839b3d52fbee124b55cc4 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 23 Oct 2024 19:37:28 +0200 Subject: Request a redraw when a window is resized If we do not request it, macOS does not get any `RedrawRequested` events. Shouldn't `winit` [take care of this]? Probably a bug. [take care of this]: https://docs.rs/winit/0.30.5/winit/event/enum.WindowEvent.html#variant.RedrawRequested --- winit/src/program.rs | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'winit/src') diff --git a/winit/src/program.rs b/winit/src/program.rs index a6729fa0..fb30ccd9 100644 --- a/winit/src/program.rs +++ b/winit/src/program.rs @@ -995,6 +995,13 @@ async fn run_instance( continue; }; + if matches!( + window_event, + winit::event::WindowEvent::Resized(_) + ) { + window.raw.request_redraw(); + } + if matches!( window_event, winit::event::WindowEvent::CloseRequested -- cgit From c6af79a1d06013343f9caf2de80597d627254084 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Tue, 29 Oct 2024 20:53:29 +0100 Subject: Fix deferred layout on resize after drawing --- winit/src/program.rs | 92 +++++++++++++++++++--------------------------------- 1 file changed, 33 insertions(+), 59 deletions(-) (limited to 'winit/src') diff --git a/winit/src/program.rs b/winit/src/program.rs index fb30ccd9..d7afb969 100644 --- a/winit/src/program.rs +++ b/winit/src/program.rs @@ -818,6 +818,39 @@ async fn run_instance( continue; }; + let physical_size = window.state.physical_size(); + + if physical_size.width == 0 || physical_size.height == 0 + { + continue; + } + + if window.viewport_version + != window.state.viewport_version() + { + let logical_size = window.state.logical_size(); + + debug.layout_started(); + let ui = user_interfaces + .remove(&id) + .expect("Remove user interface"); + + let _ = user_interfaces.insert( + id, + ui.relayout(logical_size, &mut window.renderer), + ); + debug.layout_finished(); + + compositor.configure_surface( + &mut window.surface, + physical_size.width, + physical_size.height, + ); + + window.viewport_version = + window.state.viewport_version(); + } + let redraw_event = core::Event::Window( window::Event::RedrawRequested(Instant::now()), ); @@ -877,65 +910,6 @@ async fn run_instance( } } - let physical_size = window.state.physical_size(); - - if physical_size.width == 0 || physical_size.height == 0 - { - continue; - } - - if window.viewport_version - != window.state.viewport_version() - { - let logical_size = window.state.logical_size(); - - debug.layout_started(); - let ui = user_interfaces - .remove(&id) - .expect("Remove user interface"); - - let _ = user_interfaces.insert( - id, - ui.relayout(logical_size, &mut window.renderer), - ); - debug.layout_finished(); - - debug.draw_started(); - let new_mouse_interaction = user_interfaces - .get_mut(&id) - .expect("Get user interface") - .draw( - &mut window.renderer, - window.state.theme(), - &renderer::Style { - text_color: window.state.text_color(), - }, - window.state.cursor(), - ); - debug.draw_finished(); - - if new_mouse_interaction != window.mouse_interaction - { - window.raw.set_cursor( - conversion::mouse_interaction( - new_mouse_interaction, - ), - ); - - window.mouse_interaction = - new_mouse_interaction; - } - - compositor.configure_surface( - &mut window.surface, - physical_size.width, - physical_size.height, - ); - - window.viewport_version = - window.state.viewport_version(); - } - debug.render_started(); match compositor.present( &mut window.renderer, -- cgit From 14ec3307304fbf40e7f281d2356f40456124dfef Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Mon, 4 Nov 2024 18:08:12 +0100 Subject: Replace `reactive-rendering` feature with `unconditional-rendering` --- winit/src/program.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'winit/src') diff --git a/winit/src/program.rs b/winit/src/program.rs index d7afb969..130bf220 100644 --- a/winit/src/program.rs +++ b/winit/src/program.rs @@ -1051,11 +1051,13 @@ async fn run_instance( &mut messages, ); - #[cfg(not(feature = "reactive-rendering"))] + #[cfg(feature = "unconditional-rendering")] window.raw.request_redraw(); match ui_state { - #[cfg(feature = "reactive-rendering")] + #[cfg(not( + feature = "unconditional-rendering" + ))] user_interface::State::Updated { redraw_request: Some(redraw_request), } => match redraw_request { -- cgit