diff --git a/crates/gpui/src/app.rs b/crates/gpui/src/app.rs index a9467c9996..480a9a1bdf 100644 --- a/crates/gpui/src/app.rs +++ b/crates/gpui/src/app.rs @@ -959,6 +959,7 @@ type GlobalObservationCallback = Box; type ReleaseObservationCallback = Box; type ActionObservationCallback = Box; type WindowActivationCallback = Box bool>; +type WindowFullscreenCallback = Box bool>; type DeserializeActionCallback = fn(json: &str) -> anyhow::Result>; type WindowShouldCloseSubscriptionCallback = Box bool>; @@ -1069,7 +1070,8 @@ pub struct MutableAppContext { subscriptions: SubscriptionMappings, observations: SubscriptionMappings, window_activation_observations: SubscriptionMappings, - + window_fullscreen_observations: SubscriptionMappings, + release_observations: Arc>>>, action_dispatch_observations: Arc>>, @@ -1126,6 +1128,7 @@ impl MutableAppContext { release_observations: Default::default(), global_observations: Default::default(), window_activation_observations: Default::default(), + window_fullscreen_observations: Default::default(), action_dispatch_observations: Default::default(), presenters_and_platform_windows: HashMap::new(), foreground, @@ -1662,6 +1665,26 @@ impl MutableAppContext { } } + fn observe_fullscreen(&mut self, window_id: usize, callback: F) -> Subscription + where + F: 'static + FnMut(bool, &mut MutableAppContext) -> bool, + { + let subscription_id = post_inc(&mut self.next_subscription_id); + self.pending_effects + .push_back(Effect::WindowFullscreenObservation { + window_id, + subscription_id, + callback: Box::new(callback), + }); + Subscription::WindowFullscreenObservation { + id: subscription_id, + window_id, + observations: Some(Arc::downgrade( + &self.window_activation_observations.internal, + )), + } + } + pub fn defer(&mut self, callback: impl 'static + FnOnce(&mut MutableAppContext)) { self.pending_effects.push_back(Effect::Deferred { callback: Box::new(callback), @@ -2361,6 +2384,16 @@ impl MutableAppContext { is_active, } => self.handle_window_activation_effect(window_id, is_active), + Effect::WindowFullscreenObservation { + window_id, + subscription_id, + callback, + } => self.window_fullscreen_observations.add_or_remove_callback( + window_id, + subscription_id, + callback, + ), + Effect::FullscreenWindow { window_id, is_fullscreen, @@ -2535,6 +2568,11 @@ impl MutableAppContext { let window = this.cx.windows.get_mut(&window_id)?; window.is_fullscreen = is_fullscreen; + let mut observations = this.window_fullscreen_observations.clone_ref(); + observations.emit_and_cleanup(window_id, this, |callback, this| { + callback(is_fullscreen, this) + }); + Some(()) }); } @@ -3019,6 +3057,11 @@ pub enum Effect { subscription_id: usize, callback: WindowActivationCallback, }, + WindowFullscreenObservation { + window_id: usize, + subscription_id: usize, + callback: WindowFullscreenCallback, + }, RefreshWindows, ActionDispatchNotification { action_id: TypeId, @@ -3136,6 +3179,15 @@ impl Debug for Effect { .field("window_id", window_id) .field("is_fullscreen", is_fullscreen) .finish(), + Effect::WindowFullscreenObservation { + window_id, + subscription_id, + callback: _, + } => f + .debug_struct("Effect::WindowFullscreenObservation") + .field("window_id", window_id) + .field("subscription_id", subscription_id) + .finish(), Effect::RefreshWindows => f.debug_struct("Effect::FullViewRefresh").finish(), Effect::WindowShouldCloseSubscription { window_id, .. } => f .debug_struct("Effect::WindowShouldCloseSubscription") @@ -3807,6 +3859,24 @@ impl<'a, T: View> ViewContext<'a, T> { }) } + pub fn observe_fullscreen(&mut self, mut callback: F) -> Subscription + where + F: 'static + FnMut(&mut T, bool, &mut ViewContext), + { + let observer = self.weak_handle(); + self.app + .observe_fullscreen(self.window_id(), move |active, cx| { + if let Some(observer) = observer.upgrade(cx) { + observer.update(cx, |observer, cx| { + callback(observer, active, cx); + }); + true + } else { + false + } + }) + } + pub fn emit(&mut self, payload: T::Event) { self.app.pending_effects.push_back(Effect::Event { entity_id: self.view_id, @@ -5128,6 +5198,12 @@ pub enum Subscription { observations: Option>>>>>, }, + WindowFullscreenObservation { + id: usize, + window_id: usize, + observations: + Option>>>>>, + }, } impl Subscription { @@ -5157,6 +5233,9 @@ impl Subscription { Subscription::WindowActivationObservation { observations, .. } => { observations.take(); } + Subscription::WindowFullscreenObservation { observations, .. } => { + observations.take(); + } } } } @@ -5291,6 +5370,27 @@ impl Drop for Subscription { } } } + Subscription::WindowFullscreenObservation { + id, + window_id, + observations, + } => { + if let Some(observations) = observations.as_ref().and_then(Weak::upgrade) { + match observations + .lock() + .entry(*window_id) + .or_default() + .entry(*id) + { + btree_map::Entry::Vacant(entry) => { + entry.insert(None); + } + btree_map::Entry::Occupied(entry) => { + entry.remove(); + } + } + } + } } } } diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index 045e9c6f90..302ebd65ee 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -823,6 +823,8 @@ enum FollowerItem { impl Workspace { pub fn new(project: ModelHandle, cx: &mut ViewContext) -> Self { + cx.observe_fullscreen(|_, _, cx| cx.notify()).detach(); + cx.observe_window_activation(Self::on_window_activation_changed) .detach(); cx.observe(&project, |_, _, cx| cx.notify()).detach();