Checkpoint

Antonio Scandurra created

Change summary

crates/gpui3/src/elements/div.rs |  13 ++-
crates/gpui3/src/events.rs       |  31 ++++----
crates/gpui3/src/focus.rs        |  26 +++++-
crates/gpui3/src/interactive.rs  |  16 ++-
crates/gpui3/src/window.rs       | 126 +++++++++++++--------------------
5 files changed, 102 insertions(+), 110 deletions(-)

Detailed changes

crates/gpui3/src/elements/div.rs 🔗

@@ -423,18 +423,21 @@ where
         element_state: Option<Self::ElementState>,
         cx: &mut ViewContext<Self::ViewState>,
     ) -> Self::ElementState {
+        let key_listeners = mem::take(&mut self.listeners.key);
+        let focus_listeners = mem::take(&mut self.listeners.focus);
         cx.with_focus(
             self.focusability.focus_handle().cloned(),
-            mem::take(&mut self.listeners.key_down),
-            mem::take(&mut self.listeners.key_up),
-            mem::take(&mut self.listeners.focus),
+            &key_listeners,
+            &focus_listeners,
             |cx| {
                 for child in &mut self.children {
                     child.initialize(view_state, cx);
                 }
-                element_state.unwrap_or_default()
             },
-        )
+        );
+        self.listeners.key = key_listeners;
+        self.listeners.focus = focus_listeners;
+        element_state.unwrap_or_default()
     }
 
     fn layout(

crates/gpui3/src/events.rs 🔗

@@ -2,7 +2,11 @@ use crate::{
     point, Bounds, DispatchPhase, FocusHandle, Keystroke, Modifiers, Pixels, Point, ViewContext,
 };
 use smallvec::SmallVec;
-use std::{any::Any, ops::Deref};
+use std::{
+    any::{Any, TypeId},
+    ops::Deref,
+    sync::Arc,
+};
 
 #[derive(Clone, Debug, Eq, PartialEq)]
 pub struct KeyDownEvent {
@@ -221,43 +225,40 @@ pub struct FocusEvent {
     pub focused: Option<FocusHandle>,
 }
 
-pub type MouseDownListener<V> = Box<
+pub type MouseDownListener<V> = Arc<
     dyn Fn(&mut V, &MouseDownEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
         + Send
         + Sync
         + 'static,
 >;
-pub type MouseUpListener<V> = Box<
+pub type MouseUpListener<V> = Arc<
     dyn Fn(&mut V, &MouseUpEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
         + Send
         + Sync
         + 'static,
 >;
 pub type MouseClickListener<V> =
-    Box<dyn Fn(&mut V, &MouseClickEvent, &mut ViewContext<V>) + Send + Sync + 'static>;
+    Arc<dyn Fn(&mut V, &MouseClickEvent, &mut ViewContext<V>) + Send + Sync + 'static>;
 
-pub type MouseMoveListener<V> = Box<
+pub type MouseMoveListener<V> = Arc<
     dyn Fn(&mut V, &MouseMoveEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
         + Send
         + Sync
         + 'static,
 >;
 
-pub type ScrollWheelListener<V> = Box<
+pub type ScrollWheelListener<V> = Arc<
     dyn Fn(&mut V, &ScrollWheelEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
         + Send
         + Sync
         + 'static,
 >;
 
-pub type KeyDownListener<V> =
-    Box<dyn Fn(&mut V, &KeyDownEvent, DispatchPhase, &mut ViewContext<V>) + Send + Sync + 'static>;
-
-pub type KeyUpListener<V> =
-    Box<dyn Fn(&mut V, &KeyUpEvent, DispatchPhase, &mut ViewContext<V>) + Send + Sync + 'static>;
+pub type KeyListener<V> =
+    Arc<dyn Fn(&mut V, &dyn Any, DispatchPhase, &mut ViewContext<V>) + Send + Sync + 'static>;
 
 pub type FocusListener<V> =
-    Box<dyn Fn(&mut V, &FocusEvent, &mut ViewContext<V>) + Send + Sync + 'static>;
+    Arc<dyn Fn(&mut V, &FocusEvent, &mut ViewContext<V>) + Send + Sync + 'static>;
 
 pub struct EventListeners<V: 'static> {
     pub mouse_down: SmallVec<[MouseDownListener<V>; 2]>,
@@ -265,8 +266,7 @@ pub struct EventListeners<V: 'static> {
     pub mouse_click: SmallVec<[MouseClickListener<V>; 2]>,
     pub mouse_move: SmallVec<[MouseMoveListener<V>; 2]>,
     pub scroll_wheel: SmallVec<[ScrollWheelListener<V>; 2]>,
-    pub key_down: SmallVec<[KeyDownListener<V>; 2]>,
-    pub key_up: SmallVec<[KeyUpListener<V>; 2]>,
+    pub key: SmallVec<[(TypeId, KeyListener<V>); 32]>,
     pub focus: SmallVec<[FocusListener<V>; 2]>,
 }
 
@@ -278,8 +278,7 @@ impl<V> Default for EventListeners<V> {
             mouse_click: SmallVec::new(),
             mouse_move: SmallVec::new(),
             scroll_wheel: SmallVec::new(),
-            key_down: SmallVec::new(),
-            key_up: SmallVec::new(),
+            key: SmallVec::new(),
             focus: SmallVec::new(),
         }
     }

crates/gpui3/src/focus.rs 🔗

@@ -1,3 +1,5 @@
+use std::{any::TypeId, sync::Arc};
+
 use crate::{
     DispatchPhase, FocusEvent, FocusHandle, Interactive, KeyDownEvent, KeyUpEvent, StyleRefinement,
     ViewContext,
@@ -46,7 +48,7 @@ pub trait Focus: Interactive {
         let handle = self.handle().clone();
         self.listeners()
             .focus
-            .push(Box::new(move |view, event, cx| {
+            .push(Arc::new(move |view, event, cx| {
                 if event.focused.as_ref() == Some(&handle) {
                     listener(view, event, cx)
                 }
@@ -67,7 +69,7 @@ pub trait Focus: Interactive {
         let handle = self.handle().clone();
         self.listeners()
             .focus
-            .push(Box::new(move |view, event, cx| {
+            .push(Arc::new(move |view, event, cx| {
                 if event.blurred.as_ref() == Some(&handle) {
                     listener(view, event, cx)
                 }
@@ -88,7 +90,7 @@ pub trait Focus: Interactive {
         let handle = self.handle().clone();
         self.listeners()
             .focus
-            .push(Box::new(move |view, event, cx| {
+            .push(Arc::new(move |view, event, cx| {
                 let descendant_blurred = event
                     .blurred
                     .as_ref()
@@ -118,7 +120,7 @@ pub trait Focus: Interactive {
         let handle = self.handle().clone();
         self.listeners()
             .focus
-            .push(Box::new(move |view, event, cx| {
+            .push(Arc::new(move |view, event, cx| {
                 let descendant_blurred = event
                     .blurred
                     .as_ref()
@@ -148,7 +150,13 @@ pub trait Focus: Interactive {
     where
         Self: Sized,
     {
-        self.listeners().key_down.push(Box::new(listener));
+        self.listeners().key.push((
+            TypeId::of::<KeyDownEvent>(),
+            Arc::new(move |view, event, phase, cx| {
+                let event = event.downcast_ref().unwrap();
+                listener(view, event, phase, cx)
+            }),
+        ));
         self
     }
 
@@ -162,7 +170,13 @@ pub trait Focus: Interactive {
     where
         Self: Sized,
     {
-        self.listeners().key_up.push(Box::new(listener));
+        self.listeners().key.push((
+            TypeId::of::<KeyUpEvent>(),
+            Arc::new(move |view, event, phase, cx| {
+                let event = event.downcast_ref().unwrap();
+                listener(view, event, phase, cx)
+            }),
+        ));
         self
     }
 }

crates/gpui3/src/interactive.rs 🔗

@@ -1,3 +1,5 @@
+use std::sync::Arc;
+
 use crate::{
     DispatchPhase, Element, EventListeners, MouseButton, MouseClickEvent, MouseDownEvent,
     MouseMoveEvent, MouseUpEvent, ScrollWheelEvent, ViewContext,
@@ -19,7 +21,7 @@ pub trait Interactive: Element {
     {
         self.listeners()
             .mouse_down
-            .push(Box::new(move |view, event, bounds, phase, cx| {
+            .push(Arc::new(move |view, event, bounds, phase, cx| {
                 if phase == DispatchPhase::Bubble
                     && event.button == button
                     && bounds.contains_point(&event.position)
@@ -43,7 +45,7 @@ pub trait Interactive: Element {
     {
         self.listeners()
             .mouse_up
-            .push(Box::new(move |view, event, bounds, phase, cx| {
+            .push(Arc::new(move |view, event, bounds, phase, cx| {
                 if phase == DispatchPhase::Bubble
                     && event.button == button
                     && bounds.contains_point(&event.position)
@@ -67,7 +69,7 @@ pub trait Interactive: Element {
     {
         self.listeners()
             .mouse_down
-            .push(Box::new(move |view, event, bounds, phase, cx| {
+            .push(Arc::new(move |view, event, bounds, phase, cx| {
                 if phase == DispatchPhase::Capture
                     && event.button == button
                     && !bounds.contains_point(&event.position)
@@ -91,7 +93,7 @@ pub trait Interactive: Element {
     {
         self.listeners()
             .mouse_up
-            .push(Box::new(move |view, event, bounds, phase, cx| {
+            .push(Arc::new(move |view, event, bounds, phase, cx| {
                 if phase == DispatchPhase::Capture
                     && event.button == button
                     && !bounds.contains_point(&event.position)
@@ -114,7 +116,7 @@ pub trait Interactive: Element {
     {
         self.listeners()
             .mouse_move
-            .push(Box::new(move |view, event, bounds, phase, cx| {
+            .push(Arc::new(move |view, event, bounds, phase, cx| {
                 if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
                     handler(view, event, cx);
                 }
@@ -134,7 +136,7 @@ pub trait Interactive: Element {
     {
         self.listeners()
             .scroll_wheel
-            .push(Box::new(move |view, event, bounds, phase, cx| {
+            .push(Arc::new(move |view, event, bounds, phase, cx| {
                 if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
                     handler(view, event, cx);
                 }
@@ -156,7 +158,7 @@ pub trait Click: Interactive {
     {
         self.listeners()
             .mouse_click
-            .push(Box::new(move |view, event, cx| handler(view, event, cx)));
+            .push(Arc::new(move |view, event, cx| handler(view, event, cx)));
         self
     }
 }

crates/gpui3/src/window.rs 🔗

@@ -2,12 +2,11 @@ use crate::{
     px, size, AnyBox, AnyView, AppContext, AsyncWindowContext, AvailableSpace, BorrowAppContext,
     Bounds, BoxShadow, Context, Corners, DevicePixels, DisplayId, Edges, Effect, Element, EntityId,
     EventEmitter, FocusEvent, FocusListener, FontId, GlobalElementId, GlyphId, Handle, Hsla,
-    ImageData, InputEvent, IsZero, KeyDownEvent, KeyDownListener, KeyUpEvent, KeyUpListener,
-    LayoutId, MainThread, MainThreadOnly, MonochromeSprite, MouseMoveEvent, Path, Pixels, Platform,
-    PlatformAtlas, PlatformWindow, Point, PolychromeSprite, Quad, Reference, RenderGlyphParams,
-    RenderImageParams, RenderSvgParams, ScaledPixels, SceneBuilder, Shadow, SharedString, Size,
-    Style, Subscription, TaffyLayoutEngine, Task, Underline, UnderlineStyle, WeakHandle,
-    WindowOptions, SUBPIXEL_VARIANTS,
+    ImageData, InputEvent, IsZero, KeyListener, LayoutId, MainThread, MainThreadOnly,
+    MonochromeSprite, MouseMoveEvent, Path, Pixels, Platform, PlatformAtlas, PlatformWindow, Point,
+    PolychromeSprite, Quad, Reference, RenderGlyphParams, RenderImageParams, RenderSvgParams,
+    ScaledPixels, SceneBuilder, Shadow, SharedString, Size, Style, Subscription, TaffyLayoutEngine,
+    Task, Underline, UnderlineStyle, WeakHandle, WindowOptions, SUBPIXEL_VARIANTS,
 };
 use anyhow::Result;
 use collections::HashMap;
@@ -45,15 +44,8 @@ pub enum DispatchPhase {
     Capture,
 }
 
-type AnyMouseEventListener =
-    Box<dyn Fn(&dyn Any, DispatchPhase, &mut WindowContext) + Send + Sync + 'static>;
-type AnyKeyboardEventListener =
-    Box<dyn Fn(&dyn Any, DispatchPhase, &mut WindowContext) + Send + Sync + 'static>;
-type AnyFocusListener = Box<dyn Fn(&FocusEvent, &mut WindowContext) + Send + Sync + 'static>;
-type AnyKeyDownListener =
-    Box<dyn Fn(&KeyDownEvent, DispatchPhase, &mut WindowContext) + Send + Sync + 'static>;
-type AnyKeyUpListener =
-    Box<dyn Fn(&KeyUpEvent, DispatchPhase, &mut WindowContext) + Send + Sync + 'static>;
+type AnyListener = Arc<dyn Fn(&dyn Any, DispatchPhase, &mut WindowContext) + Send + Sync + 'static>;
+type AnyFocusListener = Arc<dyn Fn(&FocusEvent, &mut WindowContext) + Send + Sync + 'static>;
 
 slotmap::new_key_type! { pub struct FocusId; }
 
@@ -153,9 +145,10 @@ pub struct Window {
     element_states: HashMap<GlobalElementId, AnyBox>,
     z_index_stack: StackingOrder,
     content_mask_stack: Vec<ContentMask<Pixels>>,
-    mouse_listeners: HashMap<TypeId, Vec<(StackingOrder, AnyMouseEventListener)>>,
-    keyboard_listeners: HashMap<TypeId, Vec<AnyKeyboardEventListener>>,
-    focus_stack: Vec<FocusStackFrame>,
+    mouse_listeners: HashMap<TypeId, Vec<(StackingOrder, AnyListener)>>,
+    key_listeners: HashMap<TypeId, Vec<AnyListener>>,
+    push_key_listeners: bool,
+    focus_stack: Vec<FocusId>,
     focus_parents_by_child: HashMap<FocusId, FocusId>,
     pub(crate) focus_listeners: Vec<AnyFocusListener>,
     pub(crate) focus_handles: Arc<RwLock<SlotMap<FocusId, AtomicUsize>>>,
@@ -226,7 +219,8 @@ impl Window {
             z_index_stack: StackingOrder(SmallVec::new()),
             content_mask_stack: Vec::new(),
             mouse_listeners: HashMap::default(),
-            keyboard_listeners: HashMap::default(),
+            key_listeners: HashMap::default(),
+            push_key_listeners: true,
             focus_stack: Vec::new(),
             focus_parents_by_child: HashMap::default(),
             focus_listeners: Vec::new(),
@@ -262,12 +256,6 @@ impl ContentMask<Pixels> {
     }
 }
 
-struct FocusStackFrame {
-    handle: FocusHandle,
-    key_down_listeners: SmallVec<[AnyKeyDownListener; 2]>,
-    key_up_listeners: SmallVec<[AnyKeyUpListener; 2]>,
-}
-
 pub struct WindowContext<'a, 'w> {
     app: Reference<'a, AppContext>,
     pub(crate) window: Reference<'w, Window>,
@@ -468,7 +456,7 @@ impl<'a, 'w> WindowContext<'a, 'w> {
             .or_default()
             .push((
                 order,
-                Box::new(move |event: &dyn Any, phase, cx| {
+                Arc::new(move |event: &dyn Any, phase, cx| {
                     handler(event.downcast_ref().unwrap(), phase, cx)
                 }),
             ))
@@ -479,10 +467,10 @@ impl<'a, 'w> WindowContext<'a, 'w> {
         handler: impl Fn(&Event, DispatchPhase, &mut WindowContext) + Send + Sync + 'static,
     ) {
         self.window
-            .keyboard_listeners
+            .key_listeners
             .entry(TypeId::of::<Event>())
             .or_default()
-            .push(Box::new(move |event: &dyn Any, phase, cx| {
+            .push(Arc::new(move |event: &dyn Any, phase, cx| {
                 handler(event.downcast_ref().unwrap(), phase, cx)
             }))
     }
@@ -833,8 +821,9 @@ impl<'a, 'w> WindowContext<'a, 'w> {
         // Clear focus state, because we determine what is focused when the new elements
         // in the upcoming frame are initialized.
         window.focus_listeners.clear();
-        window.keyboard_listeners.values_mut().for_each(Vec::clear);
+        window.key_listeners.values_mut().for_each(Vec::clear);
         window.focus_parents_by_child.clear();
+        window.push_key_listeners = true;
     }
 
     fn end_frame(&mut self) {
@@ -893,7 +882,7 @@ impl<'a, 'w> WindowContext<'a, 'w> {
         } else if let Some(any_keyboard_event) = event.keyboard_event() {
             if let Some(mut handlers) = self
                 .window
-                .keyboard_listeners
+                .key_listeners
                 .remove(&any_keyboard_event.type_id())
             {
                 for handler in &handlers {
@@ -914,13 +903,13 @@ impl<'a, 'w> WindowContext<'a, 'w> {
 
                 handlers.extend(
                     self.window
-                        .keyboard_listeners
+                        .key_listeners
                         .get_mut(&any_keyboard_event.type_id())
                         .into_iter()
                         .flat_map(|handlers| handlers.drain(..)),
                 );
                 self.window
-                    .keyboard_listeners
+                    .key_listeners
                     .insert(any_keyboard_event.type_id(), handlers);
             }
         }
@@ -1221,9 +1210,8 @@ impl<'a, 'w, V: Send + Sync + 'static> ViewContext<'a, 'w, V> {
     pub fn with_focus<R>(
         &mut self,
         focus_handle: Option<FocusHandle>,
-        key_down: impl IntoIterator<Item = KeyDownListener<V>>,
-        key_up: impl IntoIterator<Item = KeyUpListener<V>>,
-        focus: impl IntoIterator<Item = FocusListener<V>>,
+        key_listeners: &[(TypeId, KeyListener<V>)],
+        focus_listeners: &[FocusListener<V>],
         f: impl FnOnce(&mut Self) -> R,
     ) -> R {
         let Some(focus_handle) = focus_handle else {
@@ -1233,63 +1221,49 @@ impl<'a, 'w, V: Send + Sync + 'static> ViewContext<'a, 'w, V> {
         let handle = self.handle();
         let window = &mut *self.window;
 
-        for listener in focus {
+        for listener in focus_listeners.iter().cloned() {
             let handle = handle.clone();
-            window.focus_listeners.push(Box::new(move |event, cx| {
+            window.focus_listeners.push(Arc::new(move |event, cx| {
                 handle
                     .update(cx, |view, cx| listener(view, event, cx))
                     .log_err();
             }));
         }
 
-        let mut focus_stack = mem::take(&mut window.focus_stack);
-        if let Some(parent_frame) = focus_stack.last() {
+        if let Some(parent_focus_id) = window.focus_stack.last() {
             window
                 .focus_parents_by_child
-                .insert(focus_handle.id, parent_frame.handle.id);
-        }
-
-        let mut frame = FocusStackFrame {
-            handle: focus_handle.clone(),
-            key_down_listeners: SmallVec::new(),
-            key_up_listeners: SmallVec::new(),
-        };
-
-        for listener in key_down {
-            let handle = handle.clone();
-            frame
-                .key_down_listeners
-                .push(Box::new(move |event, phase, cx| {
-                    handle
-                        .update(cx, |view, cx| listener(view, event, phase, cx))
-                        .log_err();
-                }));
+                .insert(focus_handle.id, *parent_focus_id);
         }
-        for listener in key_up {
-            let handle = handle.clone();
-            frame
-                .key_up_listeners
-                .push(Box::new(move |event, phase, cx| {
-                    handle
-                        .update(cx, |view, cx| listener(view, event, phase, cx))
-                        .log_err();
-                }));
+        window.focus_stack.push(focus_handle.id);
+
+        if window.push_key_listeners {
+            for (type_id, listener) in key_listeners {
+                let handle = handle.clone();
+                let listener = listener.clone();
+                window
+                    .key_listeners
+                    .entry(*type_id)
+                    .or_default()
+                    .push(Arc::new(move |event, phase, cx| {
+                        handle
+                            .update(cx, |view, cx| listener(view, event, phase, cx))
+                            .log_err();
+                    }));
+            }
         }
-        focus_stack.push(frame);
 
         if Some(focus_handle.id) == window.focus {
-            for focus_frame in &mut focus_stack {
-                for listener in focus_frame.key_down_listeners.drain(..) {
-                    self.window_cx.on_keyboard_event(listener);
-                }
-                for listener in focus_frame.key_up_listeners.drain(..) {
-                    self.window_cx.on_keyboard_event(listener);
-                }
-            }
+            window.push_key_listeners = false;
         }
 
-        self.window.focus_stack = focus_stack;
         let result = f(self);
+
+        if self.window.push_key_listeners {
+            for (type_id, _) in key_listeners {
+                self.window.key_listeners.get_mut(type_id).unwrap().pop();
+            }
+        }
         self.window.focus_stack.pop();
         result
     }