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
lazy = ["iced_widget/lazy"]
# 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
tokio = ["iced_futures/tokio"]
# Enables `async-std` as the `executor::Default` on native platforms
@ -58,6 +58,7 @@ fira-sans = ["iced_renderer/fira-sans"]
[dependencies]
iced_core.workspace = true
iced_debug.workspace = true
iced_futures.workspace = true
iced_renderer.workspace = true
iced_widget.workspace = true
@ -85,11 +86,13 @@ strip = "debuginfo"
[workspace]
members = [
"core",
"debug",
"futures",
"graphics",
"highlighter",
"renderer",
"runtime",
"sentinel",
"style",
"tiny_skia",
"wgpu",
@ -111,11 +114,13 @@ keywords = ["gui", "ui", "graphics", "interface", "widgets"]
[workspace.dependencies]
iced = { version = "0.13.0-dev", path = "." }
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_graphics = { version = "0.13.0-dev", path = "graphics" }
iced_highlighter = { version = "0.13.0-dev", path = "highlighter" }
iced_renderer = { version = "0.13.0-dev", path = "renderer" }
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_tiny_skia = { version = "0.13.0-dev", path = "tiny_skia" }
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"
resvg = "0.36"
rustc-hash = "1.0"
serde = "1.0"
serde_json = "1.0"
semver = "1.0"
smol = "1.0"
smol_str = "0.2"
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::futures;
use iced_winit::runtime::program;
use iced_winit::runtime::Debug;
use iced_winit::style::Theme;
use iced_winit::winit;
use iced_winit::Clipboard;
@ -155,19 +154,14 @@ pub fn main() -> Result<(), Box<dyn std::error::Error>> {
let controls = Controls::new();
// Initialize iced
let mut debug = Debug::new();
let mut renderer = Renderer::new(
Backend::new(&adapter, &device, &queue, Settings::default(), format),
Font::default(),
Pixels(16.0),
);
let mut state = program::State::new(
controls,
viewport.logical_size(),
&mut renderer,
&mut debug,
);
let mut state =
program::State::new(controls, viewport.logical_size(), &mut renderer);
// Run event loop
event_loop.run(move |event, window_target| {
@ -239,7 +233,6 @@ pub fn main() -> Result<(), Box<dyn std::error::Error>> {
&view,
primitive,
&viewport,
&debug.overlay(),
);
});
@ -315,7 +308,6 @@ pub fn main() -> Result<(), Box<dyn std::error::Error>> {
text_color: Color::WHITE,
},
&mut clipboard,
&mut debug,
);
// and request a redraw

View file

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

View file

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

View file

@ -11,11 +11,12 @@ categories.workspace = true
keywords.workspace = true
[features]
debug = []
multi-window = []
[dependencies]
iced_core.workspace = true
iced_debug.workspace = true
iced_futures.workspace = true
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")]
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_debug as debug;
pub use iced_futures as futures;
pub use command::Command;
pub use debug::Debug;
pub use font::Font;
pub use program::Program;
pub use user_interface::UserInterface;

View file

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

View file

@ -3,8 +3,9 @@ use crate::core::mouse;
use crate::core::renderer;
use crate::core::widget::operation::{self, Operation};
use crate::core::{Clipboard, Size};
use crate::debug;
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
/// processing, and rendering primitive storage.
@ -30,14 +31,12 @@ where
mut program: P,
bounds: Size,
renderer: &mut P::Renderer,
debug: &mut Debug,
) -> Self {
let user_interface = build_user_interface(
&mut program,
user_interface::Cache::default(),
renderer,
bounds,
debug,
);
let cache = Some(user_interface.into_cache());
@ -94,17 +93,15 @@ where
theme: &P::Theme,
style: &renderer::Style,
clipboard: &mut dyn Clipboard,
debug: &mut Debug,
) -> (Vec<Event>, Option<Command<P::Message>>) {
let mut user_interface = build_user_interface(
&mut self.program,
self.cache.take().unwrap(),
renderer,
bounds,
debug,
);
debug.event_processing_started();
let interact_timer = debug::interact_time();
let mut messages = Vec::new();
let (_, event_statuses) = user_interface.update(
@ -127,13 +124,13 @@ where
self.queued_events.clear();
messages.append(&mut self.queued_messages);
debug.event_processing_finished();
drop(interact_timer);
let command = if messages.is_empty() {
debug.draw_started();
let draw_timer = debug::draw_time();
self.mouse_interaction =
user_interface.draw(renderer, theme, style, cursor);
debug.draw_finished();
drop(draw_timer);
self.cache = Some(user_interface.into_cache());
@ -145,11 +142,11 @@ where
let commands =
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);
debug.update_finished();
drop(update_timer);
command
}));
@ -159,13 +156,12 @@ where
temp_cache,
renderer,
bounds,
debug,
);
debug.draw_started();
let draw_timer = debug::draw_time();
self.mouse_interaction =
user_interface.draw(renderer, theme, style, cursor);
debug.draw_finished();
drop(draw_timer);
self.cache = Some(user_interface.into_cache());
@ -181,14 +177,12 @@ where
renderer: &mut P::Renderer,
operations: impl Iterator<Item = Box<dyn Operation<P::Message>>>,
bounds: Size,
debug: &mut Debug,
) {
let mut user_interface = build_user_interface(
&mut self.program,
self.cache.take().unwrap(),
renderer,
bounds,
debug,
);
for operation in operations {
@ -218,15 +212,14 @@ fn build_user_interface<'a, P: Program>(
cache: user_interface::Cache,
renderer: &mut P::Renderer,
size: Size,
debug: &mut Debug,
) -> UserInterface<'a, P::Message, P::Theme, P::Renderer> {
debug.view_started();
let view_timer = debug::view_time();
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);
debug.layout_finished();
drop(layout_timer);
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,
pixels: &mut tiny_skia::PixmapMut<'_>,
clip_mask: &mut tiny_skia::Mask,
@ -39,38 +39,9 @@ impl Backend {
viewport: &Viewport,
damage: &[Rectangle],
background_color: Color,
overlay: &[T],
) {
let physical_size = viewport.physical_size();
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 {
let path = tiny_skia::PathBuilder::from_rect(
tiny_skia::Rect::from_xywh(
@ -109,25 +80,6 @@ impl Backend {
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();

View file

@ -95,43 +95,27 @@ impl crate::graphics::Compositor for Compositor {
}
}
fn present<T: AsRef<str>>(
fn present(
&mut self,
renderer: &mut Self::Renderer,
surface: &mut Self::Surface,
viewport: &Viewport,
background_color: Color,
overlay: &[T],
) -> Result<(), compositor::SurfaceError> {
renderer.with_primitives(|backend, primitives| {
present(
backend,
surface,
primitives,
viewport,
background_color,
overlay,
)
present(backend, surface, primitives, viewport, background_color)
})
}
fn screenshot<T: AsRef<str>>(
fn screenshot(
&mut self,
renderer: &mut Self::Renderer,
surface: &mut Self::Surface,
viewport: &Viewport,
background_color: Color,
overlay: &[T],
) -> Vec<u8> {
renderer.with_primitives(|backend, primitives| {
screenshot(
surface,
backend,
primitives,
viewport,
background_color,
overlay,
)
screenshot(surface, backend, primitives, viewport, background_color)
})
}
}
@ -147,13 +131,12 @@ pub fn new<W: compositor::Window>(
Compositor { context, settings }
}
pub fn present<T: AsRef<str>>(
pub fn present(
backend: &mut Backend,
surface: &mut Surface,
primitives: &[Primitive],
viewport: &Viewport,
background_color: Color,
overlay: &[T],
) -> Result<(), compositor::SurfaceError> {
let physical_size = viewport.physical_size();
let scale_factor = viewport.scale_factor() as f32;
@ -206,19 +189,17 @@ pub fn present<T: AsRef<str>>(
viewport,
&damage,
background_color,
overlay,
);
buffer.present().map_err(|_| compositor::SurfaceError::Lost)
}
pub fn screenshot<T: AsRef<str>>(
pub fn screenshot(
surface: &mut Surface,
backend: &mut Backend,
primitives: &[Primitive],
viewport: &Viewport,
background_color: Color,
overlay: &[T],
) -> Vec<u8> {
let size = viewport.physical_size();
@ -240,7 +221,6 @@ pub fn screenshot<T: AsRef<str>>(
size.height as f32,
))],
background_color,
overlay,
);
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.
/// This is useful for rendering debug information.
pub fn present<T: AsRef<str>>(
pub fn present(
&mut self,
device: &wgpu::Device,
queue: &wgpu::Queue,
@ -77,7 +77,6 @@ impl Backend {
frame: &wgpu::TextureView,
primitives: &[Primitive],
viewport: &Viewport,
overlay_text: &[T],
) {
log::debug!("Drawing");
#[cfg(feature = "tracing")]
@ -87,11 +86,7 @@ impl Backend {
let scale_factor = viewport.scale_factor() as f32;
let transformation = viewport.projection();
let mut layers = Layer::generate(primitives, viewport);
if !overlay_text.is_empty() {
layers.push(Layer::overlay(overlay_text, viewport));
}
let layers = Layer::generate(primitives, viewport);
self.prepare(
device,

View file

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

View file

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

View file

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

View file

@ -3,7 +3,6 @@ use crate::conversion;
use crate::core::mouse;
use crate::core::{Color, Size};
use crate::graphics::Viewport;
use crate::runtime::Debug;
use crate::Application;
use std::marker::PhantomData;
@ -122,12 +121,7 @@ where
/// Processes the provided window event and updates the [`State`]
/// accordingly.
pub fn update(
&mut self,
window: &Window,
event: &WindowEvent,
_debug: &mut Debug,
) {
pub fn update(&mut self, window: &Window, event: &WindowEvent) {
match event {
WindowEvent::Resized(new_size) => {
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_runtime as runtime;
pub use iced_runtime::core;
pub use iced_runtime::debug;
pub use iced_runtime::futures;
pub use iced_style as style;
pub use winit;

View file

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

View file

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