From 8591e5a14895e8a602f863734add6922ed41fc38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Wed, 28 Feb 2024 15:25:45 +0100 Subject: [PATCH] Introduce `window::Id` to `timing::Stage` in `iced_sentinel` --- core/src/window/id.rs | 3 +- debug/src/lib.rs | 63 ++++++++++++++++--------------- runtime/src/multi_window.rs | 37 ++++++++++++++++-- runtime/src/multi_window/state.rs | 4 +- runtime/src/program/state.rs | 11 +++--- sentinel/src/timing.rs | 13 ++++--- winit/src/application.rs | 12 +++--- winit/src/multi_window.rs | 16 ++++---- 8 files changed, 97 insertions(+), 62 deletions(-) diff --git a/core/src/window/id.rs b/core/src/window/id.rs index 20474c8f..80ab8e98 100644 --- a/core/src/window/id.rs +++ b/core/src/window/id.rs @@ -2,10 +2,11 @@ use std::hash::Hash; use std::sync::atomic::{self, AtomicU64}; -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] /// The id of the window. /// /// Internally Iced reserves `window::Id::MAIN` for the first window spawned. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Id(u64); static COUNT: AtomicU64 = AtomicU64::new(1); diff --git a/debug/src/lib.rs b/debug/src/lib.rs index a71eedb9..8d7aeba8 100644 --- a/debug/src/lib.rs +++ b/debug/src/lib.rs @@ -1,6 +1,7 @@ pub use iced_core as core; pub use iced_style as style; +use crate::core::window; use crate::style::theme; pub use internal::Timer; @@ -21,33 +22,34 @@ pub fn update_time() -> Timer { internal::update_time() } -pub fn view_time() -> Timer { - internal::view_time() +pub fn view_time(window: window::Id) -> Timer { + internal::view_time(window) } -pub fn layout_time() -> Timer { - internal::layout_time() +pub fn layout_time(window: window::Id) -> Timer { + internal::layout_time(window) } -pub fn interact_time() -> Timer { - internal::interact_time() +pub fn interact_time(window: window::Id) -> Timer { + internal::interact_time(window) } -pub fn draw_time() -> Timer { - internal::draw_time() +pub fn draw_time(window: window::Id) -> Timer { + internal::draw_time(window) } -pub fn render_time() -> Timer { - internal::render_time() +pub fn render_time(window: window::Id) -> Timer { + internal::render_time(window) } -pub fn time(name: impl AsRef) -> Timer { - internal::time(name) +pub fn time(window: window::Id, name: impl AsRef) -> Timer { + internal::time(window, name) } #[cfg(feature = "enable")] mod internal { use crate::core::time::Instant; + use crate::core::window; use crate::style::theme; use iced_sentinel::client::{self, Client}; @@ -74,28 +76,28 @@ mod internal { timer(timing::Stage::Update) } - pub fn view_time() -> Timer { - timer(timing::Stage::View) + pub fn view_time(window: window::Id) -> Timer { + timer(timing::Stage::View(window)) } - pub fn layout_time() -> Timer { - timer(timing::Stage::Layout) + pub fn layout_time(window: window::Id) -> Timer { + timer(timing::Stage::Layout(window)) } - pub fn interact_time() -> Timer { - timer(timing::Stage::Interact) + pub fn interact_time(window: window::Id) -> Timer { + timer(timing::Stage::Interact(window)) } - pub fn draw_time() -> Timer { - timer(timing::Stage::Draw) + pub fn draw_time(window: window::Id) -> Timer { + timer(timing::Stage::Draw(window)) } - pub fn render_time() -> Timer { - timer(timing::Stage::Render) + pub fn render_time(window: window::Id) -> Timer { + timer(timing::Stage::Render(window)) } - pub fn time(name: impl AsRef) -> Timer { - timer(timing::Stage::Custom(name.as_ref().to_owned())) + pub fn time(window: window::Id, name: impl AsRef) -> Timer { + timer(timing::Stage::Custom(window, name.as_ref().to_owned())) } fn timer(stage: timing::Stage) -> Timer { @@ -140,6 +142,7 @@ mod internal { #[cfg(not(feature = "enable"))] mod internal { + use crate::core::window; use crate::style::theme; pub fn theme_changed(_palette: theme::Palette) {} @@ -152,27 +155,27 @@ mod internal { Timer } - pub fn view_time() -> Timer { + pub fn view_time(_window: window::Id) -> Timer { Timer } - pub fn layout_time() -> Timer { + pub fn layout_time(_window: window::Id) -> Timer { Timer } - pub fn interact_time() -> Timer { + pub fn interact_time(_window: window::Id) -> Timer { Timer } - pub fn draw_time() -> Timer { + pub fn draw_time(_window: window::Id) -> Timer { Timer } - pub fn render_time() -> Timer { + pub fn render_time(_window: window::Id) -> Timer { Timer } - pub fn time(_name: impl AsRef) -> Timer { + pub fn time(_window: window::Id, _name: impl AsRef) -> Timer { Timer } diff --git a/runtime/src/multi_window.rs b/runtime/src/multi_window.rs index cf778a20..34a2c9f4 100644 --- a/runtime/src/multi_window.rs +++ b/runtime/src/multi_window.rs @@ -1,6 +1,35 @@ //! A multi-window application. -pub mod program; -pub mod state; +use crate::core::text; +use crate::core::window; +use crate::core::{Element, Renderer}; +use crate::Command; -pub use program::Program; -pub use state::State; +/// The core of a user interface for a multi-window application following The Elm Architecture. +pub trait Program: Sized { + /// The graphics backend to use to draw the [`Program`]. + type Renderer: Renderer + text::Renderer; + + /// The type of __messages__ your [`Program`] will produce. + type Message: std::fmt::Debug + Send; + + /// The theme used to draw the [`Program`]. + type Theme; + + /// Handles a __message__ and updates the state of the [`Program`]. + /// + /// This is where you define your __update logic__. All the __messages__, + /// produced by either user interactions or commands, will be handled by + /// this method. + /// + /// Any [`Command`] returned will be executed immediately in the + /// background by shells. + fn update(&mut self, message: Self::Message) -> Command; + + /// Returns the widgets to display in the [`Program`] for the `window`. + /// + /// These widgets can produce __messages__ based on user interaction. + fn view( + &self, + window: window::Id, + ) -> Element<'_, Self::Message, Self::Theme, Self::Renderer>; +} diff --git a/runtime/src/multi_window/state.rs b/runtime/src/multi_window/state.rs index 215c87e1..2150de76 100644 --- a/runtime/src/multi_window/state.rs +++ b/runtime/src/multi_window/state.rs @@ -98,12 +98,12 @@ where bounds, ); - let interact_timer = debug::interact_time(); let mut messages = Vec::new(); let uncaptured_events = user_interfaces.iter_mut().fold( vec![], |mut uncaptured_events, ui| { + let interact_timer = debug::interact_time(); let (_, event_statuses) = ui.update( &self.queued_events, cursor, @@ -111,6 +111,7 @@ where clipboard, &mut messages, ); + interact_timer.finish(); uncaptured_events.extend( self.queued_events @@ -128,7 +129,6 @@ where self.queued_events.clear(); messages.append(&mut self.queued_messages); - drop(interact_timer); let commands = if messages.is_empty() { let draw_timer = debug::draw_time(); diff --git a/runtime/src/program/state.rs b/runtime/src/program/state.rs index 0c9051d2..cec3186b 100644 --- a/runtime/src/program/state.rs +++ b/runtime/src/program/state.rs @@ -2,6 +2,7 @@ use crate::core::event::{self, Event}; use crate::core::mouse; use crate::core::renderer; use crate::core::widget::operation::{self, Operation}; +use crate::core::window; use crate::core::{Clipboard, Size}; use crate::debug; use crate::user_interface::{self, UserInterface}; @@ -101,7 +102,7 @@ where bounds, ); - let interact_timer = debug::interact_time(); + let interact_timer = debug::interact_time(window::Id::MAIN); let mut messages = Vec::new(); let (_, event_statuses) = user_interface.update( @@ -127,7 +128,7 @@ where drop(interact_timer); let command = if messages.is_empty() { - let draw_timer = debug::draw_time(); + let draw_timer = debug::draw_time(window::Id::MAIN); self.mouse_interaction = user_interface.draw(renderer, theme, style, cursor); drop(draw_timer); @@ -158,7 +159,7 @@ where bounds, ); - let draw_timer = debug::draw_time(); + let draw_timer = debug::draw_time(window::Id::MAIN); self.mouse_interaction = user_interface.draw(renderer, theme, style, cursor); drop(draw_timer); @@ -213,11 +214,11 @@ fn build_user_interface<'a, P: Program>( renderer: &mut P::Renderer, size: Size, ) -> UserInterface<'a, P::Message, P::Theme, P::Renderer> { - let view_timer = debug::view_time(); + let view_timer = debug::view_time(window::Id::MAIN); let view = program.view(); drop(view_timer); - let layout_timer = debug::layout_time(); + let layout_timer = debug::layout_time(window::Id::MAIN); let user_interface = UserInterface::build(view, size, cache, renderer); drop(layout_timer); diff --git a/sentinel/src/timing.rs b/sentinel/src/timing.rs index b4a588f2..64ef561e 100644 --- a/sentinel/src/timing.rs +++ b/sentinel/src/timing.rs @@ -1,4 +1,5 @@ use crate::core::time::Duration; +use crate::core::window; use serde::{Deserialize, Serialize}; @@ -16,10 +17,10 @@ pub struct Timing { pub enum Stage { Boot, Update, - View, - Layout, - Interact, - Draw, - Render, - Custom(String), + View(window::Id), + Layout(window::Id), + Interact(window::Id), + Draw(window::Id), + Render(window::Id), + Custom(window::Id, String), } diff --git a/winit/src/application.rs b/winit/src/application.rs index 6a056d88..752d9c8d 100644 --- a/winit/src/application.rs +++ b/winit/src/application.rs @@ -379,7 +379,7 @@ async fn run_instance( if viewport_version != current_viewport_version { let logical_size = state.logical_size(); - let layout_timer = debug::layout_time(); + let layout_timer = debug::layout_time(window::Id::MAIN); user_interface = ManuallyDrop::new( ManuallyDrop::into_inner(user_interface) .relayout(logical_size, &mut renderer), @@ -431,7 +431,7 @@ async fn run_instance( runtime.broadcast(redraw_event, core::event::Status::Ignored); - let draw_timer = debug::draw_time(); + let draw_timer = debug::draw_time(window::Id::MAIN); let new_mouse_interaction = user_interface.draw( &mut renderer, state.theme(), @@ -451,7 +451,7 @@ async fn run_instance( mouse_interaction = new_mouse_interaction; } - let render_timer = debug::render_time(); + let render_timer = debug::render_time(window::Id::MAIN); match compositor.present( &mut renderer, &mut surface, @@ -499,7 +499,7 @@ async fn run_instance( continue; } - let interact_timer = debug::interact_time(); + let interact_timer = debug::interact_time(window::Id::MAIN); let (interface_state, statuses) = user_interface.update( &events, state.cursor(), @@ -600,11 +600,11 @@ pub fn build_user_interface<'a, A: Application>( where A::Theme: StyleSheet, { - let view_timer = debug::view_time(); + let view_timer = debug::view_time(window::Id::MAIN); let view = application.view(); view_timer.finish(); - let layout_timer = debug::layout_time(); + let layout_timer = debug::layout_time(window::Id::MAIN); let user_interface = UserInterface::build(view, size, cache, renderer); layout_timer.finish(); diff --git a/winit/src/multi_window.rs b/winit/src/multi_window.rs index 10278c77..7f361e0e 100644 --- a/winit/src/multi_window.rs +++ b/winit/src/multi_window.rs @@ -509,7 +509,7 @@ async fn run_instance( &mut messages, ); - let draw_timer = debug::draw_time(); + let draw_timer = debug::draw_time(id); let new_mouse_interaction = ui.draw( &mut window.renderer, window.state.theme(), @@ -565,7 +565,7 @@ async fn run_instance( { let logical_size = window.state.logical_size(); - let layout_time = debug::layout_time(); + let layout_time = debug::layout_time(id); let ui = user_interfaces .remove(&id) .expect("Remove user interface"); @@ -576,7 +576,7 @@ async fn run_instance( ); layout_time.finish(); - let draw_time = debug::draw_time(); + let draw_time = debug::draw_time(id); let new_mouse_interaction = user_interfaces .get_mut(&id) .expect("Get user interface") @@ -612,7 +612,7 @@ async fn run_instance( window.state.viewport_version(); } - let render_time = debug::render_time(); + let render_time = debug::render_time(id); match compositor.present( &mut window.renderer, &mut window.surface, @@ -691,10 +691,10 @@ async fn run_instance( continue; } - let interact_time = debug::interact_time(); let mut uis_stale = false; for (id, window) in window_manager.iter_mut() { + let interact_time = debug::interact_time(id); let mut window_events = vec![]; events.retain(|(window_id, event)| { @@ -737,8 +737,8 @@ async fn run_instance( { runtime.broadcast(event, status); } + interact_time.finish(); } - interact_time.finish(); // TODO mw application update returns which window IDs to update if !messages.is_empty() || uis_stale { @@ -806,11 +806,11 @@ fn build_user_interface<'a, A: Application>( where A::Theme: StyleSheet, { - let view_timer = debug::view_time(); + let view_timer = debug::view_time(id); let view = application.view(id); view_timer.finish(); - let layout_timer = debug::layout_time(); + let layout_timer = debug::layout_time(id); let user_interface = UserInterface::build(view, size, cache, renderer); layout_timer.finish();