diff --git a/crates/auto_update/src/auto_update.rs b/crates/auto_update/src/auto_update.rs index 4193e8185c..8f1a76c974 100644 --- a/crates/auto_update/src/auto_update.rs +++ b/crates/auto_update/src/auto_update.rs @@ -180,6 +180,7 @@ pub struct AutoUpdater { pending_poll: Option>>, quit_subscription: Option, update_check_type: UpdateCheckType, + _wake_subscription: gpui::Subscription, dismissed_status: Option, } @@ -441,6 +442,16 @@ impl AutoUpdater { }) .detach(); + // A download or check that was in flight when the machine went to sleep + // is almost certainly riding a TCP connection that silently died during + // suspend, so it would otherwise appear to stall indefinitely. + let wake_subscription = cx.on_system_wake({ + let this = cx.entity().downgrade(); + move |cx| { + this.update(cx, |this, cx| this.restart_after_wake(cx)).ok(); + } + }); + Self { status: AutoUpdateStatus::Idle, current_version, @@ -448,10 +459,27 @@ impl AutoUpdater { pending_poll: None, quit_subscription, update_check_type: UpdateCheckType::Automatic, + _wake_subscription: wake_subscription, dismissed_status: None, } } + fn restart_after_wake(&mut self, cx: &mut Context) { + // Only network phases can be safely restarted. `Installing` is a local + // operation (mounting a dmg, rsync, etc.) that must not be interrupted. + if !matches!( + self.status, + AutoUpdateStatus::Checking | AutoUpdateStatus::Downloading { .. } + ) { + return; + } + + let check_type = self.update_check_type; + self.pending_poll.take(); + self.status = AutoUpdateStatus::Idle; + self.poll(check_type, cx); + } + pub fn start_polling(&self, cx: &mut Context) -> Task> { let poll_interval = ReleaseChannel::try_global(cx).map_or(POLL_INTERVAL, |channel| match channel { diff --git a/crates/gpui/src/app.rs b/crates/gpui/src/app.rs index 5e09d6905a..72833abe52 100644 --- a/crates/gpui/src/app.rs +++ b/crates/gpui/src/app.rs @@ -282,23 +282,6 @@ impl Application { self } - /// Invokes a handler when the system wakes from sleep. - pub fn on_system_wake(&self, mut callback: F) -> &Self - where - F: 'static + FnMut(&mut App), - { - let this = Rc::downgrade(&self.0); - self.0 - .borrow_mut() - .platform - .on_system_wake(Box::new(move || { - if let Some(app) = this.upgrade() { - callback(&mut app.borrow_mut()); - } - })); - self - } - /// Returns a handle to the [`BackgroundExecutor`] associated with this app, which can be used to spawn futures in the background. pub fn background_executor(&self) -> BackgroundExecutor { self.0.borrow().background_executor.clone() @@ -717,6 +700,7 @@ pub struct App { pub(crate) keystroke_interceptors: SubscriberSet<(), KeystrokeObserver>, pub(crate) keyboard_layout_observers: SubscriberSet<(), Handler>, pub(crate) thermal_state_observers: SubscriberSet<(), Handler>, + pub(crate) system_wake_observers: SubscriberSet<(), Handler>, pub(crate) release_listeners: SubscriberSet, pub(crate) global_observers: SubscriberSet, pub(crate) quit_observers: SubscriberSet<(), QuitHandler>, @@ -845,6 +829,7 @@ impl App { keystroke_interceptors: SubscriberSet::new(), keyboard_layout_observers: SubscriberSet::new(), thermal_state_observers: SubscriberSet::new(), + system_wake_observers: SubscriberSet::new(), global_observers: SubscriberSet::new(), quit_observers: SubscriberSet::new(), restart_observers: SubscriberSet::new(), @@ -903,6 +888,18 @@ impl App { } })); + platform.on_system_wake(Box::new({ + let app = Rc::downgrade(&app); + move || { + if let Some(app) = app.upgrade() { + let cx = &mut app.borrow_mut(); + cx.system_wake_observers + .clone() + .retain(&(), move |callback| (callback)(cx)); + } + } + })); + platform.on_quit(Box::new({ let cx = Rc::downgrade(&app); move || { @@ -1339,6 +1336,22 @@ impl App { subscription } + /// Invokes a handler when the system wakes from sleep. + pub fn on_system_wake(&self, mut callback: F) -> Subscription + where + F: 'static + FnMut(&mut App), + { + let (subscription, activate) = self.system_wake_observers.insert( + (), + Box::new(move |cx| { + callback(cx); + true + }), + ); + activate(); + subscription + } + /// Returns the appearance of the application's windows. pub fn window_appearance(&self) -> WindowAppearance { self.platform.window_appearance()