Merge pull request #3000 from iced-rs/feature/hot-reloading
Hot Reloading
This commit is contained in:
commit
c952ea8485
11 changed files with 297 additions and 45 deletions
85
Cargo.lock
generated
85
Cargo.lock
generated
|
|
@ -519,6 +519,26 @@ dependencies = [
|
|||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bincode"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "36eaf5d7b090263e8150820482d5d93cd964a81e4019913c972f4edcc6edb740"
|
||||
dependencies = [
|
||||
"bincode_derive",
|
||||
"serde",
|
||||
"unty",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bincode_derive"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bf95709a440f45e986983918d0e8a1f30a9b1df04918fc828670606804ac3c09"
|
||||
dependencies = [
|
||||
"virtue",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bit-set"
|
||||
version = "0.8.0"
|
||||
|
|
@ -702,6 +722,17 @@ dependencies = [
|
|||
"wayland-client",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cargo-hot-protocol"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/hecrj/cargo-hot.git?rev=b8dc518b8640928178a501257e353b73bc06cf47#b8dc518b8640928178a501257e353b73bc06cf47"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bincode 2.0.1",
|
||||
"log",
|
||||
"subsecond",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cast"
|
||||
version = "0.3.0"
|
||||
|
|
@ -2419,7 +2450,7 @@ dependencies = [
|
|||
name = "iced_beacon"
|
||||
version = "0.14.0-dev"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"bincode 1.3.3",
|
||||
"futures",
|
||||
"iced_core",
|
||||
"log",
|
||||
|
|
@ -2451,6 +2482,7 @@ dependencies = [
|
|||
name = "iced_debug"
|
||||
version = "0.14.0-dev"
|
||||
dependencies = [
|
||||
"cargo-hot-protocol",
|
||||
"iced_beacon",
|
||||
"iced_core",
|
||||
"iced_futures",
|
||||
|
|
@ -3244,6 +3276,15 @@ version = "2.7.4"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
||||
|
||||
[[package]]
|
||||
name = "memfd"
|
||||
version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b2cffa4ad52c6f791f4f8b15f0c05f9824b2ced1160e88cc393d64fff9a8ac64"
|
||||
dependencies = [
|
||||
"rustix 0.38.44",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memmap2"
|
||||
version = "0.9.5"
|
||||
|
|
@ -5406,6 +5447,34 @@ dependencies = [
|
|||
"rayon",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "subsecond"
|
||||
version = "0.7.0-alpha.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43c5b40acd555d02d9a0b5bf4080dbf2cd085d5e2eb2ae7851cb14b9bf5af15c"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"libc",
|
||||
"libloading",
|
||||
"memfd",
|
||||
"memmap2",
|
||||
"serde",
|
||||
"subsecond-types",
|
||||
"thiserror 2.0.12",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "subsecond-types"
|
||||
version = "0.7.0-alpha.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bedadae58a56e137ac970c38c44bff38cee24400fef64c37d5a188a065b1ec1f"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "subtle"
|
||||
version = "2.6.1"
|
||||
|
|
@ -5483,7 +5552,7 @@ version = "5.2.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "874dcfa363995604333cf947ae9f751ca3af4522c60886774c4963943b4746b1"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"bincode 1.3.3",
|
||||
"bitflags 1.3.2",
|
||||
"flate2",
|
||||
"fnv",
|
||||
|
|
@ -6169,6 +6238,12 @@ version = "0.9.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
|
||||
|
||||
[[package]]
|
||||
name = "unty"
|
||||
version = "0.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6d49784317cd0d1ee7ec5c716dd598ec5b4483ea832a2dced265471cc0f690ae"
|
||||
|
||||
[[package]]
|
||||
name = "url"
|
||||
version = "2.5.4"
|
||||
|
|
@ -6288,6 +6363,12 @@ version = "0.9.5"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||
|
||||
[[package]]
|
||||
name = "virtue"
|
||||
version = "0.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "051eb1abcf10076295e815102942cc58f9d5e3b4560e46e53c21e8ff6f3af7b1"
|
||||
|
||||
[[package]]
|
||||
name = "visible_bounds"
|
||||
version = "0.1.0"
|
||||
|
|
|
|||
|
|
@ -41,10 +41,12 @@ qr_code = ["iced_widget/qr_code"]
|
|||
markdown = ["iced_widget/markdown"]
|
||||
# Enables lazy widgets
|
||||
lazy = ["iced_widget/lazy"]
|
||||
# Enables a debug view in native platforms (press F12)
|
||||
# Enables debug metrics in native platforms (press F12)
|
||||
debug = ["iced_winit/debug", "iced_devtools"]
|
||||
# Enables time-travel debugging (very experimental!)
|
||||
time-travel = ["debug", "iced_devtools/time-travel"]
|
||||
# Enables hot reloading (very experimental!)
|
||||
hot = ["debug", "iced_debug/hot"]
|
||||
# Enables the `thread-pool` futures executor as the `executor::Default` on native platforms
|
||||
thread-pool = ["iced_futures/thread-pool"]
|
||||
# Enables `tokio` as the `executor::Default` on native platforms
|
||||
|
|
@ -167,6 +169,7 @@ bincode = "1.3"
|
|||
bitflags = "2.0"
|
||||
bytemuck = { version = "1.0", features = ["derive"] }
|
||||
bytes = "1.6"
|
||||
cargo-hot = { package = "cargo-hot-protocol", git = "https://github.com/hecrj/cargo-hot.git", rev = "b8dc518b8640928178a501257e353b73bc06cf47" }
|
||||
cosmic-text = "0.14"
|
||||
dark-light = "2.0"
|
||||
futures = { version = "0.3", default-features = false }
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ keywords.workspace = true
|
|||
|
||||
[features]
|
||||
enable = ["dep:iced_beacon"]
|
||||
hot = ["enable", "dep:cargo-hot"]
|
||||
|
||||
[dependencies]
|
||||
iced_core.workspace = true
|
||||
|
|
@ -21,3 +22,6 @@ log.workspace = true
|
|||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||
iced_beacon.workspace = true
|
||||
iced_beacon.optional = true
|
||||
|
||||
cargo-hot.workspace = true
|
||||
cargo-hot.optional = true
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ pub fn disable() {
|
|||
|
||||
pub fn init(metadata: Metadata) {
|
||||
internal::init(metadata);
|
||||
hot::init();
|
||||
}
|
||||
|
||||
pub fn quit() -> bool {
|
||||
|
|
@ -113,6 +114,18 @@ pub fn commands() -> Subscription<Command> {
|
|||
internal::commands()
|
||||
}
|
||||
|
||||
pub fn hot<O>(f: impl FnOnce() -> O) -> O {
|
||||
hot::call(f)
|
||||
}
|
||||
|
||||
pub fn on_hotpatch(f: impl Fn() + Send + Sync + 'static) {
|
||||
hot::on_hotpatch(f)
|
||||
}
|
||||
|
||||
pub fn is_stale() -> bool {
|
||||
hot::is_stale()
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "enable", not(target_arch = "wasm32")))]
|
||||
mod internal {
|
||||
use crate::core::theme;
|
||||
|
|
@ -399,3 +412,83 @@ mod internal {
|
|||
pub fn finish(self) {}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "hot")]
|
||||
mod hot {
|
||||
use std::collections::BTreeSet;
|
||||
use std::sync::atomic::{self, AtomicBool};
|
||||
use std::sync::{Arc, Mutex, OnceLock};
|
||||
|
||||
static IS_STALE: AtomicBool = AtomicBool::new(false);
|
||||
|
||||
static HOT_FUNCTIONS_PENDING: Mutex<BTreeSet<u64>> =
|
||||
Mutex::new(BTreeSet::new());
|
||||
|
||||
static HOT_FUNCTIONS: OnceLock<BTreeSet<u64>> = OnceLock::new();
|
||||
|
||||
pub fn init() {
|
||||
cargo_hot::connect();
|
||||
|
||||
cargo_hot::subsecond::register_handler(Arc::new(|| {
|
||||
if HOT_FUNCTIONS.get().is_none() {
|
||||
HOT_FUNCTIONS
|
||||
.set(std::mem::take(
|
||||
&mut HOT_FUNCTIONS_PENDING
|
||||
.lock()
|
||||
.expect("Lock hot functions"),
|
||||
))
|
||||
.expect("Set hot functions");
|
||||
}
|
||||
|
||||
IS_STALE.store(false, atomic::Ordering::Relaxed);
|
||||
}));
|
||||
}
|
||||
|
||||
pub fn call<O>(f: impl FnOnce() -> O) -> O {
|
||||
let mut f = Some(f);
|
||||
|
||||
// The `move` here is important. Hotpatching will not work
|
||||
// otherwise.
|
||||
let mut f = cargo_hot::subsecond::HotFn::current(move || {
|
||||
f.take().expect("Hot function is stale")()
|
||||
});
|
||||
|
||||
let address = f.ptr_address().0;
|
||||
|
||||
if let Some(hot_functions) = HOT_FUNCTIONS.get() {
|
||||
if hot_functions.contains(&address) {
|
||||
IS_STALE.store(true, atomic::Ordering::Relaxed);
|
||||
}
|
||||
} else {
|
||||
let _ = HOT_FUNCTIONS_PENDING
|
||||
.lock()
|
||||
.expect("Lock hot functions")
|
||||
.insert(address);
|
||||
}
|
||||
|
||||
f.call(())
|
||||
}
|
||||
|
||||
pub fn on_hotpatch(f: impl Fn() + Send + Sync + 'static) {
|
||||
cargo_hot::subsecond::register_handler(Arc::new(f));
|
||||
}
|
||||
|
||||
pub fn is_stale() -> bool {
|
||||
IS_STALE.load(atomic::Ordering::Relaxed)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "hot"))]
|
||||
mod hot {
|
||||
pub fn init() {}
|
||||
|
||||
pub fn call<O>(f: impl FnOnce() -> O) -> O {
|
||||
f()
|
||||
}
|
||||
|
||||
pub fn on_hotpatch(_f: impl Fn() + Send + Sync + 'static) {}
|
||||
|
||||
pub fn is_stale() -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -343,21 +343,30 @@ where
|
|||
themer(derive_theme(), Element::from(mode).map(Event::Message))
|
||||
});
|
||||
|
||||
let notification = self.show_notification.then(|| {
|
||||
themer(
|
||||
derive_theme(),
|
||||
bottom_right(opaque(
|
||||
container(text("Press F12 to open debug metrics"))
|
||||
.padding(10)
|
||||
.style(container::dark),
|
||||
)),
|
||||
)
|
||||
});
|
||||
let notification = self
|
||||
.show_notification
|
||||
.then(|| text("Press F12 to open debug metrics"))
|
||||
.or_else(|| {
|
||||
debug::is_stale().then(|| {
|
||||
text(
|
||||
"Types have changed. Restart to re-enable hotpatching.",
|
||||
)
|
||||
})
|
||||
});
|
||||
|
||||
stack![view]
|
||||
.height(Fill)
|
||||
.push_maybe(mode.map(opaque))
|
||||
.push_maybe(notification)
|
||||
.push_maybe(notification.map(|notification| {
|
||||
themer(
|
||||
derive_theme(),
|
||||
bottom_right(opaque(
|
||||
container(notification)
|
||||
.padding(10)
|
||||
.style(container::dark),
|
||||
)),
|
||||
)
|
||||
}))
|
||||
.into()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -56,6 +56,9 @@ pub enum Action<T> {
|
|||
/// Run a system action.
|
||||
System(system::Action),
|
||||
|
||||
/// Recreate all user interfaces and redraw all windows.
|
||||
Reload,
|
||||
|
||||
/// Exits the runtime.
|
||||
///
|
||||
/// This will normally close any application windows and
|
||||
|
|
@ -79,6 +82,7 @@ impl<T> Action<T> {
|
|||
Action::Clipboard(action) => Err(Action::Clipboard(action)),
|
||||
Action::Window(action) => Err(Action::Window(action)),
|
||||
Action::System(action) => Err(Action::System(action)),
|
||||
Action::Reload => Err(Action::Reload),
|
||||
Action::Exit => Err(Action::Exit),
|
||||
}
|
||||
}
|
||||
|
|
@ -102,6 +106,7 @@ where
|
|||
}
|
||||
Action::Window(_) => write!(f, "Action::Window"),
|
||||
Action::System(action) => write!(f, "Action::System({action:?})"),
|
||||
Action::Reload => write!(f, "Action::Reload"),
|
||||
Action::Exit => write!(f, "Action::Exit"),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,6 +38,8 @@ use crate::{
|
|||
Element, Executor, Font, Result, Settings, Size, Subscription, Task,
|
||||
};
|
||||
|
||||
use iced_debug as debug;
|
||||
|
||||
use std::borrow::Cow;
|
||||
|
||||
pub mod timed;
|
||||
|
|
@ -126,7 +128,7 @@ where
|
|||
state: &mut Self::State,
|
||||
message: Self::Message,
|
||||
) -> Task<Self::Message> {
|
||||
self.update.update(state, message)
|
||||
debug::hot(|| self.update.update(state, message))
|
||||
}
|
||||
|
||||
fn view<'a>(
|
||||
|
|
@ -134,7 +136,7 @@ where
|
|||
state: &'a Self::State,
|
||||
_window: window::Id,
|
||||
) -> Element<'a, Self::Message, Self::Theme, Self::Renderer> {
|
||||
self.view.view(state)
|
||||
debug::hot(|| self.view.view(state))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -327,7 +329,7 @@ impl<P: Program> Application<P> {
|
|||
> {
|
||||
Application {
|
||||
raw: program::with_title(self.raw, move |state, _window| {
|
||||
title.title(state)
|
||||
debug::hot(|| title.title(state))
|
||||
}),
|
||||
settings: self.settings,
|
||||
window: self.window,
|
||||
|
|
@ -342,7 +344,9 @@ impl<P: Program> Application<P> {
|
|||
impl Program<State = P::State, Message = P::Message, Theme = P::Theme>,
|
||||
> {
|
||||
Application {
|
||||
raw: program::with_subscription(self.raw, f),
|
||||
raw: program::with_subscription(self.raw, move |state| {
|
||||
debug::hot(|| f(state))
|
||||
}),
|
||||
settings: self.settings,
|
||||
window: self.window,
|
||||
}
|
||||
|
|
@ -356,7 +360,9 @@ impl<P: Program> Application<P> {
|
|||
impl Program<State = P::State, Message = P::Message, Theme = P::Theme>,
|
||||
> {
|
||||
Application {
|
||||
raw: program::with_theme(self.raw, move |state, _window| f(state)),
|
||||
raw: program::with_theme(self.raw, move |state, _window| {
|
||||
debug::hot(|| f(state))
|
||||
}),
|
||||
settings: self.settings,
|
||||
window: self.window,
|
||||
}
|
||||
|
|
@ -370,7 +376,9 @@ impl<P: Program> Application<P> {
|
|||
impl Program<State = P::State, Message = P::Message, Theme = P::Theme>,
|
||||
> {
|
||||
Application {
|
||||
raw: program::with_style(self.raw, f),
|
||||
raw: program::with_style(self.raw, move |state, theme| {
|
||||
debug::hot(|| f(state, theme))
|
||||
}),
|
||||
settings: self.settings,
|
||||
window: self.window,
|
||||
}
|
||||
|
|
@ -385,7 +393,7 @@ impl<P: Program> Application<P> {
|
|||
> {
|
||||
Application {
|
||||
raw: program::with_scale_factor(self.raw, move |state, _window| {
|
||||
f(state)
|
||||
debug::hot(|| f(state))
|
||||
}),
|
||||
settings: self.settings,
|
||||
window: self.window,
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@ use crate::time::Instant;
|
|||
use crate::window;
|
||||
use crate::{Element, Program, Settings, Subscription, Task};
|
||||
|
||||
use iced_debug as debug;
|
||||
|
||||
/// Creates an [`Application`] with an `update` function that also
|
||||
/// takes the [`Instant`] of each `Message`.
|
||||
///
|
||||
|
|
@ -97,10 +99,12 @@ where
|
|||
state: &mut Self::State,
|
||||
(message, now): Self::Message,
|
||||
) -> Task<Self::Message> {
|
||||
self.update
|
||||
.update(state, message, now)
|
||||
.into()
|
||||
.map(|message| (message, Instant::now()))
|
||||
debug::hot(move || {
|
||||
self.update
|
||||
.update(state, message, now)
|
||||
.into()
|
||||
.map(|message| (message, Instant::now()))
|
||||
})
|
||||
}
|
||||
|
||||
fn view<'a>(
|
||||
|
|
@ -108,16 +112,21 @@ where
|
|||
state: &'a Self::State,
|
||||
_window: window::Id,
|
||||
) -> Element<'a, Self::Message, Self::Theme, Self::Renderer> {
|
||||
self.view
|
||||
.view(state)
|
||||
.map(|message| (message, Instant::now()))
|
||||
debug::hot(|| {
|
||||
self.view
|
||||
.view(state)
|
||||
.map(|message| (message, Instant::now()))
|
||||
})
|
||||
}
|
||||
|
||||
fn subscription(
|
||||
&self,
|
||||
state: &Self::State,
|
||||
) -> self::Subscription<Self::Message> {
|
||||
(self.subscription)(state).map(|message| (message, Instant::now()))
|
||||
debug::hot(|| {
|
||||
(self.subscription)(state)
|
||||
.map(|message| (message, Instant::now()))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@ use crate::theme;
|
|||
use crate::window;
|
||||
use crate::{Element, Executor, Font, Result, Settings, Subscription, Task};
|
||||
|
||||
use iced_debug as debug;
|
||||
|
||||
use std::borrow::Cow;
|
||||
|
||||
/// Creates an iced [`Daemon`] given its boot, update, and view logic.
|
||||
|
|
@ -72,7 +74,7 @@ where
|
|||
state: &mut Self::State,
|
||||
message: Self::Message,
|
||||
) -> Task<Self::Message> {
|
||||
self.update.update(state, message)
|
||||
debug::hot(|| self.update.update(state, message))
|
||||
}
|
||||
|
||||
fn view<'a>(
|
||||
|
|
@ -80,7 +82,7 @@ where
|
|||
state: &'a Self::State,
|
||||
window: window::Id,
|
||||
) -> Element<'a, Self::Message, Self::Theme, Self::Renderer> {
|
||||
self.view.view(state, window)
|
||||
debug::hot(|| self.view.view(state, window))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -176,7 +178,7 @@ impl<P: Program> Daemon<P> {
|
|||
> {
|
||||
Daemon {
|
||||
raw: program::with_title(self.raw, move |state, window| {
|
||||
title.title(state, window)
|
||||
debug::hot(|| title.title(state, window))
|
||||
}),
|
||||
settings: self.settings,
|
||||
}
|
||||
|
|
@ -190,7 +192,9 @@ impl<P: Program> Daemon<P> {
|
|||
impl Program<State = P::State, Message = P::Message, Theme = P::Theme>,
|
||||
> {
|
||||
Daemon {
|
||||
raw: program::with_subscription(self.raw, f),
|
||||
raw: program::with_subscription(self.raw, move |state| {
|
||||
debug::hot(|| f(state))
|
||||
}),
|
||||
settings: self.settings,
|
||||
}
|
||||
}
|
||||
|
|
@ -203,7 +207,9 @@ impl<P: Program> Daemon<P> {
|
|||
impl Program<State = P::State, Message = P::Message, Theme = P::Theme>,
|
||||
> {
|
||||
Daemon {
|
||||
raw: program::with_theme(self.raw, f),
|
||||
raw: program::with_theme(self.raw, move |state, window| {
|
||||
debug::hot(|| f(state, window))
|
||||
}),
|
||||
settings: self.settings,
|
||||
}
|
||||
}
|
||||
|
|
@ -216,7 +222,9 @@ impl<P: Program> Daemon<P> {
|
|||
impl Program<State = P::State, Message = P::Message, Theme = P::Theme>,
|
||||
> {
|
||||
Daemon {
|
||||
raw: program::with_style(self.raw, f),
|
||||
raw: program::with_style(self.raw, move |state, theme| {
|
||||
debug::hot(|| f(state, theme))
|
||||
}),
|
||||
settings: self.settings,
|
||||
}
|
||||
}
|
||||
|
|
@ -229,7 +237,9 @@ impl<P: Program> Daemon<P> {
|
|||
impl Program<State = P::State, Message = P::Message, Theme = P::Theme>,
|
||||
> {
|
||||
Daemon {
|
||||
raw: program::with_scale_factor(self.raw, f),
|
||||
raw: program::with_scale_factor(self.raw, move |state, window| {
|
||||
debug::hot(|| f(state, window))
|
||||
}),
|
||||
settings: self.settings,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -85,6 +85,15 @@ where
|
|||
|
||||
let (proxy, worker) = Proxy::new(event_loop.create_proxy());
|
||||
|
||||
#[cfg(feature = "debug")]
|
||||
{
|
||||
let proxy = proxy.clone();
|
||||
|
||||
debug::on_hotpatch(move || {
|
||||
proxy.send_action(Action::Reload);
|
||||
});
|
||||
}
|
||||
|
||||
let mut runtime = {
|
||||
let executor =
|
||||
P::Executor::new().map_err(Error::ExecutorCreationFailed)?;
|
||||
|
|
@ -527,7 +536,7 @@ async fn run_instance<P>(
|
|||
|
||||
let create_compositor = {
|
||||
let window = window.clone();
|
||||
let mut proxy = proxy.clone();
|
||||
let proxy = proxy.clone();
|
||||
let default_fonts = default_fonts.clone();
|
||||
|
||||
async move {
|
||||
|
|
@ -1075,9 +1084,9 @@ fn update<P: Program, E: Executor>(
|
|||
runtime.track(recipes);
|
||||
}
|
||||
|
||||
fn run_action<P, C>(
|
||||
fn run_action<'a, P, C>(
|
||||
action: Action<P::Message>,
|
||||
program: &program::Instance<P>,
|
||||
program: &'a program::Instance<P>,
|
||||
compositor: &mut Option<C>,
|
||||
events: &mut Vec<(window::Id, core::Event)>,
|
||||
messages: &mut Vec<P::Message>,
|
||||
|
|
@ -1085,7 +1094,7 @@ fn run_action<P, C>(
|
|||
control_sender: &mut mpsc::UnboundedSender<Control>,
|
||||
interfaces: &mut FxHashMap<
|
||||
window::Id,
|
||||
UserInterface<'_, P::Message, P::Theme, P::Renderer>,
|
||||
UserInterface<'a, P::Message, P::Theme, P::Renderer>,
|
||||
>,
|
||||
window_manager: &mut WindowManager<P, C>,
|
||||
ui_caches: &mut FxHashMap<window::Id, user_interface::Cache>,
|
||||
|
|
@ -1437,6 +1446,29 @@ fn run_action<P, C>(
|
|||
let _ = channel.send(Ok(()));
|
||||
}
|
||||
}
|
||||
Action::Reload => {
|
||||
for (id, window) in window_manager.iter_mut() {
|
||||
let Some(ui) = interfaces.remove(&id) else {
|
||||
continue;
|
||||
};
|
||||
|
||||
let cache = ui.into_cache();
|
||||
let size = window.size();
|
||||
|
||||
let _ = interfaces.insert(
|
||||
id,
|
||||
build_user_interface(
|
||||
program,
|
||||
cache,
|
||||
&mut window.renderer,
|
||||
size,
|
||||
id,
|
||||
),
|
||||
);
|
||||
|
||||
window.raw.request_redraw();
|
||||
}
|
||||
}
|
||||
Action::Exit => {
|
||||
control_sender
|
||||
.start_send(Control::Exit)
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ impl<T: 'static> Proxy<T> {
|
|||
///
|
||||
/// Note: This skips the backpressure mechanism with an unbounded
|
||||
/// channel. Use sparingly!
|
||||
pub fn send(&mut self, value: T)
|
||||
pub fn send(&self, value: T)
|
||||
where
|
||||
T: std::fmt::Debug,
|
||||
{
|
||||
|
|
@ -88,13 +88,11 @@ impl<T: 'static> Proxy<T> {
|
|||
///
|
||||
/// Note: This skips the backpressure mechanism with an unbounded
|
||||
/// channel. Use sparingly!
|
||||
pub fn send_action(&mut self, action: Action<T>)
|
||||
pub fn send_action(&self, action: Action<T>)
|
||||
where
|
||||
T: std::fmt::Debug,
|
||||
{
|
||||
self.raw
|
||||
.send_event(action)
|
||||
.expect("Send message to event loop");
|
||||
let _ = self.raw.send_event(action);
|
||||
}
|
||||
|
||||
/// Frees an amount of slots for additional messages to be queued in
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue