Introduce iced_sentinel and iced_debug crates

This commit is contained in:
Héctor Ramón Jiménez 2024-02-26 07:00:51 +01:00
parent 58a7007ac1
commit dd36893f7a
No known key found for this signature in database
GPG key ID: 7CC46565708259A7
26 changed files with 543 additions and 567 deletions

View file

@ -32,7 +32,7 @@ qr_code = ["iced_widget/qr_code"]
# Enables lazy widgets # Enables lazy widgets
lazy = ["iced_widget/lazy"] lazy = ["iced_widget/lazy"]
# Enables a debug view in native platforms (press F12) # Enables a debug view in native platforms (press F12)
debug = ["iced_winit/debug"] debug = ["iced_debug/enable"]
# Enables `tokio` as the `executor::Default` on native platforms # Enables `tokio` as the `executor::Default` on native platforms
tokio = ["iced_futures/tokio"] tokio = ["iced_futures/tokio"]
# Enables `async-std` as the `executor::Default` on native platforms # Enables `async-std` as the `executor::Default` on native platforms
@ -58,6 +58,7 @@ fira-sans = ["iced_renderer/fira-sans"]
[dependencies] [dependencies]
iced_core.workspace = true iced_core.workspace = true
iced_debug.workspace = true
iced_futures.workspace = true iced_futures.workspace = true
iced_renderer.workspace = true iced_renderer.workspace = true
iced_widget.workspace = true iced_widget.workspace = true
@ -85,11 +86,13 @@ strip = "debuginfo"
[workspace] [workspace]
members = [ members = [
"core", "core",
"debug",
"futures", "futures",
"graphics", "graphics",
"highlighter", "highlighter",
"renderer", "renderer",
"runtime", "runtime",
"sentinel",
"style", "style",
"tiny_skia", "tiny_skia",
"wgpu", "wgpu",
@ -111,11 +114,13 @@ keywords = ["gui", "ui", "graphics", "interface", "widgets"]
[workspace.dependencies] [workspace.dependencies]
iced = { version = "0.13.0-dev", path = "." } iced = { version = "0.13.0-dev", path = "." }
iced_core = { version = "0.13.0-dev", path = "core" } iced_core = { version = "0.13.0-dev", path = "core" }
iced_debug = { version = "0.13.0-dev", path = "debug" }
iced_futures = { version = "0.13.0-dev", path = "futures" } iced_futures = { version = "0.13.0-dev", path = "futures" }
iced_graphics = { version = "0.13.0-dev", path = "graphics" } iced_graphics = { version = "0.13.0-dev", path = "graphics" }
iced_highlighter = { version = "0.13.0-dev", path = "highlighter" } iced_highlighter = { version = "0.13.0-dev", path = "highlighter" }
iced_renderer = { version = "0.13.0-dev", path = "renderer" } iced_renderer = { version = "0.13.0-dev", path = "renderer" }
iced_runtime = { version = "0.13.0-dev", path = "runtime" } iced_runtime = { version = "0.13.0-dev", path = "runtime" }
iced_sentinel = { version = "0.13.0-dev", path = "sentinel" }
iced_style = { version = "0.13.0-dev", path = "style" } iced_style = { version = "0.13.0-dev", path = "style" }
iced_tiny_skia = { version = "0.13.0-dev", path = "tiny_skia" } iced_tiny_skia = { version = "0.13.0-dev", path = "tiny_skia" }
iced_wgpu = { version = "0.13.0-dev", path = "wgpu" } iced_wgpu = { version = "0.13.0-dev", path = "wgpu" }
@ -145,6 +150,9 @@ qrcode = { version = "0.13", default-features = false }
raw-window-handle = "0.6" raw-window-handle = "0.6"
resvg = "0.36" resvg = "0.36"
rustc-hash = "1.0" rustc-hash = "1.0"
serde = "1.0"
serde_json = "1.0"
semver = "1.0"
smol = "1.0" smol = "1.0"
smol_str = "0.2" smol_str = "0.2"
softbuffer = "0.4" softbuffer = "0.4"

23
debug/Cargo.toml Normal file
View file

@ -0,0 +1,23 @@
[package]
name = "iced_debug"
description = "A pluggable API for debugging iced applications"
version.workspace = true
edition.workspace = true
authors.workspace = true
license.workspace = true
repository.workspace = true
homepage.workspace = true
categories.workspace = true
keywords.workspace = true
[features]
enable = ["iced_sentinel", "once_cell"]
[dependencies]
iced_core.workspace = true
iced_sentinel.workspace = true
iced_sentinel.optional = true
once_cell.workspace = true
once_cell.optional = true

162
debug/src/lib.rs Normal file
View file

@ -0,0 +1,162 @@
pub use iced_core as core;
pub use internal::Timer;
pub fn open_axe() {}
pub fn log_message(_message: &impl std::fmt::Debug) {}
pub fn boot_time() -> Timer {
internal::boot_time()
}
pub fn update_time() -> Timer {
internal::update_time()
}
pub fn view_time() -> Timer {
internal::view_time()
}
pub fn layout_time() -> Timer {
internal::layout_time()
}
pub fn interact_time() -> Timer {
internal::interact_time()
}
pub fn draw_time() -> Timer {
internal::draw_time()
}
pub fn render_time() -> Timer {
internal::render_time()
}
pub fn time(name: impl AsRef<str>) -> Timer {
internal::time(name)
}
#[cfg(feature = "enable")]
mod internal {
use crate::core::time::Instant;
use iced_sentinel::client::{self, Client};
use iced_sentinel::timing::{self, Timing};
use iced_sentinel::Report;
use once_cell::sync::Lazy;
use std::sync::{Mutex, MutexGuard};
pub fn boot_time() -> Timer {
timer(timing::Stage::Boot)
}
pub fn update_time() -> Timer {
timer(timing::Stage::Update)
}
pub fn view_time() -> Timer {
timer(timing::Stage::View)
}
pub fn layout_time() -> Timer {
timer(timing::Stage::Layout)
}
pub fn interact_time() -> Timer {
timer(timing::Stage::Interact)
}
pub fn draw_time() -> Timer {
timer(timing::Stage::Draw)
}
pub fn render_time() -> Timer {
timer(timing::Stage::Render)
}
pub fn time(name: impl AsRef<str>) -> Timer {
timer(timing::Stage::Custom(name.as_ref().to_owned()))
}
fn timer(stage: timing::Stage) -> Timer {
Timer {
stage,
start: Instant::now(),
}
}
#[derive(Debug)]
pub struct Timer {
stage: timing::Stage,
start: Instant,
}
impl Timer {
pub fn finish(self) {
lock().sentinel.report(Report::Timing(Timing {
stage: self.stage,
duration: self.start.elapsed(),
}));
}
}
#[derive(Debug)]
struct Debug {
sentinel: Client,
}
fn lock() -> MutexGuard<'static, Debug> {
static DEBUG: Lazy<Mutex<Debug>> = Lazy::new(|| {
Mutex::new(Debug {
sentinel: client::connect(),
})
});
DEBUG.lock().expect("Acquire debug lock")
}
}
#[cfg(not(feature = "enable"))]
mod internal {
pub fn boot_time() -> Timer {
Timer
}
pub fn update_time() -> Timer {
Timer
}
pub fn view_time() -> Timer {
Timer
}
pub fn layout_time() -> Timer {
Timer
}
pub fn interact_time() -> Timer {
Timer
}
pub fn draw_time() -> Timer {
Timer
}
pub fn render_time() -> Timer {
Timer
}
pub fn time(_name: impl AsRef<str>) -> Timer {
Timer
}
#[derive(Debug)]
pub struct Timer;
impl Timer {
pub fn finish(self) {}
}
}

View file

@ -13,7 +13,6 @@ use iced_winit::core::window;
use iced_winit::core::{Color, Font, Pixels, Size}; use iced_winit::core::{Color, Font, Pixels, Size};
use iced_winit::futures; use iced_winit::futures;
use iced_winit::runtime::program; use iced_winit::runtime::program;
use iced_winit::runtime::Debug;
use iced_winit::style::Theme; use iced_winit::style::Theme;
use iced_winit::winit; use iced_winit::winit;
use iced_winit::Clipboard; use iced_winit::Clipboard;
@ -155,19 +154,14 @@ pub fn main() -> Result<(), Box<dyn std::error::Error>> {
let controls = Controls::new(); let controls = Controls::new();
// Initialize iced // Initialize iced
let mut debug = Debug::new();
let mut renderer = Renderer::new( let mut renderer = Renderer::new(
Backend::new(&adapter, &device, &queue, Settings::default(), format), Backend::new(&adapter, &device, &queue, Settings::default(), format),
Font::default(), Font::default(),
Pixels(16.0), Pixels(16.0),
); );
let mut state = program::State::new( let mut state =
controls, program::State::new(controls, viewport.logical_size(), &mut renderer);
viewport.logical_size(),
&mut renderer,
&mut debug,
);
// Run event loop // Run event loop
event_loop.run(move |event, window_target| { event_loop.run(move |event, window_target| {
@ -239,7 +233,6 @@ pub fn main() -> Result<(), Box<dyn std::error::Error>> {
&view, &view,
primitive, primitive,
&viewport, &viewport,
&debug.overlay(),
); );
}); });
@ -315,7 +308,6 @@ pub fn main() -> Result<(), Box<dyn std::error::Error>> {
text_color: Color::WHITE, text_color: Color::WHITE,
}, },
&mut clipboard, &mut clipboard,
&mut debug,
); );
// and request a redraw // and request a redraw

