Introduce iced_sentinel and iced_debug crates
This commit is contained in:
parent
58a7007ac1
commit
dd36893f7a
26 changed files with 543 additions and 567 deletions
10
Cargo.toml
10
Cargo.toml
|
|
@ -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
23
debug/Cargo.toml
Normal 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
162
debug/src/lib.rs
Normal 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) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)]
|
||||||
|
|
|
||||||
|
|
@ -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"]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
26
sentinel/Cargo.toml
Normal 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
80
sentinel/src/client.rs
Normal 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
105
sentinel/src/lib.rs
Normal 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
25
sentinel/src/timing.rs
Normal 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),
|
||||||
|
}
|
||||||
|
|
@ -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 ®ion in damage {
|
for ®ion 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();
|
||||||
|
|
|
||||||
|
|
@ -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(
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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(
|
||||||
|
|
|
||||||
|
|
@ -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"]
|
||||||
|
|
|
||||||
|
|
@ -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() {
|
||||||
|
|
|
||||||
|
|
@ -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(),
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
),
|
),
|
||||||
))
|
))
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue