From 81fc8122210c86e56d41423b24535382af7f77d4 Mon Sep 17 00:00:00 2001 From: Keith Simmons Date: Thu, 10 Mar 2022 20:03:01 -0800 Subject: [PATCH] Add global events to MutableAppContext and raise global event when new workspace is created --- crates/gpui/src/app.rs | 93 +++++++++++++++++++++++++++---- crates/workspace/src/workspace.rs | 21 ++++--- 2 files changed, 95 insertions(+), 19 deletions(-) diff --git a/crates/gpui/src/app.rs b/crates/gpui/src/app.rs index e91963bfa6..d19ecce152 100644 --- a/crates/gpui/src/app.rs +++ b/crates/gpui/src/app.rs @@ -740,6 +740,7 @@ type ActionCallback = type GlobalActionCallback = dyn FnMut(&dyn AnyAction, &mut MutableAppContext); type SubscriptionCallback = Box bool>; +type GlobalSubscriptionCallback = Box; type ObservationCallback = Box bool>; type ReleaseObservationCallback = Box; @@ -757,6 +758,7 @@ pub struct MutableAppContext { next_subscription_id: usize, frame_count: usize, subscriptions: Arc>>>, + global_subscriptions: Arc>>>, observations: Arc>>>, release_observations: Arc>>>, presenters_and_platform_windows: @@ -804,6 +806,7 @@ impl MutableAppContext { next_subscription_id: 0, frame_count: 0, subscriptions: Default::default(), + global_subscriptions: Default::default(), observations: Default::default(), release_observations: Default::default(), presenters_and_platform_windows: HashMap::new(), @@ -1062,6 +1065,12 @@ impl MutableAppContext { self.foreground_platform.prompt_for_new_path(directory) } + pub fn emit_global(&mut self, payload: E) { + self.pending_effects.push_back(Effect::GlobalEvent { + payload: Box::new(payload), + }); + } + pub fn subscribe(&mut self, handle: &H, mut callback: F) -> Subscription where E: Entity, @@ -1075,6 +1084,31 @@ impl MutableAppContext { }) } + pub fn global_subscribe(&mut self, mut callback: F) -> Subscription + where + E: Any + Copy, + F: 'static + FnMut(&E, &mut Self), + { + let id = post_inc(&mut self.next_subscription_id); + let type_id = TypeId::of::(); + self.global_subscriptions + .lock() + .entry(type_id) + .or_default() + .insert( + id, + Box::new(move |payload, cx| { + let payload = payload.downcast_ref().expect("downcast is type safe"); + callback(payload, cx) + })); + Subscription::GlobalSubscription { + id, + type_id, + subscriptions: Some(Arc::downgrade(&self.global_subscriptions)) + } + } + + pub fn observe(&mut self, handle: &H, mut callback: F) -> Subscription where E: Entity, @@ -1573,6 +1607,7 @@ impl MutableAppContext { if let Some(effect) = self.pending_effects.pop_front() { match effect { Effect::Event { entity_id, payload } => self.emit_event(entity_id, payload), + Effect::GlobalEvent { payload } => self.emit_global_event(payload), Effect::ModelNotification { model_id } => { self.notify_model_observers(model_id) } @@ -1700,6 +1735,16 @@ impl MutableAppContext { } } + fn emit_global_event(&mut self, payload: Box) { + let type_id = (&*payload).type_id(); + let callbacks = self.global_subscriptions.lock().remove(&type_id); + if let Some(callbacks) = callbacks { + for (_, mut callback) in callbacks { + callback(payload.as_ref(), self) + } + } + } + fn notify_model_observers(&mut self, observed_id: usize) { let callbacks = self.observations.lock().remove(&observed_id); if let Some(callbacks) = callbacks { @@ -2071,6 +2116,9 @@ pub enum Effect { entity_id: usize, payload: Box, }, + GlobalEvent { + payload: Box, + }, ModelNotification { model_id: usize, }, @@ -2104,6 +2152,10 @@ impl Debug for Effect { .debug_struct("Effect::Event") .field("entity_id", entity_id) .finish(), + Effect::GlobalEvent { payload, .. } => f + .debug_struct("Effect::GlobalEvent") + .field("type_id", &(&*payload).type_id()) + .finish(), Effect::ModelNotification { model_id } => f .debug_struct("Effect::ModelNotification") .field("model_id", model_id) @@ -3762,6 +3814,11 @@ pub enum Subscription { entity_id: usize, subscriptions: Option>>>>, }, + GlobalSubscription { + id: usize, + type_id: TypeId, + subscriptions: Option>>>>, + }, Observation { id: usize, entity_id: usize, @@ -3781,6 +3838,9 @@ impl Subscription { Subscription::Subscription { subscriptions, .. } => { subscriptions.take(); } + Subscription::GlobalSubscription { subscriptions, .. } => { + subscriptions.take(); + } Subscription::Observation { observations, .. } => { observations.take(); } @@ -3794,6 +3854,28 @@ impl Subscription { impl Drop for Subscription { fn drop(&mut self) { match self { + Subscription::Subscription { + id, + entity_id, + subscriptions, + } => { + if let Some(subscriptions) = subscriptions.as_ref().and_then(Weak::upgrade) { + if let Some(subscriptions) = subscriptions.lock().get_mut(entity_id) { + subscriptions.remove(id); + } + } + } + Subscription::GlobalSubscription { + id, + type_id, + subscriptions, + } => { + if let Some(subscriptions) = subscriptions.as_ref().and_then(Weak::upgrade) { + if let Some(subscriptions) = subscriptions.lock().get_mut(type_id) { + subscriptions.remove(id); + } + } + } Subscription::Observation { id, entity_id, @@ -3816,17 +3898,6 @@ impl Drop for Subscription { } } } - Subscription::Subscription { - id, - entity_id, - subscriptions, - } => { - if let Some(subscriptions) = subscriptions.as_ref().and_then(Weak::upgrade) { - if let Some(subscriptions) = subscriptions.lock().get_mut(entity_id) { - subscriptions.remove(id); - } - } - } } } } diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index f06a244c05..5680ad4cdf 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -1511,6 +1511,8 @@ fn open(action: &Open, cx: &mut MutableAppContext) { .detach(); } +pub struct WorkspaceBuilt(WeakViewHandle); + pub fn open_paths( abs_paths: &[PathBuf], app_state: &Arc, @@ -1537,7 +1539,7 @@ pub fn open_paths( } let workspace = existing.unwrap_or_else(|| { - cx.add_window((app_state.build_window_options)(), |cx| { + let (_, workspace) = cx.add_window((app_state.build_window_options)(), |cx| { let project = Project::local( app_state.client.clone(), app_state.user_store.clone(), @@ -1546,8 +1548,9 @@ pub fn open_paths( cx, ); (app_state.build_workspace)(project, &app_state, cx) - }) - .1 + }); + cx.emit_global(WorkspaceBuilt(workspace.downgrade())); + workspace }); let task = workspace.update(cx, |workspace, cx| workspace.open_paths(abs_paths, cx)); @@ -1581,12 +1584,13 @@ pub fn join_project( &mut cx, ) .await?; - let (_, workspace) = cx.update(|cx| { - cx.add_window((app_state.build_window_options)(), |cx| { + Ok(cx.update(|cx| { + let (_, workspace) = cx.add_window((app_state.build_window_options)(), |cx| { (app_state.build_workspace)(project, &app_state, cx) - }) - }); - Ok(workspace) + }); + cx.emit_global(WorkspaceBuilt(workspace.downgrade())); + workspace + })) }) } @@ -1601,5 +1605,6 @@ fn open_new(app_state: &Arc, cx: &mut MutableAppContext) { ); (app_state.build_workspace)(project, &app_state, cx) }); + cx.emit_global(WorkspaceBuilt(workspace.downgrade())); cx.dispatch_action(window_id, vec![workspace.id()], &OpenNew(app_state.clone())); }