View file

@ -55,26 +55,24 @@ pub trait Compositor: Sized {
/// ///
/// [`Renderer`]: Self::Renderer /// [`Renderer`]: Self::Renderer
/// [`Surface`]: Self::Surface /// [`Surface`]: Self::Surface
fn present<T: AsRef<str>>( fn present(
&mut self, &mut self,
renderer: &mut Self::Renderer, renderer: &mut Self::Renderer,
surface: &mut Self::Surface, surface: &mut Self::Surface,
viewport: &Viewport, viewport: &Viewport,
background_color: Color, background_color: Color,
overlay: &[T],
) -> Result<(), SurfaceError>; ) -> Result<(), SurfaceError>;
/// Screenshots the current [`Renderer`] primitives to an offscreen texture, and returns the bytes of /// Screenshots the current [`Renderer`] primitives to an offscreen texture, and returns the bytes of
/// the texture ordered as `RGBA` in the `sRGB` color space. /// the texture ordered as `RGBA` in the `sRGB` color space.
/// ///
/// [`Renderer`]: Self::Renderer /// [`Renderer`]: Self::Renderer
fn screenshot<T: AsRef<str>>( fn screenshot(
&mut self, &mut self,
renderer: &mut Self::Renderer, renderer: &mut Self::Renderer,
surface: &mut Self::Surface, surface: &mut Self::Surface,
viewport: &Viewport, viewport: &Viewport,
background_color: Color, background_color: Color,
overlay: &[T],
) -> Vec<u8>; ) -> Vec<u8>;
} }

View file

@ -101,13 +101,12 @@ impl crate::graphics::Compositor for Compositor {
} }
} }
fn present<T: AsRef<str>>( fn present(
&mut self, &mut self,
renderer: &mut Self::Renderer, renderer: &mut Self::Renderer,
surface: &mut Self::Surface, surface: &mut Self::Surface,
viewport: &Viewport, viewport: &Viewport,
background_color: Color, background_color: Color,
overlay: &[T],
) -> Result<(), SurfaceError> { ) -> Result<(), SurfaceError> {
match (self, renderer, surface) { match (self, renderer, surface) {
( (
@ -121,7 +120,6 @@ impl crate::graphics::Compositor for Compositor {
primitives, primitives,
viewport, viewport,
background_color, background_color,
overlay,
) )
}), }),
#[cfg(feature = "wgpu")] #[cfg(feature = "wgpu")]
@ -137,7 +135,6 @@ impl crate::graphics::Compositor for Compositor {
primitives, primitives,
viewport, viewport,
background_color, background_color,
overlay,
) )
}), }),
#[allow(unreachable_patterns)] #[allow(unreachable_patterns)]
@ -148,13 +145,12 @@ impl crate::graphics::Compositor for Compositor {
} }
} }
fn screenshot<T: AsRef<str>>( fn screenshot(
&mut self, &mut self,
renderer: &mut Self::Renderer, renderer: &mut Self::Renderer,
surface: &mut Self::Surface, surface: &mut Self::Surface,
viewport: &Viewport, viewport: &Viewport,
background_color: Color, background_color: Color,
overlay: &[T],
) -> Vec<u8> { ) -> Vec<u8> {
match (self, renderer, surface) { match (self, renderer, surface) {
( (
@ -168,7 +164,6 @@ impl crate::graphics::Compositor for Compositor {
primitives, primitives,
viewport, viewport,
background_color, background_color,
overlay,
) )
}), }),
#[cfg(feature = "wgpu")] #[cfg(feature = "wgpu")]
@ -183,7 +178,6 @@ impl crate::graphics::Compositor for Compositor {
primitives, primitives,
viewport, viewport,
background_color, background_color,
overlay,
) )
}), }),
#[allow(unreachable_patterns)] #[allow(unreachable_patterns)]

View file

@ -11,11 +11,12 @@ categories.workspace = true
keywords.workspace = true keywords.workspace = true
[features] [features]
debug = []
multi-window = [] multi-window = []
[dependencies] [dependencies]
iced_core.workspace = true iced_core.workspace = true
iced_debug.workspace = true
iced_futures.workspace = true iced_futures.workspace = true
iced_futures.features = ["thread-pool"] iced_futures.features = ["thread-pool"]

View file

@ -1,220 +0,0 @@
#![allow(missing_docs)]
use crate::core::time;
use std::collections::VecDeque;
/// A bunch of time measurements for debugging purposes.
#[derive(Debug)]
pub struct Debug {
is_enabled: bool,
startup_start: time::Instant,
startup_duration: time::Duration,
update_start: time::Instant,
update_durations: TimeBuffer,
view_start: time::Instant,
view_durations: TimeBuffer,
layout_start: time::Instant,
layout_durations: TimeBuffer,
event_start: time::Instant,
event_durations: TimeBuffer,
draw_start: time::Instant,
draw_durations: TimeBuffer,
render_start: time::Instant,
render_durations: TimeBuffer,
message_count: usize,
last_messages: VecDeque<String>,
}
impl Debug {
/// Creates a new [`struct@Debug`].
pub fn new() -> Self {
let now = time::Instant::now();
Self {
is_enabled: false,
startup_start: now,
startup_duration: time::Duration::from_secs(0),
update_start: now,
update_durations: TimeBuffer::new(200),
view_start: now,
view_durations: TimeBuffer::new(200),
layout_start: now,
layout_durations: TimeBuffer::new(200),
event_start: now,
event_durations: TimeBuffer::new(200),
draw_start: now,
draw_durations: TimeBuffer::new(200),
render_start: now,
render_durations: TimeBuffer::new(50),
message_count: 0,
last_messages: VecDeque::new(),
}
}
pub fn toggle(&mut self) {
self.is_enabled = !self.is_enabled;
}
pub fn startup_started(&mut self) {
self.startup_start = time::Instant::now();
}
pub fn startup_finished(&mut self) {
self.startup_duration = self.startup_start.elapsed();
}
pub fn update_started(&mut self) {
self.update_start = time::Instant::now();
}
pub fn update_finished(&mut self) {
self.update_durations.push(self.update_start.elapsed());
}
pub fn view_started(&mut self) {
self.view_start = time::Instant::now();
}
pub fn view_finished(&mut self) {
self.view_durations.push(self.view_start.elapsed());
}
pub fn layout_started(&mut self) {
self.layout_start = time::Instant::now();
}
pub fn layout_finished(&mut self) {
self.layout_durations.push(self.layout_start.elapsed());
}
pub fn event_processing_started(&mut self) {
self.event_start = time::Instant::now();
}
pub fn event_processing_finished(&mut self) {
self.event_durations.push(self.event_start.elapsed());
}
pub fn draw_started(&mut self) {
self.draw_start = time::Instant::now();
}
pub fn draw_finished(&mut self) {
self.draw_durations.push(self.draw_start.elapsed());
}
pub fn render_started(&mut self) {
self.render_start = time::Instant::now();
}
pub fn render_finished(&mut self) {
self.render_durations.push(self.render_start.elapsed());
}
pub fn log_message<Message: std::fmt::Debug>(&mut self, message: &Message) {
self.last_messages.push_back(format!("{message:?}"));
if self.last_messages.len() > 10 {
let _ = self.last_messages.pop_front();
}
self.message_count += 1;
}
pub fn overlay(&self) -> Vec<String> {
if !self.is_enabled {
return Vec::new();
}
let mut lines = Vec::new();
fn key_value<T: std::fmt::Debug>(key: &str, value: T) -> String {
format!("{key} {value:?}")
}
lines.push(format!(
"{} {} - {}",
env!("CARGO_PKG_NAME"),
env!("CARGO_PKG_VERSION"),
env!("CARGO_PKG_REPOSITORY"),
));
lines.push(key_value("Startup:", self.startup_duration));
lines.push(key_value("Update:", self.update_durations.average()));
lines.push(key_value("View:", self.view_durations.average()));
lines.push(key_value("Layout:", self.layout_durations.average()));
lines.push(key_value(
"Event processing:",
self.event_durations.average(),
));
lines.push(key_value(
"Primitive generation:",
self.draw_durations.average(),
));
lines.push(key_value("Render:", self.render_durations.average()));
lines.push(key_value("Message count:", self.message_count));
lines.push(String::from("Last messages:"));
lines.extend(self.last_messages.iter().map(|msg| {
if msg.len() <= 100 {
format!(" {msg}")
} else {
format!(" {msg:.100}...")
}
}));
lines
}
}
impl Default for Debug {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug)]
struct TimeBuffer {
head: usize,
size: usize,
contents: Vec<time::Duration>,
}
impl TimeBuffer {
fn new(capacity: usize) -> TimeBuffer {
TimeBuffer {
head: 0,
size: 0,
contents: vec![time::Duration::from_secs(0); capacity],
}
}
fn push(&mut self, duration: time::Duration) {
self.head = (self.head + 1) % self.contents.len();
self.contents[self.head] = duration;
self.size = (self.size + 1).min(self.contents.len());
}
fn average(&self) -> time::Duration {
let sum: time::Duration = if self.size == self.contents.len() {
self.contents[..].iter().sum()
} else {
self.contents[..self.size].iter().sum()
};
sum / self.size.max(1) as u32
}
}

View file

