From e7e4d49fdb2df20ed6c3df9e68485a8f730c2cac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20=C5=A0olt=C3=A9s?= Date: Mon, 2 Nov 2026 14:56:45 +0100 Subject: [PATCH 1/2] FerroUI b75373981: subscription guards The submodule moves to FerroUI main at b75373981, where the event, timer, property-observation and other subscription APIs return a Subscription guard that removes its handler when dropped (#423 D4/D5). --- FerroUI | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FerroUI b/FerroUI index c4c4cf8..b753739 160000 --- a/FerroUI +++ b/FerroUI @@ -1 +1 @@ -Subproject commit c4c4cf872a3f57166ebb00b343ca4b6c41a55eef +Subproject commit b753739811c34eba24c86ec383232053e914e42e From 71e4b34a39ee8eb90627edb16c9d7d96b88d44c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20=C5=A0olt=C3=A9s?= Date: Mon, 2 Nov 2026 14:59:40 +0100 Subject: [PATCH 2/2] Subscription guards: keep the window closing handler, hold the timers The closing handler of the main window (it commits the edit in progress before the window closes) detaches its Subscription guard, which would otherwise remove the handler when it is dropped. The timers of the prototype runtime and the pending save, which the app stops itself, are held as Subscription guards. --- crates/ferrodesign-app/src/app.rs | 2 +- crates/ferrodesign-app/src/prototype.rs | 4 ++-- crates/ferrodesign-app/src/shell.rs | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/crates/ferrodesign-app/src/app.rs b/crates/ferrodesign-app/src/app.rs index 80b1f11..95690d9 100644 --- a/crates/ferrodesign-app/src/app.rs +++ b/crates/ferrodesign-app/src/app.rs @@ -51,7 +51,7 @@ impl ApplicationImpl for App { if let Some(shell) = weak.upgrade() { if !shell.command("commit-edit") { event.set_cancel(true); } } - }); + }).detach(); desktop.set_main_window(Some(window)); } SHELL.with(|slot| *slot.borrow_mut() = Some(shell)); diff --git a/crates/ferrodesign-app/src/prototype.rs b/crates/ferrodesign-app/src/prototype.rs index b6b2845..8b05892 100644 --- a/crates/ferrodesign-app/src/prototype.rs +++ b/crates/ferrodesign-app/src/prototype.rs @@ -8,7 +8,7 @@ use ferrodesign_core::{ PrototypeScene, PrototypeTimer, Transition, TransitionKind, Trigger, Viewport, MAX_DOCUMENT_DEPTH, }; use ferroui_base::animation::{Clock, IClock, PlayState, TimeSpan}; -use ferroui_base::reactive::{AnonymousObserver, IDisposable, IObservable}; +use ferroui_base::reactive::{AnonymousObserver, IDisposable, IObservable, Subscription}; use ferroui_base::threading::{DispatcherPriority, DispatcherTimer}; use ferroui_base::Ref; use std::{ @@ -53,7 +53,7 @@ struct AuthoredSnapshot { } struct ScheduledTimer { - subscription: Rc, + subscription: Subscription, } pub struct PrototypeRuntime { diff --git a/crates/ferrodesign-app/src/shell.rs b/crates/ferrodesign-app/src/shell.rs index f00847f..0e2d192 100644 --- a/crates/ferrodesign-app/src/shell.rs +++ b/crates/ferrodesign-app/src/shell.rs @@ -33,7 +33,7 @@ use ferroui_base::layout::{Orientation, VerticalAlignment}; use ferroui_base::media::{FontWeight, TextWrapping}; use ferroui_base::metadata::from_markup_value; use ferroui_base::utilities::{Uri, UriKind}; -use ferroui_base::reactive::IDisposable; +use ferroui_base::reactive::{IDisposable, Subscription}; use ferroui_base::threading::{DispatcherPriority, DispatcherTimer}; use std::time::{Duration, Instant}; use ferroui_base::{BoxedValue, ObjectType, Ref, Thickness, WeakRef}; @@ -72,7 +72,7 @@ pub struct EditorShell { prototype_targets: RefCell>, prototype: Rc, pending_save: Cell, - pending_save_timer: RefCell>>, + pending_save_timer: RefCell>, save_serializations: Cell, last_serialization_ms: Cell, scene_frames: Cell,