Dispatch keystrokes and fix rerendering when window invalidated

Nathan Sobo and Antonio Scandurra created

Co-Authored-By: Antonio Scandurra <me@as-cii.com>

Change summary

gpui/src/app.rs                     | 19 ++++++++++++--
gpui/src/elements/container.rs      |  2 
gpui/src/platform/mac/renderer.rs   |  1 
gpui/src/platform/mac/window.rs     | 41 +++++++++++++++++-------------
gpui/src/platform/mod.rs            |  2 
gpui/src/presenter.rs               | 11 ++++++++
gpui/src/scene.rs                   |  2 
zed/src/file_finder.rs              |  3 --
zed/src/workspace/workspace_view.rs |  1 
9 files changed, 55 insertions(+), 27 deletions(-)

Detailed changes

gpui/src/app.rs 🔗

@@ -11,6 +11,7 @@ use anyhow::{anyhow, Result};
 use keymap::MatchResult;
 use parking_lot::Mutex;
 use pathfinder_geometry::{rect::RectF, vector::vec2f};
+use platform::Event;
 use smol::{channel, prelude::*};
 use std::{
     any::{type_name, Any, TypeId},
@@ -639,10 +640,22 @@ impl MutableAppContext {
                 {
                     let mut app = self.upgrade();
                     let presenter = presenter.clone();
-                    window.on_event(Box::new(move |event, window| {
+                    window.on_event(Box::new(move |event| {
                         log::info!("event {:?}", event);
                         app.update(|ctx| {
-                            ctx.pending_flushes += 1;
+                            if let Event::KeyDown { keystroke, .. } = &event {
+                                if ctx
+                                    .dispatch_keystroke(
+                                        window_id,
+                                        presenter.borrow().dispatch_path(ctx.downgrade()),
+                                        keystroke,
+                                    )
+                                    .unwrap()
+                                {
+                                    return;
+                                }
+                            }
+
                             let actions = presenter
                                 .borrow_mut()
                                 .dispatch_event(event, ctx.downgrade());
@@ -654,7 +667,6 @@ impl MutableAppContext {
                                     action.arg.as_ref(),
                                 );
                             }
-                            ctx.flush_effects();
                         })
                     }));
                 }
@@ -675,6 +687,7 @@ impl MutableAppContext {
                 }
 
                 self.on_window_invalidated(window_id, move |invalidation, ctx| {
+                    log::info!("window invalidated");
                     let mut presenter = presenter.borrow_mut();
                     presenter.invalidate(invalidation, ctx.downgrade());
                     let scene = presenter.build_scene(window.size(), window.scale_factor(), ctx);

gpui/src/elements/container.rs 🔗

@@ -148,7 +148,7 @@ impl Element for Container {
             bounds: RectF::new(origin, self.size.unwrap()),
             background: self.background_color,
             border: self.border,
-            corder_radius: self.corner_radius,
+            corner_radius: self.corner_radius,
         });
         self.child.paint(origin, ctx, app);
     }

gpui/src/platform/mac/renderer.rs 🔗

@@ -97,6 +97,7 @@ impl Renderer {
         for quad_batch in layer.quads().chunks(batch_size) {
             for (ix, quad) in quad_batch.iter().enumerate() {
                 let bounds = quad.bounds * scene.scale_factor();
+                log::info!("render quad {:?}", quad);
                 let shader_quad = shaders::GPUIQuad {
                     origin: bounds.origin().to_float2(),
                     size: bounds.size().to_float2(),

gpui/src/platform/mac/window.rs 🔗

@@ -2,7 +2,6 @@ use crate::{
     executor,
     geometry::vector::Vector2F,
     platform::{self, Event, WindowContext},
-    util::post_inc,
     Scene,
 };
 use anyhow::{anyhow, Result};
@@ -12,7 +11,7 @@ use cocoa::{
         NSWindow, NSWindowStyleMask,
     },
     base::{id, nil},
-    foundation::{NSAutoreleasePool, NSSize, NSString},
+    foundation::{NSAutoreleasePool, NSInteger, NSSize, NSString},
     quartzcore::AutoresizingMask,
 };
 use ctor::ctor;
@@ -42,6 +41,9 @@ const WINDOW_STATE_IVAR: &'static str = "windowState";
 static mut WINDOW_CLASS: *const Class = ptr::null();
 static mut VIEW_CLASS: *const Class = ptr::null();
 
+#[allow(non_upper_case_globals)]
+const NSViewLayerContentsRedrawDuringViewResize: NSInteger = 2;
+
 #[ctor]
 unsafe fn build_classes() {
     WINDOW_CLASS = {
@@ -117,7 +119,7 @@ pub struct Window(Rc<RefCell<WindowState>>);
 
 struct WindowState {
     native_window: id,
-    event_callback: Option<Box<dyn FnMut(Event, &mut dyn platform::WindowContext)>>,
+    event_callback: Option<Box<dyn FnMut(Event)>>,
     resize_callback: Option<Box<dyn FnMut(&mut dyn platform::WindowContext)>>,
     synthetic_drag_counter: usize,
     executor: Rc<executor::Foreground>,
@@ -219,10 +221,10 @@ impl Window {
             // on we explicitly make the view layer-backed up front so that AppKit doesn't do it
             // itself and break the association with its context.
             native_view.setWantsLayer(YES);
-
-            native_view.layer().setBackgroundColor_(
-                msg_send![class!(NSColor), colorWithRed:1.0 green:0.0 blue:0.0 alpha:1.0],
-            );
+            let _: () = msg_send![
+                native_view,
+                setLayerContentsRedrawPolicy: NSViewLayerContentsRedrawDuringViewResize
+            ];
 
             native_window.setContentView_(native_view.autorelease());
             native_window.makeFirstResponder_(native_view);
@@ -252,7 +254,7 @@ impl Drop for Window {
 }
 
 impl platform::Window for Window {
-    fn on_event(&mut self, callback: Box<dyn FnMut(Event, &mut dyn platform::WindowContext)>) {
+    fn on_event(&mut self, callback: Box<dyn FnMut(Event)>) {
         self.0.as_ref().borrow_mut().event_callback = Some(callback);
     }
 
@@ -290,6 +292,7 @@ impl platform::WindowContext for WindowState {
     }
 
     fn present_scene(&mut self, scene: Scene) {
+        log::info!("present scene");
         self.scene_to_render = Some(scene);
         unsafe {
             let _: () = msg_send![self.native_window.contentView(), setNeedsDisplay: YES];
@@ -331,32 +334,33 @@ extern "C" fn dealloc_view(this: &Object, _: Sel) {
 extern "C" fn handle_view_event(this: &Object, _: Sel, native_event: id) {
     let window_state = unsafe { get_window_state(this) };
     let weak_window_state = Rc::downgrade(&window_state);
-    let mut window_state = window_state.as_ref().borrow_mut();
+    let mut window_state_borrow = window_state.as_ref().borrow_mut();
 
-    let event = unsafe { Event::from_native(native_event, Some(window_state.size().y())) };
+    let event = unsafe { Event::from_native(native_event, Some(window_state_borrow.size().y())) };
 
     if let Some(event) = event {
         match event {
             Event::LeftMouseDragged { position } => {
-                window_state.synthetic_drag_counter += 1;
-                window_state
+                window_state_borrow.synthetic_drag_counter += 1;
+                window_state_borrow
                     .executor
                     .spawn(synthetic_drag(
                         weak_window_state,
-                        window_state.synthetic_drag_counter,
+                        window_state_borrow.synthetic_drag_counter,
                         position,
                     ))
                     .detach();
             }
             Event::LeftMouseUp { .. } => {
-                window_state.synthetic_drag_counter += 1;
+                window_state_borrow.synthetic_drag_counter += 1;
             }
             _ => {}
         }
 
-        if let Some(mut callback) = window_state.event_callback.take() {
-            callback(event, &mut *window_state);
-            window_state.event_callback = Some(callback);
+        if let Some(mut callback) = window_state_borrow.event_callback.take() {
+            drop(window_state_borrow);
+            callback(event);
+            window_state.borrow_mut().event_callback = Some(callback);
         }
     }
 }
@@ -417,6 +421,7 @@ extern "C" fn set_frame_size(this: &Object, _: Sel, size: NSSize) {
 }
 
 extern "C" fn display_layer(this: &Object, _: Sel, _: id) {
+    log::info!("display layer");
     unsafe {
         let window_state = get_window_state(this);
         let mut window_state = window_state.as_ref().borrow_mut();
@@ -470,7 +475,7 @@ async fn synthetic_drag(
             let mut window_state = window_state.borrow_mut();
             if window_state.synthetic_drag_counter == drag_id {
                 if let Some(mut callback) = window_state.event_callback.take() {
-                    callback(Event::LeftMouseDragged { position }, &mut *window_state);
+                    callback(Event::LeftMouseDragged { position });
                     window_state.event_callback = Some(callback);
                 }
             } else {

gpui/src/platform/mod.rs 🔗

@@ -41,7 +41,7 @@ pub trait Dispatcher: Send + Sync {
 }
 
 pub trait Window: WindowContext {
-    fn on_event(&mut self, callback: Box<dyn FnMut(Event, &mut dyn WindowContext)>);
+    fn on_event(&mut self, callback: Box<dyn FnMut(Event)>);
     fn on_resize(&mut self, callback: Box<dyn FnMut(&mut dyn WindowContext)>);
 }
 

gpui/src/presenter.rs 🔗

@@ -35,6 +35,17 @@ impl Presenter {
         }
     }
 
+    pub fn dispatch_path(&self, app: &AppContext) -> Vec<usize> {
+        let mut view_id = app.focused_view_id(self.window_id).unwrap();
+        let mut path = vec![view_id];
+        while let Some(parent_id) = self.parents.get(&view_id).copied() {
+            path.push(parent_id);
+            view_id = parent_id;
+        }
+        path.reverse();
+        path
+    }
+
     pub fn invalidate(&mut self, invalidation: WindowInvalidation, app: &AppContext) {
         for view_id in invalidation.updated {
             self.rendered_views

gpui/src/scene.rs 🔗

@@ -18,7 +18,7 @@ pub struct Quad {
     pub bounds: RectF,
     pub background: Option<ColorU>,
     pub border: Border,
-    pub corder_radius: f32,
+    pub corner_radius: f32,
 }
 
 #[derive(Clone, Copy, Default, Debug)]

zed/src/file_finder.rs 🔗

@@ -346,13 +346,10 @@ impl FileFinder {
 
     fn select(&mut self, entry: &(usize, usize), ctx: &mut ViewContext<Self>) {
         let (tree_id, entry_id) = *entry;
-        log::info!("selected item! {} {}", tree_id, entry_id);
         ctx.emit(Event::Selected(tree_id, entry_id));
     }
 
     fn spawn_search(&mut self, query: String, ctx: &mut ViewContext<Self>) {
-        log::info!("spawn search!");
-
         let worktrees = self.worktrees(ctx.app());
         let search_id = util::post_inc(&mut self.search_count);
         let task = ctx.background_executor().spawn(async move {