diff --git a/crates/gpui/src/key_dispatch.rs b/crates/gpui/src/key_dispatch.rs index 22c4dffc03a78df8fde5530a3059887e91a2b876..9019670b04f4c66ea76761026a73a8fd6a0931dc 100644 --- a/crates/gpui/src/key_dispatch.rs +++ b/crates/gpui/src/key_dispatch.rs @@ -1,12 +1,13 @@ use crate::{ - arena::ArenaRef, Action, ActionRegistry, DispatchPhase, FocusId, KeyBinding, KeyContext, - KeyMatch, Keymap, Keystroke, KeystrokeMatcher, WindowContext, + Action, ActionRegistry, DispatchPhase, EntityId, FocusId, KeyBinding, KeyContext, KeyMatch, + Keymap, Keystroke, KeystrokeMatcher, WindowContext, }; -use collections::HashMap; +use collections::FxHashMap; use parking_lot::Mutex; use smallvec::SmallVec; use std::{ any::{Any, TypeId}, + mem, rc::Rc, sync::Arc, }; @@ -18,8 +19,9 @@ pub(crate) struct DispatchTree { node_stack: Vec, pub(crate) context_stack: Vec, nodes: Vec, - focusable_node_ids: HashMap, - keystroke_matchers: HashMap, KeystrokeMatcher>, + focusable_node_ids: FxHashMap, + view_node_ids: FxHashMap, + keystroke_matchers: FxHashMap, KeystrokeMatcher>, keymap: Arc>, action_registry: Rc, } @@ -30,15 +32,16 @@ pub(crate) struct DispatchNode { pub action_listeners: Vec, pub context: Option, focus_id: Option, + view_id: Option, parent: Option, } -type KeyListener = ArenaRef; +type KeyListener = Rc; #[derive(Clone)] pub(crate) struct DispatchActionListener { pub(crate) action_type: TypeId, - pub(crate) listener: ArenaRef, + pub(crate) listener: Rc, } impl DispatchTree { @@ -47,8 +50,9 @@ impl DispatchTree { node_stack: Vec::new(), context_stack: Vec::new(), nodes: Vec::new(), - focusable_node_ids: HashMap::default(), - keystroke_matchers: HashMap::default(), + focusable_node_ids: FxHashMap::default(), + view_node_ids: FxHashMap::default(), + keystroke_matchers: FxHashMap::default(), keymap, action_registry, } @@ -59,6 +63,7 @@ impl DispatchTree { self.nodes.clear(); self.context_stack.clear(); self.focusable_node_ids.clear(); + self.view_node_ids.clear(); self.keystroke_matchers.clear(); } @@ -83,6 +88,56 @@ impl DispatchTree { } } + fn move_node(&mut self, source_node: &mut DispatchNode) { + self.push_node(source_node.context.take()); + if let Some(focus_id) = source_node.focus_id { + self.make_focusable(focus_id); + } + if let Some(view_id) = source_node.view_id { + self.associate_view(view_id); + } + + let target_node = self.active_node(); + target_node.key_listeners = mem::take(&mut source_node.key_listeners); + target_node.action_listeners = mem::take(&mut source_node.action_listeners); + } + + pub fn graft(&mut self, view_id: EntityId, source: &mut Self) { + let view_source_node_id = source + .view_node_ids + .get(&view_id) + .expect("view should exist in previous dispatch tree"); + let view_source_node = &mut source.nodes[view_source_node_id.0]; + self.move_node(view_source_node); + + let mut source_stack = vec![*view_source_node_id]; + for (source_node_id, source_node) in source + .nodes + .iter_mut() + .enumerate() + .skip(view_source_node_id.0 + 1) + { + let source_node_id = DispatchNodeId(source_node_id); + while let Some(source_ancestor) = source_stack.last() { + if source_node.parent != Some(*source_ancestor) { + source_stack.pop(); + self.pop_node(); + } + } + + if source_stack.is_empty() { + break; + } else { + source_stack.push(source_node_id); + self.move_node(source_node); + } + } + + while !source_stack.is_empty() { + self.pop_node(); + } + } + pub fn clear_pending_keystrokes(&mut self) { self.keystroke_matchers.clear(); } @@ -117,7 +172,7 @@ impl DispatchTree { pub fn on_action( &mut self, action_type: TypeId, - listener: ArenaRef, + listener: Rc, ) { self.active_node() .action_listeners @@ -133,6 +188,12 @@ impl DispatchTree { self.focusable_node_ids.insert(focus_id, node_id); } + pub fn associate_view(&mut self, view_id: EntityId) { + let node_id = self.active_node_id(); + self.active_node().view_id = Some(view_id); + self.view_node_ids.insert(view_id, node_id); + } + pub fn focus_contains(&self, parent: FocusId, child: FocusId) -> bool { if parent == child { return true; diff --git a/crates/gpui/src/view.rs b/crates/gpui/src/view.rs index 9d504627ab185212df7df14399dfc54bcf1d6b46..24bc00ce39796890158bc6890e0fb779801a73b3 100644 --- a/crates/gpui/src/view.rs +++ b/crates/gpui/src/view.rs @@ -285,7 +285,8 @@ impl Element for AnyView { && cache_key.text_style == cx.text_style() && !cx.window.dirty_views.contains(&self.entity_id()) { - println!("could reuse geometry for view {}", self.entity_id()); + cx.reuse_geometry(); + return; } } diff --git a/crates/gpui/src/window.rs b/crates/gpui/src/window.rs index 98c81d3883122066edef4254d90b8adb6ba0ad3c..e5f9195b692409ec176d40d6014a22b5ceaaa6f8 100644 --- a/crates/gpui/src/window.rs +++ b/crates/gpui/src/window.rs @@ -1,8 +1,8 @@ use crate::{ - px, size, transparent_black, Action, AnyDrag, AnyView, AppContext, Arena, ArenaBox, ArenaRef, - AsyncWindowContext, AvailableSpace, Bounds, BoxShadow, Context, Corners, CursorStyle, - DevicePixels, DispatchActionListener, DispatchNodeId, DispatchTree, DisplayId, Edges, Effect, - Entity, EntityId, EventEmitter, FileDropEvent, Flatten, FontId, GlobalElementId, GlyphId, Hsla, + px, size, transparent_black, Action, AnyDrag, AnyView, AppContext, Arena, AsyncWindowContext, + AvailableSpace, Bounds, BoxShadow, Context, Corners, CursorStyle, DevicePixels, + DispatchActionListener, DispatchNodeId, DispatchTree, DisplayId, Edges, Effect, Entity, + EntityId, EventEmitter, FileDropEvent, Flatten, FontId, GlobalElementId, GlyphId, Hsla, ImageData, InputEvent, IsZero, KeyBinding, KeyContext, KeyDownEvent, KeystrokeEvent, LayoutId, Model, ModelContext, Modifiers, MonochromeSprite, MouseButton, MouseMoveEvent, MouseUpEvent, Path, Pixels, PlatformAtlas, PlatformDisplay, PlatformInputHandler, PlatformWindow, Point, @@ -95,7 +95,7 @@ impl DispatchPhase { } type AnyObserver = Box bool + 'static>; -type AnyMouseListener = ArenaBox; +type AnyMouseListener = Box; type AnyWindowFocusListener = Box bool + 'static>; struct FocusEvent { @@ -257,7 +257,6 @@ pub struct Window { pub(crate) rendered_frame: Frame, pub(crate) next_frame: Frame, pub(crate) dirty_views: FxHashSet, - frame_arena: Arena, pub(crate) focus_handles: Arc>>, focus_listeners: SubscriberSet<(), AnyWindowFocusListener>, blur_listeners: SubscriberSet<(), AnyObserver>, @@ -288,7 +287,7 @@ pub(crate) struct ElementStateBox { pub(crate) struct Frame { focus: Option, pub(crate) element_states: FxHashMap, - mouse_listeners: FxHashMap>, + mouse_listeners: FxHashMap>, pub(crate) dispatch_tree: DispatchTree, pub(crate) scene_builder: SceneBuilder, pub(crate) depth_map: Vec<(StackingOrder, Bounds)>, @@ -298,6 +297,7 @@ pub(crate) struct Frame { element_offset_stack: Vec>, pub(crate) view_parents: FxHashMap, pub(crate) view_stack: Vec, + pub(crate) reused_views: FxHashSet, } impl Frame { @@ -315,6 +315,7 @@ impl Frame { element_offset_stack: Vec::new(), view_parents: FxHashMap::default(), view_stack: Vec::new(), + reused_views: FxHashSet::default(), } } @@ -326,6 +327,7 @@ impl Frame { self.next_stacking_order_id = 0; self.view_parents.clear(); debug_assert!(self.view_stack.is_empty()); + self.reused_views.clear(); } fn focus_path(&self) -> SmallVec<[FocusId; 8]> { @@ -412,7 +414,6 @@ impl Window { rendered_frame: Frame::new(DispatchTree::new(cx.keymap.clone(), cx.actions.clone())), next_frame: Frame::new(DispatchTree::new(cx.keymap.clone(), cx.actions.clone())), dirty_views: FxHashSet::default(), - frame_arena: Arena::new(1024 * 1024), focus_handles: Arc::new(RwLock::new(SlotMap::with_key())), focus_listeners: SubscriberSet::new(), blur_listeners: SubscriberSet::new(), @@ -886,21 +887,21 @@ impl<'a> WindowContext<'a> { mut handler: impl FnMut(&Event, DispatchPhase, &mut WindowContext) + 'static, ) { let order = self.window.next_frame.z_index_stack.clone(); - let handler = self - .window - .frame_arena - .alloc(|| { - move |event: &dyn Any, phase: DispatchPhase, cx: &mut WindowContext<'_>| { - handler(event.downcast_ref().unwrap(), phase, cx) - } - }) - .map(|handler| handler as _); + let view_id = *self.window.next_frame.view_stack.last().unwrap(); self.window .next_frame .mouse_listeners .entry(TypeId::of::()) .or_default() - .push((order, handler)) + .push(( + order, + view_id, + Box::new( + move |event: &dyn Any, phase: DispatchPhase, cx: &mut WindowContext<'_>| { + handler(event.downcast_ref().unwrap(), phase, cx) + }, + ), + )) } /// Register a key event listener on the window for the next frame. The type of event @@ -913,21 +914,13 @@ impl<'a> WindowContext<'a> { &mut self, listener: impl Fn(&Event, DispatchPhase, &mut WindowContext) + 'static, ) { - let listener = self - .window - .frame_arena - .alloc(|| { - move |event: &dyn Any, phase, cx: &mut WindowContext<'_>| { - if let Some(event) = event.downcast_ref::() { - listener(event, phase, cx) - } + self.window.next_frame.dispatch_tree.on_key_event(Rc::new( + move |event: &dyn Any, phase, cx: &mut WindowContext<'_>| { + if let Some(event) = event.downcast_ref::() { + listener(event, phase, cx) } - }) - .map(|handler| handler as _); - self.window - .next_frame - .dispatch_tree - .on_key_event(ArenaRef::from(listener)); + }, + )); } /// Register an action listener on the window for the next frame. The type of action @@ -941,15 +934,10 @@ impl<'a> WindowContext<'a> { action_type: TypeId, listener: impl Fn(&dyn Any, DispatchPhase, &mut WindowContext) + 'static, ) { - let listener = self - .window - .frame_arena - .alloc(|| listener) - .map(|handler| handler as _); self.window .next_frame .dispatch_tree - .on_action(action_type, ArenaRef::from(listener)); + .on_action(action_type, Rc::new(listener)); } pub fn is_action_available(&self, action: &dyn Action) -> bool { @@ -1327,6 +1315,16 @@ impl<'a> WindowContext<'a> { ); } + pub(crate) fn reuse_geometry(&mut self) { + let window = &mut self.window; + let view_id = *window.next_frame.view_stack.last().unwrap(); + assert!(window.next_frame.reused_views.insert(view_id)); + window + .next_frame + .dispatch_tree + .graft(view_id, &mut window.rendered_frame.dispatch_tree) + } + /// Draw pixels to the display for this window based on the contents of its scene. pub(crate) fn draw(&mut self) -> Scene { println!("====================="); @@ -1342,26 +1340,18 @@ impl<'a> WindowContext<'a> { self.window.platform_window.clear_input_handler(); self.window.layout_engine.as_mut().unwrap().clear(); self.window.next_frame.clear(); - self.window.frame_arena.clear(); let root_view = self.window.root_view.take().unwrap(); self.with_z_index(0, |cx| { cx.with_key_dispatch(Some(KeyContext::default()), None, |_, cx| { for (action_type, action_listeners) in &cx.app.global_action_listeners { for action_listener in action_listeners.iter().cloned() { - let listener = cx - .window - .frame_arena - .alloc(|| { - move |action: &dyn Any, phase, cx: &mut WindowContext<'_>| { - action_listener(action, phase, cx) - } - }) - .map(|listener| listener as _); - cx.window - .next_frame - .dispatch_tree - .on_action(*action_type, ArenaRef::from(listener)) + cx.window.next_frame.dispatch_tree.on_action( + *action_type, + Rc::new(move |action: &dyn Any, phase, cx: &mut WindowContext<'_>| { + action_listener(action, phase, cx) + }), + ) } } @@ -1395,6 +1385,19 @@ impl<'a> WindowContext<'a> { ); self.window.next_frame.focus = self.window.focus; self.window.root_view = Some(root_view); + for (type_id, listeners) in &mut self.window.rendered_frame.mouse_listeners { + let next_listeners = self + .window + .next_frame + .mouse_listeners + .entry(*type_id) + .or_default(); + for (order, view_id, listener) in listeners.drain(..) { + if self.window.next_frame.reused_views.contains(&view_id) { + next_listeners.push((order, view_id, listener)); + } + } + } let previous_focus_path = self.window.rendered_frame.focus_path(); mem::swap(&mut self.window.rendered_frame, &mut self.window.next_frame); @@ -1540,11 +1543,11 @@ impl<'a> WindowContext<'a> { .remove(&event.type_id()) { // Because handlers may add other handlers, we sort every time. - handlers.sort_by(|(a, _), (b, _)| a.cmp(b)); + handlers.sort_by(|(a, _, _), (b, _, _)| a.cmp(b)); // Capture phase, events bubble from back to front. Handlers for this phase are used for // special purposes, such as detecting events outside of a given Bounds. - for (_, handler) in &mut handlers { + for (_, _, handler) in &mut handlers { handler(event, DispatchPhase::Capture, self); if !self.app.propagate_event { break; @@ -1553,7 +1556,7 @@ impl<'a> WindowContext<'a> { // Bubble phase, where most normal handlers do their work. if self.app.propagate_event { - for (_, handler) in handlers.iter_mut().rev() { + for (_, _, handler) in handlers.iter_mut().rev() { handler(event, DispatchPhase::Bubble, self); if !self.app.propagate_event { break;