diff --git a/crates/gpui/src/app.rs b/crates/gpui/src/app.rs index dbdd9d7bb8cd19cfff04bc6d24448cb968acab4b..85db09785ffcd903e71b7b155aa22aafe1de05db 100644 --- a/crates/gpui/src/app.rs +++ b/crates/gpui/src/app.rs @@ -1155,7 +1155,7 @@ impl AppContext { } } - pub(crate) fn dispatch_global_action(&mut self, action: &dyn Action) { + fn dispatch_global_action(&mut self, action: &dyn Action) { self.propagate_event = true; if let Some(mut global_listeners) = self diff --git a/crates/gpui/src/window.rs b/crates/gpui/src/window.rs index 062f174c0346d4c02b3955390fe8758d9feb15f7..fcdb36e026a7c489f730cd79884b31d0330d0087 100644 --- a/crates/gpui/src/window.rs +++ b/crates/gpui/src/window.rs @@ -705,7 +705,6 @@ impl<'a> WindowContext<'a> { let window = self.window.handle; self.app.defer(move |cx| { - cx.propagate_event = true; window .update(cx, |_, cx| { let node_id = focus_handle @@ -720,9 +719,6 @@ impl<'a> WindowContext<'a> { cx.dispatch_action_on_node(node_id, action.as_ref()); }) .log_err(); - if cx.propagate_event { - cx.dispatch_global_action(action.as_ref()); - } }) } @@ -1467,7 +1463,34 @@ impl<'a> WindowContext<'a> { .dispatch_tree .dispatch_path(node_id); - // Capture phase + // Capture phase for global actions. + self.propagate_event = true; + if let Some(mut global_listeners) = self + .global_action_listeners + .remove(&action.as_any().type_id()) + { + for listener in &global_listeners { + listener(action.as_any(), DispatchPhase::Capture, self); + if !self.propagate_event { + break; + } + } + + global_listeners.extend( + self.global_action_listeners + .remove(&action.as_any().type_id()) + .unwrap_or_default(), + ); + + self.global_action_listeners + .insert(action.as_any().type_id(), global_listeners); + } + + if !self.propagate_event { + return; + } + + // Capture phase for window actions. for node_id in &dispatch_path { let node = self.window.rendered_frame.dispatch_tree.node(*node_id); for DispatchActionListener { @@ -1487,7 +1510,8 @@ impl<'a> WindowContext<'a> { } } } - // Bubble phase + + // Bubble phase for window actions. for node_id in dispatch_path.iter().rev() { let node = self.window.rendered_frame.dispatch_tree.node(*node_id); for DispatchActionListener { @@ -1509,6 +1533,30 @@ impl<'a> WindowContext<'a> { } } } + + // Bubble phase for global actions. + if let Some(mut global_listeners) = self + .global_action_listeners + .remove(&action.as_any().type_id()) + { + for listener in global_listeners.iter().rev() { + self.propagate_event = false; // Actions stop propagation by default during the bubble phase + + listener(action.as_any(), DispatchPhase::Bubble, self); + if !self.propagate_event { + break; + } + } + + global_listeners.extend( + self.global_action_listeners + .remove(&action.as_any().type_id()) + .unwrap_or_default(), + ); + + self.global_action_listeners + .insert(action.as_any().type_id(), global_listeners); + } } /// Register the given handler to be invoked whenever the global of the given type