From e0e37dba051c6ecf4039c56d79a2be4642a0d7fa 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:51:42 +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 a4c656cec07faa7eb60d387a4e7700c9970c2533 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:24 +0100 Subject: [PATCH 2/2] Keep the subscriptions that live as long as their source The timers and the event handlers of the app that are meant to last as long as their source detach their Subscription guard, which would otherwise remove the handler when it is dropped; the timers the game stops itself are held as guards. --- Solitaire/src/app.rs | 2 +- Solitaire/src/views/casino_view.rs | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Solitaire/src/app.rs b/Solitaire/src/app.rs index 0edcb0b..b77acbc 100644 --- a/Solitaire/src/app.rs +++ b/Solitaire/src/app.rs @@ -90,7 +90,7 @@ pub fn create_main_window() -> Ref { move || window.close(), std::time::Duration::from_millis(ms), ferroui::base::threading::DispatcherPriority::NORMAL, - ); + ).detach(); } window } diff --git a/Solitaire/src/views/casino_view.rs b/Solitaire/src/views/casino_view.rs index 71499e1..587cf6e 100644 --- a/Solitaire/src/views/casino_view.rs +++ b/Solitaire/src/views/casino_view.rs @@ -13,7 +13,7 @@ use ferroui::{ controls::ResourceDictionary, input::{InputElement, Key, KeyModifiers}, media::{DrawingImage, IImage}, - reactive::IDisposable, + reactive::Subscription, threading::{DispatcherPriority, DispatcherTimer}, }, controls::{ @@ -47,9 +47,9 @@ pub struct CasinoView { pub page: RefCell>>, artwork: Ref, dialog: Cell, - timer: RefCell>>, + timer: RefCell>, presentation: RefCell>>, - presentation_timer: RefCell>>, + presentation_timer: RefCell>, presentation_generation: Cell, } impl CasinoView { @@ -109,7 +109,7 @@ impl CasinoView { if let Some(timer) = this.timer.borrow_mut().take() { timer.dispose(); } - }); + }).detach(); let weak_window = window.downgrade(); self.start_clock(Rc::downgrade(self), move || { weak_window.upgrade().map(|window| window.is_active()) @@ -380,7 +380,7 @@ impl CasinoView { }, Duration::from_millis(16), DispatcherPriority::NORMAL, - ); + ).detach(); *self.page.borrow_mut() = Some(view); self.update_score(); self.refresh_message();