@ -1,47 +0,0 @@
#![allow(missing_docs)]
#[derive(Debug, Default)]
pub struct Debug;
impl Debug {
pub fn new() -> Self {
Self
}
pub fn startup_started(&mut self) {}
pub fn startup_finished(&mut self) {}
pub fn update_started(&mut self) {}
pub fn update_finished(&mut self) {}
pub fn view_started(&mut self) {}
pub fn view_finished(&mut self) {}
pub fn layout_started(&mut self) {}
pub fn layout_finished(&mut self) {}
pub fn event_processing_started(&mut self) {}
pub fn event_processing_finished(&mut self) {}
pub fn draw_started(&mut self) {}
pub fn draw_finished(&mut self) {}
pub fn render_started(&mut self) {}
pub fn render_finished(&mut self) {}
pub fn log_message<Message: std::fmt::Debug>(
&mut self,
_message: &Message,
) {
}
pub fn overlay(&self) -> Vec<String> {
Vec::new()
}
}

View file

@ -29,20 +29,11 @@ pub mod window;
#[cfg(feature = "multi-window")] #[cfg(feature = "multi-window")]
pub mod multi_window; pub mod multi_window;
// We disable debug capabilities on release builds unless the `debug` feature
// is explicitly enabled.
#[cfg(feature = "debug")]
#[path = "debug/basic.rs"]
mod debug;
#[cfg(not(feature = "debug"))]
#[path = "debug/null.rs"]
mod debug;
pub use iced_core as core; pub use iced_core as core;
pub use iced_debug as debug;
pub use iced_futures as futures; pub use iced_futures as futures;
pub use command::Command; pub use command::Command;
pub use debug::Debug;
pub use font::Font; pub use font::Font;
pub use program::Program; pub use program::Program;
pub use user_interface::UserInterface; pub use user_interface::UserInterface;

View file

