Change summary
crates/gpui2/src/key_dispatch.rs | 35 +++++++++++++++++++++++++++------
crates/gpui2/src/window.rs | 18 ++++++++++++++++
2 files changed, 45 insertions(+), 8 deletions(-)
Detailed changes
@@ -60,7 +60,7 @@ impl DispatchTree {
self.keystroke_matchers.clear();
}
- pub fn push_node(&mut self, context: KeyContext, old_dispatcher: &mut Self) {
+ pub fn push_node(&mut self, context: KeyContext) {
let parent = self.node_stack.last().copied();
let node_id = DispatchNodeId(self.nodes.len());
self.nodes.push(DispatchNode {
@@ -71,12 +71,6 @@ impl DispatchTree {
if !context.is_empty() {
self.active_node().context = context.clone();
self.context_stack.push(context);
- if let Some((context_stack, matcher)) = old_dispatcher
- .keystroke_matchers
- .remove_entry(self.context_stack.as_slice())
- {
- self.keystroke_matchers.insert(context_stack, matcher);
- }
}
}
@@ -87,6 +81,33 @@ impl DispatchTree {
}
}
+ pub fn clear_keystroke_matchers(&mut self) {
+ self.keystroke_matchers.clear();
+ }
+
+ /// Preserve keystroke matchers from previous frames to support multi-stroke
+ /// bindings across multiple frames.
+ pub fn preserve_keystroke_matchers(&mut self, old_tree: &mut Self, focus_id: Option<FocusId>) {
+ if let Some(node_id) = focus_id.and_then(|focus_id| self.focusable_node_id(focus_id)) {
+ let dispatch_path = self.dispatch_path(node_id);
+
+ self.context_stack.clear();
+ for node_id in dispatch_path {
+ let node = self.node(node_id);
+ if !node.context.is_empty() {
+ self.context_stack.push(node.context.clone());
+ }
+
+ if let Some((context_stack, matcher)) = old_tree
+ .keystroke_matchers
+ .remove_entry(self.context_stack.as_slice())
+ {
+ self.keystroke_matchers.insert(context_stack, matcher);
+ }
+ }
+ }
+ }
+
pub fn on_key_event(&mut self, listener: KeyListener) {
self.active_node().key_listeners.push(listener);
}
@@ -393,6 +393,10 @@ impl<'a> WindowContext<'a> {
/// Move focus to the element associated with the given `FocusHandle`.
pub fn focus(&mut self, handle: &FocusHandle) {
+ if self.window.focus == Some(handle.id) {
+ return;
+ }
+
let focus_id = handle.id;
if self.window.last_blur.is_none() {
@@ -400,6 +404,10 @@ impl<'a> WindowContext<'a> {
}
self.window.focus = Some(focus_id);
+ self.window
+ .current_frame
+ .dispatch_tree
+ .clear_keystroke_matchers();
self.app.push_effect(Effect::FocusChanged {
window_handle: self.window.handle,
focused: Some(focus_id),
@@ -1091,6 +1099,14 @@ impl<'a> WindowContext<'a> {
});
}
+ self.window
+ .current_frame
+ .dispatch_tree
+ .preserve_keystroke_matchers(
+ &mut self.window.previous_frame.dispatch_tree,
+ self.window.focus,
+ );
+
self.window.root_view = Some(root_view);
let scene = self.window.current_frame.scene_builder.build();
@@ -2093,7 +2109,7 @@ impl<'a, V: 'static> ViewContext<'a, V> {
window
.current_frame
.dispatch_tree
- .push_node(context.clone(), &mut window.previous_frame.dispatch_tree);
+ .push_node(context.clone());
if let Some(focus_handle) = focus_handle.as_ref() {
window
.current_frame