@ -4,8 +4,9 @@ use crate::core::mouse;
use crate::core::renderer; use crate::core::renderer;
use crate::core::widget::operation::{self, Operation}; use crate::core::widget::operation::{self, Operation};
use crate::core::{Clipboard, Size}; use crate::core::{Clipboard, Size};
use crate::debug;
use crate::user_interface::{self, UserInterface}; use crate::user_interface::{self, UserInterface};
use crate::{Command, Debug, Program}; use crate::{Command, Program};
/// The execution state of a multi-window [`Program`]. It leverages caching, event /// The execution state of a multi-window [`Program`]. It leverages caching, event
/// processing, and rendering primitive storage. /// processing, and rendering primitive storage.
@ -27,18 +28,12 @@ where
{ {
/// Creates a new [`State`] with the provided [`Program`], initializing its /// Creates a new [`State`] with the provided [`Program`], initializing its
/// primitive with the given logical bounds and renderer. /// primitive with the given logical bounds and renderer.
pub fn new( pub fn new(program: P, bounds: Size, renderer: &mut P::Renderer) -> Self {
program: P,
bounds: Size,
renderer: &mut P::Renderer,
debug: &mut Debug,
) -> Self {
let user_interface = build_user_interface( let user_interface = build_user_interface(
&program, &program,
user_interface::Cache::default(), user_interface::Cache::default(),
renderer, renderer,
bounds, bounds,
debug,
); );
let caches = Some(vec![user_interface.into_cache()]); let caches = Some(vec![user_interface.into_cache()]);
@ -95,17 +90,15 @@ where
theme: &P::Theme, theme: &P::Theme,
style: &renderer::Style, style: &renderer::Style,
clipboard: &mut dyn Clipboard, clipboard: &mut dyn Clipboard,
debug: &mut Debug,
) -> (Vec<Event>, Option<Command<P::Message>>) { ) -> (Vec<Event>, Option<Command<P::Message>>) {
let mut user_interfaces = build_user_interfaces( let mut user_interfaces = build_user_interfaces(
&self.program, &self.program,
self.caches.take().unwrap(), self.caches.take().unwrap(),
renderer, renderer,
bounds, bounds,
debug,
); );
debug.event_processing_started(); let interact_timer = debug::interact_time();
let mut messages = Vec::new(); let mut messages = Vec::new();
let uncaptured_events = user_interfaces.iter_mut().fold( let uncaptured_events = user_interfaces.iter_mut().fold(
@ -135,17 +128,15 @@ where
self.queued_events.clear(); self.queued_events.clear();
messages.append(&mut self.queued_messages); messages.append(&mut self.queued_messages);
debug.event_processing_finished(); drop(interact_timer);
let commands = if messages.is_empty() { let commands = if messages.is_empty() {
debug.draw_started(); let draw_timer = debug::draw_time();
for ui in &mut user_interfaces { for ui in &mut user_interfaces {
self.mouse_interaction = self.mouse_interaction =
ui.draw(renderer, theme, style, cursor); ui.draw(renderer, theme, style, cursor);
} }
drop(draw_timer);
debug.draw_finished();
self.caches = Some( self.caches = Some(
user_interfaces user_interfaces
@ -164,11 +155,11 @@ where
drop(user_interfaces); drop(user_interfaces);
let commands = Command::batch(messages.into_iter().map(|msg| { let commands = Command::batch(messages.into_iter().map(|msg| {
debug.log_message(&msg); debug::log_message(&msg);
debug.update_started(); let update_timer = debug::update_time();
let command = self.program.update(msg); let command = self.program.update(msg);
debug.update_finished(); drop(update_timer);
command command
})); }));
@ -178,15 +169,14 @@ where
temp_caches, temp_caches,
renderer, renderer,
bounds, bounds,
debug,
); );
debug.draw_started(); let draw_timer = debug::draw_time();
for ui in &mut user_interfaces { for ui in &mut user_interfaces {
self.mouse_interaction = self.mouse_interaction =
ui.draw(renderer, theme, style, cursor); ui.draw(renderer, theme, style, cursor);
} }
debug.draw_finished(); drop(draw_timer);
self.caches = Some( self.caches = Some(
user_interfaces user_interfaces
@ -207,14 +197,12 @@ where
renderer: &mut P::Renderer, renderer: &mut P::Renderer,
operations: impl Iterator<Item = Box<dyn Operation<P::Message>>>, operations: impl Iterator<Item = Box<dyn Operation<P::Message>>>,
bounds: Size, bounds: Size,
debug: &mut Debug,
) { ) {
let mut user_interfaces = build_user_interfaces( let mut user_interfaces = build_user_interfaces(
&self.program, &self.program,
self.caches.take().unwrap(), self.caches.take().unwrap(),
renderer, renderer,
bounds, bounds,
debug,
); );
for operation in operations { for operation in operations {
@ -251,13 +239,10 @@ fn build_user_interfaces<'a, P: Program>(
mut caches: Vec<user_interface::Cache>, mut caches: Vec<user_interface::Cache>,
renderer: &mut P::Renderer, renderer: &mut P::Renderer,
size: Size, size: Size,
debug: &mut Debug,
) -> Vec<UserInterface<'a, P::Message, P::Theme, P::Renderer>> { ) -> Vec<UserInterface<'a, P::Message, P::Theme, P::Renderer>> {
caches caches
.drain(..) .drain(..)
.map(|cache| { .map(|cache| build_user_interface(program, cache, renderer, size))
build_user_interface(program, cache, renderer, size, debug)
})
.collect() .collect()
} }
@ -266,15 +251,14 @@ fn build_user_interface<'a, P: Program>(
cache: user_interface::Cache, cache: user_interface::Cache,
renderer: &mut P::Renderer, renderer: &mut P::Renderer,
size: Size, size: Size,
debug: &mut Debug,
) -> UserInterface<'a, P::Message, P::Theme, P::Renderer> { ) -> UserInterface<'a, P::Message, P::Theme, P::Renderer> {
debug.view_started(); let view_timer = debug::view_time();
let view = program.view(); let view = program.view();
debug.view_finished(); drop(view_timer);
debug.layout_started(); let layout_timer = debug::layout_time();
let user_interface = UserInterface::build(view, size, cache, renderer); let user_interface = UserInterface::build(view, size, cache, renderer);
debug.layout_finished(); drop(layout_timer);
user_interface user_interface
} }

View file

@ -3,8 +3,9 @@ use crate::core::mouse;
use crate::core::renderer; use crate::core::renderer;
use crate::core::widget::operation::{self, Operation}; use crate::core::widget::operation::{self, Operation};
use crate::core::{Clipboard, Size}; use crate::core::{Clipboard, Size};
use crate::debug;
use crate::user_interface::{self, UserInterface}; use crate::user_interface::{self, UserInterface};
use crate::{Command, Debug, Program}; use crate::{Command, Program};
/// The execution state of a [`Program`]. It leverages caching, event /// The execution state of a [`Program`]. It leverages caching, event
/// processing, and rendering primitive storage. /// processing, and rendering primitive storage.
@ -30,14 +31,12 @@ where
mut program: P, mut program: P,
bounds: Size, bounds: Size,
renderer: &mut P::Renderer, renderer: &mut P::Renderer,
debug: &mut Debug,
) -> Self { ) -> Self {
let user_interface = build_user_interface( let user_interface = build_user_interface(
&mut program, &mut program,
user_interface::Cache::default(), user_interface::Cache::default(),
renderer, renderer,
bounds, bounds,
debug,
); );
let cache = Some(user_interface.into_cache()); let cache = Some(user_interface.into_cache());
@ -94,17 +93,15 @@ where
theme: &P::Theme, theme: &P::Theme,
style: &renderer::Style, style: &renderer::Style,
clipboard: &mut dyn Clipboard, clipboard: &mut dyn Clipboard,
debug: &mut Debug,
) -> (Vec<Event>, Option<Command<P::Message>>) { ) -> (Vec<Event>, Option<Command<P::Message>>) {
let mut user_interface = build_user_interface( let mut user_interface = build_user_interface(
&mut self.program, &mut self.program,
self.cache.take().unwrap(), self.cache.take().unwrap(),
renderer, renderer,
bounds, bounds,
debug,
); );
debug.event_processing_started(); let interact_timer = debug::interact_time();
let mut messages = Vec::new(); let mut messages = Vec::new();
let (_, event_statuses) = user_interface.update( let (_, event_statuses) = user_interface.update(
@ -127,13 +124,13 @@ where
self.queued_events.clear(); self.queued_events.clear();
messages.append(&mut self.queued_messages); messages.append(&mut self.queued_messages);
debug.event_processing_finished(); drop(interact_timer);
let command = if messages.is_empty() { let command = if messages.is_empty() {
debug.draw_started(); let draw_timer = debug::draw_time();
self.mouse_interaction = self.mouse_interaction =
user_interface.draw(renderer, theme, style, cursor); user_interface.draw(renderer, theme, style, cursor);
debug.draw_finished(); drop(draw_timer);
self.cache = Some(user_interface.into_cache()); self.cache = Some(user_interface.into_cache());
@ -145,11 +142,11 @@ where
let commands = let commands =
Command::batch(messages.into_iter().map(|message| { Command::batch(messages.into_iter().map(|message| {
debug.log_message(&message); debug::log_message(&message);
debug.update_started(); let update_timer = debug::update_time();
let command = self.program.update(message); let command = self.program.update(message);
debug.update_finished(); drop(update_timer);
command command
})); }));
@ -159,13 +156,12 @@ where
temp_cache, temp_cache,
renderer, renderer,
bounds, bounds,
debug,
); );
debug.draw_started(); let draw_timer = debug::draw_time();
self.mouse_interaction = self.mouse_interaction =
user_interface.draw(renderer, theme, style, cursor); user_interface.draw(renderer, theme, style, cursor);
debug.draw_finished(); drop(draw_timer);
self.cache = Some(user_interface.into_cache()); self.cache = Some(user_interface.into_cache());
@ -181,14 +177,12 @@ where
renderer: &mut P::Renderer, renderer: &mut P::Renderer,
operations: impl Iterator<Item = Box<dyn Operation<P::Message>>>, operations: impl Iterator<Item = Box<dyn Operation<P::Message>>>,
bounds: Size, bounds: Size,
debug: &mut Debug,
) { ) {
let mut user_interface = build_user_interface( let mut user_interface = build_user_interface(
&mut self.program, &mut self.program,
self.cache.take().unwrap(), self.cache.take().unwrap(),
renderer, renderer,
bounds, bounds,
debug,
); );
for operation in operations { for operation in operations {
@ -218,15 +212,14 @@ fn build_user_interface<'a, P: Program>(
cache: user_interface::Cache, cache: user_interface::Cache,
renderer: &mut P::Renderer, renderer: &mut P::Renderer,
size: Size, size: Size,
debug: &mut Debug,
) -> UserInterface<'a, P::Message, P::Theme, P::Renderer> { ) -> UserInterface<'a, P::Message, P::Theme, P::Renderer> {
debug.view_started(); let view_timer = debug::view_time();
let view = program.view(); let view = program.view();
debug.view_finished(); drop(view_timer);
debug.layout_started(); let layout_timer = debug::layout_time();
let user_interface = UserInterface::build(view, size, cache, renderer); let user_interface = UserInterface::build(view, size, cache, renderer);
debug.layout_finished(); drop(layout_timer);
user_interface user_interface
} }

26
sentinel/Cargo.toml Normal file
View file

@ -0,0 +1,26 @@
[package]
name = "iced_sentinel"
description = "A client/server protocol to monitor and supervise iced applications"
version.workspace = true
edition.workspace = true
authors.workspace = true
license.workspace = true
repository.workspace = true
homepage.workspace = true
categories.workspace = true
keywords.workspace = true
[dependencies]
iced_core.workspace = true
serde_json.workspace = true
futures.workspace = true
log.workspace = true
tokio.workspace = true
tokio.features = ["rt", "rt-multi-thread", "net", "sync", "time", "io-util", "macros"]
serde.workspace = true
serde.features = ["derive"]
semver.workspace = true
semver.features = ["serde"]

80
sentinel/src/client.rs Normal file
View file

@ -0,0 +1,80 @@
use crate::{Input, Report, SOCKET_ADDRESS};
use tokio::io::{self, AsyncWriteExt};
use tokio::net;
use tokio::sync::mpsc;
use tokio::time;
#[derive(Debug, Clone)]
pub struct Client {
sender: mpsc::Sender<Input>,
}
impl Client {
pub fn report(&mut self, report: Report) {
let _ = self.sender.try_send(Input::Reported(report));
}
}
#[must_use]
pub fn connect() -> Client {
let (sender, receiver) = mpsc::channel(1_000);
std::thread::spawn(move || run(receiver));
Client { sender }
}
#[tokio::main]
async fn run(mut receiver: mpsc::Receiver<Input>) {
let version = semver::Version::parse(env!("CARGO_PKG_VERSION"))
.expect("Parse package version");
loop {
match _connect().await {
Ok(mut stream) => {
let _ = send(&mut stream, Input::Connected(version)).await;
while let Some(input) = receiver.recv().await {
if send(&mut stream, input).await.is_err() {
break;
}
}
break;
}
Err(_) => {
time::sleep(time::Duration::from_secs(2)).await;
}
}
}
}
async fn _connect() -> Result<io::BufStream<net::TcpStream>, io::Error> {
log::debug!("Attempting to connect sentinel to server...");
let stream = net::TcpStream::connect(SOCKET_ADDRESS).await?;
stream.set_nodelay(true)?;
stream.writable().await?;
Ok(io::BufStream::new(stream))
}
async fn send(
stream: &mut io::BufStream<net::TcpStream>,
input: Input,
) -> Result<(), io::Error> {
stream
.write_all(
format!(
"{}\n",
serde_json::to_string(&input).expect("Serialize input message")
)
.as_bytes(),
)
.await?;
stream.flush().await?;
Ok(())
}

105
sentinel/src/lib.rs Normal file
View file

@ -0,0 +1,105 @@
pub use iced_core as core;
pub mod client;
pub mod timing;
use crate::timing::Timing;
use futures::future;
use futures::stream::{self, Stream, StreamExt};
use semver::Version;
use serde::{Deserialize, Serialize};
use tokio::io::{self, AsyncBufReadExt, BufStream};
use tokio::net;
pub const SOCKET_ADDRESS: &str = "127.0.0.1:9167";
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum Input {
Connected(Version),
Reported(Report),
}
#[derive(Debug, Clone)]
pub enum Event {
Connected(Version),
Disconnected,
Reported(Report),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum Report {
Timing(Timing),
}
pub fn run() -> impl Stream<Item = Event> {
enum State {
Disconnected,
Connected(BufStream<net::TcpStream>),
}
stream::unfold(State::Disconnected, |state| async {
match state {
State::Disconnected => match connect().await {
Ok(stream) => {
let stream = BufStream::new(stream);
Some((None, State::Connected(stream)))
}
Err(_error) => Some((None, State::Disconnected)),
},
State::Connected(stream) => match receive(stream).await {
Ok((_, Event::Disconnected)) | Err(_) => {
Some((Some(Event::Disconnected), State::Disconnected))
}
Ok((stream, message)) => {
Some((Some(message), State::Connected(stream)))
}
},
}
})
.filter_map(future::ready)
}
async fn connect() -> Result<net::TcpStream, io::Error> {
let listener = net::TcpListener::bind(SOCKET_ADDRESS).await?;
let (stream, _) = listener.accept().await?;
stream.set_nodelay(true)?;
stream.readable().await?;
Ok(stream)
}
async fn receive(
mut stream: BufStream<net::TcpStream>,
) -> Result<(BufStream<net::TcpStream>, Event), io::Error> {
let mut input = String::new();
loop {
match stream.read_line(&mut input).await? {
0 => return Ok((stream, Event::Disconnected)),
n => {
match serde_json::from_str(&input[..n]) {
Ok(input) => {
return Ok((
stream,
match dbg!(input) {
Input::Connected(version) => {
Event::Connected(version)
}
Input::Reported(report) => {
Event::Reported(report)
}
},
))
}
Err(_) => {
// TODO: Log decoding error
}
}
}
}
}
}

25
sentinel/src/timing.rs Normal file
View file

@ -0,0 +1,25 @@
use crate::core::time::Duration;
use serde::{Deserialize, Serialize};
#[derive(
Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize,
)]
pub struct Timing {
pub stage: Stage,
pub duration: Duration,
}
#[derive(
Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize,
)]
pub enum Stage {
Boot,
Update,
View,
Layout,
Interact,
Draw,
Render,
Custom(String),
}

View file

@ -31,7 +31,7 @@ impl Backend {
} }
} }
pub fn draw<T: AsRef<str>>( pub fn draw(
&mut self, &mut self,
pixels: &mut tiny_skia::PixmapMut<'_>, pixels: &mut tiny_skia::PixmapMut<'_>,
clip_mask: &mut tiny_skia::Mask, clip_mask: &mut tiny_skia::Mask,
@ -39,38 +39,9 @@ impl Backend {
viewport: &Viewport, viewport: &Viewport,
damage: &[Rectangle], damage: &[Rectangle],
background_color: Color, background_color: Color,
overlay: &[T],
) { ) {
let physical_size = viewport.physical_size();
let scale_factor = viewport.scale_factor() as f32; let scale_factor = viewport.scale_factor() as f32;
if !overlay.is_empty() {
let path = tiny_skia::PathBuilder::from_rect(
tiny_skia::Rect::from_xywh(
0.0,
0.0,
physical_size.width as f32,
physical_size.height as f32,
)
.expect("Create damage rectangle"),
);
pixels.fill_path(
&path,
&tiny_skia::Paint {
shader: tiny_skia::Shader::SolidColor(into_color(Color {
a: 0.1,
..background_color
})),
anti_alias: false,
..Default::default()
},
tiny_skia::FillRule::default(),
tiny_skia::Transform::identity(),
None,
);
}
for &region in damage { for &region in damage {
let path = tiny_skia::PathBuilder::from_rect( let path = tiny_skia::PathBuilder::from_rect(
tiny_skia::Rect::from_xywh( tiny_skia::Rect::from_xywh(
@ -109,25 +80,6 @@ impl Backend {
Transformation::IDENTITY, Transformation::IDENTITY,
); );
} }
if !overlay.is_empty() {
pixels.stroke_path(
&path,
&tiny_skia::Paint {
shader: tiny_skia::Shader::SolidColor(into_color(
Color::from_rgb(1.0, 0.0, 0.0),
)),
anti_alias: false,
..tiny_skia::Paint::default()
},
&tiny_skia::Stroke {
width: 1.0,
..tiny_skia::Stroke::default()
},
tiny_skia::Transform::identity(),
None,
);
}
} }
self.text_pipeline.trim_cache(); self.text_pipeline.trim_cache();

View file

@ -95,43 +95,27 @@ impl crate::graphics::Compositor for Compositor {
} }
} }
fn present<T: AsRef<str>>( fn present(
&mut self, &mut self,
renderer: &mut Self::Renderer, renderer: &mut Self::Renderer,
surface: &mut Self::Surface, surface: &mut Self::Surface,
viewport: &Viewport, viewport: &Viewport,
background_color: Color, background_color: Color,
overlay: &[T],
) -> Result<(), compositor::SurfaceError> { ) -> Result<(), compositor::SurfaceError> {
renderer.with_primitives(|backend, primitives| { renderer.with_primitives(|backend, primitives| {
present( present(backend, surface, primitives, viewport, background_color)
backend,
surface,
primitives,
viewport,
background_color,
overlay,
)
}) })
} }
fn screenshot<T: AsRef<str>>( fn screenshot(
&mut self, &mut self,
renderer: &mut Self::Renderer, renderer: &mut Self::Renderer,
surface: &mut Self::Surface, surface: &mut Self::Surface,
viewport: &Viewport, viewport: &Viewport,
background_color: Color, background_color: Color,
overlay: &[T],
) -> Vec<u8> { ) -> Vec<u8> {
renderer.with_primitives(|backend, primitives| { renderer.with_primitives(|backend, primitives| {
screenshot( screenshot(surface, backend, primitives, viewport, background_color)
surface,
backend,
primitives,
viewport,
background_color,
overlay,
)
}) })
} }
} }
@ -147,13 +131,12 @@ pub fn new<W: compositor::Window>(
Compositor { context, settings } Compositor { context, settings }
} }
pub fn present<T: AsRef<str>>( pub fn present(
backend: &mut Backend, backend: &mut Backend,
surface: &mut Surface, surface: &mut Surface,
primitives: &[Primitive], primitives: &[Primitive],
viewport: &Viewport, viewport: &Viewport,
background_color: Color, background_color: Color,
overlay: &[T],
) -> Result<(), compositor::SurfaceError> { ) -> Result<(), compositor::SurfaceError> {
let physical_size = viewport.physical_size(); let physical_size = viewport.physical_size();
let scale_factor = viewport.scale_factor() as f32; let scale_factor = viewport.scale_factor() as f32;
@ -206,19 +189,17 @@ pub fn present<T: AsRef<str>>(
viewport, viewport,
&damage, &damage,
background_color, background_color,
overlay,
); );
buffer.present().map_err(|_| compositor::SurfaceError::Lost) buffer.present().map_err(|_| compositor::SurfaceError::Lost)
} }
pub fn screenshot<T: AsRef<str>>( pub fn screenshot(
surface: &mut Surface, surface: &mut Surface,
backend: &mut Backend, backend: &mut Backend,
primitives: &[Primitive], primitives: &[Primitive],
viewport: &Viewport, viewport: &Viewport,
background_color: Color, background_color: Color,
overlay: &[T],
) -> Vec<u8> { ) -> Vec<u8> {
let size = viewport.physical_size(); let size = viewport.physical_size();
@ -240,7 +221,6 @@ pub fn screenshot<T: AsRef<str>>(
size.height as f32, size.height as f32,
))], ))],
background_color, background_color,
overlay,
); );
offscreen_buffer.iter().fold( offscreen_buffer.iter().fold(

View file

@ -67,7 +67,7 @@ impl Backend {
/// ///
/// The text provided as overlay will be rendered on top of the primitives. /// The text provided as overlay will be rendered on top of the primitives.
/// This is useful for rendering debug information. /// This is useful for rendering debug information.
pub fn present<T: AsRef<str>>( pub fn present(
&mut self, &mut self,
device: &wgpu::Device, device: &wgpu::Device,
queue: &wgpu::Queue, queue: &wgpu::Queue,
@ -77,7 +77,6 @@ impl Backend {
frame: &wgpu::TextureView, frame: &wgpu::TextureView,
primitives: &[Primitive], primitives: &[Primitive],
viewport: &Viewport, viewport: &Viewport,
overlay_text: &[T],
) { ) {
log::debug!("Drawing"); log::debug!("Drawing");
#[cfg(feature = "tracing")] #[cfg(feature = "tracing")]
@ -87,11 +86,7 @@ impl Backend {
let scale_factor = viewport.scale_factor() as f32; let scale_factor = viewport.scale_factor() as f32;
let transformation = viewport.projection(); let transformation = viewport.projection();
let mut layers = Layer::generate(primitives, viewport); let layers = Layer::generate(primitives, viewport);
if !overlay_text.is_empty() {
layers.push(Layer::overlay(overlay_text, viewport));
}
self.prepare( self.prepare(
device, device,

View file

@ -172,14 +172,13 @@ pub fn new<W: compositor::Window>(
} }
/// Presents the given primitives with the given [`Compositor`] and [`Backend`]. /// Presents the given primitives with the given [`Compositor`] and [`Backend`].
pub fn present<T: AsRef<str>>( pub fn present(
compositor: &mut Compositor, compositor: &mut Compositor,
backend: &mut Backend, backend: &mut Backend,
surface: &mut wgpu::Surface<'static>, surface: &mut wgpu::Surface<'static>,
primitives: &[Primitive], primitives: &[Primitive],
viewport: &Viewport, viewport: &Viewport,
background_color: Color, background_color: Color,
overlay: &[T],
) -> Result<(), compositor::SurfaceError> { ) -> Result<(), compositor::SurfaceError> {
match surface.get_current_texture() { match surface.get_current_texture() {
Ok(frame) => { Ok(frame) => {
@ -202,7 +201,6 @@ pub fn present<T: AsRef<str>>(
view, view,
primitives, primitives,
viewport, viewport,
overlay,
); );
// Submit work // Submit work
@ -294,13 +292,12 @@ impl graphics::Compositor for Compositor {
} }
} }
fn present<T: AsRef<str>>( fn present(
&mut self, &mut self,
renderer: &mut Self::Renderer, renderer: &mut Self::Renderer,
surface: &mut Self::Surface, surface: &mut Self::Surface,
viewport: &Viewport, viewport: &Viewport,
background_color: Color, background_color: Color,
overlay: &[T],
) -> Result<(), compositor::SurfaceError> { ) -> Result<(), compositor::SurfaceError> {
renderer.with_primitives(|backend, primitives| { renderer.with_primitives(|backend, primitives| {
present( present(
@ -310,28 +307,19 @@ impl graphics::Compositor for Compositor {
primitives, primitives,
viewport, viewport,
background_color, background_color,
overlay,
) )
}) })
} }
fn screenshot<T: AsRef<str>>( fn screenshot(
&mut self, &mut self,
renderer: &mut Self::Renderer, renderer: &mut Self::Renderer,
_surface: &mut Self::Surface, _surface: &mut Self::Surface,
viewport: &Viewport, viewport: &Viewport,
background_color: Color, background_color: Color,
overlay: &[T],
) -> Vec<u8> { ) -> Vec<u8> {
renderer.with_primitives(|backend, primitives| { renderer.with_primitives(|backend, primitives| {
screenshot( screenshot(self, backend, primitives, viewport, background_color)
self,
backend,
primitives,
viewport,
background_color,
overlay,
)
}) })
} }
} }
@ -339,13 +327,12 @@ impl graphics::Compositor for Compositor {
/// Renders the current surface to an offscreen buffer. /// Renders the current surface to an offscreen buffer.
/// ///
/// Returns RGBA bytes of the texture data. /// Returns RGBA bytes of the texture data.
pub fn screenshot<T: AsRef<str>>( pub fn screenshot(
compositor: &Compositor, compositor: &Compositor,
backend: &mut Backend, backend: &mut Backend,
primitives: &[Primitive], primitives: &[Primitive],
viewport: &Viewport, viewport: &Viewport,
background_color: Color, background_color: Color,
overlay: &[T],
) -> Vec<u8> { ) -> Vec<u8> {
let mut encoder = compositor.device.create_command_encoder( let mut encoder = compositor.device.create_command_encoder(
&wgpu::CommandEncoderDescriptor { &wgpu::CommandEncoderDescriptor {
@ -385,7 +372,6 @@ pub fn screenshot<T: AsRef<str>>(
&view, &view,
primitives, primitives,
viewport, viewport,
overlay,
); );
let texture = crate::color::convert( let texture = crate::color::convert(

View file

@ -12,7 +12,6 @@ keywords.workspace = true
[features] [features]
default = ["x11", "wayland", "wayland-dlopen", "wayland-csd-adwaita"] default = ["x11", "wayland", "wayland-dlopen", "wayland-csd-adwaita"]
debug = ["iced_runtime/debug"]
system = ["sysinfo"] system = ["sysinfo"]
application = [] application = []
x11 = ["winit/x11"] x11 = ["winit/x11"]

View file

@ -11,13 +11,14 @@ use crate::core::time::Instant;
use crate::core::widget::operation; use crate::core::widget::operation;
use crate::core::window; use crate::core::window;
use crate::core::{Event, Point, Size}; use crate::core::{Event, Point, Size};
use crate::debug;
use crate::futures::futures; use crate::futures::futures;
use crate::futures::{Executor, Runtime, Subscription}; use crate::futures::{Executor, Runtime, Subscription};
use crate::graphics::compositor::{self, Compositor}; use crate::graphics::compositor::{self, Compositor};
use crate::runtime::clipboard; use crate::runtime::clipboard;
use crate::runtime::program::Program; use crate::runtime::program::Program;
use crate::runtime::user_interface::{self, UserInterface}; use crate::runtime::user_interface::{self, UserInterface};
use crate::runtime::{Command, Debug}; use crate::runtime::Command;
use crate::style::application::{Appearance, StyleSheet}; use crate::style::application::{Appearance, StyleSheet};
use crate::{Clipboard, Error, Proxy, Settings}; use crate::{Clipboard, Error, Proxy, Settings};
@ -111,8 +112,7 @@ where
use futures::Future; use futures::Future;
use winit::event_loop::EventLoopBuilder; use winit::event_loop::EventLoopBuilder;
let mut debug = Debug::new(); let boot_timer = debug::boot_time();
debug.startup_started();
let event_loop = EventLoopBuilder::with_user_event() let event_loop = EventLoopBuilder::with_user_event()
.build() .build()
@ -206,13 +206,13 @@ where
renderer, renderer,
runtime, runtime,
proxy, proxy,
debug,
event_receiver, event_receiver,
control_sender, control_sender,
init_command, init_command,
window, window,
should_be_visible, should_be_visible,
exit_on_close_request, exit_on_close_request,
boot_timer,
)); ));
let mut context = task::Context::from_waker(task::noop_waker_ref()); let mut context = task::Context::from_waker(task::noop_waker_ref());
@ -276,7 +276,6 @@ async fn run_instance<A, E, C>(
mut renderer: A::Renderer, mut renderer: A::Renderer,
mut runtime: Runtime<E, Proxy<A::Message>, A::Message>, mut runtime: Runtime<E, Proxy<A::Message>, A::Message>,
mut proxy: winit::event_loop::EventLoopProxy<A::Message>, mut proxy: winit::event_loop::EventLoopProxy<A::Message>,
mut debug: Debug,
mut event_receiver: mpsc::UnboundedReceiver< mut event_receiver: mpsc::UnboundedReceiver<
winit::event::Event<A::Message>, winit::event::Event<A::Message>,
>, >,
@ -285,6 +284,7 @@ async fn run_instance<A, E, C>(
window: Arc<winit::window::Window>, window: Arc<winit::window::Window>,
should_be_visible: bool, should_be_visible: bool,
exit_on_close_request: bool, exit_on_close_request: bool,
boot_timer: debug::Timer,
) where ) where
A: Application + 'static, A: Application + 'static,
E: Executor + 'static, E: Executor + 'static,
@ -324,17 +324,16 @@ async fn run_instance<A, E, C>(
&mut clipboard, &mut clipboard,
&mut should_exit, &mut should_exit,
&mut proxy, &mut proxy,
&mut debug,
&window, &window,
); );
runtime.track(application.subscription().into_recipes()); runtime.track(application.subscription().into_recipes());
boot_timer.finish();
let mut user_interface = ManuallyDrop::new(build_user_interface( let mut user_interface = ManuallyDrop::new(build_user_interface(
&application, &application,
cache, cache,
&mut renderer, &mut renderer,
state.logical_size(), state.logical_size(),
&mut debug,
)); ));
let mut mouse_interaction = mouse::Interaction::default(); let mut mouse_interaction = mouse::Interaction::default();
@ -342,8 +341,6 @@ async fn run_instance<A, E, C>(
let mut messages = Vec::new(); let mut messages = Vec::new();
let mut redraw_pending = false; let mut redraw_pending = false;
debug.startup_finished();
while let Some(event) = event_receiver.next().await { while let Some(event) = event_receiver.next().await {
match event { match event {
event::Event::NewEvents( event::Event::NewEvents(
@ -382,12 +379,12 @@ async fn run_instance<A, E, C>(
if viewport_version != current_viewport_version { if viewport_version != current_viewport_version {
let logical_size = state.logical_size(); let logical_size = state.logical_size();
debug.layout_started(); let layout_timer = debug::layout_time();
user_interface = ManuallyDrop::new( user_interface = ManuallyDrop::new(
ManuallyDrop::into_inner(user_interface) ManuallyDrop::into_inner(user_interface)
.relayout(logical_size, &mut renderer), .relayout(logical_size, &mut renderer),
); );
debug.layout_finished(); layout_timer.finish();
compositor.configure_surface( compositor.configure_surface(
&mut surface, &mut surface,
@ -434,7 +431,7 @@ async fn run_instance<A, E, C>(
runtime.broadcast(redraw_event, core::event::Status::Ignored); runtime.broadcast(redraw_event, core::event::Status::Ignored);
debug.draw_started(); let draw_timer = debug::draw_time();
let new_mouse_interaction = user_interface.draw( let new_mouse_interaction = user_interface.draw(
&mut renderer, &mut renderer,
state.theme(), state.theme(),
@ -444,7 +441,7 @@ async fn run_instance<A, E, C>(
state.cursor(), state.cursor(),
); );
redraw_pending = false; redraw_pending = false;
debug.draw_finished(); draw_timer.finish();
if new_mouse_interaction != mouse_interaction { if new_mouse_interaction != mouse_interaction {
window.set_cursor_icon(conversion::mouse_interaction( window.set_cursor_icon(conversion::mouse_interaction(
@ -454,19 +451,15 @@ async fn run_instance<A, E, C>(
mouse_interaction = new_mouse_interaction; mouse_interaction = new_mouse_interaction;
} }
debug.render_started(); let render_timer = debug::render_time();
match compositor.present( match compositor.present(
&mut renderer, &mut renderer,
&mut surface, &mut surface,
state.viewport(), state.viewport(),
state.background_color(), state.background_color(),
&debug.overlay(),
) { ) {
Ok(()) => { Ok(()) => {
debug.render_finished(); render_timer.finish();
// TODO: Handle animations!
// Maybe we can use `ControlFlow::WaitUntil` for this.
} }
Err(error) => match error { Err(error) => match error {
// This is an unrecoverable error. // This is an unrecoverable error.
@ -474,8 +467,6 @@ async fn run_instance<A, E, C>(
panic!("{error:?}"); panic!("{error:?}");
} }
_ => { _ => {
debug.render_finished();
// Try rendering again next frame. // Try rendering again next frame.
window.request_redraw(); window.request_redraw();
} }
@ -492,7 +483,7 @@ async fn run_instance<A, E, C>(
break; break;
} }
state.update(&window, &window_event, &mut debug); state.update(&window, &window_event);
if let Some(event) = conversion::window_event( if let Some(event) = conversion::window_event(
window::Id::MAIN, window::Id::MAIN,
@ -508,8 +499,7 @@ async fn run_instance<A, E, C>(
continue; continue;
} }
debug.event_processing_started(); let interact_timer = debug::interact_time();
let (interface_state, statuses) = user_interface.update( let (interface_state, statuses) = user_interface.update(
&events, &events,
state.cursor(), state.cursor(),
@ -517,8 +507,7 @@ async fn run_instance<A, E, C>(
&mut clipboard, &mut clipboard,
&mut messages, &mut messages,
); );
interact_timer.finish();
debug.event_processing_finished();
for (event, status) in for (event, status) in
events.drain(..).zip(statuses.into_iter()) events.drain(..).zip(statuses.into_iter())
@ -547,7 +536,6 @@ async fn run_instance<A, E, C>(
&mut clipboard, &mut clipboard,
&mut should_exit, &mut should_exit,
&mut proxy, &mut proxy,
&mut debug,
&mut messages, &mut messages,
&window, &window,
); );
@ -557,7 +545,6 @@ async fn run_instance<A, E, C>(
cache, cache,
&mut renderer, &mut renderer,
state.logical_size(), state.logical_size(),
&mut debug,
)); ));
if should_exit { if should_exit {
@ -609,18 +596,17 @@ pub fn build_user_interface<'a, A: Application>(
cache: user_interface::Cache, cache: user_interface::Cache,
renderer: &mut A::Renderer, renderer: &mut A::Renderer,
size: Size, size: Size,
debug: &mut Debug,
) -> UserInterface<'a, A::Message, A::Theme, A::Renderer> ) -> UserInterface<'a, A::Message, A::Theme, A::Renderer>
where where
A::Theme: StyleSheet, A::Theme: StyleSheet,
{ {
debug.view_started(); let view_timer = debug::view_time();
let view = application.view(); let view = application.view();
debug.view_finished(); view_timer.finish();
debug.layout_started(); let layout_timer = debug::layout_time();
let user_interface = UserInterface::build(view, size, cache, renderer); let user_interface = UserInterface::build(view, size, cache, renderer);
debug.layout_finished(); layout_timer.finish();
user_interface user_interface
} }
@ -638,7 +624,6 @@ pub fn update<A: Application, C, E: Executor>(
clipboard: &mut Clipboard, clipboard: &mut Clipboard,
should_exit: &mut bool, should_exit: &mut bool,
proxy: &mut winit::event_loop::EventLoopProxy<A::Message>, proxy: &mut winit::event_loop::EventLoopProxy<A::Message>,
debug: &mut Debug,
messages: &mut Vec<A::Message>, messages: &mut Vec<A::Message>,
window: &winit::window::Window, window: &winit::window::Window,
) where ) where
@ -646,11 +631,11 @@ pub fn update<A: Application, C, E: Executor>(
A::Theme: StyleSheet, A::Theme: StyleSheet,
{ {
for message in messages.drain(..) { for message in messages.drain(..) {
debug.log_message(&message); debug::log_message(&message);
debug.update_started(); let update_timer = debug::update_time();
let command = runtime.enter(|| application.update(message)); let command = runtime.enter(|| application.update(message));
debug.update_finished(); update_timer.finish();
run_command( run_command(
application, application,
@ -664,7 +649,6 @@ pub fn update<A: Application, C, E: Executor>(
clipboard, clipboard,
should_exit, should_exit,
proxy, proxy,
debug,
window, window,
); );
} }
@ -688,7 +672,6 @@ pub fn run_command<A, C, E>(
clipboard: &mut Clipboard, clipboard: &mut Clipboard,
should_exit: &mut bool, should_exit: &mut bool,
proxy: &mut winit::event_loop::EventLoopProxy<A::Message>, proxy: &mut winit::event_loop::EventLoopProxy<A::Message>,
debug: &mut Debug,
window: &winit::window::Window, window: &winit::window::Window,
) where ) where
A: Application, A: Application,
@ -855,7 +838,6 @@ pub fn run_command<A, C, E>(
surface, surface,
state.viewport(), state.viewport(),
state.background_color(), state.background_color(),
&debug.overlay(),
); );
proxy proxy
@ -895,7 +877,6 @@ pub fn run_command<A, C, E>(
current_cache, current_cache,
renderer, renderer,
state.logical_size(), state.logical_size(),
debug,
); );
while let Some(mut operation) = current_operation.take() { while let Some(mut operation) = current_operation.take() {

View file

@ -3,7 +3,6 @@ use crate::conversion;
use crate::core::mouse; use crate::core::mouse;
use crate::core::{Color, Size}; use crate::core::{Color, Size};
use crate::graphics::Viewport; use crate::graphics::Viewport;
use crate::runtime::Debug;
use crate::Application; use crate::Application;
use std::marker::PhantomData; use std::marker::PhantomData;
@ -122,12 +121,7 @@ where
/// Processes the provided window event and updates the [`State`] /// Processes the provided window event and updates the [`State`]
/// accordingly. /// accordingly.
pub fn update( pub fn update(&mut self, window: &Window, event: &WindowEvent) {
&mut self,
window: &Window,
event: &WindowEvent,
_debug: &mut Debug,
) {
match event { match event {
WindowEvent::Resized(new_size) => { WindowEvent::Resized(new_size) => {
let size = Size::new(new_size.width, new_size.height); let size = Size::new(new_size.width, new_size.height);
@ -176,7 +170,7 @@ where
.. ..
}, },
.. ..
} => _debug.toggle(), } => crate::debug::open_axe(),
_ => {} _ => {}
} }
} }

View file

@ -29,6 +29,7 @@
pub use iced_graphics as graphics; pub use iced_graphics as graphics;
pub use iced_runtime as runtime; pub use iced_runtime as runtime;
pub use iced_runtime::core; pub use iced_runtime::core;
pub use iced_runtime::debug;
pub use iced_runtime::futures; pub use iced_runtime::futures;
pub use iced_style as style; pub use iced_style as style;
pub use winit; pub use winit;

View file

@ -11,6 +11,7 @@ use crate::core::renderer;
use crate::core::widget::operation; use crate::core::widget::operation;
use crate::core::window; use crate::core::window;
use crate::core::{Point, Size}; use crate::core::{Point, Size};
use crate::debug;
use crate::futures::futures::channel::mpsc; use crate::futures::futures::channel::mpsc;
use crate::futures::futures::{task, Future, StreamExt}; use crate::futures::futures::{task, Future, StreamExt};
use crate::futures::{Executor, Runtime, Subscription}; use crate::futures::{Executor, Runtime, Subscription};
@ -19,7 +20,6 @@ use crate::multi_window::window_manager::WindowManager;
use crate::runtime::command::{self, Command}; use crate::runtime::command::{self, Command};
use crate::runtime::multi_window::Program; use crate::runtime::multi_window::Program;
use crate::runtime::user_interface::{self, UserInterface}; use crate::runtime::user_interface::{self, UserInterface};
use crate::runtime::Debug;
use crate::style::application::StyleSheet; use crate::style::application::StyleSheet;
use crate::{Clipboard, Error, Proxy, Settings}; use crate::{Clipboard, Error, Proxy, Settings};
@ -112,8 +112,7 @@ where
{ {
use winit::event_loop::EventLoopBuilder; use winit::event_loop::EventLoopBuilder;
let mut debug = Debug::new(); let boot_timer = debug::boot_time();
debug.startup_started();
let event_loop = EventLoopBuilder::with_user_event() let event_loop = EventLoopBuilder::with_user_event()
.build() .build()
@ -202,12 +201,12 @@ where
compositor, compositor,
runtime, runtime,
proxy, proxy,
debug,
event_receiver, event_receiver,
control_sender, control_sender,
init_command, init_command,
window_manager, window_manager,
should_main_be_visible, should_main_be_visible,
boot_timer,
)); ));
let mut context = task::Context::from_waker(task::noop_waker_ref()); let mut context = task::Context::from_waker(task::noop_waker_ref());
@ -339,12 +338,12 @@ async fn run_instance<A, E, C>(
mut compositor: C, mut compositor: C,
mut runtime: Runtime<E, Proxy<A::Message>, A::Message>, mut runtime: Runtime<E, Proxy<A::Message>, A::Message>,
mut proxy: winit::event_loop::EventLoopProxy<A::Message>, mut proxy: winit::event_loop::EventLoopProxy<A::Message>,
mut debug: Debug,
mut event_receiver: mpsc::UnboundedReceiver<Event<A::Message>>, mut event_receiver: mpsc::UnboundedReceiver<Event<A::Message>>,
mut control_sender: mpsc::UnboundedSender<Control>, mut control_sender: mpsc::UnboundedSender<Control>,
init_command: Command<A::Message>, init_command: Command<A::Message>,
mut window_manager: WindowManager<A, C>, mut window_manager: WindowManager<A, C>,
should_main_window_be_visible: bool, should_main_window_be_visible: bool,
boot_timer: debug::Timer,
) where ) where
A: Application + 'static, A: Application + 'static,
E: Executor + 'static, E: Executor + 'static,
@ -377,15 +376,6 @@ async fn run_instance<A, E, C>(
}; };
let mut ui_caches = HashMap::new(); let mut ui_caches = HashMap::new();
let mut user_interfaces = ManuallyDrop::new(build_user_interfaces(
&application,
&mut debug,
&mut window_manager,
HashMap::from_iter([(
window::Id::MAIN,
user_interface::Cache::default(),
)]),
));
run_command( run_command(
&application, &application,
@ -395,17 +385,24 @@ async fn run_instance<A, E, C>(
&mut clipboard, &mut clipboard,
&mut control_sender, &mut control_sender,
&mut proxy, &mut proxy,
&mut debug,
&mut window_manager, &mut window_manager,
&mut ui_caches, &mut ui_caches,
); );
runtime.track(application.subscription().into_recipes()); runtime.track(application.subscription().into_recipes());
boot_timer.finish();
let mut user_interfaces = ManuallyDrop::new(build_user_interfaces(
&application,
&mut window_manager,
HashMap::from_iter([(
window::Id::MAIN,
user_interface::Cache::default(),
)]),
));
let mut messages = Vec::new(); let mut messages = Vec::new();
debug.startup_finished();
'main: while let Some(event) = event_receiver.next().await { 'main: while let Some(event) = event_receiver.next().await {
match event { match event {
Event::WindowCreated { Event::WindowCreated {
@ -430,7 +427,6 @@ async fn run_instance<A, E, C>(
user_interface::Cache::default(), user_interface::Cache::default(),
&mut window.renderer, &mut window.renderer,
logical_size, logical_size,
&mut debug,
id, id,
), ),
); );
@ -513,7 +509,7 @@ async fn run_instance<A, E, C>(
&mut messages, &mut messages,
); );
debug.draw_started(); let draw_timer = debug::draw_time();
let new_mouse_interaction = ui.draw( let new_mouse_interaction = ui.draw(
&mut window.renderer, &mut window.renderer,
window.state.theme(), window.state.theme(),
@ -522,7 +518,7 @@ async fn run_instance<A, E, C>(
}, },
cursor, cursor,
); );
debug.draw_finished(); draw_timer.finish();
if new_mouse_interaction != window.mouse_interaction { if new_mouse_interaction != window.mouse_interaction {
window.raw.set_cursor_icon( window.raw.set_cursor_icon(
@ -569,7 +565,7 @@ async fn run_instance<A, E, C>(
{ {
let logical_size = window.state.logical_size(); let logical_size = window.state.logical_size();
debug.layout_started(); let layout_time = debug::layout_time();
let ui = user_interfaces let ui = user_interfaces
.remove(&id) .remove(&id)
.expect("Remove user interface"); .expect("Remove user interface");
@ -578,9 +574,9 @@ async fn run_instance<A, E, C>(
id, id,
ui.relayout(logical_size, &mut window.renderer), ui.relayout(logical_size, &mut window.renderer),
); );
debug.layout_finished(); layout_time.finish();
debug.draw_started(); let draw_time = debug::draw_time();
let new_mouse_interaction = user_interfaces let new_mouse_interaction = user_interfaces
.get_mut(&id) .get_mut(&id)
.expect("Get user interface") .expect("Get user interface")
@ -592,7 +588,7 @@ async fn run_instance<A, E, C>(
}, },
window.state.cursor(), window.state.cursor(),
); );
debug.draw_finished(); draw_time.finish();
if new_mouse_interaction != window.mouse_interaction if new_mouse_interaction != window.mouse_interaction
{ {
@ -616,16 +612,15 @@ async fn run_instance<A, E, C>(
window.state.viewport_version(); window.state.viewport_version();
} }
debug.render_started(); let render_time = debug::render_time();
match compositor.present( match compositor.present(
&mut window.renderer, &mut window.renderer,
&mut window.surface, &mut window.surface,
window.state.viewport(), window.state.viewport(),
window.state.background_color(), window.state.background_color(),
&debug.overlay(),
) { ) {
Ok(()) => { Ok(()) => {
debug.render_finished(); render_time.finish();
// TODO: Handle animations! // TODO: Handle animations!
// Maybe we can use `ControlFlow::WaitUntil` for this. // Maybe we can use `ControlFlow::WaitUntil` for this.
@ -636,8 +631,6 @@ async fn run_instance<A, E, C>(
panic!("{:?}", error); panic!("{:?}", error);
} }
_ => { _ => {
debug.render_finished();
log::error!( log::error!(
"Error {error:?} when \ "Error {error:?} when \
presenting surface." presenting surface."
@ -681,11 +674,7 @@ async fn run_instance<A, E, C>(
break 'main; break 'main;
} }
} else { } else {
window.state.update( window.state.update(&window.raw, &window_event);
&window.raw,
&window_event,
&mut debug,
);
if let Some(event) = conversion::window_event( if let Some(event) = conversion::window_event(
id, id,
@ -702,7 +691,7 @@ async fn run_instance<A, E, C>(
continue; continue;
} }
debug.event_processing_started(); let interact_time = debug::interact_time();
let mut uis_stale = false; let mut uis_stale = false;
for (id, window) in window_manager.iter_mut() { for (id, window) in window_manager.iter_mut() {
@ -749,8 +738,7 @@ async fn run_instance<A, E, C>(
runtime.broadcast(event, status); runtime.broadcast(event, status);
} }
} }
interact_time.finish();
debug.event_processing_finished();
// TODO mw application update returns which window IDs to update // TODO mw application update returns which window IDs to update
if !messages.is_empty() || uis_stale { if !messages.is_empty() || uis_stale {
@ -770,7 +758,6 @@ async fn run_instance<A, E, C>(
&mut clipboard, &mut clipboard,
&mut control_sender, &mut control_sender,
&mut proxy, &mut proxy,
&mut debug,
&mut messages, &mut messages,
&mut window_manager, &mut window_manager,
&mut cached_interfaces, &mut cached_interfaces,
@ -794,7 +781,6 @@ async fn run_instance<A, E, C>(
user_interfaces = user_interfaces =
ManuallyDrop::new(build_user_interfaces( ManuallyDrop::new(build_user_interfaces(
&application, &application,
&mut debug,
&mut window_manager, &mut window_manager,
cached_interfaces, cached_interfaces,
)); ));
@ -815,19 +801,18 @@ fn build_user_interface<'a, A: Application>(
cache: user_interface::Cache, cache: user_interface::Cache,
renderer: &mut A::Renderer, renderer: &mut A::Renderer,
size: Size, size: Size,
debug: &mut Debug,
id: window::Id, id: window::Id,
) -> UserInterface<'a, A::Message, A::Theme, A::Renderer> ) -> UserInterface<'a, A::Message, A::Theme, A::Renderer>
where where
A::Theme: StyleSheet, A::Theme: StyleSheet,
{ {
debug.view_started(); let view_timer = debug::view_time();
let view = application.view(id); let view = application.view(id);
debug.view_finished(); view_timer.finish();
debug.layout_started(); let layout_timer = debug::layout_time();
let user_interface = UserInterface::build(view, size, cache, renderer); let user_interface = UserInterface::build(view, size, cache, renderer);
debug.layout_finished(); layout_timer.finish();
user_interface user_interface
} }
@ -841,7 +826,6 @@ fn update<A: Application, C, E: Executor>(
clipboard: &mut Clipboard, clipboard: &mut Clipboard,
control_sender: &mut mpsc::UnboundedSender<Control>, control_sender: &mut mpsc::UnboundedSender<Control>,
proxy: &mut winit::event_loop::EventLoopProxy<A::Message>, proxy: &mut winit::event_loop::EventLoopProxy<A::Message>,
debug: &mut Debug,
messages: &mut Vec<A::Message>, messages: &mut Vec<A::Message>,
window_manager: &mut WindowManager<A, C>, window_manager: &mut WindowManager<A, C>,
ui_caches: &mut HashMap<window::Id, user_interface::Cache>, ui_caches: &mut HashMap<window::Id, user_interface::Cache>,
@ -850,11 +834,11 @@ fn update<A: Application, C, E: Executor>(
A::Theme: StyleSheet, A::Theme: StyleSheet,
{ {
for message in messages.drain(..) { for message in messages.drain(..) {
debug.log_message(&message); debug::log_message(&message);
debug.update_started();
let update_timer = debug::update_time();
let command = runtime.enter(|| application.update(message)); let command = runtime.enter(|| application.update(message));
debug.update_finished(); update_timer.finish();
run_command( run_command(
application, application,
@ -864,7 +848,6 @@ fn update<A: Application, C, E: Executor>(
clipboard, clipboard,
control_sender, control_sender,
proxy, proxy,
debug,
window_manager, window_manager,
ui_caches, ui_caches,
); );
@ -883,7 +866,6 @@ fn run_command<A, C, E>(
clipboard: &mut Clipboard, clipboard: &mut Clipboard,
control_sender: &mut mpsc::UnboundedSender<Control>, control_sender: &mut mpsc::UnboundedSender<Control>,
proxy: &mut winit::event_loop::EventLoopProxy<A::Message>, proxy: &mut winit::event_loop::EventLoopProxy<A::Message>,
debug: &mut Debug,
window_manager: &mut WindowManager<A, C>, window_manager: &mut WindowManager<A, C>,
ui_caches: &mut HashMap<window::Id, user_interface::Cache>, ui_caches: &mut HashMap<window::Id, user_interface::Cache>,
) where ) where
@ -1118,7 +1100,6 @@ fn run_command<A, C, E>(
&mut window.surface, &mut window.surface,
window.state.viewport(), window.state.viewport(),
window.state.background_color(), window.state.background_color(),
&debug.overlay(),
); );
proxy proxy
@ -1155,7 +1136,6 @@ fn run_command<A, C, E>(
let mut uis = build_user_interfaces( let mut uis = build_user_interfaces(
application, application,
debug,
window_manager, window_manager,
std::mem::take(ui_caches), std::mem::take(ui_caches),
); );
@ -1211,7 +1191,6 @@ fn run_command<A, C, E>(
/// Build the user interface for every window. /// Build the user interface for every window.
pub fn build_user_interfaces<'a, A: Application, C: Compositor>( pub fn build_user_interfaces<'a, A: Application, C: Compositor>(
application: &'a A, application: &'a A,
debug: &mut Debug,
window_manager: &mut WindowManager<A, C>, window_manager: &mut WindowManager<A, C>,
mut cached_user_interfaces: HashMap<window::Id, user_interface::Cache>, mut cached_user_interfaces: HashMap<window::Id, user_interface::Cache>,
) -> HashMap<window::Id, UserInterface<'a, A::Message, A::Theme, A::Renderer>> ) -> HashMap<window::Id, UserInterface<'a, A::Message, A::Theme, A::Renderer>>
@ -1231,7 +1210,6 @@ where
cache, cache,
&mut window.renderer, &mut window.renderer,
window.state.logical_size(), window.state.logical_size(),
debug,
id, id,
), ),
)) ))

View file

@ -138,12 +138,7 @@ where
} }
/// Processes the provided window event and updates the [`State`] accordingly. /// Processes the provided window event and updates the [`State`] accordingly.
pub fn update( pub fn update(&mut self, window: &Window, event: &WindowEvent) {
&mut self,
window: &Window,
event: &WindowEvent,
_debug: &mut crate::runtime::Debug,
) {
match event { match event {
WindowEvent::Resized(new_size) => { WindowEvent::Resized(new_size) => {
let size = Size::new(new_size.width, new_size.height); let size = Size::new(new_size.width, new_size.height);