WIP

Nathan Sobo created

Change summary

crates/activity_indicator/src/activity_indicator.rs    |   6 
crates/auto_update/src/update_notification.rs          |   2 
crates/breadcrumbs/src/breadcrumbs.rs                  |   6 
crates/collab_ui/src/collab_titlebar_item.rs           |  30 
crates/collab_ui/src/collaborator_list_popover.rs      |  11 
crates/collab_ui/src/contact_finder.rs                 |   6 
crates/collab_ui/src/contact_list.rs                   |  22 
crates/collab_ui/src/contact_notification.rs           |   5 
crates/collab_ui/src/contacts_popover.rs               |   6 
crates/collab_ui/src/face_pile.rs                      |   4 
crates/collab_ui/src/incoming_call_notification.rs     |   8 
crates/collab_ui/src/notifications.rs                  |   4 
crates/collab_ui/src/project_shared_notification.rs    |   8 
crates/collab_ui/src/sharing_status_indicator.rs       |   4 
crates/command_palette/src/command_palette.rs          |   9 
crates/context_menu/src/context_menu.rs                |  38 
crates/copilot/src/sign_in.rs                          |  10 
crates/copilot_button/src/copilot_button.rs            |   6 
crates/diagnostics/src/diagnostics.rs                  |   5 
crates/diagnostics/src/items.rs                        |   6 
crates/drag_and_drop/src/drag_and_drop.rs              |  54 
crates/editor/src/display_map/block_map.rs             |   6 
crates/editor/src/editor.rs                            |  18 
crates/editor/src/element.rs                           | 149 +-
crates/editor/src/hover_popover.rs                     |   8 
crates/editor/src/items.rs                             |   6 
crates/feedback/src/deploy_feedback_button.rs          |   4 
crates/feedback/src/feedback_editor.rs                 |   6 
crates/feedback/src/feedback_info_text.rs              |   4 
crates/feedback/src/submit_feedback_button.rs          |   4 
crates/file_finder/src/file_finder.rs                  |   6 
crates/go_to_line/src/go_to_line.rs                    |   4 
crates/gpui/examples/text.rs                           |  25 
crates/gpui/src/app.rs                                 | 613 +++++------
crates/gpui/src/app/menu.rs                            |   6 
crates/gpui/src/app/test_app_context.rs                |  43 
crates/gpui/src/app/window.rs                          | 449 +++++---
crates/gpui/src/app/window_input_handler.rs            |  49 
crates/gpui/src/elements.rs                            |  58 
crates/gpui/src/elements/align.rs                      |  14 
crates/gpui/src/elements/canvas.rs                     |   4 
crates/gpui/src/elements/clipped.rs                    |   8 
crates/gpui/src/elements/constrained_box.rs            |   2 
crates/gpui/src/elements/container.rs                  |  20 
crates/gpui/src/elements/empty.rs                      |   3 
crates/gpui/src/elements/expanded.rs                   |   2 
crates/gpui/src/elements/flex.rs                       |  23 
crates/gpui/src/elements/hook.rs                       |   2 
crates/gpui/src/elements/image.rs                      |   6 
crates/gpui/src/elements/keystroke_label.rs            |   7 
crates/gpui/src/elements/label.rs                      |  14 
crates/gpui/src/elements/list.rs                       |  59 
crates/gpui/src/elements/mouse_event_handler.rs        |  57 
crates/gpui/src/elements/overlay.rs                    |  31 
crates/gpui/src/elements/resizable.rs                  |  38 
crates/gpui/src/elements/stack.rs                      |  11 
crates/gpui/src/elements/svg.rs                        |   2 
crates/gpui/src/elements/text.rs                       |  34 
crates/gpui/src/elements/tooltip.rs                    |  59 
crates/gpui/src/elements/uniform_list.rs               |  45 
crates/gpui/src/gpui.rs                                |   4 
crates/gpui/src/scene.rs                               |  22 
crates/gpui/src/scene/mouse_region.rs                  | 180 ++
crates/gpui/src/text_layout.rs                         |  12 
crates/gpui/src/views/select.rs                        |  34 
crates/language_selector/src/active_buffer_language.rs |   4 
crates/language_selector/src/language_selector.rs      |   6 
crates/outline/src/outline.rs                          |   4 
crates/picker/src/picker.rs                            |   6 
crates/project_panel/src/project_panel.rs              |  16 
crates/project_symbols/src/project_symbols.rs          |   6 
crates/recent_projects/src/recent_projects.rs          |   5 
crates/search/src/buffer_search.rs                     |  15 
crates/search/src/project_search.rs                    |  13 
crates/terminal_view/src/terminal_button.rs            |   8 
crates/terminal_view/src/terminal_element.rs           |  52 
crates/terminal_view/src/terminal_view.rs              |  10 
crates/theme/src/ui.rs                                 |  69 
crates/theme_selector/src/theme_selector.rs            |   6 
crates/theme_testbench/src/theme_testbench.rs          |  20 
crates/welcome/src/base_keymap_picker.rs               |   2 
crates/welcome/src/welcome.rs                          |   2 
crates/workspace/src/dock.rs                           |   5 
crates/workspace/src/dock/toggle_dock_button.rs        |   2 
crates/workspace/src/item.rs                           |   6 
crates/workspace/src/notifications.rs                  |   2 
crates/workspace/src/pane.rs                           |  53 
crates/workspace/src/pane/dragged_item_receiver.rs     |  16 
crates/workspace/src/pane_group.rs                     |   8 
crates/workspace/src/shared_screen.rs                  |   6 
crates/workspace/src/sidebar.rs                        |   6 
crates/workspace/src/status_bar.rs                     |  23 
crates/workspace/src/toolbar.rs                        |   6 
crates/workspace/src/workspace.rs                      |  11 
94 files changed, 1,478 insertions(+), 1,311 deletions(-)

Detailed changes

crates/activity_indicator/src/activity_indicator.rs 🔗

@@ -5,7 +5,7 @@ use gpui::{
     actions,
     elements::*,
     platform::{CursorStyle, MouseButton},
-    Action, AppContext, Entity, ModelHandle, RenderContext, View, ViewContext, ViewHandle,
+    Action, AppContext, Entity, ModelHandle, View, ViewContext, ViewHandle,
 };
 use language::{LanguageRegistry, LanguageServerBinaryStatus};
 use project::{LanguageServerProgress, Project};
@@ -172,7 +172,7 @@ impl ActivityIndicator {
             .flatten()
     }
 
-    fn content_to_render(&mut self, cx: &mut RenderContext<Self>) -> Content {
+    fn content_to_render(&mut self, cx: &mut ViewContext<Self>) -> Content {
         // Show any language server has pending activity.
         let mut pending_work = self.pending_language_server_work(cx);
         if let Some(PendingWork {
@@ -314,7 +314,7 @@ impl View for ActivityIndicator {
         "ActivityIndicator"
     }
 
-    fn render(&mut self, cx: &mut RenderContext<Self>) -> ElementBox {
+    fn render(&mut self, cx: &mut ViewContext<Self>) -> ElementBox {
         let Content {
             icon,
             message,

crates/auto_update/src/update_notification.rs 🔗

@@ -26,7 +26,7 @@ impl View for UpdateNotification {
         "UpdateNotification"
     }
 
-    fn render(&mut self, cx: &mut gpui::RenderContext<'_, Self>) -> gpui::ElementBox {
+    fn render(&mut self, cx: &mut gpui::ViewContext<Self>) -> gpui::ElementBox {
         let theme = cx.global::<Settings>().theme.clone();
         let theme = &theme.update_notification;
 

crates/breadcrumbs/src/breadcrumbs.rs 🔗

@@ -1,6 +1,6 @@
 use gpui::{
-    elements::*, platform::MouseButton, AppContext, Entity, RenderContext, Subscription, View,
-    ViewContext, ViewHandle,
+    elements::*, platform::MouseButton, AppContext, Entity, Subscription, View, ViewContext,
+    ViewHandle,
 };
 use itertools::Itertools;
 use search::ProjectSearchView;
@@ -41,7 +41,7 @@ impl View for Breadcrumbs {
         "Breadcrumbs"
     }
 
-    fn render(&mut self, cx: &mut RenderContext<Self>) -> ElementBox {
+    fn render(&mut self, cx: &mut ViewContext<Self>) -> ElementBox {
         let active_item = match &self.active_item {
             Some(active_item) => active_item,
             None => return Empty::new().boxed(),

crates/collab_ui/src/collab_titlebar_item.rs 🔗

@@ -16,8 +16,8 @@ use gpui::{
     impl_internal_actions,
     json::{self, ToJson},
     platform::{CursorStyle, MouseButton},
-    AppContext, Entity, ImageData, ModelHandle, RenderContext, Subscription, View, ViewContext,
-    ViewHandle, WeakViewHandle,
+    AppContext, Entity, ImageData, ModelHandle, Subscription, View, ViewContext, ViewHandle,
+    WeakViewHandle,
 };
 use settings::Settings;
 use std::{ops::Range, sync::Arc};
@@ -68,7 +68,7 @@ impl View for CollabTitlebarItem {
         "CollabTitlebarItem"
     }
 
-    fn render(&mut self, cx: &mut RenderContext<Self>) -> ElementBox {
+    fn render(&mut self, cx: &mut ViewContext<Self>) -> ElementBox {
         let workspace = if let Some(workspace) = self.workspace.upgrade(cx) {
             workspace
         } else {
@@ -325,7 +325,7 @@ impl CollabTitlebarItem {
     fn render_toggle_contacts_button(
         &self,
         theme: &Theme,
-        cx: &mut RenderContext<Self>,
+        cx: &mut ViewContext<Self>,
     ) -> ElementBox {
         let titlebar = &theme.workspace.titlebar;
 
@@ -390,7 +390,7 @@ impl CollabTitlebarItem {
         &self,
         theme: &Theme,
         room: &ModelHandle<Room>,
-        cx: &mut RenderContext<Self>,
+        cx: &mut ViewContext<Self>,
     ) -> ElementBox {
         let icon;
         let tooltip;
@@ -436,7 +436,7 @@ impl CollabTitlebarItem {
         &self,
         workspace: &ViewHandle<Workspace>,
         theme: &Theme,
-        cx: &mut RenderContext<Self>,
+        cx: &mut ViewContext<Self>,
     ) -> Option<ElementBox> {
         let project = workspace.read(cx).project();
         if project.read(cx).is_remote() {
@@ -491,7 +491,7 @@ impl CollabTitlebarItem {
         )
     }
 
-    fn render_user_menu_button(&self, theme: &Theme, cx: &mut RenderContext<Self>) -> ElementBox {
+    fn render_user_menu_button(&self, theme: &Theme, cx: &mut ViewContext<Self>) -> ElementBox {
         let titlebar = &theme.workspace.titlebar;
 
         Stack::new()
@@ -535,7 +535,7 @@ impl CollabTitlebarItem {
             .boxed()
     }
 
-    fn render_sign_in_button(&self, theme: &Theme, cx: &mut RenderContext<Self>) -> ElementBox {
+    fn render_sign_in_button(&self, theme: &Theme, cx: &mut ViewContext<Self>) -> ElementBox {
         let titlebar = &theme.workspace.titlebar;
         MouseEventHandler::<SignIn>::new(0, cx, |state, _| {
             let style = titlebar.sign_in_prompt.style_for(state, false);
@@ -554,7 +554,7 @@ impl CollabTitlebarItem {
     fn render_contacts_popover_host<'a>(
         &'a self,
         _theme: &'a theme::Titlebar,
-        cx: &'a RenderContext<Self>,
+        cx: &'a ViewContext<Self>,
     ) -> Option<ElementBox> {
         self.contacts_popover.as_ref().map(|popover| {
             Overlay::new(ChildView::new(popover, cx).boxed())
@@ -573,7 +573,7 @@ impl CollabTitlebarItem {
         workspace: &ViewHandle<Workspace>,
         theme: &Theme,
         room: &ModelHandle<Room>,
-        cx: &mut RenderContext<Self>,
+        cx: &mut ViewContext<Self>,
     ) -> Vec<ElementBox> {
         let mut participants = room
             .read(cx)
@@ -615,7 +615,7 @@ impl CollabTitlebarItem {
         theme: &Theme,
         user: &Arc<User>,
         peer_id: PeerId,
-        cx: &mut RenderContext<Self>,
+        cx: &mut ViewContext<Self>,
     ) -> ElementBox {
         let replica_id = workspace.read(cx).project().read(cx).replica_id();
         Container::new(self.render_face_pile(
@@ -639,7 +639,7 @@ impl CollabTitlebarItem {
         location: Option<ParticipantLocation>,
         workspace: &ViewHandle<Workspace>,
         theme: &Theme,
-        cx: &mut RenderContext<Self>,
+        cx: &mut ViewContext<Self>,
     ) -> ElementBox {
         let project_id = workspace.read(cx).project().read(cx).remote_id();
         let room = ActiveCall::global(cx).read(cx).room();
@@ -804,7 +804,7 @@ impl CollabTitlebarItem {
         workspace: &ViewHandle<Workspace>,
         location: Option<ParticipantLocation>,
         mut style: AvatarStyle,
-        cx: &RenderContext<Self>,
+        cx: &ViewContext<Self>,
     ) -> AvatarStyle {
         if let Some(location) = location {
             if let ParticipantLocation::SharedProject { project_id } = location {
@@ -840,7 +840,7 @@ impl CollabTitlebarItem {
     fn render_connection_status(
         &self,
         status: &client::Status,
-        cx: &mut RenderContext<Self>,
+        cx: &mut ViewContext<Self>,
     ) -> Option<ElementBox> {
         enum ConnectionStatusButton {}
 
@@ -927,7 +927,7 @@ impl Element for AvatarRibbon {
         path.line_to(bounds.upper_right() - vec2f(bounds.height(), 0.));
         path.curve_to(bounds.lower_right(), bounds.upper_right());
         path.line_to(bounds.lower_left());
-        cx.scene.push_path(path.build(self.color, None));
+        scene.push_path(path.build(self.color, None));
     }
 
     fn rect_for_text_range(

crates/collab_ui/src/collaborator_list_popover.rs 🔗

@@ -1,10 +1,7 @@
 use call::ActiveCall;
 use client::UserStore;
 use gpui::Action;
-use gpui::{
-    actions, elements::*, platform::MouseButton, Entity, ModelHandle, RenderContext, View,
-    ViewContext,
-};
+use gpui::{actions, elements::*, platform::MouseButton, Entity, ModelHandle, View, ViewContext};
 use settings::Settings;
 
 use crate::collab_titlebar_item::ToggleCollaboratorList;
@@ -21,7 +18,7 @@ enum Collaborator {
 actions!(collaborator_list_popover, [NoOp]);
 
 pub(crate) struct CollaboratorListPopover {
-    list_state: ListState,
+    list_state: ListState<Self>,
 }
 
 impl Entity for CollaboratorListPopover {
@@ -33,7 +30,7 @@ impl View for CollaboratorListPopover {
         "CollaboratorListPopover"
     }
 
-    fn render(&mut self, cx: &mut RenderContext<Self>) -> ElementBox {
+    fn render(&mut self, cx: &mut ViewContext<Self>) -> ElementBox {
         let theme = cx.global::<Settings>().theme.clone();
 
         MouseEventHandler::<Self>::new(0, cx, |_, _| {
@@ -120,7 +117,7 @@ fn render_collaborator_list_entry<UA: Action + Clone, IA: Action + Clone>(
     icon: Svg,
     icon_action: IA,
     icon_tooltip: String,
-    cx: &mut RenderContext<CollaboratorListPopover>,
+    cx: &mut ViewContext<CollaboratorListPopover>,
 ) -> ElementBox {
     enum Username {}
     enum UsernameTooltip {}

crates/collab_ui/src/contact_finder.rs 🔗

@@ -1,7 +1,7 @@
 use client::{ContactRequestStatus, User, UserStore};
 use gpui::{
-    elements::*, AnyViewHandle, AppContext, Entity, ModelHandle, MouseState, RenderContext, Task,
-    View, ViewContext, ViewHandle,
+    elements::*, AnyViewHandle, AppContext, Entity, ModelHandle, MouseState, Task, View,
+    ViewContext, ViewHandle,
 };
 use picker::{Picker, PickerDelegate};
 use settings::Settings;
@@ -32,7 +32,7 @@ impl View for ContactFinder {
         "ContactFinder"
     }
 
-    fn render(&mut self, cx: &mut RenderContext<Self>) -> ElementBox {
+    fn render(&mut self, cx: &mut ViewContext<Self>) -> ElementBox {
         ChildView::new(&self.picker, cx).boxed()
     }
 

crates/collab_ui/src/contact_list.rs 🔗

@@ -11,7 +11,7 @@ use gpui::{
     impl_actions, impl_internal_actions,
     keymap_matcher::KeymapContext,
     platform::{CursorStyle, MouseButton, PromptLevel},
-    AppContext, Entity, ModelHandle, RenderContext, Subscription, View, ViewContext, ViewHandle,
+    AppContext, Entity, ModelHandle, Subscription, View, ViewContext, ViewHandle,
 };
 use menu::{Confirm, SelectNext, SelectPrev};
 use project::Project;
@@ -799,7 +799,7 @@ impl ContactList {
         is_last: bool,
         is_selected: bool,
         theme: &theme::ContactList,
-        cx: &mut RenderContext<Self>,
+        cx: &mut ViewContext<Self>,
     ) -> ElementBox {
         let font_cache = cx.font_cache();
         let host_avatar_height = theme
@@ -834,7 +834,7 @@ impl ContactList {
                                 let start_y = bounds.min_y();
                                 let end_y = bounds.min_y() + baseline_offset - (cap_height / 2.);
 
-                                cx.scene.push_quad(gpui::Quad {
+                                scene.push_quad(gpui::Quad {
                                     bounds: RectF::from_points(
                                         vec2f(start_x, start_y),
                                         vec2f(
@@ -846,7 +846,7 @@ impl ContactList {
                                     border: gpui::Border::default(),
                                     corner_radius: 0.,
                                 });
-                                cx.scene.push_quad(gpui::Quad {
+                                scene.push_quad(gpui::Quad {
                                     bounds: RectF::from_points(
                                         vec2f(start_x, end_y),
                                         vec2f(end_x, end_y + tree_branch.width),
@@ -898,7 +898,7 @@ impl ContactList {
         is_last: bool,
         is_selected: bool,
         theme: &theme::ContactList,
-        cx: &mut RenderContext<Self>,
+        cx: &mut ViewContext<Self>,
     ) -> ElementBox {
         let font_cache = cx.font_cache();
         let host_avatar_height = theme
@@ -932,7 +932,7 @@ impl ContactList {
                                     let end_y =
                                         bounds.min_y() + baseline_offset - (cap_height / 2.);
 
-                                    cx.scene.push_quad(gpui::Quad {
+                                    scene.push_quad(gpui::Quad {
                                         bounds: RectF::from_points(
                                             vec2f(start_x, start_y),
                                             vec2f(
@@ -944,7 +944,7 @@ impl ContactList {
                                         border: gpui::Border::default(),
                                         corner_radius: 0.,
                                     });
-                                    cx.scene.push_quad(gpui::Quad {
+                                    scene.push_quad(gpui::Quad {
                                         bounds: RectF::from_points(
                                             vec2f(start_x, end_y),
                                             vec2f(end_x, end_y + tree_branch.width),
@@ -999,7 +999,7 @@ impl ContactList {
         theme: &theme::ContactList,
         is_selected: bool,
         is_collapsed: bool,
-        cx: &mut RenderContext<Self>,
+        cx: &mut ViewContext<Self>,
     ) -> ElementBox {
         enum Header {}
         enum LeaveCallContactList {}
@@ -1077,7 +1077,7 @@ impl ContactList {
         project: &ModelHandle<Project>,
         theme: &theme::ContactList,
         is_selected: bool,
-        cx: &mut RenderContext<Self>,
+        cx: &mut ViewContext<Self>,
     ) -> ElementBox {
         let online = contact.online;
         let busy = contact.busy || calling;
@@ -1194,7 +1194,7 @@ impl ContactList {
         theme: &theme::ContactList,
         is_incoming: bool,
         is_selected: bool,
-        cx: &mut RenderContext<Self>,
+        cx: &mut ViewContext<Self>,
     ) -> ElementBox {
         enum Decline {}
         enum Accept {}
@@ -1331,7 +1331,7 @@ impl View for ContactList {
         cx
     }
 
-    fn render(&mut self, cx: &mut RenderContext<Self>) -> ElementBox {
+    fn render(&mut self, cx: &mut ViewContext<Self>) -> ElementBox {
         enum AddContact {}
         let theme = cx.global::<Settings>().theme.clone();
 

crates/collab_ui/src/contact_notification.rs 🔗

@@ -3,8 +3,7 @@ use std::sync::Arc;
 use crate::notifications::render_user_notification;
 use client::{ContactEventKind, User, UserStore};
 use gpui::{
-    elements::*, impl_internal_actions, AppContext, Entity, ModelHandle, RenderContext, View,
-    ViewContext,
+    elements::*, impl_internal_actions, AppContext, Entity, ModelHandle, View, ViewContext,
 };
 use workspace::notifications::Notification;
 
@@ -43,7 +42,7 @@ impl View for ContactNotification {
         "ContactNotification"
     }
 
-    fn render(&mut self, cx: &mut RenderContext<Self>) -> ElementBox {
+    fn render(&mut self, cx: &mut ViewContext<Self>) -> ElementBox {
         match self.kind {
             ContactEventKind::Requested => render_user_notification(
                 self.user.clone(),

crates/collab_ui/src/contacts_popover.rs 🔗

@@ -1,8 +1,8 @@
 use crate::{contact_finder::ContactFinder, contact_list::ContactList, ToggleContactsMenu};
 use client::UserStore;
 use gpui::{
-    actions, elements::*, platform::MouseButton, AppContext, Entity, ModelHandle, RenderContext,
-    View, ViewContext, ViewHandle,
+    actions, elements::*, platform::MouseButton, AppContext, Entity, ModelHandle, View,
+    ViewContext, ViewHandle,
 };
 use project::Project;
 use settings::Settings;
@@ -91,7 +91,7 @@ impl View for ContactsPopover {
         "ContactsPopover"
     }
 
-    fn render(&mut self, cx: &mut RenderContext<Self>) -> ElementBox {
+    fn render(&mut self, cx: &mut ViewContext<Self>) -> ElementBox {
         let theme = cx.global::<Settings>().theme.clone();
         let child = match &self.child {
             Child::ContactList(child) => ChildView::new(child, cx),

crates/collab_ui/src/face_pile.rs 🔗

@@ -37,7 +37,7 @@ impl Element for FacePile {
 
         let mut width = 0.;
         for face in &mut self.faces {
-            width += face.layout(constraint, cx).x();
+            width += face.layout(constraint, view, cx).x();
         }
         width -= self.overlap * self.faces.len().saturating_sub(1) as f32;
 
@@ -60,7 +60,7 @@ impl Element for FacePile {
             let size = face.size();
             origin_x -= size.x();
             cx.paint_layer(None, |cx| {
-                face.paint(vec2f(origin_x, origin_y), visible_bounds, cx);
+                face.paint(scene, vec2f(origin_x, origin_y), visible_bounds, view, cx);
             });
             origin_x += self.overlap;
         }

crates/collab_ui/src/incoming_call_notification.rs 🔗

@@ -6,7 +6,7 @@ use gpui::{
     geometry::{rect::RectF, vector::vec2f},
     impl_internal_actions,
     platform::{CursorStyle, MouseButton, WindowBounds, WindowKind, WindowOptions},
-    AppContext, Entity, RenderContext, View, ViewContext,
+    AppContext, Entity, View, ViewContext,
 };
 use settings::Settings;
 use util::ResultExt;
@@ -99,7 +99,7 @@ impl IncomingCallNotification {
         }
     }
 
-    fn render_caller(&self, cx: &mut RenderContext<Self>) -> ElementBox {
+    fn render_caller(&self, cx: &mut ViewContext<Self>) -> ElementBox {
         let theme = &cx.global::<Settings>().theme.incoming_call_notification;
         let default_project = proto::ParticipantProject::default();
         let initial_project = self
@@ -165,7 +165,7 @@ impl IncomingCallNotification {
             .boxed()
     }
 
-    fn render_buttons(&self, cx: &mut RenderContext<Self>) -> ElementBox {
+    fn render_buttons(&self, cx: &mut ViewContext<Self>) -> ElementBox {
         enum Accept {}
         enum Decline {}
 
@@ -222,7 +222,7 @@ impl View for IncomingCallNotification {
         "IncomingCallNotification"
     }
 
-    fn render(&mut self, cx: &mut RenderContext<Self>) -> gpui::ElementBox {
+    fn render(&mut self, cx: &mut ViewContext<Self>) -> gpui::ElementBox {
         let background = cx
             .global::<Settings>()
             .theme

crates/collab_ui/src/notifications.rs 🔗

@@ -2,7 +2,7 @@ use client::User;
 use gpui::{
     elements::*,
     platform::{CursorStyle, MouseButton},
-    Action, Element, ElementBox, RenderContext, View,
+    Action, Element, ElementBox, View, ViewContext,
 };
 use settings::Settings;
 use std::sync::Arc;
@@ -16,7 +16,7 @@ pub fn render_user_notification<V: View, A: Action + Clone>(
     body: Option<&'static str>,
     dismiss_action: A,
     buttons: Vec<(&'static str, Box<dyn Action>)>,
-    cx: &mut RenderContext<V>,
+    cx: &mut ViewContext<V>,
 ) -> ElementBox {
     let theme = cx.global::<Settings>().theme.clone();
     let theme = &theme.contact_notification;

crates/collab_ui/src/project_shared_notification.rs 🔗

@@ -6,7 +6,7 @@ use gpui::{
     elements::*,
     geometry::{rect::RectF, vector::vec2f},
     platform::{CursorStyle, MouseButton, WindowBounds, WindowKind, WindowOptions},
-    AppContext, Entity, RenderContext, View, ViewContext,
+    AppContext, Entity, View, ViewContext,
 };
 use settings::Settings;
 use std::sync::Arc;
@@ -104,7 +104,7 @@ impl ProjectSharedNotification {
         cx.remove_window(window_id);
     }
 
-    fn render_owner(&self, cx: &mut RenderContext<Self>) -> ElementBox {
+    fn render_owner(&self, cx: &mut ViewContext<Self>) -> ElementBox {
         let theme = &cx.global::<Settings>().theme.project_shared_notification;
         Flex::row()
             .with_children(self.owner.avatar.clone().map(|avatar| {
@@ -164,7 +164,7 @@ impl ProjectSharedNotification {
             .boxed()
     }
 
-    fn render_buttons(&self, cx: &mut RenderContext<Self>) -> ElementBox {
+    fn render_buttons(&self, cx: &mut ViewContext<Self>) -> ElementBox {
         enum Open {}
         enum Dismiss {}
 
@@ -227,7 +227,7 @@ impl View for ProjectSharedNotification {
         "ProjectSharedNotification"
     }
 
-    fn render(&mut self, cx: &mut RenderContext<Self>) -> gpui::ElementBox {
+    fn render(&mut self, cx: &mut ViewContext<Self>) -> gpui::ElementBox {
         let background = cx
             .global::<Settings>()
             .theme

crates/collab_ui/src/sharing_status_indicator.rs 🔗

@@ -3,7 +3,7 @@ use gpui::{
     color::Color,
     elements::{MouseEventHandler, Svg},
     platform::{Appearance, MouseButton},
-    AppContext, Element, ElementBox, Entity, RenderContext, View,
+    AppContext, Element, ElementBox, Entity, View, ViewContext,
 };
 use settings::Settings;
 
@@ -40,7 +40,7 @@ impl View for SharingStatusIndicator {
         "SharingStatusIndicator"
     }
 
-    fn render(&mut self, cx: &mut RenderContext<'_, Self>) -> ElementBox {
+    fn render(&mut self, cx: &mut ViewContext<'_, Self>) -> ElementBox {
         let color = match cx.appearance {
             Appearance::Light | Appearance::VibrantLight => Color::black(),
             Appearance::Dark | Appearance::VibrantDark => Color::white(),

crates/command_palette/src/command_palette.rs 🔗

@@ -4,8 +4,7 @@ use gpui::{
     actions,
     elements::{ChildView, Flex, Label, ParentElement},
     keymap_matcher::Keystroke,
-    Action, AnyViewHandle, AppContext, Element, Entity, MouseState, RenderContext, View,
-    ViewContext, ViewHandle,
+    Action, AnyViewHandle, AppContext, Element, Entity, MouseState, View, ViewContext, ViewHandle,
 };
 use picker::{Picker, PickerDelegate};
 use settings::Settings;
@@ -80,9 +79,7 @@ impl CommandPalette {
     fn toggle(_: &mut Workspace, _: &Toggle, cx: &mut ViewContext<Workspace>) {
         let workspace = cx.handle();
         let window_id = cx.window_id();
-        let focused_view_id = cx
-            .focused_view_id(window_id)
-            .unwrap_or_else(|| workspace.id());
+        let focused_view_id = cx.focused_view_id().unwrap_or_else(|| workspace.id());
 
         cx.as_mut().defer(move |cx| {
             let this = cx.add_view(&workspace, |cx| Self::new(focused_view_id, cx));
@@ -128,7 +125,7 @@ impl View for CommandPalette {
         "CommandPalette"
     }
 
-    fn render(&mut self, cx: &mut RenderContext<Self>) -> gpui::ElementBox {
+    fn render(&mut self, cx: &mut ViewContext<Self>) -> gpui::ElementBox {
         ChildView::new(&self.picker, cx).boxed()
     }
 

crates/context_menu/src/context_menu.rs 🔗

@@ -4,15 +4,13 @@ use gpui::{
     impl_internal_actions,
     keymap_matcher::KeymapContext,
     platform::{CursorStyle, MouseButton},
-    Action, AnyViewHandle, AppContext, Axis, Entity, MouseState, RenderContext, SizeConstraint,
-    Subscription, View, ViewContext,
+    Action, AnyViewHandle, AppContext, Axis, Entity, MouseState, SizeConstraint, Subscription,
+    View, ViewContext,
 };
 use menu::*;
 use settings::Settings;
 use std::{any::TypeId, borrow::Cow, time::Duration};
 
-pub type StaticItem = Box<dyn Fn(&mut AppContext) -> ElementBox>;
-
 #[derive(Copy, Clone, PartialEq)]
 struct Clicked;
 
@@ -28,8 +26,10 @@ pub fn init(cx: &mut AppContext) {
     cx.add_action(ContextMenu::cancel);
 }
 
+pub type StaticItem = Box<dyn Fn(&mut AppContext) -> ElementBox<ContextMenu>>;
+
 type ContextMenuItemBuilder =
-    Box<dyn Fn(&mut MouseState, &theme::ContextMenuItem) -> ElementBox>;
+    Box<dyn Fn(&mut MouseState, &theme::ContextMenuItem) -> ElementBox<ContextMenu>>;
 
 pub enum ContextMenuItemLabel {
     String(Cow<'static, str>),
@@ -142,7 +142,7 @@ impl View for ContextMenu {
         cx
     }
 
-    fn render(&mut self, cx: &mut RenderContext<Self>) -> ElementBox {
+    fn render(&mut self, cx: &mut ViewContext<Self>) -> ElementBox<Self> {
         if !self.visible {
             return Empty::new().boxed();
         }
@@ -152,10 +152,10 @@ impl View for ContextMenu {
         let expanded_menu = self
             .render_menu(cx)
             .constrained()
-            .dynamically(move |constraint, cx| {
+            .dynamically(move |constraint, view, cx| {
                 SizeConstraint::strict_along(
                     Axis::Horizontal,
-                    collapsed_menu.layout(constraint, cx).x(),
+                    collapsed_menu.layout(constraint, view, cx).x(),
                 )
             })
             .boxed();
@@ -315,7 +315,7 @@ impl ContextMenu {
             self.visible = true;
             self.show_count += 1;
             if !cx.is_self_focused() {
-                self.previously_focused_view_id = cx.focused_view_id(cx.window_id());
+                self.previously_focused_view_id = cx.focused_view_id();
             }
             cx.focus_self();
         } else {
@@ -328,7 +328,7 @@ impl ContextMenu {
         self.position_mode = mode;
     }
 
-    fn render_menu_for_measurement(&self, cx: &mut RenderContext<Self>) -> impl Element {
+    fn render_menu_for_measurement(&self, cx: &mut ViewContext<Self>) -> impl Element<ContextMenu> {
         let window_id = cx.window_id();
         let style = cx.global::<Settings>().theme.context_menu.clone();
         Flex::row()
@@ -415,14 +415,14 @@ impl ContextMenu {
             .with_style(style.container)
     }
 
-    fn render_menu(&self, cx: &mut RenderContext<Self>) -> impl Element {
+    fn render_menu(&self, cx: &mut ViewContext<Self>) -> impl Element<ContextMenu> {
         enum Menu {}
         enum MenuItem {}
 
         let style = cx.global::<Settings>().theme.context_menu.clone();
 
         let window_id = cx.window_id();
-        MouseEventHandler::<Menu>::new(0, cx, |_, cx| {
+        MouseEventHandler::<Menu, ContextMenu>::new(0, cx, |_, cx| {
             Flex::column()
                 .with_children(self.items.iter().enumerate().map(|(ix, item)| {
                     match item {
@@ -436,7 +436,7 @@ impl ContextMenu {
                                 }
                             };
 
-                            MouseEventHandler::<MenuItem>::new(ix, cx, |state, _| {
+                            MouseEventHandler::<MenuItem, ContextMenu>::new(ix, cx, |state, _| {
                                 let style =
                                     style.item.style_for(state, Some(ix) == self.selected_index);
 
@@ -467,14 +467,14 @@ impl ContextMenu {
                                     .boxed()
                             })
                             .with_cursor_style(CursorStyle::PointingHand)
-                            .on_up(MouseButton::Left, |_, _| {}) // Capture these events
-                            .on_down(MouseButton::Left, |_, _| {}) // Capture these events
-                            .on_click(MouseButton::Left, move |_, cx| {
+                            .on_up(MouseButton::Left, |_, _, _| {}) // Capture these events
+                            .on_down(MouseButton::Left, |_, _, _| {}) // Capture these events
+                            .on_click(MouseButton::Left, move |_, _, cx| {
                                 cx.dispatch_action(Clicked);
                                 let window_id = cx.window_id();
                                 cx.dispatch_any_action_at(window_id, view_id, action.boxed_clone());
                             })
-                            .on_drag(MouseButton::Left, |_, _| {})
+                            .on_drag(MouseButton::Left, |_, _, _| {})
                             .boxed()
                         }
 
@@ -492,7 +492,7 @@ impl ContextMenu {
                 .with_style(style.container)
                 .boxed()
         })
-        .on_down_out(MouseButton::Left, |_, cx| cx.dispatch_action(Cancel))
-        .on_down_out(MouseButton::Right, |_, cx| cx.dispatch_action(Cancel))
+        .on_down_out(MouseButton::Left, |_, _, cx| cx.dispatch_action(Cancel))
+        .on_down_out(MouseButton::Right, |_, _, cx| cx.dispatch_action(Cancel))
     }
 }

crates/copilot/src/sign_in.rs 🔗

@@ -96,7 +96,7 @@ impl CopilotCodeVerification {
     fn render_device_code(
         data: &PromptUserDeviceFlow,
         style: &theme::Copilot,
-        cx: &mut gpui::RenderContext<Self>,
+        cx: &mut gpui::ViewContext<Self>,
     ) -> ElementBox {
         let copied = cx
             .read_from_clipboard()
@@ -145,7 +145,7 @@ impl CopilotCodeVerification {
     fn render_prompting_modal(
         data: &PromptUserDeviceFlow,
         style: &theme::Copilot,
-        cx: &mut gpui::RenderContext<Self>,
+        cx: &mut gpui::ViewContext<Self>,
     ) -> ElementBox {
         Flex::column()
             .with_children([
@@ -205,7 +205,7 @@ impl CopilotCodeVerification {
     }
     fn render_enabled_modal(
         style: &theme::Copilot,
-        cx: &mut gpui::RenderContext<Self>,
+        cx: &mut gpui::ViewContext<Self>,
     ) -> ElementBox {
         let enabled_style = &style.auth.authorized;
         Flex::column()
@@ -254,7 +254,7 @@ impl CopilotCodeVerification {
     }
     fn render_unauthorized_modal(
         style: &theme::Copilot,
-        cx: &mut gpui::RenderContext<Self>,
+        cx: &mut gpui::ViewContext<Self>,
     ) -> ElementBox {
         let unauthorized_style = &style.auth.not_authorized;
 
@@ -333,7 +333,7 @@ impl View for CopilotCodeVerification {
         cx.notify()
     }
 
-    fn render(&mut self, cx: &mut gpui::RenderContext<'_, Self>) -> gpui::ElementBox {
+    fn render(&mut self, cx: &mut gpui::ViewContext<'_, Self>) -> gpui::ElementBox {
         let style = cx.global::<Settings>().theme.clone();
 
         modal("Connect Copilot to Zed", &style.copilot.modal, cx, |cx| {

crates/copilot_button/src/copilot_button.rs 🔗

@@ -6,8 +6,8 @@ use gpui::{
     elements::*,
     impl_internal_actions,
     platform::{CursorStyle, MouseButton},
-    AppContext, Element, ElementBox, Entity, MouseState, RenderContext, Subscription, View,
-    ViewContext, ViewHandle,
+    AppContext, Element, ElementBox, Entity, MouseState, Subscription, View, ViewContext,
+    ViewHandle,
 };
 use settings::{settings_file::SettingsFile, Settings};
 use workspace::{
@@ -91,7 +91,7 @@ impl View for CopilotButton {
         "CopilotButton"
     }
 
-    fn render(&mut self, cx: &mut RenderContext<'_, Self>) -> ElementBox {
+    fn render(&mut self, cx: &mut ViewContext<'_, Self>) -> ElementBox {
         let settings = cx.global::<Settings>();
 
         if !settings.enable_copilot_integration {

crates/diagnostics/src/diagnostics.rs 🔗

@@ -11,8 +11,7 @@ use editor::{
 };
 use gpui::{
     actions, elements::*, fonts::TextStyle, impl_internal_actions, serde_json, AnyViewHandle,
-    AppContext, Entity, ModelHandle, RenderContext, Task, View, ViewContext, ViewHandle,
-    WeakViewHandle,
+    AppContext, Entity, ModelHandle, Task, View, ViewContext, ViewHandle, WeakViewHandle,
 };
 use language::{
     Anchor, Bias, Buffer, Diagnostic, DiagnosticEntry, DiagnosticSeverity, Point, Selection,
@@ -87,7 +86,7 @@ impl View for ProjectDiagnosticsEditor {
         "ProjectDiagnosticsEditor"
     }
 
-    fn render(&mut self, cx: &mut RenderContext<Self>) -> ElementBox {
+    fn render(&mut self, cx: &mut ViewContext<Self>) -> ElementBox {
         if self.path_states.is_empty() {
             let theme = &cx.global::<Settings>().theme.project_diagnostics;
             Label::new("No problems in workspace", theme.empty_message.clone())

crates/diagnostics/src/items.rs 🔗

@@ -3,8 +3,8 @@ use editor::{Editor, GoToDiagnostic};
 use gpui::{
     elements::*,
     platform::{CursorStyle, MouseButton},
-    serde_json, AppContext, Entity, ModelHandle, RenderContext, Subscription, View, ViewContext,
-    ViewHandle, WeakViewHandle,
+    serde_json, AppContext, Entity, ModelHandle, Subscription, View, ViewContext, ViewHandle,
+    WeakViewHandle,
 };
 use language::Diagnostic;
 use project::Project;
@@ -84,7 +84,7 @@ impl View for DiagnosticIndicator {
         "DiagnosticIndicator"
     }
 
-    fn render(&mut self, cx: &mut RenderContext<Self>) -> ElementBox {
+    fn render(&mut self, cx: &mut ViewContext<Self>) -> ElementBox {
         enum Summary {}
         enum Message {}
 

crates/drag_and_drop/src/drag_and_drop.rs 🔗

@@ -6,7 +6,7 @@ use gpui::{
     geometry::{rect::RectF, vector::Vector2F},
     platform::{CursorStyle, MouseButton},
     scene::{MouseDown, MouseDrag},
-    AppContext, Element, ElementBox, EventContext, RenderContext, View, WeakViewHandle,
+    AppContext, Element, ElementBox, View, ViewContext, WeakViewHandle,
 };
 
 const DEAD_ZONE: f32 = 4.;
@@ -26,7 +26,7 @@ enum State<V: View> {
         region_offset: Vector2F,
         region: RectF,
         payload: Rc<dyn Any + 'static>,
-        render: Rc<dyn Fn(Rc<dyn Any>, &mut RenderContext<V>) -> ElementBox>,
+        render: Rc<dyn Fn(Rc<dyn Any>, &mut ViewContext<V>) -> ElementBox<V>>,
     },
     Canceled,
 }
@@ -111,7 +111,7 @@ impl<V: View> DragAndDrop<V> {
         })
     }
 
-    pub fn drag_started(event: MouseDown, cx: &mut EventContext) {
+    pub fn drag_started(event: MouseDown, cx: &mut ViewContext<V>) {
         cx.update_global(|this: &mut Self, _| {
             this.currently_dragged = Some(State::Down {
                 region_offset: event.position - event.region.origin(),
@@ -123,8 +123,8 @@ impl<V: View> DragAndDrop<V> {
     pub fn dragging<T: Any>(
         event: MouseDrag,
         payload: Rc<T>,
-        cx: &mut EventContext,
-        render: Rc<impl 'static + Fn(&T, &mut RenderContext<V>) -> ElementBox>,
+        cx: &mut ViewContext<V>,
+        render: Rc<impl 'static + Fn(&T, &mut ViewContext<V>) -> ElementBox<V>>,
     ) {
         let window_id = cx.window_id();
         cx.update_global(|this: &mut Self, cx| {
@@ -178,7 +178,7 @@ impl<V: View> DragAndDrop<V> {
         });
     }
 
-    pub fn render(cx: &mut RenderContext<V>) -> Option<ElementBox> {
+    pub fn render(cx: &mut ViewContext<V>) -> Option<ElementBox<V>> {
         enum DraggedElementHandler {}
         cx.global::<Self>()
             .currently_dragged
@@ -202,20 +202,22 @@ impl<V: View> DragAndDrop<V> {
                         let position = position - region_offset;
                         Some(
                             Overlay::new(
-                                MouseEventHandler::<DraggedElementHandler>::new(0, cx, |_, cx| {
-                                    render(payload, cx)
-                                })
+                                MouseEventHandler::<DraggedElementHandler, V>::new(
+                                    0,
+                                    cx,
+                                    |_, cx| render(payload, cx),
+                                )
                                 .with_cursor_style(CursorStyle::Arrow)
-                                .on_up(MouseButton::Left, |_, cx| {
-                                    cx.defer(|cx| {
+                                .on_up(MouseButton::Left, |_, _, cx| {
+                                    cx.defer(|_, cx| {
                                         cx.update_global::<Self, _, _>(|this, cx| {
                                             this.finish_dragging(cx)
                                         });
                                     });
                                     cx.propagate_event();
                                 })
-                                .on_up_out(MouseButton::Left, |_, cx| {
-                                    cx.defer(|cx| {
+                                .on_up_out(MouseButton::Left, |_, _, cx| {
+                                    cx.defer(|_, cx| {
                                         cx.update_global::<Self, _, _>(|this, cx| {
                                             this.finish_dragging(cx)
                                         });
@@ -234,22 +236,22 @@ impl<V: View> DragAndDrop<V> {
                     }
 
                     State::Canceled => Some(
-                        MouseEventHandler::<DraggedElementHandler>::new(0, cx, |_, _| {
+                        MouseEventHandler::<DraggedElementHandler, V>::new(0, cx, |_, _| {
                             Empty::new()
                                 .constrained()
                                 .with_width(0.)
                                 .with_height(0.)
                                 .boxed()
                         })
-                        .on_up(MouseButton::Left, |_, cx| {
-                            cx.defer(|cx| {
+                        .on_up(MouseButton::Left, |_, _, cx| {
+                            cx.defer(|_, cx| {
                                 cx.update_global::<Self, _, _>(|this, _| {
                                     this.currently_dragged = None;
                                 });
                             });
                         })
-                        .on_up_out(MouseButton::Left, |_, cx| {
-                            cx.defer(|cx| {
+                        .on_up_out(MouseButton::Left, |_, _, cx| {
+                            cx.defer(|_, cx| {
                                 cx.update_global::<Self, _, _>(|this, _| {
                                     this.currently_dragged = None;
                                 });
@@ -294,32 +296,32 @@ impl<V: View> DragAndDrop<V> {
     }
 }
 
-pub trait Draggable {
-    fn as_draggable<V: View, P: Any>(
+pub trait Draggable<V: View> {
+    fn as_draggable<P: Any>(
         self,
         payload: P,
-        render: impl 'static + Fn(&P, &mut RenderContext<V>) -> ElementBox,
+        render: impl 'static + Fn(&P, &mut ViewContext<V>) -> ElementBox<V>,
     ) -> Self
     where
         Self: Sized;
 }
 
-impl<Tag> Draggable for MouseEventHandler<Tag> {
-    fn as_draggable<V: View, P: Any>(
+impl<Tag, V: View> Draggable<V> for MouseEventHandler<Tag, V> {
+    fn as_draggable<P: Any>(
         self,
         payload: P,
-        render: impl 'static + Fn(&P, &mut RenderContext<V>) -> ElementBox,
+        render: impl 'static + Fn(&P, &mut ViewContext<V>) -> ElementBox<V>,
     ) -> Self
     where
         Self: Sized,
     {
         let payload = Rc::new(payload);
         let render = Rc::new(render);
-        self.on_down(MouseButton::Left, move |e, cx| {
+        self.on_down(MouseButton::Left, move |e, _, cx| {
             cx.propagate_event();
             DragAndDrop::<V>::drag_started(e, cx);
         })
-        .on_drag(MouseButton::Left, move |e, cx| {
+        .on_drag(MouseButton::Left, move |e, _, cx| {
             let payload = payload.clone();
             let render = render.clone();
             DragAndDrop::<V>::dragging(e, payload, cx, render)

crates/editor/src/display_map/block_map.rs 🔗

@@ -4,7 +4,7 @@ use super::{
 };
 use crate::{Anchor, ExcerptId, ExcerptRange, ToPoint as _};
 use collections::{Bound, HashMap, HashSet};
-use gpui::{fonts::HighlightStyle, RenderContext, ElementBox};
+use gpui::{fonts::HighlightStyle, ElementBox, ViewContext};
 use language::{BufferSnapshot, Chunk, Patch, Point};
 use parking_lot::Mutex;
 use std::{
@@ -81,7 +81,7 @@ pub enum BlockStyle {
 }
 
 pub struct BlockContext<'a, 'b> {
-    pub cx: &'b mut RenderContext<'a, crate::Editor>,
+    pub cx: &'b mut ViewContext<'a, crate::Editor>,
     pub anchor_x: f32,
     pub scroll_x: f32,
     pub gutter_width: f32,
@@ -933,7 +933,7 @@ impl BlockDisposition {
 }
 
 impl<'a, 'b> Deref for BlockContext<'a, 'b> {
-    type Target = RenderContext<'a, crate::Editor>;
+    type Target = ViewContext<'a, crate::Editor>;
 
     fn deref(&self) -> &Self::Target {
         self.cx

crates/editor/src/editor.rs 🔗

@@ -42,7 +42,7 @@ use gpui::{
     platform::{CursorStyle, MouseButton},
     serde_json::{self, json},
     AnyViewHandle, AppContext, AsyncAppContext, ClipboardItem, Element, ElementBox, Entity,
-    ModelHandle, RenderContext, Subscription, Task, View, ViewContext, ViewHandle, WeakViewHandle,
+    ModelHandle, Subscription, Task, View, ViewContext, ViewHandle, WeakViewHandle,
 };
 use highlight_matching_bracket::refresh_matching_bracket_highlights;
 use hover_popover::{hide_hover, HideHover, HoverState};
@@ -721,7 +721,7 @@ impl ContextMenu {
         &self,
         cursor_position: DisplayPoint,
         style: EditorStyle,
-        cx: &mut RenderContext<Editor>,
+        cx: &mut ViewContext<Editor>,
     ) -> (DisplayPoint, ElementBox) {
         match self {
             ContextMenu::Completions(menu) => (cursor_position, menu.render(style, cx)),
@@ -774,7 +774,7 @@ impl CompletionsMenu {
         !self.matches.is_empty()
     }
 
-    fn render(&self, style: EditorStyle, cx: &mut RenderContext<Editor>) -> ElementBox {
+    fn render(&self, style: EditorStyle, cx: &mut ViewContext<Editor>) -> ElementBox {
         enum CompletionTag {}
 
         let completions = self.completions.clone();
@@ -950,7 +950,7 @@ impl CodeActionsMenu {
         &self,
         mut cursor_position: DisplayPoint,
         style: EditorStyle,
-        cx: &mut RenderContext<Editor>,
+        cx: &mut ViewContext<Editor>,
     ) -> (DisplayPoint, ElementBox) {
         enum ActionTag {}
 
@@ -2928,7 +2928,7 @@ impl Editor {
         &self,
         style: &EditorStyle,
         active: bool,
-        cx: &mut RenderContext<Self>,
+        cx: &mut ViewContext<Self>,
     ) -> Option<ElementBox> {
         if self.available_code_actions.is_some() {
             enum CodeActions {}
@@ -2959,7 +2959,7 @@ impl Editor {
         gutter_hovered: bool,
         line_height: f32,
         gutter_margin: f32,
-        cx: &mut RenderContext<Self>,
+        cx: &mut ViewContext<Self>,
     ) -> Vec<Option<ElementBox>> {
         enum FoldIndicators {}
 
@@ -3027,7 +3027,7 @@ impl Editor {
         &self,
         cursor_position: DisplayPoint,
         style: EditorStyle,
-        cx: &mut RenderContext<Editor>,
+        cx: &mut ViewContext<Editor>,
     ) -> Option<(DisplayPoint, ElementBox)> {
         self.context_menu
             .as_ref()
@@ -6795,7 +6795,7 @@ impl Entity for Editor {
 }
 
 impl View for Editor {
-    fn render(&mut self, cx: &mut RenderContext<Self>) -> ElementBox {
+    fn render(&mut self, cx: &mut ViewContext<Self>) -> ElementBox {
         let style = self.style(cx);
         let font_changed = self.display_map.update(cx, |map, cx| {
             map.set_fold_ellipses_color(style.folds.ellipses.text_color);
@@ -6804,7 +6804,7 @@ impl View for Editor {
 
         if font_changed {
             let handle = self.handle.clone();
-            cx.defer(move |cx| {
+            cx.defer(move |cx: &mut ViewContext<Editor>| {
                 if let Some(editor) = handle.upgrade(cx) {
                     editor.update(cx, |editor, cx| {
                         hide_hover(editor, &HideHover, cx);

crates/editor/src/element.rs 🔗

@@ -31,8 +31,8 @@ use gpui::{
     json::{self, ToJson},
     platform::{CursorStyle, Modifiers, MouseButton, MouseButtonEvent, MouseMovedEvent},
     text_layout::{self, Line, RunStyle, TextLayoutCache},
-    AppContext, Axis, Border, CursorRegion, Element, ElementBox, EventContext, LayoutContext,
-    MouseRegion, PaintContext, Quad, SceneBuilder, SizeConstraint, ViewContext, WeakViewHandle,
+    AppContext, Axis, Border, CursorRegion, Element, ElementBox, MouseRegion, Quad, SceneBuilder,
+    SizeConstraint, ViewContext, WeakViewHandle,
 };
 use itertools::Itertools;
 use json::json;
@@ -124,7 +124,7 @@ impl EditorElement {
         cx: &mut PaintContext,
     ) {
         enum EditorElementMouseHandlers {}
-        cx.scene.push_mouse_region(
+        scene.push_mouse_region(
             MouseRegion::new::<EditorElementMouseHandlers>(view.id(), view.id(), visible_bounds)
                 .on_down(MouseButton::Left, {
                     let position_map = position_map.clone();
@@ -216,7 +216,7 @@ impl EditorElement {
         );
 
         enum GutterHandlers {}
-        cx.scene.push_mouse_region(
+        scene.push_mouse_region(
             MouseRegion::new::<GutterHandlers>(view.id(), view.id() + 1, gutter_bounds).on_hover(
                 |hover, cx| {
                     cx.dispatch_action(GutterHover {
@@ -409,7 +409,7 @@ impl EditorElement {
         }: MouseMovedEvent,
         position_map: &PositionMap,
         text_bounds: RectF,
-        cx: &mut EventContext,
+        cx: &mut ViewContext<Editor>,
     ) -> bool {
         // This will be handled more correctly once https://github.com/zed-industries/zed/issues/1218 is completed
         // Don't trigger hover popover if mouse is hovering over context menu
@@ -432,7 +432,7 @@ impl EditorElement {
         precise: bool,
         position_map: &PositionMap,
         bounds: RectF,
-        cx: &mut EventContext,
+        cx: &mut ViewContext<Editor>,
     ) -> bool {
         if !bounds.contains_point(position) {
             return false;
@@ -465,21 +465,22 @@ impl EditorElement {
 
     fn paint_background(
         &self,
+        scene: &mut SceneBuilder,
         gutter_bounds: RectF,
         text_bounds: RectF,
         layout: &LayoutState,
-        cx: &mut PaintContext,
+        cx: &mut ViewContext<Editor>,
     ) {
         let bounds = gutter_bounds.union_rect(text_bounds);
         let scroll_top =
             layout.position_map.snapshot.scroll_position().y() * layout.position_map.line_height;
-        cx.scene.push_quad(Quad {
+        scene.push_quad(Quad {
             bounds: gutter_bounds,
             background: Some(self.style.gutter_background),
             border: Border::new(0., Color::transparent_black()),
             corner_radius: 0.,
         });
-        cx.scene.push_quad(Quad {
+        c.push_quad(Quad {
             bounds: text_bounds,
             background: Some(self.style.background),
             border: Border::new(0., Color::transparent_black()),
@@ -507,7 +508,7 @@ impl EditorElement {
                         bounds.width(),
                         layout.position_map.line_height * (end_row - start_row + 1) as f32,
                     );
-                    cx.scene.push_quad(Quad {
+                    scene.push_quad(Quad {
                         bounds: RectF::new(origin, size),
                         background: Some(self.style.active_line_background),
                         border: Border::default(),
@@ -527,7 +528,7 @@ impl EditorElement {
                     bounds.width(),
                     layout.position_map.line_height * highlighted_rows.len() as f32,
                 );
-                cx.scene.push_quad(Quad {
+                scene.push_quad(Quad {
                     bounds: RectF::new(origin, size),
                     background: Some(self.style.highlighted_line_background),
                     border: Border::default(),
@@ -539,9 +540,11 @@ impl EditorElement {
 
     fn paint_gutter(
         &mut self,
+        scene: &mut SceneBuilder,
         bounds: RectF,
         visible_bounds: RectF,
         layout: &mut LayoutState,
+        editor: &mut Editor,
         cx: &mut PaintContext,
     ) {
         let line_height = layout.position_map.line_height;
@@ -569,7 +572,7 @@ impl EditorElement {
                         ix as f32 * line_height - (scroll_top % line_height),
                     );
 
-                line.paint(line_origin, visible_bounds, line_height, cx);
+                line.paint(scene, line_origin, visible_bounds, line_height, cx);
             }
         }
 
@@ -586,7 +589,7 @@ impl EditorElement {
 
                 let indicator_origin = bounds.origin() + position + centering_offset;
 
-                indicator.paint(indicator_origin, visible_bounds, cx);
+                indicator.paint(scene, indicator_origin, visible_bounds, editor, cx);
             }
         }
 
@@ -595,7 +598,13 @@ impl EditorElement {
             let mut y = *row as f32 * line_height - scroll_top;
             x += ((layout.gutter_padding + layout.gutter_margin) - indicator.size().x()) / 2.;
             y += (line_height - indicator.size().y()) / 2.;
-            indicator.paint(bounds.origin() + vec2f(x, y), visible_bounds, cx);
+            indicator.paint(
+                scene,
+                bounds.origin() + vec2f(x, y),
+                visible_bounds,
+                editor,
+                cx,
+            );
         }
     }
 
@@ -618,7 +627,7 @@ impl EditorElement {
                     let highlight_size = vec2f(width * 2., end_y - start_y);
                     let highlight_bounds = RectF::new(highlight_origin, highlight_size);
 
-                    cx.scene.push_quad(Quad {
+                    scene.push_quad(Quad {
                         bounds: highlight_bounds,
                         background: Some(diff_style.modified),
                         border: Border::new(0., Color::transparent_black()),
@@ -651,7 +660,7 @@ impl EditorElement {
                     let highlight_size = vec2f(width * 2., end_y - start_y);
                     let highlight_bounds = RectF::new(highlight_origin, highlight_size);
 
-                    cx.scene.push_quad(Quad {
+                    scene.push_quad(Quad {
                         bounds: highlight_bounds,
                         background: Some(diff_style.deleted),
                         border: Border::new(0., Color::transparent_black()),
@@ -673,7 +682,7 @@ impl EditorElement {
             let highlight_size = vec2f(width * 2., end_y - start_y);
             let highlight_bounds = RectF::new(highlight_origin, highlight_size);
 
-            cx.scene.push_quad(Quad {
+            scene.push_quad(Quad {
                 bounds: highlight_bounds,
                 background: Some(color),
                 border: Border::new(0., Color::transparent_black()),
@@ -684,9 +693,11 @@ impl EditorElement {
 
     fn paint_text(
         &mut self,
+        scene: &mut SceneBuilder,
         bounds: RectF,
         visible_bounds: RectF,
         layout: &mut LayoutState,
+        editor: &mut Editor,
         cx: &mut PaintContext,
     ) {
         let view = self.view(cx.app);
@@ -700,9 +711,9 @@ impl EditorElement {
         let content_origin = bounds.origin() + vec2f(layout.gutter_margin, 0.);
         let line_end_overshoot = 0.15 * layout.position_map.line_height;
 
-        cx.scene.push_layer(Some(bounds));
+        scene.push_layer(Some(bounds));
 
-        cx.scene.push_cursor_region(CursorRegion {
+        scene.push_cursor_region(CursorRegion {
             bounds,
             style: if !view.link_go_to_definition_state.definitions.is_empty() {
                 CursorStyle::PointingHand
@@ -715,6 +726,7 @@ impl EditorElement {
             self.style.folds.ellipses.corner_radius_factor * layout.position_map.line_height;
         for (id, range, color) in layout.fold_ranges.iter() {
             self.paint_highlighted_range(
+                scene,
                 range.clone(),
                 *color,
                 fold_corner_radius,
@@ -736,7 +748,7 @@ impl EditorElement {
                 line_end_overshoot,
                 &layout.position_map,
             ) {
-                cx.scene.push_cursor_region(CursorRegion {
+                scene.push_cursor_region(CursorRegion {
                     bounds: bound,
                     style: CursorStyle::PointingHand,
                 });
@@ -747,7 +759,7 @@ impl EditorElement {
                     .to_point(&layout.position_map.snapshot.display_snapshot)
                     .row;
 
-                cx.scene.push_mouse_region(
+                scene.push_mouse_region(
                     MouseRegion::new::<FoldMarkers>(self.view.id(), *id as usize, bound)
                         .on_click(MouseButton::Left, move |_, cx| {
                             cx.dispatch_action(UnfoldAt { buffer_row })
@@ -760,6 +772,7 @@ impl EditorElement {
 
         for (range, color) in &layout.highlighted_ranges {
             self.paint_highlighted_range(
+                scene,
                 range.clone(),
                 *color,
                 0.,
@@ -781,6 +794,7 @@ impl EditorElement {
 
             for selection in selections {
                 self.paint_highlighted_range(
+                    scene,
                     selection.range.clone(),
                     selection_style.selection,
                     corner_radius,
@@ -858,6 +872,7 @@ impl EditorElement {
             for (ix, line) in layout.position_map.line_layouts.iter().enumerate() {
                 let row = start_row + ix as u32;
                 line.paint(
+                    scene,
                     content_origin
                         + vec2f(
                             -scroll_left,
@@ -870,14 +885,16 @@ impl EditorElement {
             }
         }
 
-        cx.scene.push_layer(Some(bounds));
-        for cursor in cursors {
-            cursor.paint(content_origin, cx);
-        }
-        cx.scene.pop_layer();
+        scene.push_layer(Some(bounds));
+
+        scene.paint_layer(Some(bounds), |scene| {
+            for cursor in cursors {
+                cursor.paint(scene, content_origin, cx);
+            }
+        });
 
         if let Some((position, context_menu)) = layout.context_menu.as_mut() {
-            cx.scene.push_stacking_context(None, None);
+            scene.push_stacking_context(None, None);
             let cursor_row_layout =
                 &layout.position_map.line_layouts[(position.row() - start_row) as usize];
             let x = cursor_row_layout.x_for_index(position.column() as usize) - scroll_left;
@@ -897,16 +914,18 @@ impl EditorElement {
             }
 
             context_menu.paint(
+                scene,
                 list_origin,
                 RectF::from_points(Vector2F::zero(), vec2f(f32::MAX, f32::MAX)), // Let content bleed outside of editor
+                editor,
                 cx,
             );
 
-            cx.scene.pop_stacking_context();
+            scene.pop_stacking_context();
         }
 
         if let Some((position, hover_popovers)) = layout.hover_popovers.as_mut() {
-            cx.scene.push_stacking_context(None, None);
+            scene.push_stacking_context(None, None);
 
             // This is safe because we check on layout whether the required row is available
             let hovered_row_layout =
@@ -937,8 +956,10 @@ impl EditorElement {
                     }
 
                     hover_popover.paint(
+                        scene,
                         popover_origin,
                         RectF::from_points(Vector2F::zero(), vec2f(f32::MAX, f32::MAX)), // Let content bleed outside of editor
+                        editor,
                         cx,
                     );
 
@@ -957,8 +978,10 @@ impl EditorElement {
                     }
 
                     hover_popover.paint(
+                        scene,
                         popover_origin,
                         RectF::from_points(Vector2F::zero(), vec2f(f32::MAX, f32::MAX)), // Let content bleed outside of editor
+                        editor,
                         cx,
                     );
 
@@ -966,13 +989,19 @@ impl EditorElement {
                 }
             }
 
-            cx.scene.pop_stacking_context();
+            scene.pop_stacking_context();
         }
 
-        cx.scene.pop_layer();
+        scene.pop_layer();
     }
 
-    fn paint_scrollbar(&mut self, bounds: RectF, layout: &mut LayoutState, cx: &mut PaintContext) {
+    fn paint_scrollbar(
+        &mut self,
+        scene: &mut SceneBuilder,
+        bounds: RectF,
+        layout: &mut LayoutState,
+        cx: &mut ViewContext<Editor>,
+    ) {
         enum ScrollbarMouseHandlers {}
         if layout.mode != EditorMode::Full {
             return;
@@ -1008,13 +1037,13 @@ impl EditorElement {
         let thumb_bounds = RectF::from_points(vec2f(left, thumb_top), vec2f(right, thumb_bottom));
 
         if layout.show_scrollbars {
-            cx.scene.push_quad(Quad {
+            scene.push_quad(Quad {
                 bounds: track_bounds,
                 border: style.track.border,
                 background: style.track.background_color,
                 ..Default::default()
             });
-            cx.scene.push_quad(Quad {
+            scene.push_quad(Quad {
                 bounds: thumb_bounds,
                 border: style.thumb.border,
                 background: style.thumb.background_color,
@@ -1022,11 +1051,11 @@ impl EditorElement {
             });
         }
 
-        cx.scene.push_cursor_region(CursorRegion {
+        scene.push_cursor_region(CursorRegion {
             bounds: track_bounds,
             style: CursorStyle::Arrow,
         });
-        cx.scene.push_mouse_region(
+        scene.push_mouse_region(
             MouseRegion::new::<ScrollbarMouseHandlers>(view.id(), view.id(), track_bounds)
                 .on_move({
                     let view = view.clone();
@@ -1088,6 +1117,7 @@ impl EditorElement {
     #[allow(clippy::too_many_arguments)]
     fn paint_highlighted_range(
         &self,
+        scene: &mut SceneBuilder,
         range: Range<DisplayPoint>,
         color: Color,
         corner_radius: f32,
@@ -1097,7 +1127,7 @@ impl EditorElement {
         scroll_top: f32,
         scroll_left: f32,
         bounds: RectF,
-        cx: &mut PaintContext,
+        cx: &mut ViewContext<Self>,
     ) {
         let start_row = layout.visible_display_row_range.start;
         let end_row = layout.visible_display_row_range.end;
@@ -1141,15 +1171,17 @@ impl EditorElement {
                     .collect(),
             };
 
-            highlighted_range.paint(bounds, cx.scene);
+            highlighted_range.paint(bounds, scene);
         }
     }
 
     fn paint_blocks(
         &mut self,
+        scene: &mut SceneBuilder,
         bounds: RectF,
         visible_bounds: RectF,
         layout: &mut LayoutState,
+        editor: &mut Editor,
         cx: &mut PaintContext,
     ) {
         let scroll_position = layout.position_map.snapshot.scroll_position();
@@ -1165,7 +1197,9 @@ impl EditorElement {
             if !matches!(block.style, BlockStyle::Sticky) {
                 origin += vec2f(-scroll_left, 0.);
             }
-            block.element.paint(origin, visible_bounds, cx);
+            block
+                .element
+                .paint(scene, origin, visible_bounds, editor, cx);
         }
     }
 
@@ -1384,14 +1418,9 @@ impl EditorElement {
         style: &EditorStyle,
         line_layouts: &[text_layout::Line],
         include_root: bool,
+        editor: &mut Editor,
         cx: &mut LayoutContext,
     ) -> (f32, Vec<BlockLayout>) {
-        let editor = if let Some(editor) = self.view.upgrade(cx) {
-            editor
-        } else {
-            return Default::default();
-        };
-
         let tooltip_style = cx.global::<Settings>().theme.tooltip.clone();
         let scroll_x = snapshot.scroll_anchor.offset.x();
         let (fixed_blocks, non_fixed_blocks) = snapshot
@@ -1542,6 +1571,7 @@ impl EditorElement {
                     min: Vector2F::zero(),
                     max: vec2f(width, block.height() as f32 * line_height),
                 },
+                editor,
                 cx,
             );
             element
@@ -1847,6 +1877,7 @@ impl Element for EditorElement {
             &style,
             &line_layouts,
             include_root,
+            editor,
             cx,
         );
 
@@ -1924,6 +1955,7 @@ impl Element for EditorElement {
                         (12. * line_height).min((size.y() - line_height) / 2.),
                     ),
                 },
+                editor,
                 cx,
             );
         }
@@ -1934,6 +1966,7 @@ impl Element for EditorElement {
                     Axis::Vertical,
                     line_height * style.code_actions.vertical_scale,
                 ),
+                editor,
                 cx,
             );
         }
@@ -2014,7 +2047,7 @@ impl Element for EditorElement {
         cx: &mut PaintContext,
     ) -> Self::PaintState {
         let visible_bounds = bounds.intersection(visible_bounds).unwrap_or_default();
-        cx.scene.push_layer(Some(visible_bounds));
+        scene.push_layer(Some(visible_bounds));
 
         let gutter_bounds = RectF::new(bounds.origin(), layout.gutter_size);
         let text_bounds = RectF::new(
@@ -2033,20 +2066,20 @@ impl Element for EditorElement {
             cx,
         );
 
-        self.paint_background(gutter_bounds, text_bounds, layout, cx);
+        self.paint_background(scene, gutter_bounds, text_bounds, layout, cx);
         if layout.gutter_size.x() > 0. {
-            self.paint_gutter(gutter_bounds, visible_bounds, layout, cx);
+            self.paint_gutter(scene, gutter_bounds, visible_bounds, layout, editor, cx);
         }
-        self.paint_text(text_bounds, visible_bounds, layout, cx);
+        self.paint_text(scene, text_bounds, visible_bounds, layout, editor, cx);
 
-        cx.scene.push_layer(Some(bounds));
+        scene.push_layer(Some(bounds));
         if !layout.blocks.is_empty() {
-            self.paint_blocks(bounds, visible_bounds, layout, cx);
+            self.paint_blocks(scene, bounds, visible_bounds, layout, editor, cx);
         }
-        self.paint_scrollbar(bounds, layout, cx);
-        cx.scene.pop_layer();
+        self.paint_scrollbar(scene, bounds, layout, cx);
+        scene.pop_layer();
 
-        cx.scene.pop_layer();
+        scene.pop_layer();
     }
 
     fn rect_for_text_range(
@@ -2254,7 +2287,7 @@ impl Cursor {
         )
     }
 
-    pub fn paint(&self, origin: Vector2F, cx: &mut PaintContext) {
+    pub fn paint(&self, scene: &mut SceneBuilder, origin: Vector2F, cx: &mut AppContext) {
         let bounds = match self.shape {
             CursorShape::Bar => RectF::new(self.origin + origin, vec2f(2.0, self.line_height)),
             CursorShape::Block | CursorShape::Hollow => RectF::new(
@@ -2269,14 +2302,14 @@ impl Cursor {
 
         //Draw background or border quad
         if matches!(self.shape, CursorShape::Hollow) {
-            cx.scene.push_quad(Quad {
+            scene.push_quad(Quad {
                 bounds,
                 background: None,
                 border: Border::all(1., self.color),
                 corner_radius: 0.,
             });
         } else {
-            cx.scene.push_quad(Quad {
+            scene.push_quad(Quad {
                 bounds,
                 background: Some(self.color),
                 border: Default::default(),
@@ -2285,7 +2318,7 @@ impl Cursor {
         }
 
         if let Some(block_text) = &self.block_text {
-            block_text.paint(self.origin + origin, bounds, self.line_height, cx);
+            block_text.paint(scene, self.origin + origin, bounds, self.line_height, cx);
         }
     }
 

crates/editor/src/hover_popover.rs 🔗

@@ -4,7 +4,7 @@ use gpui::{
     elements::{Flex, MouseEventHandler, Padding, Text},
     impl_internal_actions,
     platform::{CursorStyle, MouseButton},
-    AppContext, Axis, Element, ElementBox, ModelHandle, RenderContext, Task, ViewContext,
+    AppContext, Axis, Element, ElementBox, ModelHandle, Task, ViewContext,
 };
 use language::{Bias, DiagnosticEntry, DiagnosticSeverity};
 use project::{HoverBlock, Project};
@@ -282,7 +282,7 @@ impl HoverState {
         snapshot: &EditorSnapshot,
         style: &EditorStyle,
         visible_rows: Range<u32>,
-        cx: &mut RenderContext<Editor>,
+        cx: &mut ViewContext<Editor>,
     ) -> Option<(DisplayPoint, Vec<ElementBox>)> {
         // If there is a diagnostic, position the popovers based on that.
         // Otherwise use the start of the hover range
@@ -323,7 +323,7 @@ pub struct InfoPopover {
 }
 
 impl InfoPopover {
-    pub fn render(&self, style: &EditorStyle, cx: &mut RenderContext<Editor>) -> ElementBox {
+    pub fn render(&self, style: &EditorStyle, cx: &mut ViewContext<Editor>) -> ElementBox {
         MouseEventHandler::<InfoPopover>::new(0, cx, |_, cx| {
             let mut flex = Flex::new(Axis::Vertical).scrollable::<HoverBlock, _>(1, None, cx);
             flex.extend(self.contents.iter().map(|content| {
@@ -378,7 +378,7 @@ pub struct DiagnosticPopover {
 }
 
 impl DiagnosticPopover {
-    pub fn render(&self, style: &EditorStyle, cx: &mut RenderContext<Editor>) -> ElementBox {
+    pub fn render(&self, style: &EditorStyle, cx: &mut ViewContext<Editor>) -> ElementBox {
         enum PrimaryDiagnostic {}
 
         let mut text_style = style.hover_popover.prose.clone();

crates/editor/src/items.rs 🔗

@@ -7,8 +7,8 @@ use anyhow::{anyhow, Context, Result};
 use collections::HashSet;
 use futures::future::try_join_all;
 use gpui::{
-    elements::*, geometry::vector::vec2f, AppContext, Entity, ModelHandle, RenderContext,
-    Subscription, Task, View, ViewContext, ViewHandle, WeakViewHandle,
+    elements::*, geometry::vector::vec2f, AppContext, Entity, ModelHandle, Subscription, Task,
+    View, ViewContext, ViewContext, ViewHandle, WeakViewHandle,
 };
 use language::{
     proto::serialize_anchor as serialize_text_anchor, Bias, Buffer, OffsetRangeExt, Point,
@@ -1078,7 +1078,7 @@ impl View for CursorPosition {
         "CursorPosition"
     }
 
-    fn render(&mut self, cx: &mut RenderContext<Self>) -> ElementBox {
+    fn render(&mut self, cx: &mut ViewContext<Self>) -> ElementBox {
         if let Some(position) = self.position {
             let theme = &cx.global::<Settings>().theme.workspace.status_bar;
             let mut text = format!("{},{}", position.row + 1, position.column + 1);

crates/feedback/src/deploy_feedback_button.rs 🔗

@@ -1,7 +1,7 @@
 use gpui::{
     elements::*,
     platform::{CursorStyle, MouseButton},
-    Entity, RenderContext, View, ViewContext,
+    Entity, View, ViewContext,
 };
 use settings::Settings;
 use workspace::{item::ItemHandle, StatusItemView};
@@ -27,7 +27,7 @@ impl View for DeployFeedbackButton {
         "DeployFeedbackButton"
     }
 
-    fn render(&mut self, cx: &mut RenderContext<'_, Self>) -> ElementBox {
+    fn render(&mut self, cx: &mut ViewContext<'_, Self>) -> ElementBox {
         let active = self.active;
         let theme = cx.global::<Settings>().theme.clone();
         Stack::new()

crates/feedback/src/feedback_editor.rs 🔗

@@ -12,8 +12,8 @@ use gpui::{
     actions,
     elements::{ChildView, Flex, Label, ParentElement, Svg},
     platform::PromptLevel,
-    serde_json, AnyViewHandle, AppContext, Element, ElementBox, Entity, ModelHandle, RenderContext,
-    Task, View, ViewContext, ViewHandle,
+    serde_json, AnyViewHandle, AppContext, Element, ElementBox, Entity, ModelHandle, Task, View,
+    ViewContext, ViewContext, ViewHandle,
 };
 use isahc::Request;
 use language::Buffer;
@@ -232,7 +232,7 @@ impl View for FeedbackEditor {
         "FeedbackEditor"
     }
 
-    fn render(&mut self, cx: &mut RenderContext<Self>) -> ElementBox {
+    fn render(&mut self, cx: &mut ViewContext<Self>) -> ElementBox {
         ChildView::new(&self.editor, cx).boxed()
     }
 

crates/feedback/src/feedback_info_text.rs 🔗

@@ -1,7 +1,7 @@
 use gpui::{
     elements::{Flex, Label, MouseEventHandler, ParentElement, Text},
     platform::{CursorStyle, MouseButton},
-    Element, ElementBox, Entity, RenderContext, View, ViewContext, ViewHandle,
+    Element, ElementBox, Entity, View, ViewContext, ViewHandle,
 };
 use settings::Settings;
 use workspace::{item::ItemHandle, ToolbarItemLocation, ToolbarItemView};
@@ -29,7 +29,7 @@ impl View for FeedbackInfoText {
         "FeedbackInfoText"
     }
 
-    fn render(&mut self, cx: &mut RenderContext<Self>) -> ElementBox {
+    fn render(&mut self, cx: &mut ViewContext<Self>) -> ElementBox {
         let theme = cx.global::<Settings>().theme.clone();
 
         Flex::row()

crates/feedback/src/submit_feedback_button.rs 🔗

@@ -1,7 +1,7 @@
 use gpui::{
     elements::{Label, MouseEventHandler},
     platform::{CursorStyle, MouseButton},
-    Element, ElementBox, Entity, RenderContext, View, ViewContext, ViewHandle,
+    Element, ElementBox, Entity, View, ViewContext, ViewHandle,
 };
 use settings::Settings;
 use workspace::{item::ItemHandle, ToolbarItemLocation, ToolbarItemView};
@@ -29,7 +29,7 @@ impl View for SubmitFeedbackButton {
         "SubmitFeedbackButton"
     }
 
-    fn render(&mut self, cx: &mut RenderContext<Self>) -> ElementBox {
+    fn render(&mut self, cx: &mut ViewContext<Self>) -> ElementBox {
         let theme = cx.global::<Settings>().theme.clone();
         enum SubmitFeedbackButton {}
         MouseEventHandler::<SubmitFeedbackButton>::new(0, cx, |state, _| {

crates/file_finder/src/file_finder.rs 🔗

@@ -1,7 +1,7 @@
 use fuzzy::PathMatch;
 use gpui::{
-    actions, elements::*, AnyViewHandle, AppContext, Entity, ModelHandle, MouseState,
-    RenderContext, Task, View, ViewContext, ViewHandle,
+    actions, elements::*, AnyViewHandle, AppContext, Entity, ModelHandle, MouseState, Task, View,
+    ViewContext, ViewHandle,
 };
 use picker::{Picker, PickerDelegate};
 use project::{PathMatchCandidateSet, Project, ProjectPath, WorktreeId};
@@ -50,7 +50,7 @@ impl View for FileFinder {
         "FileFinder"
     }
 
-    fn render(&mut self, cx: &mut RenderContext<Self>) -> ElementBox {
+    fn render(&mut self, cx: &mut ViewContext<Self>) -> ElementBox {
         ChildView::new(&self.picker, cx).boxed()
     }
 

crates/go_to_line/src/go_to_line.rs 🔗

@@ -3,7 +3,7 @@ use std::sync::Arc;
 use editor::{display_map::ToDisplayPoint, scroll::autoscroll::Autoscroll, DisplayPoint, Editor};
 use gpui::{
     actions, elements::*, geometry::vector::Vector2F, AnyViewHandle, AppContext, Axis, Entity,
-    RenderContext, View, ViewContext, ViewHandle,
+    View, ViewContext, ViewHandle,
 };
 use menu::{Cancel, Confirm};
 use settings::Settings;
@@ -156,7 +156,7 @@ impl View for GoToLine {
         "GoToLine"
     }
 
-    fn render(&mut self, cx: &mut RenderContext<Self>) -> ElementBox {
+    fn render(&mut self, cx: &mut ViewContext<Self>) -> ElementBox {
         let theme = &cx.global::<Settings>().theme.picker;
 
         let label = format!(

crates/gpui/examples/text.rs 🔗

@@ -2,7 +2,7 @@ use gpui::{
     color::Color,
     fonts::{Properties, Weight},
     text_layout::RunStyle,
-    DebugContext, Element as _, MeasurementContext, Quad,
+    Element, ElementBox, Quad, SceneBuilder, View, ViewContext,
 };
 use log::LevelFilter;
 use pathfinder_geometry::rect::RectF;
@@ -30,12 +30,12 @@ impl gpui::View for TextView {
         "View"
     }
 
-    fn render(&mut self, _: &mut gpui::RenderContext<Self>) -> gpui::ElementBox {
+    fn render(&mut self, _: &mut gpui::ViewContext<Self>) -> ElementBox<TextView> {
         TextElement.boxed()
     }
 }
 
-impl gpui::Element for TextElement {
+impl<V: View> Element<V> for TextElement {
     type LayoutState = ();
 
     type PaintState = ();
@@ -43,17 +43,20 @@ impl gpui::Element for TextElement {
     fn layout(
         &mut self,
         constraint: gpui::SizeConstraint,
-        _: &mut gpui::LayoutContext,
+        _: &mut V,
+        _: &mut ViewContext<V>,
     ) -> (pathfinder_geometry::vector::Vector2F, Self::LayoutState) {
         (constraint.max, ())
     }
 
     fn paint(
         &mut self,
+        scene: &mut SceneBuilder,
         bounds: RectF,
         visible_bounds: RectF,
         _: &mut Self::LayoutState,
-        cx: &mut gpui::PaintContext,
+        _: &mut V,
+        cx: &mut ViewContext<V>,
     ) -> Self::PaintState {
         let font_size = 12.;
         let family = cx
@@ -84,7 +87,7 @@ impl gpui::Element for TextElement {
         };
 
         let text = "Hello world!";
-        let line = cx.text_layout_cache.layout_str(
+        let line = cx.text_layout_cache().layout_str(
             text,
             font_size,
             &[
@@ -96,12 +99,12 @@ impl gpui::Element for TextElement {
             ],
         );
 
-        cx.scene.push_quad(Quad {
+        scene.push_quad(Quad {
             bounds,
             background: Some(Color::white()),
             ..Default::default()
         });
-        line.paint(bounds.origin(), visible_bounds, bounds.height(), cx);
+        line.paint(scene, bounds.origin(), visible_bounds, bounds.height(), cx);
     }
 
     fn rect_for_text_range(
@@ -111,7 +114,8 @@ impl gpui::Element for TextElement {
         _: RectF,
         _: &Self::LayoutState,
         _: &Self::PaintState,
-        _: &MeasurementContext,
+        _: &V,
+        _: &ViewContext<V>,
     ) -> Option<RectF> {
         None
     }
@@ -121,7 +125,8 @@ impl gpui::Element for TextElement {
         _: RectF,
         _: &Self::LayoutState,
         _: &Self::PaintState,
-        _: &DebugContext,
+        _: &V,
+        _: &ViewContext<V>,
     ) -> gpui::json::Value {
         todo!()
     }

crates/gpui/src/app.rs 🔗

@@ -69,7 +69,7 @@ pub trait Entity: 'static {
 
 pub trait View: Entity + Sized {
     fn ui_name() -> &'static str;
-    fn render(&mut self, cx: &mut ViewContext<'_, '_, Self>) -> ElementBox<Self>;
+    fn render(&mut self, cx: &mut ViewContext<'_, '_, '_, Self>) -> ElementBox<Self>;
     fn focus_in(&mut self, _: AnyViewHandle, _: &mut ViewContext<Self>) {}
     fn focus_out(&mut self, _: AnyViewHandle, _: &mut ViewContext<Self>) {}
     fn key_down(&mut self, _: &KeyDownEvent, _: &mut ViewContext<Self>) -> bool {
@@ -488,7 +488,7 @@ impl ReadViewWith for AsyncAppContext {
     }
 }
 
-type ActionCallback = dyn FnMut(&mut dyn AnyView, &dyn Action, &mut AppContext, usize, usize);
+type ActionCallback = dyn FnMut(&mut dyn AnyView, &dyn Action, &mut WindowContext, usize);
 type GlobalActionCallback = dyn FnMut(&dyn Action, &mut AppContext);
 
 type SubscriptionCallback = Box<dyn FnMut(&dyn Any, &mut AppContext) -> bool>;
@@ -725,11 +725,10 @@ impl AppContext {
         let handler = Box::new(
             move |view: &mut dyn AnyView,
                   action: &dyn Action,
-                  cx: &mut AppContext,
-                  window_id: usize,
+                  cx: &mut WindowContext,
                   view_id: usize| {
                 let action = action.as_any().downcast_ref().unwrap();
-                let mut cx = ViewContext::new(cx, view_id);
+                let mut cx = ViewContext::mutable(cx, view_id);
                 handler(
                     view.as_any_mut()
                         .downcast_mut()
@@ -842,6 +841,12 @@ impl AppContext {
         }
     }
 
+    fn focused_view_id(&self, window_id: usize) -> Option<usize> {
+        self.windows
+            .get(&window_id)
+            .and_then(|window| window.focused_view_id)
+    }
+
     pub fn is_child_focused(&self, view: &AnyViewHandle) -> bool {
         if let Some(focused_view_id) = self.focused_view_id(view.window_id) {
             self.ancestors(view.window_id, focused_view_id)
@@ -858,57 +863,59 @@ impl AppContext {
         self.active_labeled_tasks.values().cloned()
     }
 
-    // pub fn render_view(&mut self, params: RenderParams) -> Result<ElementBox<Self>> {
-    //     let window_id = params.window_id;
-    //     let view_id = params.view_id;
-    //     let mut view = self
-    //         .views
-    //         .remove(&(window_id, view_id))
-    //         .ok_or_else(|| anyhow!("view not found"))?;
-    //     let element = view.render(params, self);
-    //     self.views.insert((window_id, view_id), view);
-    //     Ok(element)
-    // }
-
-    // pub fn render_views(
-    //     &mut self,
-    //     window_id: usize,
-    //     titlebar_height: f32,
-    //     appearance: Appearance,
-    // ) -> HashMap<usize, ElementBox> {
-    //     self.start_frame();
-    //     #[allow(clippy::needless_collect)]
-    //     let view_ids = self
-    //         .views
-    //         .keys()
-    //         .filter_map(|(win_id, view_id)| {
-    //             if *win_id == window_id {
-    //                 Some(*view_id)
-    //             } else {
-    //                 None
-    //             }
-    //         })
-    //         .collect::<Vec<_>>();
-
-    //     view_ids
-    //         .into_iter()
-    //         .map(|view_id| {
-    //             (
-    //                 view_id,
-    //                 self.render_view(RenderParams {
-    //                     window_id,
-    //                     view_id,
-    //                     titlebar_height,
-    //                     hovered_region_ids: Default::default(),
-    //                     clicked_region_ids: None,
-    //                     refreshing: false,
-    //                     appearance,
-    //                 })
-    //                 .unwrap(),
-    //             )
-    //         })
-    //         .collect()
-    // }
+    pub fn render_view(&mut self, params: RenderParams) -> Result<Box<dyn RenderedView>> {
+        todo!()
+        // let window_id = params.window_id;
+        // let view_id = params.view_id;
+        // let mut view = self
+        //     .views
+        //     .remove(&(window_id, view_id))
+        //     .ok_or_else(|| anyhow!("view not found"))?;
+        // let element = view.render(params, self);
+        // self.views.insert((window_id, view_id), view);
+        // Ok(element)
+    }
+
+    pub fn render_views(
+        &mut self,
+        window_id: usize,
+        titlebar_height: f32,
+        appearance: Appearance,
+    ) -> HashMap<usize, Box<dyn RenderedView>> {
+        todo!()
+        // self.start_frame();
+        // #[allow(clippy::needless_collect)]
+        // let view_ids = self
+        //     .views
+        //     .keys()
+        //     .filter_map(|(win_id, view_id)| {
+        //         if *win_id == window_id {
+        //             Some(*view_id)
+        //         } else {
+        //             None
+        //         }
+        //     })
+        //     .collect::<Vec<_>>();
+
+        // view_ids
+        //     .into_iter()
+        //     .map(|view_id| {
+        //         (
+        //             view_id,
+        //             self.render_view(RenderParams {
+        //                 window_id,
+        //                 view_id,
+        //                 titlebar_height,
+        //                 hovered_region_ids: Default::default(),
+        //                 clicked_region_ids: None,
+        //                 refreshing: false,
+        //                 appearance,
+        //             })
+        //             .unwrap(),
+        //         )
+        //     })
+        //     .collect()
+    }
 
     pub(crate) fn start_frame(&mut self) {
         self.frame_count += 1;
@@ -932,6 +939,7 @@ impl AppContext {
                 app_context,
                 window: &mut window,
                 window_id,
+                refreshing: false,
             };
 
             let result = callback(&mut window_context);
@@ -1510,25 +1518,22 @@ impl AppContext {
         })
     }
 
-    pub fn add_window<T, F>(
+    pub fn add_window<V, F>(
         &mut self,
         window_options: WindowOptions,
         build_root_view: F,
-    ) -> (usize, ViewHandle<T>)
+    ) -> (usize, ViewHandle<V>)
     where
-        T: View,
-        F: FnOnce(&mut ViewContext<T>) -> T,
+        V: View,
+        F: FnOnce(&mut ViewContext<V>) -> V,
     {
         self.update(|this| {
             let window_id = post_inc(&mut this.next_window_id);
-            let root_view = this
-                .build_and_insert_view(window_id, ParentId::Root, |cx| Some(build_root_view(cx)))
-                .unwrap();
             let platform_window =
                 this.platform
                     .open_window(window_id, window_options, this.foreground.clone());
-            let window =
-                this.build_window(window_id, root_view.clone().into_any(), platform_window);
+            let window = this.build_window(window_id, platform_window, build_root_view);
+            let root_view = window.root_view().clone().downcast::<V>().unwrap();
 
             this.windows.insert(window_id, window);
             root_view.update(this, |view, cx| view.focus_in(cx.handle().into_any(), cx));
@@ -1537,20 +1542,16 @@ impl AppContext {
         })
     }
 
-    pub fn add_status_bar_item<T, F>(&mut self, build_root_view: F) -> (usize, ViewHandle<T>)
+    pub fn add_status_bar_item<V, F>(&mut self, build_root_view: F) -> (usize, ViewHandle<V>)
     where
-        T: View,
-        F: FnOnce(&mut ViewContext<T>) -> T,
+        V: View,
+        F: FnOnce(&mut ViewContext<V>) -> V,
     {
         self.update(|this| {
             let window_id = post_inc(&mut this.next_window_id);
-            let root_view = this
-                .build_and_insert_view(window_id, ParentId::Root, |cx| Some(build_root_view(cx)))
-                .unwrap();
-
             let platform_window = this.platform.add_status_item();
-            let window =
-                this.build_window(window_id, root_view.clone().into_any(), platform_window);
+            let window = this.build_window(window_id, platform_window, build_root_view);
+            let root_view = window.root_view().clone().downcast::<V>().unwrap();
 
             this.windows.insert(window_id, window);
             root_view.update(this, |view, cx| view.focus_in(cx.handle().into_any(), cx));
@@ -1563,33 +1564,21 @@ impl AppContext {
         self.remove_window(id);
     }
 
-    pub fn replace_root_view<T, F>(&mut self, window_id: usize, build_root_view: F) -> ViewHandle<T>
-    where
-        T: View,
-        F: FnOnce(&mut ViewContext<T>) -> T,
-    {
-        self.update(|this| {
-            let root_view = this
-                .build_and_insert_view(window_id, ParentId::Root, |cx| Some(build_root_view(cx)))
-                .unwrap();
-            let window = this.windows.get_mut(&window_id).unwrap();
-            window.root_view = root_view.clone().into_any();
-            window.focused_view_id = Some(root_view.id());
-            root_view
-        })
-    }
-
     pub fn remove_window(&mut self, window_id: usize) {
         self.windows.remove(&window_id);
         self.flush_effects();
     }
 
-    pub fn build_window(
+    pub fn build_window<V, F>(
         &mut self,
         window_id: usize,
-        root_view: AnyViewHandle,
         mut platform_window: Box<dyn platform::Window>,
-    ) -> Window {
+        build_root_view: F,
+    ) -> Window
+    where
+        V: View,
+        F: FnOnce(&mut ViewContext<V>) -> V,
+    {
         {
             let mut app = self.upgrade();
 
@@ -1653,73 +1642,22 @@ impl AppContext {
             window_id,
         }));
 
-        let mut window = Window::new(window_id, root_view, platform_window, self);
+        let mut window = Window::new(window_id, platform_window, self, build_root_view);
         let scene = WindowContext::new(self, &mut window, window_id).build_scene();
         window.platform_window.present_scene(scene);
         window
     }
 
-    pub fn add_view<T, F>(&mut self, parent_handle: &AnyViewHandle, build_view: F) -> ViewHandle<T>
-    where
-        T: View,
-        F: FnOnce(&mut ViewContext<T>) -> T,
-    {
-        self.build_and_insert_view(
-            parent_handle.window_id,
-            ParentId::View(parent_handle.view_id),
-            |cx| Some(build_view(cx)),
-        )
-        .unwrap()
-    }
-
-    pub fn add_option_view<T, F>(
-        &mut self,
-        parent_handle: impl Into<AnyViewHandle>,
-        build_view: F,
-    ) -> Option<ViewHandle<T>>
-    where
-        T: View,
-        F: FnOnce(&mut ViewContext<T>) -> Option<T>,
-    {
-        let parent_handle = parent_handle.into();
-        self.build_and_insert_view(
-            parent_handle.window_id,
-            ParentId::View(parent_handle.view_id),
-            build_view,
-        )
-    }
-
-    pub(crate) fn build_and_insert_view<T, F>(
-        &mut self,
-        window_id: usize,
-        parent_id: ParentId,
-        build_view: F,
-    ) -> Option<ViewHandle<T>>
+    pub fn add_view<S, F>(&mut self, parent: &AnyViewHandle, build_view: F) -> ViewHandle<S>
     where
-        T: View,
-        F: FnOnce(&mut ViewContext<T>) -> Option<T>,
+        S: View,
+        F: FnOnce(&mut ViewContext<S>) -> S,
     {
-        self.update(|this| {
-            let view_id = post_inc(&mut this.next_entity_id);
-            // Make sure we can tell child views about their parent
-            this.parents.insert((window_id, view_id), parent_id);
-            let mut cx = ViewContext::new(this, view_id);
-            let handle = if let Some(view) = build_view(&mut cx) {
-                this.views.insert((window_id, view_id), Box::new(view));
-                if let Some(window) = this.windows.get_mut(&window_id) {
-                    window
-                        .invalidation
-                        .get_or_insert_with(Default::default)
-                        .updated
-                        .insert(view_id);
-                }
-                Some(ViewHandle::new(window_id, view_id, &this.ref_counts))
-            } else {
-                this.parents.remove(&(window_id, view_id));
-                None
-            };
-            handle
+        self.update_window(parent.window_id, |cx| {
+            cx.build_and_insert_view(ParentId::View(parent.view_id), |cx| Some(build_view(cx)))
+                .unwrap()
         })
+        .unwrap()
     }
 
     fn remove_dropped_entities(&mut self) {
@@ -1754,7 +1692,7 @@ impl AppContext {
                         .removed
                         .push(view_id);
                     if window.focused_view_id == Some(view_id) {
-                        Some(window.root_view.id())
+                        Some(window.root_view().id())
                     } else {
                         None
                     }
@@ -2174,7 +2112,10 @@ impl AppContext {
 
         self.update(|cx| {
             cx.update_window(window_id, |cx| {
-                let focused_id = cx.window.focused_view_id?;
+                let Some(focused_id) = cx.window.focused_view_id else {
+                    return;
+                };
+
                 for view_id in cx.ancestors(window_id, focused_id).collect::<Vec<_>>() {
                     cx.update_any_view(focused_id, |view, cx| {
                         if active {
@@ -2254,29 +2195,28 @@ impl AppContext {
             if let Some(view_id) = view_id {
                 this.halt_action_dispatch = false;
                 this.visit_dispatch_path(window_id, view_id, |view_id, capture_phase, this| {
-                    if let Some(mut view) = this.views.remove(&(window_id, view_id)) {
-                        let type_id = view.as_any().type_id();
-
-                        if let Some((name, mut handlers)) = this
-                            .actions_mut(capture_phase)
-                            .get_mut(&type_id)
-                            .and_then(|h| h.remove_entry(&action.id()))
-                        {
-                            for handler in handlers.iter_mut().rev() {
-                                this.halt_action_dispatch = true;
-                                handler(view.as_mut(), action, this, window_id, view_id);
-                                if this.halt_action_dispatch {
-                                    break;
+                    this.update_window(window_id, |cx| {
+                        cx.update_any_view(view_id, |view, cx| {
+                            let type_id = view.as_any().type_id();
+                            if let Some((name, mut handlers)) = cx
+                                .actions_mut(capture_phase)
+                                .get_mut(&type_id)
+                                .and_then(|h| h.remove_entry(&action.id()))
+                            {
+                                for handler in handlers.iter_mut().rev() {
+                                    cx.halt_action_dispatch = true;
+                                    handler(view, action, cx, view_id);
+                                    if cx.halt_action_dispatch {
+                                        break;
+                                    }
                                 }
+                                cx.actions_mut(capture_phase)
+                                    .get_mut(&type_id)
+                                    .unwrap()
+                                    .insert(name, handlers);
                             }
-                            this.actions_mut(capture_phase)
-                                .get_mut(&type_id)
-                                .unwrap()
-                                .insert(name, handlers);
-                        }
-
-                        this.views.insert((window_id, view_id), view);
-                    }
+                        })
+                    });
 
                     !this.halt_action_dispatch
                 });
@@ -2523,22 +2463,19 @@ impl UpdateView for AppContext {
     where
         T: View,
     {
-        self.update(|this| {
-            let mut view = this
-                .views
-                .remove(&(handle.window_id, handle.view_id))
-                .expect("circular view update");
-
-            let mut cx = ViewContext::new(this, handle.view_id);
-            let result = update(
-                view.as_any_mut()
-                    .downcast_mut()
-                    .expect("downcast is type safe"),
-                &mut cx,
-            );
-            this.views.insert((handle.window_id, handle.view_id), view);
-            result
+        self.update_window(handle.window_id, |cx| {
+            cx.update_any_view(handle.view_id, |view, cx| {
+                let mut cx = ViewContext::mutable(cx, handle.view_id);
+                update(
+                    view.as_any_mut()
+                        .downcast_mut()
+                        .expect("downcast is type safe"),
+                    &mut cx,
+                )
+            })
+            .unwrap() // TODO: Are these unwraps safe?
         })
+        .unwrap()
     }
 }
 
@@ -2877,68 +2814,42 @@ pub trait AnyView {
         cx: &mut AppContext,
     ) -> Option<Pin<Box<dyn 'static + Future<Output = ()>>>>;
     fn ui_name(&self) -> &'static str;
-    fn render<'a, 'b>(
-        &mut self,
-        params: RenderParams,
-        cx: &'b mut WindowContext<'a, 'b>,
-    ) -> Box<dyn RenderedView>;
+    fn render(&mut self, params: RenderParams, cx: &mut WindowContext) -> Box<dyn RenderedView>;
     fn focus_in<'a, 'b>(
         &mut self,
         focused_id: usize,
-        cx: &'b mut WindowContext<'a, 'b>,
-        view_id: usize,
-    );
-    fn focus_out<'a, 'b>(
-        &mut self,
-        focused_id: usize,
-        cx: &'b mut WindowContext<'a, 'b>,
+        cx: &mut WindowContext<'a, 'b>,
         view_id: usize,
     );
-    fn key_down<'a, 'b>(
-        &mut self,
-        event: &KeyDownEvent,
-        cx: &'b mut WindowContext<'a, 'b>,
-        view_id: usize,
-    ) -> bool;
-    fn key_up<'a, 'b>(
-        &mut self,
-        event: &KeyUpEvent,
-        cx: &'b mut WindowContext<'a, 'b>,
-        view_id: usize,
-    ) -> bool;
-    fn modifiers_changed<'a, 'b>(
+    fn focus_out(&mut self, focused_id: usize, cx: &mut WindowContext, view_id: usize);
+    fn key_down(&mut self, event: &KeyDownEvent, cx: &mut WindowContext, view_id: usize) -> bool;
+    fn key_up(&mut self, event: &KeyUpEvent, cx: &mut WindowContext, view_id: usize) -> bool;
+    fn modifiers_changed(
         &mut self,
         event: &ModifiersChangedEvent,
-        cx: &'b mut WindowContext<'a, 'b>,
+        cx: &mut WindowContext,
         view_id: usize,
     ) -> bool;
-    fn keymap_context<'a, 'b>(&self, cx: &'b mut WindowContext<'a, 'b>) -> KeymapContext;
-    fn debug_json<'a, 'b>(&self, cx: &'b WindowContext<'a, 'b>) -> serde_json::Value;
+    fn keymap_context(&self, cx: &AppContext) -> KeymapContext;
+    fn debug_json(&self, cx: &WindowContext) -> serde_json::Value;
 
-    fn text_for_range<'a, 'b>(
-        &self,
-        range: Range<usize>,
-        cx: &'b mut WindowContext<'a, 'b>,
-    ) -> Option<String>;
-    fn selected_text_range<'a, 'b>(
-        &self,
-        cx: &'b mut WindowContext<'a, 'b>,
-    ) -> Option<Range<usize>>;
-    fn marked_text_range<'a, 'b>(&self, cx: &'b mut WindowContext<'a, 'b>) -> Option<Range<usize>>;
-    fn unmark_text<'a, 'b>(&mut self, cx: &'b mut WindowContext<'a, 'b>, view_id: usize);
-    fn replace_text_in_range<'a, 'b>(
+    fn text_for_range(&self, range: Range<usize>, cx: &WindowContext) -> Option<String>;
+    fn selected_text_range(&self, cx: &WindowContext) -> Option<Range<usize>>;
+    fn marked_text_range(&self, cx: &WindowContext) -> Option<Range<usize>>;
+    fn unmark_text(&mut self, cx: &mut WindowContext, view_id: usize);
+    fn replace_text_in_range(
         &mut self,
         range: Option<Range<usize>>,
         text: &str,
-        cx: &'b mut WindowContext<'a, 'b>,
+        cx: &mut WindowContext,
         view_id: usize,
     );
-    fn replace_and_mark_text_in_range<'a, 'b>(
+    fn replace_and_mark_text_in_range(
         &mut self,
         range: Option<Range<usize>>,
         new_text: &str,
         new_selected_range: Option<Range<usize>>,
-        cx: &'b mut WindowContext<'a, 'b>,
+        cx: &mut WindowContext,
         view_id: usize,
     );
     fn any_handle(&self, window_id: usize, view_id: usize, cx: &AppContext) -> AnyViewHandle {
@@ -2978,21 +2889,13 @@ where
         T::ui_name()
     }
 
-    fn render<'a, 'b>(
-        &mut self,
-        params: RenderParams,
-        cx: &mut WindowContext<'a, 'b>,
-    ) -> Box<dyn RenderedView> {
-        View::render(self, &mut ViewContext::new(params, cx))
+    fn render(&mut self, params: RenderParams, cx: &mut WindowContext) -> Box<dyn RenderedView> {
+        todo!()
+        // Box::new(View::render(self, &mut ViewContext::new(params.view_id, cx)))
     }
 
-    fn focus_in<'a, 'b>(
-        &mut self,
-        cx: &mut WindowContext<'a, 'b>,
-        view_id: usize,
-        focused_id: usize,
-    ) {
-        let mut cx = ViewContext::new(cx, view_id);
+    fn focus_in(&mut self, focused_id: usize, cx: &mut WindowContext, view_id: usize) {
+        let mut cx = ViewContext::mutable(cx, view_id);
         let focused_view_handle: AnyViewHandle = if view_id == focused_id {
             cx.handle().into_any()
         } else {
@@ -3012,13 +2915,8 @@ where
         View::focus_in(self, focused_view_handle, &mut cx);
     }
 
-    fn focus_out<'a, 'b>(
-        &mut self,
-        cx: &mut WindowContext<'a, 'b>,
-        view_id: usize,
-        blurred_id: usize,
-    ) {
-        let mut cx = ViewContext::new(cx, view_id);
+    fn focus_out(&mut self, blurred_id: usize, cx: &mut WindowContext, view_id: usize) {
+        let mut cx = ViewContext::mutable(cx, view_id);
         let blurred_view_handle: AnyViewHandle = if view_id == blurred_id {
             cx.handle().into_any()
         } else {
@@ -3038,85 +2936,71 @@ where
         View::focus_out(self, blurred_view_handle, &mut cx);
     }
 
-    fn key_down<'a, 'b>(
-        &mut self,
-        event: &KeyDownEvent,
-        cx: &mut WindowContext<'a, 'b>,
-        view_id: usize,
-    ) -> bool {
-        let mut cx = ViewContext::new(cx, view_id);
+    fn key_down(&mut self, event: &KeyDownEvent, cx: &mut WindowContext, view_id: usize) -> bool {
+        let mut cx = ViewContext::mutable(cx, view_id);
         View::key_down(self, event, &mut cx)
     }
 
-    fn key_up<'a, 'b>(
-        &mut self,
-        event: &KeyUpEvent,
-        cx: &mut WindowContext<'a, 'b>,
-        view_id: usize,
-    ) -> bool {
-        let mut cx = ViewContext::new(cx, view_id);
+    fn key_up(&mut self, event: &KeyUpEvent, cx: &mut WindowContext, view_id: usize) -> bool {
+        let mut cx = ViewContext::mutable(cx, view_id);
         View::key_up(self, event, &mut cx)
     }
 
-    fn modifiers_changed<'a, 'b>(
+    fn modifiers_changed(
         &mut self,
         event: &ModifiersChangedEvent,
-        cx: &mut WindowContext<'a, 'b>,
+        cx: &mut WindowContext,
         view_id: usize,
     ) -> bool {
-        let mut cx = ViewContext::new(cx, view_id);
+        let mut cx = ViewContext::mutable(cx, view_id);
         View::modifiers_changed(self, event, &mut cx)
     }
 
-    fn keymap_context<'a, 'b>(&self, cx: &mut WindowContext<'a, 'b>) -> KeymapContext {
+    fn keymap_context(&self, cx: &AppContext) -> KeymapContext {
         View::keymap_context(self, cx)
     }
 
-    fn debug_json<'a, 'b>(&self, cx: &mut WindowContext<'a, 'b>) -> serde_json::Value {
+    fn debug_json(&self, cx: &WindowContext) -> serde_json::Value {
         View::debug_json(self, cx)
     }
 
-    fn text_for_range<'a, 'b>(
-        &self,
-        range: Range<usize>,
-        cx: &mut WindowContext<'a, 'b>,
-    ) -> Option<String> {
+    fn text_for_range(&self, range: Range<usize>, cx: &WindowContext) -> Option<String> {
         View::text_for_range(self, range, cx)
     }
 
-    fn selected_text_range<'a, 'b>(&self, cx: &mut WindowContext<'a, 'b>) -> Option<Range<usize>> {
+    fn selected_text_range(&self, cx: &WindowContext) -> Option<Range<usize>> {
         View::selected_text_range(self, cx)
     }
 
-    fn marked_text_range<'a, 'b>(&self, cx: &mut WindowContext<'a, 'b>) -> Option<Range<usize>> {
+    fn marked_text_range(&self, cx: &WindowContext) -> Option<Range<usize>> {
         View::marked_text_range(self, cx)
     }
 
-    fn unmark_text<'a, 'b>(&mut self, cx: &mut WindowContext<'a, 'b>, view_id: usize) {
-        let mut cx = ViewContext::new(cx, view_id);
+    fn unmark_text(&mut self, cx: &mut WindowContext, view_id: usize) {
+        let mut cx = ViewContext::mutable(cx, view_id);
         View::unmark_text(self, &mut cx)
     }
 
-    fn replace_text_in_range<'a, 'b>(
+    fn replace_text_in_range(
         &mut self,
         range: Option<Range<usize>>,
         text: &str,
-        cx: &mut WindowContext<'a, 'b>,
+        cx: &mut WindowContext,
         view_id: usize,
     ) {
-        let mut cx = ViewContext::new(cx, view_id);
+        let mut cx = ViewContext::mutable(cx, view_id);
         View::replace_text_in_range(self, range, text, &mut cx)
     }
 
-    fn replace_and_mark_text_in_range<'a, 'b>(
+    fn replace_and_mark_text_in_range(
         &mut self,
         range: Option<Range<usize>>,
         new_text: &str,
         new_selected_range: Option<Range<usize>>,
-        cx: &mut WindowContext<'a, 'b>,
+        cx: &mut WindowContext,
         view_id: usize,
     ) {
-        let mut cx = ViewContext::new(cx, view_id);
+        let mut cx = ViewContext::mutable(cx, view_id);
         View::replace_and_mark_text_in_range(self, range, new_text, new_selected_range, &mut cx)
     }
 }
@@ -3339,13 +3223,13 @@ impl<M> DerefMut for ModelContext<'_, M> {
     }
 }
 
-pub struct ViewContext<'a, 'b, T: ?Sized> {
-    window_context: WindowContext<'a, 'b>,
+pub struct ViewContext<'a, 'b, 'c, T: ?Sized> {
+    window_context: WindowContextRef<'a, 'b, 'c>,
     view_id: usize,
     view_type: PhantomData<T>,
 }
 
-impl<'a, 'b, T: View> Deref for ViewContext<'a, 'b, T> {
+impl<'a, 'b, 'c, T: View> Deref for ViewContext<'a, 'b, 'c, T> {
     type Target = WindowContext<'a, 'b>;
 
     fn deref(&self) -> &Self::Target {
@@ -3353,16 +3237,24 @@ impl<'a, 'b, T: View> Deref for ViewContext<'a, 'b, T> {
     }
 }
 
-impl<'a, 'b, T: View> DerefMut for ViewContext<'a, 'b, T> {
+impl<T: View> DerefMut for ViewContext<'_, '_, '_, T> {
     fn deref_mut(&mut self) -> &mut Self::Target {
         &mut self.window_context
     }
 }
 
-impl<'a, 'b, V: View> ViewContext<'a, 'b, V> {
-    fn new(window_context: &'b mut WindowContext<'a, 'b>, view_id: usize) -> Self {
+impl<'a, 'b, 'c, V: View> ViewContext<'a, 'b, 'c, V> {
+    pub(crate) fn mutable(window_context: &'c mut WindowContext<'a, 'b>, view_id: usize) -> Self {
         Self {
-            window_context,
+            window_context: WindowContextRef::Mutable(window_context),
+            view_id,
+            view_type: PhantomData,
+        }
+    }
+
+    pub(crate) fn immutable(window_context: &'c WindowContext<'a, 'b>, view_id: usize) -> Self {
+        Self {
+            window_context: WindowContextRef::Immutable(window_context),
             view_id,
             view_type: PhantomData,
         }
@@ -3425,12 +3317,13 @@ impl<'a, 'b, V: View> ViewContext<'a, 'b, V> {
     }
 
     pub fn focus_self(&mut self) {
-        self.window_context
-            .focus(self.window_id, Some(self.view_id));
+        let window_id = self.window_id;
+        let view_id = self.view_id;
+        self.window_context.focus(window_id, Some(view_id));
     }
 
     pub fn is_self_focused(&self) -> bool {
-        self.window.focused_view == Some(self.view_id)
+        self.window.focused_view_id == Some(self.view_id)
     }
 
     pub fn is_child(&self, view: impl Into<AnyViewHandle>) -> bool {
@@ -3444,7 +3337,8 @@ impl<'a, 'b, V: View> ViewContext<'a, 'b, V> {
     }
 
     pub fn blur(&mut self) {
-        self.window_context.focus(self.window_id, None);
+        let window_id = self.window_id;
+        self.window_context.focus(window_id, None);
     }
 
     pub fn on_window_should_close<F>(&mut self, mut callback: F)
@@ -3466,23 +3360,13 @@ impl<'a, 'b, V: View> ViewContext<'a, 'b, V> {
             });
     }
 
-    pub fn add_model<S, F>(&mut self, build_model: F) -> ModelHandle<S>
-    where
-        S: Entity,
-        F: FnOnce(&mut ModelContext<S>) -> S,
-    {
-        self.window_context.add_model(build_model)
-    }
-
     pub fn add_view<S, F>(&mut self, build_view: F) -> ViewHandle<S>
     where
         S: View,
         F: FnOnce(&mut ViewContext<S>) -> S,
     {
         self.window_context
-            .build_and_insert_view(self.window_id, ParentId::View(self.view_id), |cx| {
-                Some(build_view(cx))
-            })
+            .build_and_insert_view(ParentId::View(self.view_id), |cx| Some(build_view(cx)))
             .unwrap()
     }
 
@@ -3491,11 +3375,8 @@ impl<'a, 'b, V: View> ViewContext<'a, 'b, V> {
         S: View,
         F: FnOnce(&mut ViewContext<S>) -> Option<S>,
     {
-        self.window_context.build_and_insert_view(
-            self.window_id,
-            ParentId::View(self.view_id),
-            build_view,
-        )
+        self.window_context
+            .build_and_insert_view(ParentId::View(self.view_id), build_view)
     }
 
     pub fn reparent(&mut self, view_handle: &AnyViewHandle) {
@@ -3511,23 +3392,6 @@ impl<'a, 'b, V: View> ViewContext<'a, 'b, V> {
         );
     }
 
-    pub fn replace_root_view<W, F>(&mut self, build_root_view: F) -> ViewHandle<W>
-    where
-        W: View,
-        F: FnOnce(&mut ViewContext<W>) -> W,
-    {
-        let window_id = self.window_id;
-        self.update(|this| {
-            let root_view = this
-                .build_and_insert_view(window_id, ParentId::Root, |cx| Some(build_root_view(cx)))
-                .unwrap();
-            let window = this.windows.get_mut(&window_id).unwrap();
-            window.root_view = root_view.clone().into_any();
-            window.focused_view_id = Some(root_view.id());
-            root_view
-        })
-    }
-
     pub fn subscribe<E, H, F>(&mut self, handle: &H, mut callback: F) -> Subscription
     where
         E: Entity,
@@ -3637,8 +3501,9 @@ impl<'a, 'b, V: View> ViewContext<'a, 'b, V> {
         F: 'static + FnMut(&mut V, bool, &mut ViewContext<V>),
     {
         let observer = self.weak_handle();
+        let window_id = self.window_id;
         self.window_context
-            .observe_window_activation(self.window_id(), move |active, cx| {
+            .observe_window_activation(window_id, move |active, cx| {
                 if let Some(observer) = observer.upgrade(cx) {
                     observer.update(cx, |observer, cx| {
                         callback(observer, active, cx);
@@ -3655,8 +3520,9 @@ impl<'a, 'b, V: View> ViewContext<'a, 'b, V> {
         F: 'static + FnMut(&mut V, bool, &mut ViewContext<V>),
     {
         let observer = self.weak_handle();
+        let window_id = self.window_id;
         self.window_context
-            .observe_fullscreen(self.window_id(), move |active, cx| {
+            .observe_fullscreen(window_id, move |active, cx| {
                 if let Some(observer) = observer.upgrade(cx) {
                     observer.update(cx, |observer, cx| {
                         callback(observer, active, cx);
@@ -3680,8 +3546,9 @@ impl<'a, 'b, V: View> ViewContext<'a, 'b, V> {
             ) -> bool,
     {
         let observer = self.weak_handle();
+        let window_id = self.window_id;
         self.window_context.observe_keystrokes(
-            self.window_id(),
+            window_id,
             move |keystroke, result, handled_by, cx| {
                 if let Some(observer) = observer.upgrade(cx) {
                     observer.update(cx, |observer, cx| {
@@ -3700,8 +3567,9 @@ impl<'a, 'b, V: View> ViewContext<'a, 'b, V> {
         F: 'static + FnMut(&mut V, WindowBounds, Uuid, &mut ViewContext<V>),
     {
         let observer = self.weak_handle();
+        let window_id = self.window_id;
         self.window_context
-            .observe_window_bounds(self.window_id(), move |bounds, display, cx| {
+            .observe_window_bounds(window_id, move |bounds, display, cx| {
                 if let Some(observer) = observer.upgrade(cx) {
                     observer.update(cx, |observer, cx| {
                         callback(observer, bounds, display, cx);
@@ -3740,18 +3608,23 @@ impl<'a, 'b, V: View> ViewContext<'a, 'b, V> {
     }
 
     pub fn notify(&mut self) {
-        self.window_context
-            .notify_view(self.window_id, self.view_id);
+        let window_id = self.window_id;
+        let view_id = self.view_id;
+        self.window_context.notify_view(window_id, view_id);
     }
 
     pub fn dispatch_action(&mut self, action: impl Action) {
+        let window_id = self.window_id;
+        let view_id = self.view_id;
         self.window_context
-            .dispatch_action_at(self.window_id, self.view_id, action)
+            .dispatch_action_at(window_id, view_id, action)
     }
 
     pub fn dispatch_any_action(&mut self, action: Box<dyn Action>) {
+        let window_id = self.window_id;
+        let view_id = self.view_id;
         self.window_context
-            .dispatch_any_action_at(self.window_id, self.view_id, action)
+            .dispatch_any_action_at(window_id, view_id, action)
     }
 
     pub fn defer(&mut self, callback: impl 'static + FnOnce(&mut V, &mut ViewContext<V>)) {
@@ -3813,14 +3686,12 @@ impl<'a, 'b, V: View> ViewContext<'a, 'b, V> {
     pub fn mouse_state<Tag: 'static>(&self, region_id: usize) -> MouseState {
         let region_id = MouseRegionId::new::<Tag>(self.view_id, region_id);
         MouseState {
-            hovered: self.hovered_region_ids.contains(&region_id),
-            clicked: self.clicked_region_ids.as_ref().and_then(|(ids, button)| {
-                if ids.contains(&region_id) {
-                    Some(*button)
-                } else {
-                    None
-                }
-            }),
+            hovered: self.window.hovered_region_ids.contains(&region_id),
+            clicked: self
+                .window
+                .clicked_region_ids
+                .get(&region_id)
+                .and_then(|_| self.window.clicked_button),
             accessed_hovered: false,
             accessed_clicked: false,
         }
@@ -3850,7 +3721,7 @@ impl<'a, 'b, V: View> ViewContext<'a, 'b, V> {
     }
 }
 
-impl<V> UpgradeModelHandle for ViewContext<'_, '_, V> {
+impl<V> UpgradeModelHandle for ViewContext<'_, '_, '_, V> {
     fn upgrade_model_handle<T: Entity>(
         &self,
         handle: &WeakModelHandle<T>,
@@ -3867,7 +3738,7 @@ impl<V> UpgradeModelHandle for ViewContext<'_, '_, V> {
     }
 }
 
-impl<V> UpgradeViewHandle for ViewContext<'_, '_, V> {
+impl<V> UpgradeViewHandle for ViewContext<'_, '_, '_, V> {
     fn upgrade_view_handle<T: View>(&self, handle: &WeakViewHandle<T>) -> Option<ViewHandle<T>> {
         self.window_context.upgrade_view_handle(handle)
     }
@@ -3877,7 +3748,13 @@ impl<V> UpgradeViewHandle for ViewContext<'_, '_, V> {
     }
 }
 
-impl<V: View> UpdateModel for ViewContext<'_, '_, V> {
+impl<V: View> ReadModel for ViewContext<'_, '_, '_, V> {
+    fn read_model<T: Entity>(&self, handle: &ModelHandle<T>) -> &T {
+        self.window_context.read_model(handle)
+    }
+}
+
+impl<V: View> UpdateModel for ViewContext<'_, '_, '_, V> {
     fn update_model<T: Entity, O>(
         &mut self,
         handle: &ModelHandle<T>,
@@ -3887,13 +3764,13 @@ impl<V: View> UpdateModel for ViewContext<'_, '_, V> {
     }
 }
 
-impl<V: View> ReadView for ViewContext<'_, '_, V> {
+impl<V: View> ReadView for ViewContext<'_, '_, '_, V> {
     fn read_view<T: View>(&self, handle: &ViewHandle<T>) -> &T {
         self.window_context.read_view(handle)
     }
 }
 
-impl<V: View> UpdateView for ViewContext<'_, '_, V> {
+impl<V: View> UpdateView for ViewContext<'_, '_, '_, V> {
     fn update_view<T, S>(
         &mut self,
         handle: &ViewHandle<T>,
@@ -3906,6 +3783,33 @@ impl<V: View> UpdateView for ViewContext<'_, '_, V> {
     }
 }
 
+enum WindowContextRef<'a, 'b, 'c> {
+    Immutable(&'c WindowContext<'a, 'b>),
+    Mutable(&'c mut WindowContext<'a, 'b>),
+}
+
+impl<'a, 'b, 'c> Deref for WindowContextRef<'a, 'b, 'c> {
+    type Target = WindowContext<'a, 'b>;
+
+    fn deref(&self) -> &Self::Target {
+        match self {
+            WindowContextRef::Immutable(window_context) => window_context,
+            WindowContextRef::Mutable(window_context) => window_context,
+        }
+    }
+}
+
+impl<'a, 'b, 'c> DerefMut for WindowContextRef<'a, 'b, 'c> {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        match self {
+            WindowContextRef::Immutable(_) => {
+                panic!("cannot mutably deref an immutable WindowContext. this is a bug in GPUI.");
+            }
+            WindowContextRef::Mutable(window_context) => window_context,
+        }
+    }
+}
+
 pub struct RenderParams {
     pub window_id: usize,
     pub view_id: usize,
@@ -4686,9 +4590,10 @@ impl<T: 'static> ElementStateHandle<T> {
             .unwrap()
     }
 
-    pub fn update<C, R>(&self, cx: &mut C, f: impl FnOnce(&mut T, &mut C) -> R) -> R
+    pub fn update<C, D, R>(&self, cx: &mut C, f: impl FnOnce(&mut T, &mut C) -> R) -> R
     where
-        C: DerefMut<Target = AppContext>,
+        C: DerefMut<Target = D>,
+        D: DerefMut<Target = AppContext>,
     {
         let mut element_state = cx.deref_mut().element_states.remove(&self.id).unwrap();
         let result = f(element_state.downcast_mut().unwrap(), cx);

crates/gpui/src/app/menu.rs 🔗

@@ -78,7 +78,11 @@ pub(crate) fn setup_menu_handlers(foreground_platform: &dyn ForegroundPlatform,
         move |action| {
             let mut cx = cx.borrow_mut();
             if let Some(main_window_id) = cx.platform.main_window_id() {
-                if let Some(view_id) = cx.focused_view_id(main_window_id) {
+                if let Some(view_id) = cx
+                    .windows
+                    .get(&main_window_id)
+                    .and_then(|w| w.focused_view_id)
+                {
                     cx.handle_dispatch_action_from_effect(main_window_id, Some(view_id), action);
                     return;
                 }

crates/gpui/src/app/test_app_context.rs 🔗

@@ -1,6 +1,5 @@
 use std::{
     cell::RefCell,
-    marker::PhantomData,
     mem,
     path::PathBuf,
     rc::Rc,
@@ -21,7 +20,7 @@ use crate::{
     geometry::vector::Vector2F,
     keymap_matcher::Keystroke,
     platform,
-    platform::{Appearance, Event, InputHandler, KeyDownEvent, Platform},
+    platform::{Event, InputHandler, KeyDownEvent, Platform},
     Action, AnyViewHandle, AppContext, Entity, FontCache, Handle, ModelContext, ModelHandle,
     ReadModelWith, ReadViewWith, Task, UpdateModel, UpdateView, View, ViewContext, ViewHandle,
     WeakHandle,
@@ -74,7 +73,7 @@ impl TestAppContext {
 
     pub fn dispatch_action<A: Action>(&self, window_id: usize, action: A) {
         let mut cx = self.cx.borrow_mut();
-        if let Some(view_id) = cx.focused_view_id {
+        if let Some(view_id) = cx.windows.get(&window_id).and_then(|w| w.focused_view_id) {
             cx.handle_dispatch_action_from_effect(window_id, Some(view_id), &action);
         }
     }
@@ -149,7 +148,14 @@ impl TestAppContext {
     }
 
     pub fn root_view(&self, window_id: usize) -> Option<AnyViewHandle> {
-        self.cx.borrow().root_view(window_id)
+        Some(
+            self.cx
+                .borrow()
+                .windows
+                .get(&window_id)?
+                .root_view()
+                .clone(),
+        )
     }
 
     pub fn read<T, F: FnOnce(&AppContext) -> T>(&self, callback: F) -> T {
@@ -172,20 +178,21 @@ impl TestAppContext {
         F: FnOnce(&mut V, &mut ViewContext<V>) -> T,
         V: View,
     {
-        handle.update(&mut *self.cx.borrow_mut(), |view, cx| {
-            let mut render_cx = ViewContext {
-                app: cx,
-                window_id: handle.window_id(),
-                view_id: handle.id(),
-                view_type: PhantomData,
-                titlebar_height: 0.,
-                hovered_region_ids: Default::default(),
-                clicked_region_ids: None,
-                refreshing: false,
-                appearance: Appearance::Light,
-            };
-            f(view, &mut render_cx)
-        })
+        todo!()
+        // handle.update(&mut *self.cx.borrow_mut(), |view, cx| {
+        //     let mut render_cx = ViewContext {
+        //         app: cx,
+        //         window_id: handle.window_id(),
+        //         view_id: handle.id(),
+        //         view_type: PhantomData,
+        //         titlebar_height: 0.,
+        //         hovered_region_ids: Default::default(),
+        //         clicked_region_ids: None,
+        //         refreshing: false,
+        //         appearance: Appearance::Light,
+        //     };
+        //     f(view, &mut render_cx)
+        // })
     }
 
     pub fn to_async(&self) -> AsyncAppContext {

crates/gpui/src/app/window.rs 🔗

@@ -1,6 +1,4 @@
 use crate::{
-    app::WindowInvalidation,
-    elements::Element,
     geometry::rect::RectF,
     json::{self, ToJson},
     keymap_matcher::{Keystroke, MatchResult},
@@ -13,8 +11,9 @@ use crate::{
         MouseMove, MouseMoveOut, MouseScrollWheel, MouseUp, MouseUpOut, Scene,
     },
     text_layout::TextLayoutCache,
-    Action, AnyView, AnyViewHandle, AnyWeakViewHandle, AppContext, ElementBox, MouseRegion,
-    MouseRegionId, RenderParams, SceneBuilder, View,
+    util::post_inc,
+    AnyView, AnyViewHandle, AppContext, Element, ElementBox, MouseRegion, MouseRegionId, ParentId,
+    RenderParams, SceneBuilder, View, ViewContext, ViewHandle, WindowInvalidation,
 };
 use anyhow::bail;
 use collections::{HashMap, HashSet};
@@ -30,8 +29,7 @@ use std::ops::{Deref, DerefMut, Range};
 use uuid::Uuid;
 
 pub struct Window {
-    window_id: usize,
-    pub(crate) root_view: AnyViewHandle,
+    pub(crate) root_view: Option<AnyViewHandle>,
     pub(crate) focused_view_id: Option<usize>,
     pub(crate) is_active: bool,
     pub(crate) is_fullscreen: bool,
@@ -43,27 +41,29 @@ pub struct Window {
     cursor_regions: Vec<CursorRegion>,
     mouse_regions: Vec<(MouseRegion, usize)>,
     last_mouse_moved_event: Option<Event>,
-    hovered_region_ids: HashSet<MouseRegionId>,
-    clicked_region_ids: HashSet<MouseRegionId>,
-    clicked_button: Option<MouseButton>,
+    pub(crate) hovered_region_ids: HashSet<MouseRegionId>,
+    pub(crate) clicked_region_ids: HashSet<MouseRegionId>,
+    pub(crate) clicked_button: Option<MouseButton>,
     mouse_position: Vector2F,
     text_layout_cache: TextLayoutCache,
 }
 
 impl Window {
-    pub fn new(
+    pub fn new<V, F>(
         window_id: usize,
-        root_view: AnyViewHandle,
         platform_window: Box<dyn platform::Window>,
         cx: &mut AppContext,
-    ) -> Self {
-        let focused_view_id = Some(root_view.id());
+        build_view: F,
+    ) -> Self
+    where
+        F: FnOnce(&mut ViewContext<V>) -> V,
+        V: View,
+    {
         let titlebar_height = platform_window.titlebar_height();
         let appearance = platform_window.appearance();
-        Self {
-            window_id,
-            root_view,
-            focused_view_id,
+        let mut window = Self {
+            root_view: None,
+            focused_view_id: None,
             is_active: false,
             invalidation: None,
             is_fullscreen: false,
@@ -79,15 +79,30 @@ impl Window {
             mouse_position: vec2f(0., 0.),
             titlebar_height,
             appearance,
-        }
+        };
+
+        let mut window_context = WindowContext::new(cx, &mut window, window_id);
+        let root_view = window_context
+            .build_and_insert_view(ParentId::Root, |cx| Some(build_view(cx)))
+            .unwrap();
+        window.focused_view_id = Some(root_view.id());
+        window.root_view = Some(root_view.into_any());
+        window
+    }
+
+    pub fn root_view(&self) -> &AnyViewHandle {
+        &self
+            .root_view
+            .as_ref()
+            .expect("root_view called during window construction")
     }
 }
 
 pub struct WindowContext<'a: 'b, 'b> {
-    app_context: &'a mut AppContext,
+    pub(crate) app_context: &'a mut AppContext,
     pub(crate) window: &'b mut Window, // TODO: make this private?
     pub(crate) window_id: usize,
-    pub refreshing: bool,
+    pub(crate) refreshing: bool,
 }
 
 impl Deref for WindowContext<'_, '_> {
@@ -110,16 +125,30 @@ impl<'a: 'b, 'b> WindowContext<'a, 'b> {
             app_context,
             window,
             window_id,
+            refreshing: false,
         }
     }
 
-    pub fn update_any_view<F, T>(&mut self, view_id: usize, f: F) -> Option<T>
+    pub fn window_id(&self) -> usize {
+        self.window_id
+    }
+
+    pub fn window_size(&self) -> Vector2F {
+        self.window.platform_window.content_size()
+    }
+
+    pub fn text_layout_cache(&self) -> &TextLayoutCache {
+        &self.window.text_layout_cache
+    }
+
+    pub(crate) fn update_any_view<F, T>(&mut self, view_id: usize, f: F) -> Option<T>
     where
         F: FnOnce(&mut dyn AnyView, &mut Self) -> T,
     {
-        let view = self.views.remove(&(self.window_id, view_id))?;
-        let result = f(view.as_any_mut(), self);
-        self.views.insert((self.window_id, view_id), view);
+        let window_id = self.window_id;
+        let mut view = self.views.remove(&(window_id, view_id))?;
+        let result = f(view.as_mut(), self);
+        self.views.insert((window_id, view_id), view);
         Some(result)
     }
 
@@ -453,8 +482,7 @@ impl<'a: 'b, 'b> WindowContext<'a, 'b> {
             //3. Fire region events
             let hovered_region_ids = self.window.hovered_region_ids.clone();
             for valid_region in valid_regions.into_iter() {
-                let mut event_cx = self.build_event_context(&mut notified_views);
-
+                let mut handled = false;
                 mouse_event.set_region(valid_region.bounds);
                 if let MouseEvent::Hover(e) = &mut mouse_event {
                     e.started = hovered_region_ids.contains(&valid_region.id())
@@ -473,25 +501,25 @@ impl<'a: 'b, 'b> WindowContext<'a, 'b> {
                         .handlers
                         .contains(MouseEvent::down_disc(), Some(e.button));
                     if !has_down && (has_click || has_drag) {
-                        event_cx.handled = true;
+                        handled = true;
                     }
                 }
 
                 // `event_consumed` should only be true if there are any handlers for this event.
-                let mut event_consumed = event_cx.handled;
+                let mut event_consumed = handled;
                 if let Some(callbacks) = valid_region.handlers.get(&mouse_event.handler_key()) {
                     for callback in callbacks {
-                        event_cx.handled = true;
-                        event_cx.with_current_view(valid_region.id().view_id(), {
-                            let region_event = mouse_event.clone();
-                            |cx| callback(region_event, cx)
+                        handled = true;
+                        let view_id = valid_region.id().view_id();
+                        self.update_any_view(view_id, |view, cx| {
+                            handled = callback(mouse_event.clone(), view.as_any_mut(), cx, view_id);
                         });
-                        event_consumed |= event_cx.handled;
-                        any_event_handled |= event_cx.handled;
+                        event_consumed |= handled;
+                        any_event_handled |= handled;
                     }
                 }
 
-                any_event_handled |= event_cx.handled;
+                any_event_handled |= handled;
 
                 // For bubbling events, if the event was handled, don't continue dispatching.
                 // This only makes sense for local events which return false from is_capturable.
@@ -530,7 +558,7 @@ impl<'a: 'b, 'b> WindowContext<'a, 'b> {
     }
 
     pub fn dispatch_key_up(&mut self, window_id: usize, event: &KeyUpEvent) -> bool {
-        if let Some(focused_view_id) = self.window.fo {
+        if let Some(focused_view_id) = self.window.focused_view_id {
             for view_id in self
                 .ancestors(window_id, focused_view_id)
                 .collect::<Vec<_>>()
@@ -645,18 +673,17 @@ impl<'a: 'b, 'b> WindowContext<'a, 'b> {
         let window_size = self.window.platform_window.content_size();
         let scale_factor = self.window.platform_window.scale_factor();
 
-        let root_view_id = self.window.root_view.id();
-        let rendered_root = self.window.rendered_views.remove(&root_view_id).unwrap();
-        rendered_root.layout(root_view_id, SizeConstraint::strict(window_size), self);
+        let root_view_id = self.window.root_view().id();
+        let mut rendered_root = self.window.rendered_views.remove(&root_view_id).unwrap();
+        rendered_root.layout(SizeConstraint::strict(window_size), self, root_view_id);
 
         let mut scene_builder = SceneBuilder::new(scale_factor);
-        let paint_bounds = RectF::from_points(Vector2F::zero(), window_size);
         rendered_root.paint(
-            root_view_id,
             &mut scene_builder,
-            paint_bounds,
-            paint_bounds,
+            Vector2F::zero(),
+            RectF::from_points(Vector2F::zero(), window_size),
             self,
+            root_view_id,
         );
 
         self.window.text_layout_cache.finish_frame();
@@ -719,14 +746,6 @@ impl<'a: 'b, 'b> WindowContext<'a, 'b> {
         self.window.is_fullscreen
     }
 
-    pub fn root_view(&self, window_id: usize) -> &AnyViewHandle {
-        &self.window.root_view
-    }
-
-    pub fn root_view_id(&self) -> usize {
-        self.window.root_view.id()
-    }
-
     pub fn focused_view_id(&self) -> Option<usize> {
         self.window.focused_view_id
     }
@@ -739,7 +758,7 @@ impl<'a: 'b, 'b> WindowContext<'a, 'b> {
         self.window.platform_window.screen().display_uuid()
     }
 
-    fn show_character_palette(&self) {
+    pub fn show_character_palette(&self) {
         self.window.platform_window.show_character_palette();
     }
 
@@ -763,47 +782,162 @@ impl<'a: 'b, 'b> WindowContext<'a, 'b> {
     ) -> oneshot::Receiver<usize> {
         self.window.platform_window.prompt(level, msg, answers)
     }
+
+    fn add_view<T, F>(&mut self, parent: &AnyViewHandle, build_view: F) -> ViewHandle<T>
+    where
+        T: View,
+        F: FnOnce(&mut ViewContext<T>) -> T,
+    {
+        if parent.window_id == self.window_id {
+            self.build_and_insert_view(ParentId::View(parent.view_id), |cx| Some(build_view(cx)))
+                .unwrap()
+        } else {
+            self.app_context.add_view(parent, build_view)
+        }
+    }
+
+    fn add_option_view<T, F>(
+        &mut self,
+        parent_handle: impl Into<AnyViewHandle>,
+        build_view: F,
+    ) -> Option<ViewHandle<T>>
+    where
+        T: View,
+        F: FnOnce(&mut ViewContext<T>) -> Option<T>,
+    {
+        let parent_handle = parent_handle.into();
+        self.build_and_insert_view(ParentId::View(parent_handle.view_id), build_view)
+    }
+
+    pub fn replace_root_view<V, F>(&mut self, build_root_view: F) -> ViewHandle<V>
+    where
+        V: View,
+        F: FnOnce(&mut ViewContext<V>) -> V,
+    {
+        let root_view = self
+            .build_and_insert_view(ParentId::Root, |cx| Some(build_root_view(cx)))
+            .unwrap();
+        self.window.root_view = Some(root_view.clone().into_any());
+        self.window.focused_view_id = Some(root_view.id());
+        root_view
+    }
+
+    pub(crate) fn build_and_insert_view<T, F>(
+        &mut self,
+        parent_id: ParentId,
+        build_view: F,
+    ) -> Option<ViewHandle<T>>
+    where
+        T: View,
+        F: FnOnce(&mut ViewContext<T>) -> Option<T>,
+    {
+        let window_id = self.window_id;
+        let view_id = post_inc(&mut self.next_entity_id);
+        // Make sure we can tell child views about their parentu
+        self.parents.insert((window_id, view_id), parent_id);
+        let mut cx = ViewContext::mutable(self, view_id);
+        let handle = if let Some(view) = build_view(&mut cx) {
+            self.views.insert((window_id, view_id), Box::new(view));
+            self.window
+                .invalidation
+                .get_or_insert_with(Default::default)
+                .updated
+                .insert(view_id);
+            Some(ViewHandle::new(window_id, view_id, &self.ref_counts))
+        } else {
+            self.parents.remove(&(window_id, view_id));
+            None
+        };
+        handle
+    }
 }
 
 pub trait RenderedView {
     fn layout(
-        &self,
-        view_id: usize,
+        &mut self,
         constraint: SizeConstraint,
         cx: &mut WindowContext,
+        view_id: usize,
     ) -> Vector2F;
     fn paint(
-        &self,
-        view_id: usize,
+        &mut self,
         scene: &mut SceneBuilder,
-        bounds: RectF,
+        origin: Vector2F,
         visible_bounds: RectF,
         cx: &mut WindowContext,
+        view_id: usize,
     );
+    fn rect_for_text_range(
+        &self,
+        range_utf16: Range<usize>,
+        cx: &WindowContext,
+        view_id: usize,
+    ) -> Option<RectF>;
+    fn debug(&self, cx: &WindowContext, view_id: usize) -> serde_json::Value;
+    fn name(&self) -> Option<&str>;
 }
 
 impl<V: View> RenderedView for ElementBox<V> {
     fn layout(
-        &self,
-        view_id: usize,
+        &mut self,
         constraint: SizeConstraint,
         cx: &mut WindowContext,
+        view_id: usize,
     ) -> Vector2F {
-        cx.update_view_for_id(view_id, |view, cx| self.layout(view, constraint, cx))
-            .unwrap()
+        cx.update_any_view(view_id, |view, cx| {
+            let view = view.as_any_mut().downcast_mut::<V>().unwrap();
+            let mut cx = ViewContext::mutable(cx, view_id);
+            ElementBox::layout(self, constraint, view, &mut cx)
+        })
+        .unwrap()
     }
 
     fn paint(
-        &self,
-        view_id: usize,
+        &mut self,
         scene: &mut SceneBuilder,
-        bounds: RectF,
+        origin: Vector2F,
         visible_bounds: RectF,
         cx: &mut WindowContext,
+        view_id: usize,
     ) {
-        cx.update_view_for_id(view_id, |view, cx| {
-            self.paint(view, scene, bounds, visible_bounds, cx)
-        })
+        cx.update_any_view(view_id, |view, cx| {
+            let view = view.as_any_mut().downcast_mut::<V>().unwrap();
+            let mut cx = ViewContext::mutable(cx, view_id);
+            ElementBox::paint(self, scene, origin, visible_bounds, view, &mut cx)
+        });
+    }
+
+    fn rect_for_text_range(
+        &self,
+        range_utf16: Range<usize>,
+        cx: &WindowContext,
+        view_id: usize,
+    ) -> Option<RectF> {
+        let view = cx
+            .views
+            .get(&(cx.window_id, view_id))
+            .unwrap()
+            .as_any()
+            .downcast_ref::<V>()
+            .unwrap();
+        let cx = ViewContext::immutable(cx, view_id);
+        ElementBox::rect_for_text_range(self, range_utf16, view, &cx)
+    }
+
+    fn debug(&self, cx: &WindowContext, view_id: usize) -> serde_json::Value {
+        let view = cx
+            .views
+            .get(&(cx.window_id, view_id))
+            .unwrap()
+            .as_any()
+            .downcast_ref::<V>()
+            .unwrap();
+        let cx = ViewContext::immutable(cx, view_id);
+        ElementBox::debug(self, view, &cx)
+    }
+
+    fn name(&self) -> Option<&str> {
+        ElementBox::name(self)
     }
 }
 
@@ -950,7 +1084,7 @@ impl ToJson for SizeConstraint {
 }
 
 pub struct ChildView {
-    view: AnyWeakViewHandle,
+    view_id: usize,
     view_name: &'static str,
 }
 
@@ -958,94 +1092,101 @@ impl ChildView {
     pub fn new(view: &AnyViewHandle, cx: &AppContext) -> Self {
         let view_name = cx.view_ui_name(view.window_id(), view.id()).unwrap();
         Self {
-            view: view.downgrade(),
+            view_id: view.id(),
             view_name,
         }
     }
 }
 
-// impl Element for ChildView {
-//     type LayoutState = bool;
-//     type PaintState = ();
-
-//     fn layout(
-//         &mut self,
-//         constraint: SizeConstraint,
-//         cx: &mut LayoutContext,
-//     ) -> (Vector2F, Self::LayoutState) {
-//         if cx.rendered_views.contains_key(&self.view.id()) {
-//             let size = cx.layout(self.view.id(), constraint);
-//             (size, true)
-//         } else {
-//             log::error!(
-//                 "layout called on a ChildView element whose underlying view was dropped (view_id: {}, name: {:?})",
-//                 self.view.id(),
-//                 self.view_name
-//             );
-//             (Vector2F::zero(), false)
-//         }
-//     }
-
-//     fn paint(
-//         &mut self,
-//         bounds: RectF,
-//         visible_bounds: RectF,
-//         view_is_valid: &mut Self::LayoutState,
-//         cx: &mut PaintContext,
-//     ) {
-//         if *view_is_valid {
-//             cx.paint(self.view.id(), bounds.origin(), visible_bounds);
-//         } else {
-//             log::error!(
-//                 "paint called on a ChildView element whose underlying view was dropped (view_id: {}, name: {:?})",
-//                 self.view.id(),
-//                 self.view_name
-//             );
-//         }
-//     }
-
-//     fn rect_for_text_range(
-//         &self,
-//         range_utf16: Range<usize>,
-//         _: RectF,
-//         _: RectF,
-//         view_is_valid: &Self::LayoutState,
-//         _: &Self::PaintState,
-//         cx: &MeasurementContext,
-//     ) -> Option<RectF> {
-//         if *view_is_valid {
-//             cx.rect_for_text_range(self.view.id(), range_utf16)
-//         } else {
-//             log::error!(
-//                 "rect_for_text_range called on a ChildView element whose underlying view was dropped (view_id: {}, name: {:?})",
-//                 self.view.id(),
-//                 self.view_name
-//             );
-//             None
-//         }
-//     }
-
-//     fn debug(
-//         &self,
-//         bounds: RectF,
-//         _: &Self::LayoutState,
-//         _: &Self::PaintState,
-//         cx: &DebugContext,
-//     ) -> serde_json::Value {
-//         json!({
-//             "type": "ChildView",
-//             "view_id": self.view.id(),
-//             "bounds": bounds.to_json(),
-//             "view": if let Some(view) = self.view.upgrade(cx.app) {
-//                 view.debug_json(cx.app)
-//             } else {
-//                 json!(null)
-//             },
-//             "child": if let Some(view) = cx.rendered_views.get(&self.view.id()) {
-//                 view.debug(cx)
-//             } else {
-//                 json!(null)
-//             }
-//         })
-//     }
-// }
+impl<V: View> Element<V> for ChildView {
+    type LayoutState = ();
+    type PaintState = ();
+
+    fn layout(
+        &mut self,
+        constraint: SizeConstraint,
+        _: &mut V,
+        cx: &mut ViewContext<V>,
+    ) -> (Vector2F, Self::LayoutState) {
+        if let Some(mut rendered_view) = cx.window.rendered_views.remove(&self.view_id) {
+            let size = rendered_view.layout(constraint, cx, self.view_id);
+            cx.window.rendered_views.insert(self.view_id, rendered_view);
+            (size, ())
+        } else {
+            log::error!(
+                "layout called on a ChildView element whose underlying view was dropped (view_id: {}, name: {:?})",
+                self.view_id,
+                self.view_name
+            );
+            (Vector2F::zero(), ())
+        }
+    }
+
+    fn paint(
+        &mut self,
+        scene: &mut SceneBuilder,
+        bounds: RectF,
+        visible_bounds: RectF,
+        _: &mut Self::LayoutState,
+        _: &mut V,
+        cx: &mut ViewContext<V>,
+    ) {
+        if let Some(mut rendered_view) = cx.window.rendered_views.remove(&self.view_id) {
+            rendered_view.paint(scene, bounds.origin(), visible_bounds, cx, self.view_id);
+            cx.window.rendered_views.insert(self.view_id, rendered_view);
+        } else {
+            log::error!(
+                "paint called on a ChildView element whose underlying view was dropped (view_id: {}, name: {:?})",
+                self.view_id,
+                self.view_name
+            );
+        }
+    }
+
+    fn rect_for_text_range(
+        &self,
+        range_utf16: Range<usize>,
+        _: RectF,
+        _: RectF,
+        _: &Self::LayoutState,
+        _: &Self::PaintState,
+        _: &V,
+        cx: &ViewContext<V>,
+    ) -> Option<RectF> {
+        if let Some(rendered_view) = cx.window.rendered_views.get(&self.view_id) {
+            rendered_view.rect_for_text_range(range_utf16, &cx.window_context, self.view_id)
+        } else {
+            log::error!(
+                "rect_for_text_range called on a ChildView element whose underlying view was dropped (view_id: {}, name: {:?})",
+                self.view_id,
+                self.view_name
+            );
+            None
+        }
+    }
+
+    fn debug(
+        &self,
+        bounds: RectF,
+        _: &Self::LayoutState,
+        _: &Self::PaintState,
+        _: &V,
+        cx: &ViewContext<V>,
+    ) -> serde_json::Value {
+        json!({
+            "type": "ChildView",
+            "view_id": self.view_id,
+            "bounds": bounds.to_json(),
+            "view": if let Some(view) = cx.views.get(&(cx.window_id, self.view_id))  {
+                view.debug_json(cx)
+            } else {
+                json!(null)
+            },
+            "child": if let Some(element) = cx.window.rendered_views.get(&self.view_id) {
+                element.debug(&cx.window_context, self.view_id)
+            } else {
+                json!(null)
+            }
+        })
+    }
+}

crates/gpui/src/app/window_input_handler.rs 🔗

@@ -2,7 +2,7 @@ use std::{cell::RefCell, ops::Range, rc::Rc};
 
 use pathfinder_geometry::rect::RectF;
 
-use crate::{platform::InputHandler, AnyView, AppContext};
+use crate::{platform::InputHandler, window::WindowContext, AnyView, AppContext};
 
 pub struct WindowInputHandler {
     pub app: Rc<RefCell<AppContext>>,
@@ -12,7 +12,7 @@ pub struct WindowInputHandler {
 impl WindowInputHandler {
     fn read_focused_view<T, F>(&self, f: F) -> Option<T>
     where
-        F: FnOnce(&dyn AnyView, &AppContext) -> T,
+        F: FnOnce(&dyn AnyView, &WindowContext) -> T,
     {
         // Input-related application hooks are sometimes called by the OS during
         // a call to a window-manipulation API, like prompting the user for file
@@ -20,26 +20,26 @@ impl WindowInputHandler {
         // InputHandler methods need to fail gracefully.
         //
         // See https://github.com/zed-industries/community/issues/444
-        let app = self.app.try_borrow().ok()?;
-
-        let view_id = app.focused_view_id(self.window_id)?;
-        let view = app.views.get(&(self.window_id, view_id))?;
-        let result = f(view.as_ref(), &app);
-        Some(result)
+        let mut app = self.app.try_borrow_mut().ok()?;
+        app.update_window(self.window_id, |cx| {
+            let view_id = cx.window.focused_view_id?;
+            let view = cx.views.get(&(self.window_id, view_id))?;
+            let result = f(view.as_ref(), &cx);
+            Some(result)
+        })
+        .flatten()
     }
 
     fn update_focused_view<T, F>(&mut self, f: F) -> Option<T>
     where
-        F: FnOnce(usize, usize, &mut dyn AnyView, &mut AppContext) -> T,
+        F: FnOnce(&mut dyn AnyView, &mut WindowContext, usize) -> T,
     {
         let mut app = self.app.try_borrow_mut().ok()?;
-        app.update(|app| {
-            let view_id = app.focused_view_id(self.window_id)?;
-            let mut view = app.views.remove(&(self.window_id, view_id))?;
-            let result = f(self.window_id, view_id, view.as_mut(), &mut *app);
-            app.views.insert((self.window_id, view_id), view);
-            Some(result)
+        app.update_window(self.window_id, |cx| {
+            let view_id = cx.window.focused_view_id?;
+            cx.update_any_view(view_id, |view, cx| f(view, cx, view_id))
         })
+        .flatten()
     }
 }
 
@@ -55,8 +55,8 @@ impl InputHandler for WindowInputHandler {
     }
 
     fn replace_text_in_range(&mut self, range: Option<Range<usize>>, text: &str) {
-        self.update_focused_view(|window_id, view_id, view, cx| {
-            view.replace_text_in_range(range, text, cx, window_id, view_id);
+        self.update_focused_view(|view, cx, view_id| {
+            view.replace_text_in_range(range, text, cx, view_id);
         });
     }
 
@@ -66,8 +66,8 @@ impl InputHandler for WindowInputHandler {
     }
 
     fn unmark_text(&mut self) {
-        self.update_focused_view(|window_id, view_id, view, cx| {
-            view.unmark_text(cx, window_id, view_id);
+        self.update_focused_view(|view, cx, view_id| {
+            view.unmark_text(cx, view_id);
         });
     }
 
@@ -77,15 +77,8 @@ impl InputHandler for WindowInputHandler {
         new_text: &str,
         new_selected_range: Option<Range<usize>>,
     ) {
-        self.update_focused_view(|window_id, view_id, view, cx| {
-            view.replace_and_mark_text_in_range(
-                range,
-                new_text,
-                new_selected_range,
-                cx,
-                window_id,
-                view_id,
-            );
+        self.update_focused_view(|view, cx, view_id| {
+            view.replace_and_mark_text_in_range(range, new_text, new_selected_range, cx, view_id);
         });
     }
 

crates/gpui/src/elements.rs 🔗

@@ -35,29 +35,29 @@ use crate::{
 };
 use core::panic;
 use json::ToJson;
-use std::{any::Any, borrow::Cow, cell::RefCell, marker::PhantomData, mem, ops::Range};
+use std::{any::Any, borrow::Cow, marker::PhantomData, mem, ops::Range};
 
 trait AnyElement<V: View> {
     fn layout(
         &mut self,
-        view: &mut V,
         constraint: SizeConstraint,
+        view: &mut V,
         cx: &mut ViewContext<V>,
     ) -> Vector2F;
 
     fn paint(
         &mut self,
-        view: &mut V,
         scene: &mut SceneBuilder,
         origin: Vector2F,
         visible_bounds: RectF,
+        view: &mut V,
         cx: &mut ViewContext<V>,
     );
 
     fn rect_for_text_range(
         &self,
-        view: &V,
         range_utf16: Range<usize>,
+        view: &V,
         cx: &ViewContext<V>,
     ) -> Option<RectF>;
 
@@ -118,7 +118,8 @@ pub trait Element<V: View> {
         Self: 'static + Sized,
     {
         ElementBox {
-            element: RefCell::new(Lifecycle::Init { element: self }),
+            element: Box::new(Lifecycle::Init { element: self }),
+            view_type: PhantomData,
             name: None,
         }
     }
@@ -128,7 +129,8 @@ pub trait Element<V: View> {
         Self: 'static + Sized,
     {
         ElementBox {
-            element: RefCell::new(Lifecycle::Init { element: self }),
+            element: Box::new(Lifecycle::Init { element: self }),
+            view_type: PhantomData,
             name: Some(name.into()),
         }
     }
@@ -193,7 +195,7 @@ pub trait Element<V: View> {
     where
         Self: 'static + Sized,
     {
-        Tooltip::new::<Tag>(id, text, action, style, self.boxed(), cx)
+        Tooltip::new::<Tag, V>(id, text, action, style, self.boxed(), cx)
     }
 
     fn with_resize_handle<Tag: 'static>(
@@ -207,7 +209,7 @@ pub trait Element<V: View> {
     where
         Self: 'static + Sized,
     {
-        Resizable::new::<Tag>(
+        Resizable::new::<Tag, V>(
             self.boxed(),
             element_id,
             side,
@@ -242,8 +244,8 @@ pub enum Lifecycle<V: View, E: Element<V>> {
 impl<V: View, E: Element<V>> AnyElement<V> for Lifecycle<V, E> {
     fn layout(
         &mut self,
-        view: &mut V,
         constraint: SizeConstraint,
+        view: &mut V,
         cx: &mut ViewContext<V>,
     ) -> Vector2F {
         let result;
@@ -252,7 +254,7 @@ impl<V: View, E: Element<V>> AnyElement<V> for Lifecycle<V, E> {
             Lifecycle::Init { mut element }
             | Lifecycle::PostLayout { mut element, .. }
             | Lifecycle::PostPaint { mut element, .. } => {
-                let (size, layout) = element.layout(view, constraint, cx);
+                let (size, layout) = element.layout(constraint, view, cx);
                 debug_assert!(size.x().is_finite());
                 debug_assert!(size.y().is_finite());
 
@@ -271,9 +273,9 @@ impl<V: View, E: Element<V>> AnyElement<V> for Lifecycle<V, E> {
     fn paint(
         &mut self,
         scene: &mut SceneBuilder,
-        view: &mut V,
         origin: Vector2F,
         visible_bounds: RectF,
+        view: &mut V,
         cx: &mut ViewContext<V>,
     ) {
         *self = match mem::take(self) {
@@ -321,9 +323,9 @@ impl<V: View, E: Element<V>> AnyElement<V> for Lifecycle<V, E> {
 
     fn rect_for_text_range(
         &self,
-        view: &V,
         range_utf16: Range<usize>,
-        cx: &mut ViewContext<V>,
+        view: &V,
+        cx: &ViewContext<V>,
     ) -> Option<RectF> {
         if let Lifecycle::PostPaint {
             element,
@@ -404,41 +406,40 @@ impl<V: View, E: Element<V>> Default for Lifecycle<V, E> {
 }
 
 pub struct ElementBox<V: View> {
-    element: Box<RefCell<dyn AnyElement<V>>>,
+    element: Box<dyn AnyElement<V>>,
     view_type: PhantomData<V>,
     name: Option<Cow<'static, str>>,
 }
 
 impl<V: View> ElementBox<V> {
     pub fn name(&self) -> Option<&str> {
-        self.0.name.as_deref()
+        self.name.as_deref()
     }
 
     pub fn metadata<T: 'static>(&self) -> Option<&T> {
-        // let element = unsafe { &*self.0.element.as_ptr() };
-        // element.metadata().and_then(|m| m.downcast_ref())
+        self.element
+            .metadata()
+            .and_then(|data| data.downcast_ref::<T>())
     }
 
     pub fn layout(
-        &self,
+        &mut self,
         constraint: SizeConstraint,
         view: &mut V,
         cx: &mut ViewContext<V>,
     ) -> Vector2F {
-        self.element.borrow_mut().layout(view, constraint, cx)
+        self.element.layout(constraint, view, cx)
     }
 
     pub fn paint(
-        &self,
+        &mut self,
         scene: &mut SceneBuilder,
         origin: Vector2F,
         visible_bounds: RectF,
         view: &mut V,
         cx: &mut ViewContext<V>,
     ) {
-        self.element
-            .borrow_mut()
-            .paint(view, scene, origin, visible_bounds, cx);
+        self.element.paint(scene, origin, visible_bounds, view, cx);
     }
 
     pub fn rect_for_text_range(
@@ -447,17 +448,15 @@ impl<V: View> ElementBox<V> {
         view: &V,
         cx: &ViewContext<V>,
     ) -> Option<RectF> {
-        self.element
-            .borrow()
-            .rect_for_text_range(view, range_utf16, cx)
+        self.element.rect_for_text_range(range_utf16, view, cx)
     }
 
     pub fn size(&self) -> Vector2F {
-        self.element.borrow().size()
+        self.element.size()
     }
 
     pub fn debug(&self, view: &V, cx: &ViewContext<V>) -> json::Value {
-        let mut value = self.element.borrow().debug(view, cx);
+        let mut value = self.element.debug(view, cx);
 
         if let Some(name) = &self.name {
             if let json::Value::Object(map) = &mut value {
@@ -476,8 +475,7 @@ impl<V: View> ElementBox<V> {
         T: 'static,
         F: FnOnce(Option<&T>) -> R,
     {
-        let element = self.element.borrow();
-        f(element.metadata().and_then(|m| m.downcast_ref()))
+        f(self.element.metadata().and_then(|m| m.downcast_ref()))
     }
 }
 

crates/gpui/src/elements/align.rs 🔗

@@ -46,13 +46,13 @@ impl<V: View> Element<V> for Align<V> {
 
     fn layout(
         &mut self,
-        view: &mut V,
         mut constraint: SizeConstraint,
+        view: &mut V,
         cx: &mut ViewContext<V>,
     ) -> (Vector2F, Self::LayoutState) {
         let mut size = constraint.max;
         constraint.min = Vector2F::zero();
-        let child_size = self.child.layout(view, constraint, cx);
+        let child_size = self.child.layout(constraint, view, cx);
         if size.x().is_infinite() {
             size.set_x(child_size.x());
         }
@@ -64,11 +64,11 @@ impl<V: View> Element<V> for Align<V> {
 
     fn paint(
         &mut self,
-        view: &mut V,
         scene: &mut SceneBuilder,
         bounds: RectF,
         visible_bounds: RectF,
         _: &mut Self::LayoutState,
+        view: &mut V,
         cx: &mut ViewContext<V>,
     ) -> Self::PaintState {
         let my_center = bounds.size() / 2.;
@@ -78,33 +78,33 @@ impl<V: View> Element<V> for Align<V> {
         let child_target = child_center + child_center * self.alignment;
 
         self.child.paint(
-            view,
             scene,
             bounds.origin() - (child_target - my_target),
             visible_bounds,
+            view,
             cx,
         );
     }
 
     fn rect_for_text_range(
         &self,
-        view: &V,
         range_utf16: std::ops::Range<usize>,
         _: RectF,
         _: RectF,
         _: &Self::LayoutState,
         _: &Self::PaintState,
+        view: &V,
         cx: &ViewContext<V>,
     ) -> Option<RectF> {
-        self.child.rect_for_text_range(view, range_utf16, cx)
+        self.child.rect_for_text_range(range_utf16, view, cx)
     }
 
     fn debug(
         &self,
-        view: &V,
         bounds: pathfinder_geometry::rect::RectF,
         _: &Self::LayoutState,
         _: &Self::PaintState,
+        view: &V,
         cx: &ViewContext<V>,
     ) -> json::Value {
         json!({

crates/gpui/src/elements/canvas.rs 🔗

@@ -25,7 +25,7 @@ where
 
 impl<V: View, F> Element<V> for Canvas<V, F>
 where
-    F: FnMut(RectF, RectF, &mut ViewContext<V>),
+    F: FnMut(&mut SceneBuilder, RectF, RectF, &mut V, &mut ViewContext<V>),
 {
     type LayoutState = ();
     type PaintState = ();
@@ -58,7 +58,7 @@ where
         view: &mut V,
         cx: &mut ViewContext<V>,
     ) -> Self::PaintState {
-        self.0(bounds, visible_bounds, cx)
+        self.0(scene, bounds, visible_bounds, view, cx)
     }
 
     fn rect_for_text_range(

crates/gpui/src/elements/clipped.rs 🔗

@@ -37,10 +37,10 @@ impl<V: View> Element<V> for Clipped<V> {
         view: &mut V,
         cx: &mut ViewContext<V>,
     ) -> Self::PaintState {
-        cx.scene.push_layer(Some(bounds));
-        self.child
-            .paint(scene, bounds.origin(), visible_bounds, view, cx);
-        cx.scene.pop_layer();
+        scene.paint_layer(Some(bounds), |scene| {
+            self.child
+                .paint(scene, bounds.origin(), visible_bounds, view, cx)
+        })
     }
 
     fn rect_for_text_range(

crates/gpui/src/elements/constrained_box.rs 🔗

@@ -157,7 +157,7 @@ impl<V: View> Element<V> for ConstrainedBox<V> {
         view: &mut V,
         cx: &mut ViewContext<V>,
     ) -> Self::PaintState {
-        cx.paint_layer(Some(visible_bounds), |cx| {
+        scene.paint_layer(Some(visible_bounds), |scene| {
             self.child
                 .paint(scene, bounds.origin(), visible_bounds, view, cx);
         })

crates/gpui/src/elements/container.rs 🔗

@@ -221,7 +221,7 @@ impl<V: View> Element<V> for Container<V> {
         );
 
         if let Some(shadow) = self.style.shadow.as_ref() {
-            cx.scene.push_shadow(scene::Shadow {
+            scene.push_shadow(scene::Shadow {
                 bounds: quad_bounds + shadow.offset,
                 corner_radius: self.style.corner_radius,
                 sigma: shadow.blur,
@@ -231,7 +231,7 @@ impl<V: View> Element<V> for Container<V> {
 
         if let Some(hit_bounds) = quad_bounds.intersection(visible_bounds) {
             if let Some(style) = self.style.cursor {
-                cx.scene.push_cursor_region(CursorRegion {
+                scene.push_cursor_region(CursorRegion {
                     bounds: hit_bounds,
                     style,
                 });
@@ -242,7 +242,7 @@ impl<V: View> Element<V> for Container<V> {
             quad_bounds.origin() + vec2f(self.style.padding.left, self.style.padding.top);
 
         if self.style.border.overlay {
-            cx.scene.push_quad(Quad {
+            scene.push_quad(Quad {
                 bounds: quad_bounds,
                 background: self.style.background_color,
                 border: Default::default(),
@@ -252,16 +252,16 @@ impl<V: View> Element<V> for Container<V> {
             self.child
                 .paint(scene, child_origin, visible_bounds, view, cx);
 
-            cx.scene.push_layer(None);
-            cx.scene.push_quad(Quad {
+            scene.push_layer(None);
+            scene.push_quad(Quad {
                 bounds: quad_bounds,
                 background: self.style.overlay_color,
                 border: self.style.border,
                 corner_radius: self.style.corner_radius,
             });
-            cx.scene.pop_layer();
+            scene.pop_layer();
         } else {
-            cx.scene.push_quad(Quad {
+            scene.push_quad(Quad {
                 bounds: quad_bounds,
                 background: self.style.background_color,
                 border: self.style.border,
@@ -277,14 +277,14 @@ impl<V: View> Element<V> for Container<V> {
                 .paint(scene, child_origin, visible_bounds, view, cx);
 
             if self.style.overlay_color.is_some() {
-                cx.scene.push_layer(None);
-                cx.scene.push_quad(Quad {
+                scene.push_layer(None);
+                scene.push_quad(Quad {
                     bounds: quad_bounds,
                     background: self.style.overlay_color,
                     border: Default::default(),
                     corner_radius: 0.,
                 });
-                cx.scene.pop_layer();
+                scene.pop_layer();
             }
         }
     }

crates/gpui/src/elements/empty.rs 🔗

@@ -33,7 +33,7 @@ impl<V: View> Element<V> for Empty {
     fn layout(
         &mut self,
         constraint: SizeConstraint,
-        _: &V,
+        _: &mut V,
         _: &mut ViewContext<V>,
     ) -> (Vector2F, Self::LayoutState) {
         let x = if constraint.max.x().is_finite() && !self.collapsed {
@@ -56,6 +56,7 @@ impl<V: View> Element<V> for Empty {
         _: RectF,
         _: RectF,
         _: &mut Self::LayoutState,
+        _: &mut V,
         _: &mut ViewContext<V>,
     ) -> Self::PaintState {
     }

crates/gpui/src/elements/expanded.rs 🔗

@@ -42,7 +42,7 @@ impl<V: View> Element<V> for Expanded<V> {
         &mut self,
         mut constraint: SizeConstraint,
         view: &mut V,
-        cx: &mut ViewContext<Self>,
+        cx: &mut ViewContext<V>,
     ) -> (Vector2F, Self::LayoutState) {
         if self.full_width {
             constraint.min.set_x(constraint.max.x());

crates/gpui/src/elements/flex.rs 🔗

@@ -73,7 +73,7 @@ impl<V: View> Flex<V> {
         remaining_space: &mut f32,
         remaining_flex: &mut f32,
         cross_axis_max: &mut f32,
-        view: &V,
+        view: &mut V,
         cx: &mut ViewContext<V>,
     ) {
         let cross_axis = self.axis.invert();
@@ -124,7 +124,7 @@ impl<V: View> Element<V> for Flex<V> {
     fn layout(
         &mut self,
         constraint: SizeConstraint,
-        view: &V,
+        view: &mut V,
         cx: &mut ViewContext<V>,
     ) -> (Vector2F, Self::LayoutState) {
         let mut total_flex = None;
@@ -253,7 +253,7 @@ impl<V: View> Element<V> for Flex<V> {
         bounds: RectF,
         visible_bounds: RectF,
         remaining_space: &mut Self::LayoutState,
-        view: &V,
+        view: &mut V,
         cx: &mut ViewContext<V>,
     ) -> Self::PaintState {
         let visible_bounds = bounds.intersection(visible_bounds).unwrap_or_default();
@@ -261,16 +261,16 @@ impl<V: View> Element<V> for Flex<V> {
         let mut remaining_space = *remaining_space;
         let overflowing = remaining_space < 0.;
         if overflowing {
-            cx.scene.push_layer(Some(visible_bounds));
+            scene.push_layer(Some(visible_bounds));
         }
 
         if let Some(scroll_state) = &self.scroll_state {
-            cx.scene.push_mouse_region(
+            scene.push_mouse_region(
                 crate::MouseRegion::new::<Self>(scroll_state.1, 0, bounds)
                     .on_scroll({
                         let scroll_state = scroll_state.0.read(cx).clone();
                         let axis = self.axis;
-                        move |e, cx| {
+                        move |e, _: &mut V, cx| {
                             if remaining_space < 0. {
                                 let scroll_delta = e.delta.raw();
 
@@ -298,7 +298,7 @@ impl<V: View> Element<V> for Flex<V> {
                             }
                         }
                     })
-                    .on_move(|_, _| { /* Capture move events */ }),
+                    .on_move(|_, _: &mut V, _| { /* Capture move events */ }),
             )
         }
 
@@ -356,7 +356,7 @@ impl<V: View> Element<V> for Flex<V> {
         }
 
         if overflowing {
-            cx.scene.pop_layer();
+            scene.pop_layer();
         }
     }
 
@@ -372,7 +372,7 @@ impl<V: View> Element<V> for Flex<V> {
     ) -> Option<RectF> {
         self.children
             .iter()
-            .find_map(|child| child.rect_for_text_range(view, range_utf16.clone(), cx))
+            .find_map(|child| child.rect_for_text_range(range_utf16.clone(), view, cx))
     }
 
     fn debug(
@@ -431,7 +431,7 @@ impl<V: View> Element<V> for FlexItem<V> {
     fn layout(
         &mut self,
         constraint: SizeConstraint,
-        view: &V,
+        view: &mut V,
         cx: &mut ViewContext<V>,
     ) -> (Vector2F, Self::LayoutState) {
         let size = self.child.layout(constraint, view, cx);
@@ -444,7 +444,7 @@ impl<V: View> Element<V> for FlexItem<V> {
         bounds: RectF,
         visible_bounds: RectF,
         _: &mut Self::LayoutState,
-        view: &V,
+        view: &mut V,
         cx: &mut ViewContext<V>,
     ) -> Self::PaintState {
         self.child
@@ -474,7 +474,6 @@ impl<V: View> Element<V> for FlexItem<V> {
         _: &Self::LayoutState,
         _: &Self::PaintState,
         view: &V,
-
         cx: &ViewContext<V>,
     ) -> Value {
         json!({

crates/gpui/src/elements/hook.rs 🔗

@@ -35,7 +35,7 @@ impl<V: View> Element<V> for Hook<V> {
     fn layout(
         &mut self,
         constraint: SizeConstraint,
-        view: &V,
+        view: &mut V,
         cx: &mut ViewContext<V>,
     ) -> (Vector2F, Self::LayoutState) {
         let size = self.child.layout(constraint, view, cx);

crates/gpui/src/elements/image.rs 🔗

@@ -62,7 +62,7 @@ impl<V: View> Element<V> for Image {
     fn layout(
         &mut self,
         constraint: SizeConstraint,
-        view: &V,
+        _: &mut V,
         cx: &mut ViewContext<V>,
     ) -> (Vector2F, Self::LayoutState) {
         let data = match &self.source {
@@ -94,8 +94,8 @@ impl<V: View> Element<V> for Image {
         bounds: RectF,
         _: RectF,
         layout: &mut Self::LayoutState,
-        _: &V,
-        cx: &mut ViewContext<V>,
+        _: &mut V,
+        _: &mut ViewContext<V>,
     ) -> Self::PaintState {
         if let Some(data) = layout {
             scene.push_image(scene::Image {

crates/gpui/src/elements/keystroke_label.rs 🔗

@@ -41,12 +41,11 @@ impl<V: View> Element<V> for KeystrokeLabel {
     fn layout(
         &mut self,
         constraint: SizeConstraint,
-        view: &V,
+        view: &mut V,
         cx: &mut ViewContext<V>,
     ) -> (Vector2F, ElementBox<V>) {
         let mut element = if let Some(keystrokes) =
-            cx.app
-                .keystrokes_for_action(self.window_id, self.view_id, self.action.as_ref())
+            cx.keystrokes_for_action(self.window_id, self.view_id, self.action.as_ref())
         {
             Flex::row()
                 .with_children(keystrokes.iter().map(|keystroke| {
@@ -70,7 +69,7 @@ impl<V: View> Element<V> for KeystrokeLabel {
         bounds: RectF,
         visible_bounds: RectF,
         element: &mut ElementBox<V>,
-        view: &V,
+        view: &mut V,
         cx: &mut ViewContext<V>,
     ) {
         element.paint(scene, bounds.origin(), visible_bounds, view, cx);

crates/gpui/src/elements/label.rs 🔗

@@ -134,13 +134,15 @@ impl<V: View> Element<V> for Label {
     fn layout(
         &mut self,
         constraint: SizeConstraint,
-        view: &V,
+        _: &mut V,
         cx: &mut ViewContext<V>,
     ) -> (Vector2F, Self::LayoutState) {
         let runs = self.compute_runs();
-        let line =
-            cx.text_layout_cache
-                .layout_str(&self.text, self.style.text.font_size, runs.as_slice());
+        let line = cx.text_layout_cache().layout_str(
+            &self.text,
+            self.style.text.font_size,
+            runs.as_slice(),
+        );
 
         let size = vec2f(
             line.width()
@@ -159,8 +161,8 @@ impl<V: View> Element<V> for Label {
         bounds: RectF,
         visible_bounds: RectF,
         line: &mut Self::LayoutState,
-        _: &V,
-        cx: &mut ViewContext<Self>,
+        _: &mut V,
+        cx: &mut ViewContext<V>,
     ) -> Self::PaintState {
         line.paint(
             scene,

crates/gpui/src/elements/list.rs 🔗

@@ -13,7 +13,6 @@ pub struct List<V: View> {
     state: ListState<V>,
 }
 
-#[derive(Clone)]
 pub struct ListState<V: View>(Rc<RefCell<StateInner<V>>>);
 
 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
@@ -42,7 +41,7 @@ pub struct ListOffset {
 
 enum ListItem<V: View> {
     Unrendered,
-    Rendered(Rc<ElementBox<V>>),
+    Rendered(Rc<RefCell<ElementBox<V>>>),
     Removed(f32),
 }
 
@@ -145,7 +144,7 @@ impl<V: View> Element<V> for List<V> {
                 view,
                 cx,
             ) {
-                rendered_height += element.size().y();
+                rendered_height += element.borrow().size().y();
                 rendered_items.push_back(ListItem::Rendered(element));
             }
         }
@@ -162,7 +161,7 @@ impl<V: View> Element<V> for List<V> {
                     if let Some(element) =
                         state.render_item(cursor.start().0, None, item_constraint, view, cx)
                     {
-                        rendered_height += element.size().y();
+                        rendered_height += element.borrow().size().y();
                         rendered_items.push_front(ListItem::Rendered(element));
                     }
                 } else {
@@ -198,7 +197,7 @@ impl<V: View> Element<V> for List<V> {
                 if let Some(element) =
                     state.render_item(cursor.start().0, Some(item), item_constraint, view, cx)
                 {
-                    leading_overdraw += element.size().y();
+                    leading_overdraw += element.borrow().size().y();
                     rendered_items.push_front(ListItem::Rendered(element));
                 }
             } else {
@@ -264,12 +263,13 @@ impl<V: View> Element<V> for List<V> {
                 let state = self.state.clone();
                 let height = bounds.height();
                 let scroll_top = scroll_top.clone();
-                move |e, cx| {
+                move |e, view, cx| {
                     state.0.borrow_mut().scroll(
                         &scroll_top,
                         height,
                         *e.platform_event.delta.raw(),
                         e.platform_event.delta.precise(),
+                        view,
                         cx,
                     )
                 }
@@ -277,8 +277,10 @@ impl<V: View> Element<V> for List<V> {
         );
 
         let state = &mut *self.state.0.borrow_mut();
-        for (mut element, origin) in state.visible_elements(bounds, scroll_top) {
-            element.paint(scene, origin, visible_bounds, view, cx);
+        for (element, origin) in state.visible_elements(bounds, scroll_top) {
+            element
+                .borrow_mut()
+                .paint(scene, origin, visible_bounds, view, cx);
         }
 
         scene.pop_layer();
@@ -304,11 +306,15 @@ impl<V: View> Element<V> for List<V> {
             }
 
             if let ListItem::Rendered(element) = item {
-                if let Some(rect) = element.rect_for_text_range(range_utf16.clone(), view, cx) {
+                if let Some(rect) =
+                    element
+                        .borrow()
+                        .rect_for_text_range(range_utf16.clone(), view, cx)
+                {
                     return Some(rect);
                 }
 
-                item_origin.set_y(item_origin.y() + element.size().y());
+                item_origin.set_y(item_origin.y() + element.borrow().size().y());
                 cursor.next(&());
             } else {
                 unreachable!();
@@ -329,7 +335,7 @@ impl<V: View> Element<V> for List<V> {
         let state = self.state.0.borrow_mut();
         let visible_elements = state
             .visible_elements(bounds, scroll_top)
-            .map(|e| e.0.debug(view, cx))
+            .map(|e| e.0.borrow().debug(view, cx))
             .collect::<Vec<_>>();
         let visible_range = scroll_top.item_ix..(scroll_top.item_ix + visible_elements.len());
         json!({
@@ -345,8 +351,7 @@ impl<V: View> ListState<V> {
         element_count: usize,
         orientation: Orientation,
         overdraw: f32,
-        cx: &mut ViewContext<V>,
-        mut render_item: F,
+        render_item: F,
     ) -> Self
     where
         V: View,
@@ -354,14 +359,9 @@ impl<V: View> ListState<V> {
     {
         let mut items = SumTree::new();
         items.extend((0..element_count).map(|_| ListItem::Unrendered), &());
-        let handle = cx.weak_handle();
         Self(Rc::new(RefCell::new(StateInner {
             last_layout_width: None,
-            render_item: Box::new(move |ix, view, cx| {
-                render_item(view, ix, cx)
-                // let handle = handle.upgrade(cx)?;
-                // Some(cx.render(&handle, |view, cx| render_item(view, ix, cx)))
-            }),
+            render_item: Box::new(render_item),
             rendered_range: 0..0,
             items,
             logical_scroll_top: None,
@@ -439,6 +439,12 @@ impl<V: View> ListState<V> {
     }
 }
 
+impl<V: View> Clone for ListState<V> {
+    fn clone(&self) -> Self {
+        Self(self.0.clone())
+    }
+}
+
 impl<V: View> StateInner<V> {
     fn render_item(
         &mut self,
@@ -447,13 +453,13 @@ impl<V: View> StateInner<V> {
         constraint: SizeConstraint,
         view: &mut V,
         cx: &mut ViewContext<V>,
-    ) -> Option<Rc<ElementBox<V>>> {
+    ) -> Option<Rc<RefCell<ElementBox<V>>>> {
         if let Some(ListItem::Rendered(element)) = existing_element {
             Some(element.clone())
         } else {
             let mut element = (self.render_item)(view, ix, cx);
             element.layout(constraint, view, cx);
-            Some(element.into())
+            Some(Rc::new(RefCell::new(element)))
         }
     }
 
@@ -469,7 +475,7 @@ impl<V: View> StateInner<V> {
         &'a self,
         bounds: RectF,
         scroll_top: &ListOffset,
-    ) -> impl Iterator<Item = (Rc<ElementBox<V>>, Vector2F)> + 'a {
+    ) -> impl Iterator<Item = (Rc<RefCell<ElementBox<V>>>, Vector2F)> + 'a {
         let mut item_origin = bounds.origin() - vec2f(0., scroll_top.offset_in_item);
         let mut cursor = self.items.cursor::<Count>();
         cursor.seek(&Count(scroll_top.item_ix), Bias::Right, &());
@@ -481,7 +487,7 @@ impl<V: View> StateInner<V> {
 
                 if let ListItem::Rendered(element) = item {
                     let result = (element.clone(), item_origin);
-                    item_origin.set_y(item_origin.y() + element.size().y());
+                    item_origin.set_y(item_origin.y() + element.borrow().size().y());
                     cursor.next(&());
                     return Some(result);
                 }
@@ -526,7 +532,7 @@ impl<V: View> StateInner<V> {
 
         if self.scroll_handler.is_some() {
             let visible_range = self.visible_range(height, scroll_top);
-            self.scroll_handler.as_mut().unwrap()(visible_range, cx);
+            self.scroll_handler.as_mut().unwrap()(visible_range, view, cx);
         }
 
         cx.notify();
@@ -557,7 +563,7 @@ impl<V: View> ListItem<V> {
     fn remove(&self) -> Self {
         match self {
             ListItem::Unrendered => ListItem::Unrendered,
-            ListItem::Rendered(element) => ListItem::Removed(element.size().y()),
+            ListItem::Rendered(element) => ListItem::Removed(element.borrow().size().y()),
             ListItem::Removed(height) => ListItem::Removed(*height),
         }
     }
@@ -578,7 +584,7 @@ impl<V: View> sum_tree::Item for ListItem<V> {
                 count: 1,
                 rendered_count: 1,
                 unrendered_count: 0,
-                height: element.size().y(),
+                height: element.borrow().size().y(),
             },
             ListItem::Removed(height) => ListItemSummary {
                 count: 1,
@@ -642,7 +648,6 @@ mod tests {
     use super::*;
     use crate::{elements::Empty, geometry::vector::vec2f, Entity};
     use rand::prelude::*;
-    use std::env;
 
     #[crate::test(self)]
     fn test_layout(cx: &mut crate::AppContext) {

crates/gpui/src/elements/mouse_event_handler.rs 🔗

@@ -7,8 +7,8 @@ use crate::{
     platform::CursorStyle,
     platform::MouseButton,
     scene::{
-        CursorRegion, HandlerSet, MouseClick, MouseDown, MouseDownOut, MouseDrag, MouseHover,
-        MouseMove, MouseMoveOut, MouseScrollWheel, MouseUp, MouseUpOut,
+        CursorRegion, EventContext, HandlerSet, MouseClick, MouseDown, MouseDownOut, MouseDrag,
+        MouseHover, MouseMove, MouseMoveOut, MouseScrollWheel, MouseUp, MouseUpOut,
     },
     Element, ElementBox, MouseRegion, MouseState, SceneBuilder, SizeConstraint, View, ViewContext,
 };
@@ -31,13 +31,13 @@ pub struct MouseEventHandler<Tag: 'static, V: View> {
 /// Element which provides a render_child callback with a MouseState and paints a mouse
 /// region under (or above) it for easy mouse event handling.
 impl<Tag, V: View> MouseEventHandler<Tag, V> {
-    pub fn new<F>(region_id: usize, view: &mut V, cx: &mut ViewContext<V>, render_child: F) -> Self
+    pub fn new<F>(region_id: usize, cx: &mut ViewContext<V>, render_child: F) -> Self
     where
         V: View,
-        F: FnOnce(&mut MouseState, &mut V, &mut ViewContext<V>) -> ElementBox<V>,
+        F: FnOnce(&mut MouseState, &mut ViewContext<V>) -> ElementBox<V>,
     {
         let mut mouse_state = cx.mouse_state::<Tag>(region_id);
-        let child = render_child(&mut mouse_state, view, cx);
+        let child = render_child(&mut mouse_state, cx);
         let notify_on_hover = mouse_state.accessed_hovered();
         let notify_on_click = mouse_state.accessed_clicked();
         Self {
@@ -57,17 +57,12 @@ impl<Tag, V: View> MouseEventHandler<Tag, V> {
     /// Modifies the MouseEventHandler to render the MouseRegion above the child element. Useful
     /// for drag and drop handling and similar events which should be captured before the child
     /// gets the opportunity
-    pub fn above<F>(
-        region_id: usize,
-        view: &mut V,
-        cx: &mut ViewContext<V>,
-        render_child: F,
-    ) -> Self
+    pub fn above<F>(region_id: usize, cx: &mut ViewContext<V>, render_child: F) -> Self
     where
         V: View,
-        F: FnOnce(&mut MouseState, &mut V, &mut ViewContext<V>) -> ElementBox<V>,
+        F: FnOnce(&mut MouseState, &mut ViewContext<V>) -> ElementBox<V>,
     {
-        let mut handler = Self::new(region_id, view, cx, render_child);
+        let mut handler = Self::new(region_id, cx, render_child);
         handler.above = true;
         handler
     }
@@ -82,14 +77,17 @@ impl<Tag, V: View> MouseEventHandler<Tag, V> {
         self
     }
 
-    pub fn on_move(mut self, handler: impl Fn(MouseMove, &mut ViewContext<V>) + 'static) -> Self {
+    pub fn on_move(
+        mut self,
+        handler: impl Fn(MouseMove, &mut V, &mut EventContext<V>) + 'static,
+    ) -> Self {
         self.handlers = self.handlers.on_move(handler);
         self
     }
 
     pub fn on_move_out(
         mut self,
-        handler: impl Fn(MouseMoveOut, &mut ViewContext<V>) + 'static,
+        handler: impl Fn(MouseMoveOut, &mut V, &mut EventContext<V>) + 'static,
     ) -> Self {
         self.handlers = self.handlers.on_move_out(handler);
         self
@@ -98,7 +96,7 @@ impl<Tag, V: View> MouseEventHandler<Tag, V> {
     pub fn on_down(
         mut self,
         button: MouseButton,
-        handler: impl Fn(MouseDown, &mut ViewContext<V>) + 'static,
+        handler: impl Fn(MouseDown, &mut V, &mut EventContext<V>) + 'static,
     ) -> Self {
         self.handlers = self.handlers.on_down(button, handler);
         self
@@ -107,7 +105,7 @@ impl<Tag, V: View> MouseEventHandler<Tag, V> {
     pub fn on_up(
         mut self,
         button: MouseButton,
-        handler: impl Fn(MouseUp, &mut ViewContext<V>) + 'static,
+        handler: impl Fn(MouseUp, &mut V, &mut EventContext<V>) + 'static,
     ) -> Self {
         self.handlers = self.handlers.on_up(button, handler);
         self
@@ -116,7 +114,7 @@ impl<Tag, V: View> MouseEventHandler<Tag, V> {
     pub fn on_click(
         mut self,
         button: MouseButton,
-        handler: impl Fn(MouseClick, &mut ViewContext<V>) + 'static,
+        handler: impl Fn(MouseClick, &mut V, &mut EventContext<V>) + 'static,
     ) -> Self {
         self.handlers = self.handlers.on_click(button, handler);
         self
@@ -125,7 +123,7 @@ impl<Tag, V: View> MouseEventHandler<Tag, V> {
     pub fn on_down_out(
         mut self,
         button: MouseButton,
-        handler: impl Fn(MouseDownOut, &mut ViewContext<V>) + 'static,
+        handler: impl Fn(MouseDownOut, &mut V, &mut EventContext<V>) + 'static,
     ) -> Self {
         self.handlers = self.handlers.on_down_out(button, handler);
         self
@@ -134,7 +132,7 @@ impl<Tag, V: View> MouseEventHandler<Tag, V> {
     pub fn on_up_out(
         mut self,
         button: MouseButton,
-        handler: impl Fn(MouseUpOut, &mut ViewContext<V>) + 'static,
+        handler: impl Fn(MouseUpOut, &mut V, &mut EventContext<V>) + 'static,
     ) -> Self {
         self.handlers = self.handlers.on_up_out(button, handler);
         self
@@ -143,20 +141,23 @@ impl<Tag, V: View> MouseEventHandler<Tag, V> {
     pub fn on_drag(
         mut self,
         button: MouseButton,
-        handler: impl Fn(MouseDrag, &mut ViewContext<V>) + 'static,
+        handler: impl Fn(MouseDrag, &mut V, &mut EventContext<V>) + 'static,
     ) -> Self {
         self.handlers = self.handlers.on_drag(button, handler);
         self
     }
 
-    pub fn on_hover(mut self, handler: impl Fn(MouseHover, &mut ViewContext<V>) + 'static) -> Self {
+    pub fn on_hover(
+        mut self,
+        handler: impl Fn(MouseHover, &mut V, &mut EventContext<V>) + 'static,
+    ) -> Self {
         self.handlers = self.handlers.on_hover(handler);
         self
     }
 
     pub fn on_scroll(
         mut self,
-        handler: impl Fn(MouseScrollWheel, &mut ViewContext<V>) + 'static,
+        handler: impl Fn(MouseScrollWheel, &mut V, &mut EventContext<V>) + 'static,
     ) -> Self {
         self.handlers = self.handlers.on_scroll(handler);
         self
@@ -191,14 +192,14 @@ impl<Tag, V: View> MouseEventHandler<Tag, V> {
         let hit_bounds = self.hit_bounds(visible_bounds);
 
         if let Some(style) = self.cursor_style {
-            cx.scene.push_cursor_region(CursorRegion {
+            scene.push_cursor_region(CursorRegion {
                 bounds: hit_bounds,
                 style,
             });
         }
-        cx.scene.push_mouse_region(
+        scene.push_mouse_region(
             MouseRegion::from_handlers::<Tag>(
-                cx.current_view_id(),
+                cx.view_id(),
                 self.region_id,
                 hit_bounds,
                 self.handlers.clone(),
@@ -236,7 +237,7 @@ impl<Tag, V: View> Element<V> for MouseEventHandler<Tag, V> {
             self.child
                 .paint(scene, bounds.origin(), visible_bounds, view, cx);
 
-            cx.paint_layer(None, |cx| {
+            scene.paint_layer(None, |scene| {
                 self.paint_regions(scene, bounds, visible_bounds, cx);
             });
         } else {
@@ -254,7 +255,7 @@ impl<Tag, V: View> Element<V> for MouseEventHandler<Tag, V> {
         _: &Self::LayoutState,
         _: &Self::PaintState,
         view: &V,
-        cx: &ViewContext<Self>,
+        cx: &ViewContext<V>,
     ) -> Option<RectF> {
         self.child.rect_for_text_range(range_utf16, view, cx)
     }

crates/gpui/src/elements/overlay.rs 🔗

@@ -127,7 +127,7 @@ impl<V: View> Element<V> for Overlay<V> {
         cx: &mut ViewContext<V>,
     ) -> (Vector2F, Self::LayoutState) {
         let constraint = if self.anchor_position.is_some() {
-            SizeConstraint::new(Vector2F::zero(), cx.window_size)
+            SizeConstraint::new(Vector2F::zero(), cx.window_size())
         } else {
             constraint
         };
@@ -137,7 +137,7 @@ impl<V: View> Element<V> for Overlay<V> {
 
     fn paint(
         &mut self,
-        scene: SceneBuilder,
+        scene: &mut SceneBuilder,
         bounds: RectF,
         _: RectF,
         size: &mut Self::LayoutState,
@@ -163,9 +163,9 @@ impl<V: View> Element<V> for Overlay<V> {
             OverlayFitMode::SnapToWindow => {
                 // Snap the horizontal edges of the overlay to the horizontal edges of the window if
                 // its horizontal bounds overflow
-                if bounds.max_x() > cx.window_size.x() {
+                if bounds.max_x() > cx.window_size().x() {
                     let mut lower_right = bounds.lower_right();
-                    lower_right.set_x(cx.window_size.x());
+                    lower_right.set_x(cx.window_size().x());
                     bounds = RectF::from_points(lower_right - *size, lower_right);
                 } else if bounds.min_x() < 0. {
                     let mut upper_left = bounds.origin();
@@ -175,9 +175,9 @@ impl<V: View> Element<V> for Overlay<V> {
 
                 // Snap the vertical edges of the overlay to the vertical edges of the window if
                 // its vertical bounds overflow.
-                if bounds.max_y() > cx.window_size.y() {
+                if bounds.max_y() > cx.window_size().y() {
                     let mut lower_right = bounds.lower_right();
-                    lower_right.set_y(cx.window_size.y());
+                    lower_right.set_y(cx.window_size().y());
                     bounds = RectF::from_points(lower_right - *size, lower_right);
                 } else if bounds.min_y() < 0. {
                     let mut upper_left = bounds.origin();
@@ -188,11 +188,11 @@ impl<V: View> Element<V> for Overlay<V> {
             OverlayFitMode::SwitchAnchor => {
                 let mut anchor_corner = self.anchor_corner;
 
-                if bounds.max_x() > cx.window_size.x() {
+                if bounds.max_x() > cx.window_size().x() {
                     anchor_corner = anchor_corner.switch_axis(Axis::Horizontal);
                 }
 
-                if bounds.max_y() > cx.window_size.y() {
+                if bounds.max_y() > cx.window_size().y() {
                     anchor_corner = anchor_corner.switch_axis(Axis::Vertical);
                 }
 
@@ -212,22 +212,21 @@ impl<V: View> Element<V> for Overlay<V> {
             OverlayFitMode::None => {}
         }
 
-        cx.paint_stacking_context(None, self.z_index, |cx| {
+        scene.paint_stacking_context(None, self.z_index, |scene| {
             if self.hoverable {
                 enum OverlayHoverCapture {}
                 // Block hovers in lower stacking contexts
-                cx.scene
-                    .push_mouse_region(MouseRegion::new::<OverlayHoverCapture>(
-                        cx.current_view_id(),
-                        cx.current_view_id(),
-                        bounds,
-                    ));
+                scene.push_mouse_region(MouseRegion::new::<OverlayHoverCapture>(
+                    cx.view_id(),
+                    cx.view_id(),
+                    bounds,
+                ));
             }
 
             self.child.paint(
                 scene,
                 bounds.origin(),
-                RectF::new(Vector2F::zero(), cx.window_size),
+                RectF::new(Vector2F::zero(), cx.window_size()),
                 view,
                 cx,
             );

crates/gpui/src/elements/resizable.rs 🔗

@@ -154,32 +154,28 @@ impl<V: View> Element<V> for Resizable<V> {
         view: &mut V,
         cx: &mut ViewContext<V>,
     ) -> Self::PaintState {
-        cx.scene.push_stacking_context(None, None);
+        scene.push_stacking_context(None, None);
 
         let handle_region = self.side.of_rect(bounds, self.handle_size);
 
         enum ResizeHandle {}
-        cx.scene.push_mouse_region(
-            MouseRegion::new::<ResizeHandle>(
-                cx.current_view_id(),
-                self.side as usize,
-                handle_region,
-            )
-            .on_down(MouseButton::Left, |_, _| {}) // This prevents the mouse down event from being propagated elsewhere
-            .on_drag(MouseButton::Left, {
-                let state = self.state.clone();
-                let side = self.side;
-                move |e, cx| {
-                    let prev_width = state.actual_dimension.get();
-                    state
-                        .custom_dimension
-                        .set(0f32.max(prev_width + side.compute_delta(e)).round());
-                    cx.notify();
-                }
-            }),
+        scene.push_mouse_region(
+            MouseRegion::new::<ResizeHandle>(cx.view_id(), self.side as usize, handle_region)
+                .on_down(MouseButton::Left, |_, _: &mut V, _| {}) // This prevents the mouse down event from being propagated elsewhere
+                .on_drag(MouseButton::Left, {
+                    let state = self.state.clone();
+                    let side = self.side;
+                    move |e, _: &mut V, cx| {
+                        let prev_width = state.actual_dimension.get();
+                        state
+                            .custom_dimension
+                            .set(0f32.max(prev_width + side.compute_delta(e)).round());
+                        cx.notify();
+                    }
+                }),
         );
 
-        cx.scene.push_cursor_region(crate::CursorRegion {
+        scene.push_cursor_region(crate::CursorRegion {
             bounds: handle_region,
             style: match self.side.axis() {
                 Axis::Horizontal => CursorStyle::ResizeLeftRight,
@@ -187,7 +183,7 @@ impl<V: View> Element<V> for Resizable<V> {
             },
         });
 
-        cx.scene.pop_stacking_context();
+        scene.pop_stacking_context();
 
         self.child
             .paint(scene, bounds.origin(), visible_bounds, view, cx);

crates/gpui/src/elements/stack.rs 🔗

@@ -8,11 +8,18 @@ use crate::{
 
 /// Element which renders it's children in a stack on top of each other.
 /// The first child determines the size of the others.
-#[derive(Default)]
 pub struct Stack<V: View> {
     children: Vec<ElementBox<V>>,
 }
 
+impl<V: View> Default for Stack<V> {
+    fn default() -> Self {
+        Self {
+            children: Vec::new(),
+        }
+    }
+}
+
 impl<V: View> Stack<V> {
     pub fn new() -> Self {
         Self::default()
@@ -53,7 +60,7 @@ impl<V: View> Element<V> for Stack<V> {
         cx: &mut ViewContext<V>,
     ) -> Self::PaintState {
         for child in &mut self.children {
-            cx.paint_layer(None, |cx| {
+            scene.paint_layer(None, |scene| {
                 child.paint(scene, bounds.origin(), visible_bounds, view, cx);
             });
         }

crates/gpui/src/elements/svg.rs 🔗

@@ -37,7 +37,7 @@ impl<V: View> Element<V> for Svg {
     fn layout(
         &mut self,
         constraint: SizeConstraint,
-        view: &mut V,
+        _: &mut V,
         cx: &mut ViewContext<V>,
     ) -> (Vector2F, Self::LayoutState) {
         match cx.asset_cache.svg(&self.path) {

crates/gpui/src/elements/text.rs 🔗

@@ -98,7 +98,7 @@ impl<V: View> Element<V> for Text {
         let shaped_lines = layout_highlighted_chunks(
             chunks,
             &self.style,
-            cx.text_layout_cache,
+            cx.text_layout_cache(),
             &cx.font_cache,
             usize::MAX,
             self.text.matches('\n').count() + 1,
@@ -213,9 +213,9 @@ impl<V: View> Element<V> for Text {
 /// Perform text layout on a series of highlighted chunks of text.
 pub fn layout_highlighted_chunks<'a>(
     chunks: impl Iterator<Item = (&'a str, Option<HighlightStyle>)>,
-    text_style: &'a TextStyle,
-    text_layout_cache: &'a TextLayoutCache,
-    font_cache: &'a Arc<FontCache>,
+    text_style: &TextStyle,
+    text_layout_cache: &TextLayoutCache,
+    font_cache: &Arc<FontCache>,
     max_line_len: usize,
     max_line_count: usize,
 ) -> Vec<Line> {
@@ -276,26 +276,22 @@ pub fn layout_highlighted_chunks<'a>(
 #[cfg(test)]
 mod tests {
     use super::*;
-    use crate::{
-        elements::Empty, fonts, platform, AppContext, ElementBox, Entity, View, ViewContext,
-    };
+    use crate::{elements::Empty, fonts, AppContext, ElementBox, Entity, View, ViewContext};
 
     #[crate::test(self)]
     fn test_soft_wrapping_with_carriage_returns(cx: &mut AppContext) {
         let (window_id, root_view) = cx.add_window(Default::default(), |_| TestView);
-        let mut presenter = cx.build_window(
-            window_id,
-            root_view.into_any(),
-            Box::new(platform::test::Window::new(Vector2F::new(800., 600.))),
-        );
         fonts::with_font_cache(cx.font_cache().clone(), || {
-            let mut text = Text::new("Hello\r\n", Default::default()).with_soft_wrap(true);
-            let (_, state) = text.layout(
-                SizeConstraint::new(Default::default(), vec2f(f32::INFINITY, f32::INFINITY)),
-                &mut presenter.build_layout_context(Default::default(), false, cx),
-            );
-            assert_eq!(state.shaped_lines.len(), 2);
-            assert_eq!(state.wrap_boundaries.len(), 2);
+            root_view.update(cx, |view, cx| {
+                let mut text = Text::new("Hello\r\n", Default::default()).with_soft_wrap(true);
+                let (_, state) = text.layout(
+                    SizeConstraint::new(Default::default(), vec2f(f32::INFINITY, f32::INFINITY)),
+                    view,
+                    cx,
+                );
+                assert_eq!(state.shaped_lines.len(), 2);
+                assert_eq!(state.wrap_boundaries.len(), 2);
+            });
         });
     }
 

crates/gpui/src/elements/tooltip.rs 🔗

@@ -55,7 +55,6 @@ impl<V: View> Tooltip<V> {
         action: Option<Box<dyn Action>>,
         style: TooltipStyle,
         child: ElementBox<V>,
-        view: &mut V,
         cx: &mut ViewContext<V>,
     ) -> Self {
         struct ElementState<Tag>(Tag);
@@ -78,10 +77,10 @@ impl<V: View> Tooltip<V> {
                 Overlay::new(
                     Self::render_tooltip(cx.window_id, focused_view_id, text, style, action, false)
                         .constrained()
-                        .dynamically(move |constraint, cx| {
+                        .dynamically(move |constraint, view, cx| {
                             SizeConstraint::strict_along(
                                 Axis::Vertical,
-                                collapsed_tooltip.layout(constraint, cx).y(),
+                                collapsed_tooltip.layout(constraint, view, cx).y(),
                             )
                         })
                         .boxed(),
@@ -93,36 +92,34 @@ impl<V: View> Tooltip<V> {
         } else {
             None
         };
-        let child =
-            MouseEventHandler::<MouseEventHandlerState<Tag>>::new(id, view, cx, |_, _| child)
-                .on_hover(move |e, cx| {
-                    let position = e.position;
-                    let window_id = cx.window_id();
-                    if let Some(view_id) = cx.view_id() {
-                        if e.started {
-                            if !state.visible.get() {
-                                state.position.set(position);
+        let child = MouseEventHandler::<MouseEventHandlerState<Tag>, _>::new(id, cx, |_, _| child)
+            .on_hover(move |e, _, cx| {
+                let position = e.position;
+                let window_id = cx.window_id();
+                let view_id = cx.view_id();
+                if e.started {
+                    if !state.visible.get() {
+                        state.position.set(position);
 
-                                let mut debounce = state.debounce.borrow_mut();
-                                if debounce.is_none() {
-                                    *debounce = Some(cx.spawn({
-                                        let state = state.clone();
-                                        |mut cx| async move {
-                                            cx.background().timer(DEBOUNCE_TIMEOUT).await;
-                                            state.visible.set(true);
-                                            cx.update(|cx| cx.notify_view(window_id, view_id));
-                                        }
-                                    }));
+                        let mut debounce = state.debounce.borrow_mut();
+                        if debounce.is_none() {
+                            *debounce = Some(cx.spawn({
+                                let state = state.clone();
+                                |_, mut cx| async move {
+                                    cx.background().timer(DEBOUNCE_TIMEOUT).await;
+                                    state.visible.set(true);
+                                    cx.update(|cx| cx.notify_view(window_id, view_id));
                                 }
-                            }
-                        } else {
-                            state.visible.set(false);
-                            state.debounce.take();
-                            cx.notify();
+                            }));
                         }
                     }
-                })
-                .boxed();
+                } else {
+                    state.visible.set(false);
+                    state.debounce.take();
+                    cx.notify();
+                }
+            })
+            .boxed();
         Self {
             child,
             tooltip,
@@ -137,7 +134,7 @@ impl<V: View> Tooltip<V> {
         style: TooltipStyle,
         action: Option<Box<dyn Action>>,
         measure: bool,
-    ) -> impl Element {
+    ) -> impl Element<V> {
         Flex::row()
             .with_child({
                 let text = Text::new(text, style.text)
@@ -181,7 +178,7 @@ impl<V: View> Element<V> for Tooltip<V> {
         let size = self.child.layout(constraint, view, cx);
         if let Some(tooltip) = self.tooltip.as_mut() {
             tooltip.layout(
-                SizeConstraint::new(Vector2F::zero(), cx.window_size),
+                SizeConstraint::new(Vector2F::zero(), cx.window_size()),
                 view,
                 cx,
             );

crates/gpui/src/elements/uniform_list.rs 🔗

@@ -6,7 +6,6 @@ use crate::{
     },
     json::{self, json},
     platform::ScrollWheelEvent,
-    scene::MouseScrollWheel,
     ElementBox, MouseRegion, SceneBuilder, View, ViewContext,
 };
 use json::ToJson;
@@ -47,7 +46,7 @@ pub struct UniformList<V: View> {
     state: UniformListState,
     item_count: usize,
     #[allow(clippy::type_complexity)]
-    append_items: Box<dyn Fn(Range<usize>, &mut Vec<ElementBox<V>>, &mut V, &mut ViewContext<V>)>,
+    append_items: Box<dyn Fn(&mut V, Range<usize>, &mut Vec<ElementBox<V>>, &mut ViewContext<V>)>,
     padding_top: f32,
     padding_bottom: f32,
     get_width_from_item: Option<usize>,
@@ -63,19 +62,12 @@ impl<V: View> UniformList<V> {
     ) -> Self
     where
         V: View,
-        F: 'static + Fn(&mut V, Range<usize>, &mut Vec<ElementBox<V>>, &mut V, &mut ViewContext<V>),
+        F: 'static + Fn(&mut V, Range<usize>, &mut Vec<ElementBox<V>>, &mut ViewContext<V>),
     {
-        let handle = cx.handle();
         Self {
             state,
             item_count,
-            append_items: Box::new(move |range, items, cx| {
-                if let Some(handle) = handle.upgrade(cx) {
-                    cx.render(&handle, |view, cx| {
-                        append_items(view, range, items, cx);
-                    });
-                }
-            }),
+            append_items: Box::new(append_items),
             padding_top: 0.,
             padding_bottom: 0.,
             get_width_from_item: None,
@@ -194,18 +186,18 @@ impl<V: View> Element<V> for UniformList<V> {
         let sample_item_ix;
         let sample_item;
         if let Some(sample_ix) = self.get_width_from_item {
-            (self.append_items)(sample_ix..sample_ix + 1, &mut items, cx);
+            (self.append_items)(view, sample_ix..sample_ix + 1, &mut items, cx);
             sample_item_ix = sample_ix;
 
             if let Some(mut item) = items.pop() {
-                item_size = item.layout(constraint, cx);
+                item_size = item.layout(constraint, view, cx);
                 size.set_x(item_size.x());
                 sample_item = item;
             } else {
                 return no_items;
             }
         } else {
-            (self.append_items)(0..1, &mut items, cx);
+            (self.append_items)(view, 0..1, &mut items, cx);
             sample_item_ix = 0;
             if let Some(mut item) = items.pop() {
                 item_size = item.layout(
@@ -213,6 +205,7 @@ impl<V: View> Element<V> for UniformList<V> {
                         vec2f(constraint.max.x(), 0.0),
                         vec2f(constraint.max.x(), f32::INFINITY),
                     ),
+                    view,
                     cx,
                 );
                 item_size.set_x(size.x());
@@ -249,16 +242,16 @@ impl<V: View> Element<V> for UniformList<V> {
 
         if (start..end).contains(&sample_item_ix) {
             if sample_item_ix > start {
-                (self.append_items)(start..sample_item_ix, &mut items, cx);
+                (self.append_items)(view, start..sample_item_ix, &mut items, cx);
             }
 
             items.push(sample_item);
 
             if sample_item_ix < end {
-                (self.append_items)(sample_item_ix + 1..end, &mut items, cx);
+                (self.append_items)(view, sample_item_ix + 1..end, &mut items, cx);
             }
         } else {
-            (self.append_items)(start..end, &mut items, cx);
+            (self.append_items)(view, start..end, &mut items, cx);
         }
 
         for item in &mut items {
@@ -289,20 +282,16 @@ impl<V: View> Element<V> for UniformList<V> {
     ) -> Self::PaintState {
         let visible_bounds = visible_bounds.intersection(bounds).unwrap_or_default();
 
-        cx.scene.push_layer(Some(visible_bounds));
+        scene.push_layer(Some(visible_bounds));
 
-        cx.scene.push_mouse_region(
+        scene.push_mouse_region(
             MouseRegion::new::<Self>(self.view_id, 0, visible_bounds).on_scroll({
                 let scroll_max = layout.scroll_max;
                 let state = self.state.clone();
-                move |MouseScrollWheel {
-                          platform_event:
-                              ScrollWheelEvent {
-                                  position, delta, ..
-                              },
-                          ..
-                      },
-                      cx| {
+                move |event, _, cx| {
+                    let ScrollWheelEvent {
+                        position, delta, ..
+                    } = event.platform_event;
                     if !Self::scroll(
                         state.clone(),
                         position,
@@ -328,7 +317,7 @@ impl<V: View> Element<V> for UniformList<V> {
             item_origin += vec2f(0.0, layout.item_height);
         }
 
-        cx.scene.pop_layer();
+        scene.pop_layer();
     }
 
     fn rect_for_text_range(

crates/gpui/src/gpui.rs 🔗

@@ -15,7 +15,9 @@ pub use clipboard::ClipboardItem;
 pub mod fonts;
 pub mod geometry;
 pub mod scene;
-pub use scene::{Border, CursorRegion, MouseRegion, MouseRegionId, Quad, Scene, SceneBuilder};
+pub use scene::{
+    Border, CursorRegion, EventContext, MouseRegion, MouseRegionId, Quad, Scene, SceneBuilder,
+};
 pub mod text_layout;
 pub use text_layout::TextLayoutCache;
 mod util;

crates/gpui/src/scene.rs 🔗

@@ -236,6 +236,19 @@ impl SceneBuilder {
         self.scale_factor
     }
 
+    pub fn paint_stacking_context<F>(
+        &mut self,
+        clip_bounds: Option<RectF>,
+        z_index: Option<usize>,
+        f: F,
+    ) where
+        F: FnOnce(&mut Self),
+    {
+        self.push_stacking_context(clip_bounds, z_index);
+        f(self);
+        self.pop_stacking_context();
+    }
+
     pub fn push_stacking_context(&mut self, clip_bounds: Option<RectF>, z_index: Option<usize>) {
         let z_index = z_index.unwrap_or_else(|| self.active_stacking_context().z_index + 1);
         self.active_stacking_context_stack
@@ -249,6 +262,15 @@ impl SceneBuilder {
         assert!(!self.active_stacking_context_stack.is_empty());
     }
 
+    pub fn paint_layer<F>(&mut self, clip_bounds: Option<RectF>, f: F)
+    where
+        F: FnOnce(&mut Self),
+    {
+        self.push_layer(clip_bounds);
+        f(self);
+        self.pop_layer();
+    }
+
     pub fn push_layer(&mut self, clip_bounds: Option<RectF>) {
         self.active_stacking_context().push_layer(clip_bounds);
     }

crates/gpui/src/scene/mouse_region.rs 🔗

@@ -1,4 +1,10 @@
-use std::{any::TypeId, fmt::Debug, mem::Discriminant, rc::Rc};
+use std::{
+    any::{Any, TypeId},
+    fmt::Debug,
+    mem::Discriminant,
+    ops::{Deref, DerefMut},
+    rc::Rc,
+};
 
 use collections::HashMap;
 
@@ -63,7 +69,7 @@ impl MouseRegion {
     pub fn on_down<V, F>(mut self, button: MouseButton, handler: F) -> Self
     where
         V: View,
-        F: Fn(MouseDown, &mut V, &mut ViewContext<V>) + 'static,
+        F: Fn(MouseDown, &mut V, &mut EventContext<V>) + 'static,
     {
         self.handlers = self.handlers.on_down(button, handler);
         self
@@ -72,7 +78,7 @@ impl MouseRegion {
     pub fn on_up<V, F>(mut self, button: MouseButton, handler: F) -> Self
     where
         V: View,
-        F: Fn(MouseUp, &mut V, &mut ViewContext<V>) + 'static,
+        F: Fn(MouseUp, &mut V, &mut EventContext<V>) + 'static,
     {
         self.handlers = self.handlers.on_up(button, handler);
         self
@@ -81,7 +87,7 @@ impl MouseRegion {
     pub fn on_click<V, F>(mut self, button: MouseButton, handler: F) -> Self
     where
         V: View,
-        F: Fn(MouseClick, &mut V, &mut ViewContext<V>) + 'static,
+        F: Fn(MouseClick, &mut V, &mut EventContext<V>) + 'static,
     {
         self.handlers = self.handlers.on_click(button, handler);
         self
@@ -90,7 +96,7 @@ impl MouseRegion {
     pub fn on_down_out<V, F>(mut self, button: MouseButton, handler: F) -> Self
     where
         V: View,
-        F: Fn(MouseDownOut, &mut V, &mut ViewContext<V>) + 'static,
+        F: Fn(MouseDownOut, &mut V, &mut EventContext<V>) + 'static,
     {
         self.handlers = self.handlers.on_down_out(button, handler);
         self
@@ -99,7 +105,7 @@ impl MouseRegion {
     pub fn on_up_out<V, F>(mut self, button: MouseButton, handler: F) -> Self
     where
         V: View,
-        F: Fn(MouseUpOut, &mut V, &mut ViewContext<V>) + 'static,
+        F: Fn(MouseUpOut, &mut V, &mut EventContext<V>) + 'static,
     {
         self.handlers = self.handlers.on_up_out(button, handler);
         self
@@ -108,7 +114,7 @@ impl MouseRegion {
     pub fn on_drag<V, F>(mut self, button: MouseButton, handler: F) -> Self
     where
         V: View,
-        F: Fn(MouseDrag, &mut V, &mut ViewContext<V>) + 'static,
+        F: Fn(MouseDrag, &mut V, &mut EventContext<V>) + 'static,
     {
         self.handlers = self.handlers.on_drag(button, handler);
         self
@@ -117,7 +123,7 @@ impl MouseRegion {
     pub fn on_hover<V, F>(mut self, handler: F) -> Self
     where
         V: View,
-        F: Fn(&mut V, &mut ViewContext<V>) + 'static,
+        F: Fn(MouseHover, &mut V, &mut EventContext<V>) + 'static,
     {
         self.handlers = self.handlers.on_hover(handler);
         self
@@ -126,7 +132,7 @@ impl MouseRegion {
     pub fn on_move<V, F>(mut self, handler: F) -> Self
     where
         V: View,
-        F: Fn(&mut V, &mut ViewContext<V>) + 'static,
+        F: Fn(MouseMove, &mut V, &mut EventContext<V>) + 'static,
     {
         self.handlers = self.handlers.on_move(handler);
         self
@@ -135,7 +141,7 @@ impl MouseRegion {
     pub fn on_move_out<V, F>(mut self, handler: F) -> Self
     where
         V: View,
-        F: Fn(&mut V, &mut ViewContext<V>) + 'static,
+        F: Fn(MouseMoveOut, &mut V, &mut EventContext<V>) + 'static,
     {
         self.handlers = self.handlers.on_move_out(handler);
         self
@@ -144,7 +150,7 @@ impl MouseRegion {
     pub fn on_scroll<V, F>(mut self, handler: F) -> Self
     where
         V: View,
-        F: Fn(&mut V, &mut ViewContext<V>) + 'static,
+        F: Fn(MouseScrollWheel, &mut V, &mut EventContext<V>) + 'static,
     {
         self.handlers = self.handlers.on_scroll(handler);
         self
@@ -196,7 +202,39 @@ impl MouseRegionId {
     }
 }
 
-pub type HandlerCallback = Rc<dyn Fn(MouseEvent, &mut WindowContext)>;
+pub struct EventContext<'a, 'b, 'c, 'd, V: View> {
+    view_context: &'d mut ViewContext<'a, 'b, 'c, V>,
+    handled: bool,
+}
+
+impl<'a, 'b, 'c, 'd, V: View> EventContext<'a, 'b, 'c, 'd, V> {
+    fn new(view_context: &'d mut ViewContext<'a, 'b, 'c, V>) -> Self {
+        EventContext {
+            view_context,
+            handled: true,
+        }
+    }
+
+    pub fn propagate_event(&mut self) {
+        self.handled = false;
+    }
+}
+
+impl<'a, 'b, 'c, 'd, V: View> Deref for EventContext<'a, 'b, 'c, 'd, V> {
+    type Target = ViewContext<'a, 'b, 'c, V>;
+
+    fn deref(&self) -> &Self::Target {
+        &self.view_context
+    }
+}
+
+impl<V: View> DerefMut for EventContext<'_, '_, '_, '_, V> {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.view_context
+    }
+}
+
+pub type HandlerCallback = Rc<dyn Fn(MouseEvent, &mut dyn Any, &mut WindowContext, usize) -> bool>;
 
 #[derive(Clone, PartialEq, Eq, Hash)]
 pub struct HandlerKey {
@@ -221,41 +259,41 @@ impl HandlerSet {
 
         set.insert(
             HandlerKey::new(MouseEvent::move_disc(), None),
-            SmallVec::from_buf([Rc::new(|_, _| {})]),
+            SmallVec::from_buf([Rc::new(|_, _, _, _| false)]),
         );
         set.insert(
             HandlerKey::new(MouseEvent::hover_disc(), None),
-            SmallVec::from_buf([Rc::new(|_, _| {})]),
+            SmallVec::from_buf([Rc::new(|_, _, _, _| false)]),
         );
         for button in MouseButton::all() {
             set.insert(
                 HandlerKey::new(MouseEvent::drag_disc(), Some(button)),
-                SmallVec::from_buf([Rc::new(|_, _| {})]),
+                SmallVec::from_buf([Rc::new(|_, _, _, _| false)]),
             );
             set.insert(
                 HandlerKey::new(MouseEvent::down_disc(), Some(button)),
-                SmallVec::from_buf([Rc::new(|_, _| {})]),
+                SmallVec::from_buf([Rc::new(|_, _, _, _| false)]),
             );
             set.insert(
                 HandlerKey::new(MouseEvent::up_disc(), Some(button)),
-                SmallVec::from_buf([Rc::new(|_, _| {})]),
+                SmallVec::from_buf([Rc::new(|_, _, _, _| false)]),
             );
             set.insert(
                 HandlerKey::new(MouseEvent::click_disc(), Some(button)),
-                SmallVec::from_buf([Rc::new(|_, _| {})]),
+                SmallVec::from_buf([Rc::new(|_, _, _, _| false)]),
             );
             set.insert(
                 HandlerKey::new(MouseEvent::down_out_disc(), Some(button)),
-                SmallVec::from_buf([Rc::new(|_, _| {})]),
+                SmallVec::from_buf([Rc::new(|_, _, _, _| false)]),
             );
             set.insert(
                 HandlerKey::new(MouseEvent::up_out_disc(), Some(button)),
-                SmallVec::from_buf([Rc::new(|_, _| {})]),
+                SmallVec::from_buf([Rc::new(|_, _, _, _| false)]),
             );
         }
         set.insert(
             HandlerKey::new(MouseEvent::scroll_wheel_disc(), None),
-            SmallVec::from_buf([Rc::new(|_, _| {})]),
+            SmallVec::from_buf([Rc::new(|_, _, _, _| false)]),
         );
 
         HandlerSet { set }
@@ -296,12 +334,16 @@ impl HandlerSet {
     pub fn on_move<V, F>(mut self, handler: F) -> Self
     where
         V: View,
-        F: Fn(MouseMove, &mut V, &mut ViewContext<Self>) + 'static,
+        F: Fn(MouseMove, &mut V, &mut EventContext<V>) + 'static,
     {
         self.insert(MouseEvent::move_disc(), None,
-            Rc::new(move |region_event, cx| {
+            Rc::new(move |region_event, view, cx, view_id| {
                 if let MouseEvent::Move(e) = region_event {
-                    handler(e, cx);
+                    let view = view.downcast_mut().unwrap();
+                    let mut cx = ViewContext::mutable(cx, view_id);
+                    let mut cx = EventContext::new(&mut cx);
+                    handler(e, view, &mut cx);
+                    cx.handled
                 } else {
                     panic!(
                         "Mouse Region Event incorrectly called with mismatched event type. Expected MouseRegionEvent::Move, found {:?}",
@@ -314,12 +356,16 @@ impl HandlerSet {
     pub fn on_move_out<V, F>(mut self, handler: F) -> Self
     where
         V: View,
-        F: Fn(MouseMoveOut, &mut V, &mut ViewContext<V>) + 'static,
+        F: Fn(MouseMoveOut, &mut V, &mut EventContext<V>) + 'static,
     {
         self.insert(MouseEvent::move_out_disc(), None,
-            Rc::new(move |region_event, cx| {
+            Rc::new(move |region_event, view, cx, view_id| {
                 if let MouseEvent::MoveOut(e) = region_event {
-                    handler(e, cx);
+                    let view = view.downcast_mut().unwrap();
+                    let mut cx = ViewContext::<V>::mutable(cx, view_id);
+                    let mut cx = EventContext::new(&mut cx);
+                    handler(e, view, &mut cx);
+                    cx.handled
                 } else {
                     panic!(
                         "Mouse Region Event incorrectly called with mismatched event type. Expected MouseRegionEvent::MoveOut, found {:?}",
@@ -332,12 +378,16 @@ impl HandlerSet {
     pub fn on_down<V, F>(mut self, button: MouseButton, handler: F) -> Self
     where
         V: View,
-        F: Fn(MouseDown, &mut V, &mut ViewContext<V>) + 'static,
+        F: Fn(MouseDown, &mut V, &mut EventContext<V>) + 'static,
     {
         self.insert(MouseEvent::down_disc(), Some(button),
-            Rc::new(move |region_event, cx| {
+            Rc::new(move |region_event, view, cx, view_id| {
                 if let MouseEvent::Down(e) = region_event {
-                    handler(e, cx);
+                    let view = view.downcast_mut().unwrap();
+                    let mut cx = ViewContext::mutable(cx, view_id);
+                    let mut cx = EventContext::new(&mut cx);
+                    handler(e, view, &mut cx);
+                    cx.handled
                 } else {
                     panic!(
                         "Mouse Region Event incorrectly called with mismatched event type. Expected MouseRegionEvent::Down, found {:?}",
@@ -350,12 +400,16 @@ impl HandlerSet {
     pub fn on_up<V, F>(mut self, button: MouseButton, handler: F) -> Self
     where
         V: View,
-        F: Fn(MouseUp, &mut V, &mut ViewContext<V>) + 'static,
+        F: Fn(MouseUp, &mut V, &mut EventContext<V>) + 'static,
     {
         self.insert(MouseEvent::up_disc(), Some(button),
-            Rc::new(move |region_event, cx| {
+            Rc::new(move |region_event, view, cx, view_id| {
                 if let MouseEvent::Up(e) = region_event {
-                    handler(e, cx);
+                    let view = view.downcast_mut().unwrap();
+                    let mut cx = ViewContext::mutable(cx, view_id);
+                    let mut cx = EventContext::new(&mut cx);
+                    handler(e, view, &mut cx);
+                    cx.handled
                 } else {
                     panic!(
                         "Mouse Region Event incorrectly called with mismatched event type. Expected MouseRegionEvent::Up, found {:?}",
@@ -368,12 +422,16 @@ impl HandlerSet {
     pub fn on_click<V, F>(mut self, button: MouseButton, handler: F) -> Self
     where
         V: View,
-        F: Fn(MouseClick, &mut V, &mut ViewContext<V>) + 'static,
+        F: Fn(MouseClick, &mut V, &mut EventContext<V>) + 'static,
     {
         self.insert(MouseEvent::click_disc(), Some(button),
-            Rc::new(move |region_event, cx| {
+            Rc::new(move |region_event, view, cx, view_id| {
                 if let MouseEvent::Click(e) = region_event {
-                    handler(e, cx);
+                    let view = view.downcast_mut().unwrap();
+                    let mut cx = ViewContext::mutable(cx, view_id);
+                    let mut cx = EventContext::new(&mut cx);
+                    handler(e, view, &mut cx);
+                    cx.handled
                 } else {
                     panic!(
                         "Mouse Region Event incorrectly called with mismatched event type. Expected MouseRegionEvent::Click, found {:?}",
@@ -386,12 +444,16 @@ impl HandlerSet {
     pub fn on_down_out<V, F>(mut self, button: MouseButton, handler: F) -> Self
     where
         V: View,
-        F: Fn(MouseDownOut, &mut V, &mut ViewContext<V>) + 'static,
+        F: Fn(MouseDownOut, &mut V, &mut EventContext<V>) + 'static,
     {
         self.insert(MouseEvent::down_out_disc(), Some(button),
-            Rc::new(move |region_event, cx| {
+            Rc::new(move |region_event, view, cx, view_id| {
                 if let MouseEvent::DownOut(e) = region_event {
-                    handler(e, cx);
+                    let view = view.downcast_mut().unwrap();
+                    let mut cx = ViewContext::mutable(cx, view_id);
+                    let mut cx = EventContext::new(&mut cx);
+                    handler(e, view, &mut cx);
+                    cx.handled
                 } else {
                     panic!(
                         "Mouse Region Event incorrectly called with mismatched event type. Expected MouseRegionEvent::DownOut, found {:?}",
@@ -404,12 +466,16 @@ impl HandlerSet {
     pub fn on_up_out<V, F>(mut self, button: MouseButton, handler: F) -> Self
     where
         V: View,
-        F: Fn(MouseUpOut, &mut V, &mut ViewContext<V>) + 'static,
+        F: Fn(MouseUpOut, &mut V, &mut EventContext<V>) + 'static,
     {
         self.insert(MouseEvent::up_out_disc(), Some(button),
-            Rc::new(move |region_event, cx| {
+            Rc::new(move |region_event, view, cx, view_id| {
                 if let MouseEvent::UpOut(e) = region_event {
-                    handler(e, cx);
+                    let view = view.downcast_mut().unwrap();
+                    let mut cx = ViewContext::mutable(cx, view_id);
+                    let mut cx = EventContext::new(&mut cx);
+                    handler(e, view, &mut cx);
+                    cx.handled
                 } else {
                     panic!(
                         "Mouse Region Event incorrectly called with mismatched event type. Expected MouseRegionEvent::UpOut, found {:?}",
@@ -422,12 +488,16 @@ impl HandlerSet {
     pub fn on_drag<V, F>(mut self, button: MouseButton, handler: F) -> Self
     where
         V: View,
-        F: Fn(MouseDrag, &mut V, &mut ViewContext<V>) + 'static,
+        F: Fn(MouseDrag, &mut V, &mut EventContext<V>) + 'static,
     {
         self.insert(MouseEvent::drag_disc(), Some(button),
-            Rc::new(move |region_event, cx| {
+            Rc::new(move |region_event, view, cx, view_id| {
                 if let MouseEvent::Drag(e) = region_event {
-                    handler(e, cx);
+                    let view = view.downcast_mut().unwrap();
+                    let mut cx = ViewContext::mutable(cx, view_id);
+                    let mut cx = EventContext::new(&mut cx);
+                    handler(e, view, &mut cx);
+                    cx.handled
                 } else {
                     panic!(
                         "Mouse Region Event incorrectly called with mismatched event type. Expected MouseRegionEvent::Drag, found {:?}",
@@ -440,12 +510,16 @@ impl HandlerSet {
     pub fn on_hover<V, F>(mut self, handler: F) -> Self
     where
         V: View,
-        F: Fn(MouseHover, &mut V, &mut ViewContext<V>) + 'static,
+        F: Fn(MouseHover, &mut V, &mut EventContext<V>) + 'static,
     {
         self.insert(MouseEvent::hover_disc(), None,
-            Rc::new(move |region_event, cx| {
+            Rc::new(move |region_event, view, cx, view_id| {
                 if let MouseEvent::Hover(e) = region_event {
-                    handler(e, cx);
+                    let view = view.downcast_mut().unwrap();
+                    let mut cx = ViewContext::mutable(cx, view_id);
+                    let mut cx = EventContext::new(&mut cx);
+                    handler(e, view, &mut cx);
+                    cx.handled
                 } else {
                     panic!(
                         "Mouse Region Event incorrectly called with mismatched event type. Expected MouseRegionEvent::Hover, found {:?}",
@@ -458,12 +532,16 @@ impl HandlerSet {
     pub fn on_scroll<V, F>(mut self, handler: F) -> Self
     where
         V: View,
-        F: Fn(MouseScrollWheel, &mut V, &mut ViewContext<V>) + 'static,
+        F: Fn(MouseScrollWheel, &mut V, &mut EventContext<V>) + 'static,
     {
         self.insert(MouseEvent::scroll_wheel_disc(), None,
-            Rc::new(move |region_event, cx| {
+            Rc::new(move |region_event, view, cx, view_id| {
                 if let MouseEvent::ScrollWheel(e) = region_event {
-                    handler(e, cx);
+                    let view = view.downcast_mut().unwrap();
+                    let mut cx = ViewContext::mutable(cx, view_id);
+                    let mut cx = EventContext::new(&mut cx);
+                    handler(e, view, &mut cx);
+                    cx.handled
                 } else {
                     panic!(
                         "Mouse Region Event incorrectly called with mismatched event type. Expected MouseRegionEvent::ScrollWheel, found {:?}",

crates/gpui/src/text_layout.rs 🔗

@@ -273,7 +273,7 @@ impl Line {
 
     pub fn paint(
         &self,
-        scene: &SceneBuilder,
+        scene: &mut SceneBuilder,
         origin: Vector2F,
         visible_bounds: RectF,
         line_height: f32,
@@ -334,7 +334,7 @@ impl Line {
                 }
 
                 if let Some((underline_origin, underline_style)) = finished_underline {
-                    cx.scene.push_underline(scene::Underline {
+                    scene.push_underline(scene::Underline {
                         origin: underline_origin,
                         width: glyph_origin.x() - underline_origin.x(),
                         thickness: underline_style.thickness.into(),
@@ -344,14 +344,14 @@ impl Line {
                 }
 
                 if glyph.is_emoji {
-                    cx.scene.push_image_glyph(scene::ImageGlyph {
+                    scene.push_image_glyph(scene::ImageGlyph {
                         font_id: run.font_id,
                         font_size: self.layout.font_size,
                         id: glyph.id,
                         origin: glyph_origin,
                     });
                 } else {
-                    cx.scene.push_glyph(scene::Glyph {
+                    scene.push_glyph(scene::Glyph {
                         font_id: run.font_id,
                         font_size: self.layout.font_size,
                         id: glyph.id,
@@ -364,7 +364,7 @@ impl Line {
 
         if let Some((underline_start, underline_style)) = underline.take() {
             let line_end_x = origin.x() + self.layout.width;
-            cx.scene.push_underline(scene::Underline {
+            scene.push_underline(scene::Underline {
                 origin: underline_start,
                 width: line_end_x - underline_start.x(),
                 color: underline_style.color.unwrap(),
@@ -376,7 +376,7 @@ impl Line {
 
     pub fn paint_wrapped(
         &self,
-        scene: &SceneBuilder,
+        scene: &mut SceneBuilder,
         origin: Vector2F,
         visible_bounds: RectF,
         line_height: f32,

crates/gpui/src/views/select.rs 🔗

@@ -106,22 +106,17 @@ impl View for Select {
             Default::default()
         };
         let mut result = Flex::column().with_child(
-            MouseEventHandler::<Header>::new(
-                self.handle.id(),
-                self,
-                cx,
-                |mouse_state, this, cx| {
-                    Container::new((self.render_item)(
-                        self.selected_item_ix,
-                        ItemType::Header,
-                        mouse_state.hovered(),
-                        cx,
-                    ))
-                    .with_style(style.header)
-                    .boxed()
-                },
-            )
-            .on_click(MouseButton::Left, move |_, cx| {
+            MouseEventHandler::<Header, _>::new(self.handle.id(), cx, |mouse_state, cx| {
+                Container::new((self.render_item)(
+                    self.selected_item_ix,
+                    ItemType::Header,
+                    mouse_state.hovered(),
+                    cx,
+                ))
+                .with_style(style.header)
+                .boxed()
+            })
+            .on_click(MouseButton::Left, move |_, _, cx| {
                 cx.dispatch_action(ToggleSelect)
             })
             .boxed(),
@@ -139,11 +134,10 @@ impl View for Select {
                                     let selected_item_ix = this.selected_item_ix;
                                     range.end = range.end.min(this.item_count);
                                     items.extend(range.map(|ix| {
-                                        MouseEventHandler::<Item>::new(
+                                        MouseEventHandler::<Item, _>::new(
                                             ix,
-                                            self,
                                             cx,
-                                            |mouse_state, this, cx| {
+                                            |mouse_state, cx| {
                                                 (this.render_item)(
                                                     ix,
                                                     if ix == selected_item_ix {
@@ -156,7 +150,7 @@ impl View for Select {
                                                 )
                                             },
                                         )
-                                        .on_click(MouseButton::Left, move |_, cx| {
+                                        .on_click(MouseButton::Left, move |_, _, cx| {
                                             cx.dispatch_action(SelectItem(ix))
                                         })
                                         .boxed()

crates/language_selector/src/active_buffer_language.rs 🔗

@@ -2,7 +2,7 @@ use editor::Editor;
 use gpui::{
     elements::*,
     platform::{CursorStyle, MouseButton},
-    Entity, RenderContext, Subscription, View, ViewContext, ViewHandle,
+    Entity, Subscription, View, ViewContext, ViewHandle,
 };
 use settings::Settings;
 use std::sync::Arc;
@@ -50,7 +50,7 @@ impl View for ActiveBufferLanguage {
         "ActiveBufferLanguage"
     }
 
-    fn render(&mut self, cx: &mut RenderContext<Self>) -> ElementBox {
+    fn render(&mut self, cx: &mut ViewContext<Self>) -> ElementBox {
         if let Some(active_language) = self.active_language.as_ref() {
             let active_language_text = if let Some(active_language_text) = active_language {
                 active_language_text.to_string()

crates/language_selector/src/language_selector.rs 🔗

@@ -4,8 +4,8 @@ pub use active_buffer_language::ActiveBufferLanguage;
 use editor::Editor;
 use fuzzy::{match_strings, StringMatch, StringMatchCandidate};
 use gpui::{
-    actions, elements::*, AnyViewHandle, AppContext, Entity, ModelHandle, MouseState,
-    RenderContext, View, ViewContext, ViewHandle,
+    actions, elements::*, AnyViewHandle, AppContext, Entity, ModelHandle, MouseState, View,
+    ViewContext, ViewHandle,
 };
 use language::{Buffer, LanguageRegistry};
 use picker::{Picker, PickerDelegate};
@@ -120,7 +120,7 @@ impl View for LanguageSelector {
         "LanguageSelector"
     }
 
-    fn render(&mut self, cx: &mut RenderContext<Self>) -> ElementBox {
+    fn render(&mut self, cx: &mut ViewContext<Self>) -> ElementBox {
         ChildView::new(&self.picker, cx).boxed()
     }
 

crates/outline/src/outline.rs 🔗

@@ -5,7 +5,7 @@ use editor::{
 use fuzzy::StringMatch;
 use gpui::{
     actions, elements::*, geometry::vector::Vector2F, AnyViewHandle, AppContext, Entity,
-    MouseState, RenderContext, Task, View, ViewContext, ViewHandle,
+    MouseState, Task, View, ViewContext, ViewHandle,
 };
 use language::Outline;
 use ordered_float::OrderedFloat;
@@ -48,7 +48,7 @@ impl View for OutlineView {
         "OutlineView"
     }
 
-    fn render(&mut self, cx: &mut RenderContext<Self>) -> ElementBox {
+    fn render(&mut self, cx: &mut ViewContext<Self>) -> ElementBox {
         ChildView::new(&self.picker, cx).boxed()
     }
 

crates/picker/src/picker.rs 🔗

@@ -4,8 +4,8 @@ use gpui::{
     geometry::vector::{vec2f, Vector2F},
     keymap_matcher::KeymapContext,
     platform::{CursorStyle, MouseButton},
-    AnyViewHandle, AppContext, Axis, Entity, MouseState, RenderContext, Task, View, ViewContext,
-    ViewHandle, WeakViewHandle,
+    AnyViewHandle, AppContext, Axis, Entity, MouseState, Task, View, ViewContext, ViewHandle,
+    WeakViewHandle,
 };
 use menu::{Cancel, Confirm, SelectFirst, SelectIndex, SelectLast, SelectNext, SelectPrev};
 use parking_lot::Mutex;
@@ -48,7 +48,7 @@ impl<D: PickerDelegate> View for Picker<D> {
         "Picker"
     }
 
-    fn render(&mut self, cx: &mut RenderContext<Self>) -> gpui::ElementBox {
+    fn render(&mut self, cx: &mut ViewContext<Self>) -> gpui::ElementBox {
         let theme = (self.theme.lock())(&cx.global::<settings::Settings>().theme);
         let query = self.query(cx);
         let delegate = self.delegate.clone();

crates/project_panel/src/project_panel.rs 🔗

@@ -13,8 +13,8 @@ use gpui::{
     impl_internal_actions,
     keymap_matcher::KeymapContext,
     platform::{CursorStyle, MouseButton, PromptLevel},
-    AppContext, ClipboardItem, Element, ElementBox, Entity, ModelHandle, RenderContext, Task, View,
-    ViewContext, ViewHandle,
+    AppContext, ClipboardItem, Element, ElementBox, Entity, ModelHandle, Task, View, ViewContext,
+    ViewHandle,
 };
 use menu::{Confirm, SelectNext, SelectPrev};
 use project::{Entry, EntryKind, Project, ProjectEntryId, ProjectPath, Worktree, WorktreeId};
@@ -1015,8 +1015,8 @@ impl ProjectPanel {
     fn for_each_visible_entry(
         &self,
         range: Range<usize>,
-        cx: &mut RenderContext<ProjectPanel>,
-        mut callback: impl FnMut(ProjectEntryId, EntryDetails, &mut RenderContext<ProjectPanel>),
+        cx: &mut ViewContext<ProjectPanel>,
+        mut callback: impl FnMut(ProjectEntryId, EntryDetails, &mut ViewContext<ProjectPanel>),
     ) {
         let mut ix = 0;
         for (worktree_id, visible_worktree_entries) in &self.visible_entries {
@@ -1097,7 +1097,7 @@ impl ProjectPanel {
         padding: f32,
         row_container_style: ContainerStyle,
         style: &ProjectPanelEntry,
-        cx: &mut RenderContext<V>,
+        cx: &mut ViewContext<V>,
     ) -> ElementBox {
         let kind = details.kind;
         let show_editor = details.is_editing && !details.is_processing;
@@ -1154,7 +1154,7 @@ impl ProjectPanel {
         editor: &ViewHandle<Editor>,
         dragged_entry_destination: &mut Option<Arc<Path>>,
         theme: &theme::ProjectPanel,
-        cx: &mut RenderContext<Self>,
+        cx: &mut ViewContext<Self>,
     ) -> ElementBox {
         let this = cx.handle();
         let kind = details.kind;
@@ -1251,7 +1251,7 @@ impl ProjectPanel {
         .as_draggable(entry_id, {
             let row_container_style = theme.dragged_entry.container;
 
-            move |_, cx: &mut RenderContext<Workspace>| {
+            move |_, cx: &mut ViewContext<Workspace>| {
                 let theme = cx.global::<Settings>().theme.clone();
                 Self::render_entry_visual_element(
                     &details,
@@ -1273,7 +1273,7 @@ impl View for ProjectPanel {
         "ProjectPanel"
     }
 
-    fn render(&mut self, cx: &mut gpui::RenderContext<'_, Self>) -> gpui::ElementBox {
+    fn render(&mut self, cx: &mut gpui::ViewContext<'_, Self>) -> gpui::ElementBox {
         enum ProjectPanel {}
         let theme = &cx.global::<Settings>().theme.project_panel;
         let mut container_style = theme.container;

crates/project_symbols/src/project_symbols.rs 🔗

@@ -4,8 +4,8 @@ use editor::{
 };
 use fuzzy::{StringMatch, StringMatchCandidate};
 use gpui::{
-    actions, elements::*, AnyViewHandle, AppContext, Entity, ModelHandle, MouseState,
-    RenderContext, Task, View, ViewContext, ViewHandle,
+    actions, elements::*, AnyViewHandle, AppContext, Entity, ModelHandle, MouseState, Task, View,
+    ViewContext, ViewHandle,
 };
 use ordered_float::OrderedFloat;
 use picker::{Picker, PickerDelegate};
@@ -48,7 +48,7 @@ impl View for ProjectSymbolsView {
         "ProjectSymbolsView"
     }
 
-    fn render(&mut self, cx: &mut RenderContext<Self>) -> ElementBox {
+    fn render(&mut self, cx: &mut ViewContext<Self>) -> ElementBox {
         ChildView::new(&self.picker, cx).boxed()
     }
 

crates/recent_projects/src/recent_projects.rs 🔗

@@ -4,8 +4,7 @@ use fuzzy::{StringMatch, StringMatchCandidate};
 use gpui::{
     actions,
     elements::{ChildView, Flex, ParentElement},
-    AnyViewHandle, AppContext, Element, ElementBox, Entity, RenderContext, Task, View, ViewContext,
-    ViewHandle,
+    AnyViewHandle, AppContext, Element, ElementBox, Entity, Task, View, ViewContext, ViewHandle,
 };
 use highlighted_workspace_location::HighlightedWorkspaceLocation;
 use ordered_float::OrderedFloat;
@@ -102,7 +101,7 @@ impl View for RecentProjectsView {
         "RecentProjectsView"
     }
 
-    fn render(&mut self, cx: &mut RenderContext<Self>) -> ElementBox {
+    fn render(&mut self, cx: &mut ViewContext<Self>) -> ElementBox {
         ChildView::new(&self.picker, cx).boxed()
     }
 

crates/search/src/buffer_search.rs 🔗

@@ -9,8 +9,7 @@ use gpui::{
     elements::*,
     impl_actions,
     platform::{CursorStyle, MouseButton},
-    Action, AnyViewHandle, AppContext, Entity, RenderContext, Subscription, Task, View,
-    ViewContext, ViewHandle,
+    Action, AnyViewHandle, AppContext, Entity, Subscription, Task, View, ViewContext, ViewHandle,
 };
 use project::search::SearchQuery;
 use serde::Deserialize;
@@ -92,7 +91,7 @@ impl View for BufferSearchBar {
         }
     }
 
-    fn render(&mut self, cx: &mut RenderContext<Self>) -> ElementBox {
+    fn render(&mut self, cx: &mut ViewContext<Self>) -> ElementBox {
         let theme = cx.global::<Settings>().theme.clone();
         let editor_container = if self.query_contains_error {
             theme.search.invalid_editor
@@ -324,7 +323,7 @@ impl BufferSearchBar {
         option_supported: bool,
         icon: &'static str,
         option: SearchOption,
-        cx: &mut RenderContext<Self>,
+        cx: &mut ViewContext<Self>,
     ) -> Option<ElementBox> {
         if !option_supported {
             return None;
@@ -364,7 +363,7 @@ impl BufferSearchBar {
         &self,
         icon: &'static str,
         direction: Direction,
-        cx: &mut RenderContext<Self>,
+        cx: &mut ViewContext<Self>,
     ) -> ElementBox {
         let action: Box<dyn Action>;
         let tooltip;
@@ -408,11 +407,7 @@ impl BufferSearchBar {
         .boxed()
     }
 
-    fn render_close_button(
-        &self,
-        theme: &theme::Search,
-        cx: &mut RenderContext<Self>,
-    ) -> ElementBox {
+    fn render_close_button(&self, theme: &theme::Search, cx: &mut ViewContext<Self>) -> ElementBox {
         let action = Box::new(Dismiss);
         let tooltip = "Dismiss Buffer Search";
         let tooltip_style = cx.global::<Settings>().theme.tooltip.clone();

crates/search/src/project_search.rs 🔗

@@ -12,9 +12,8 @@ use gpui::{
     actions,
     elements::*,
     platform::{CursorStyle, MouseButton},
-    Action, AnyViewHandle, AppContext, Entity, ModelContext, ModelHandle, RenderContext,
-    Subscription, Task, View, ViewContext, ElementBox, ViewHandle, WeakModelHandle,
-    WeakViewHandle,
+    Action, AnyViewHandle, AppContext, ElementBox, Entity, ModelContext, ModelHandle, Subscription,
+    Task, View, ViewContext, ViewHandle, WeakModelHandle, WeakViewHandle,
 };
 use menu::Confirm;
 use project::{search::SearchQuery, Project};
@@ -178,7 +177,7 @@ impl View for ProjectSearchView {
         "ProjectSearchView"
     }
 
-    fn render(&mut self, cx: &mut RenderContext<Self>) -> ElementBox {
+    fn render(&mut self, cx: &mut ViewContext<Self>) -> ElementBox {
         let model = &self.model.read(cx);
         if model.match_ranges.is_empty() {
             enum Status {}
@@ -747,7 +746,7 @@ impl ProjectSearchBar {
         &self,
         icon: &'static str,
         direction: Direction,
-        cx: &mut RenderContext<Self>,
+        cx: &mut ViewContext<Self>,
     ) -> ElementBox {
         let action: Box<dyn Action>;
         let tooltip;
@@ -795,7 +794,7 @@ impl ProjectSearchBar {
         &self,
         icon: &'static str,
         option: SearchOption,
-        cx: &mut RenderContext<Self>,
+        cx: &mut ViewContext<Self>,
     ) -> ElementBox {
         let tooltip_style = cx.global::<Settings>().theme.tooltip.clone();
         let is_active = self.is_option_enabled(option, cx);
@@ -848,7 +847,7 @@ impl View for ProjectSearchBar {
         "ProjectSearchBar"
     }
 
-    fn render(&mut self, cx: &mut RenderContext<Self>) -> ElementBox {
+    fn render(&mut self, cx: &mut ViewContext<Self>) -> ElementBox {
         if let Some(search) = self.active_project_search.as_ref() {
             let search = search.read(cx);
             let theme = cx.global::<Settings>().theme.clone();

crates/terminal_view/src/terminal_button.rs 🔗

@@ -3,8 +3,8 @@ use gpui::{
     elements::*,
     impl_internal_actions,
     platform::{CursorStyle, MouseButton},
-    AppContext, Element, ElementBox, Entity, RenderContext, View, ViewContext, ViewHandle,
-    WeakModelHandle, WeakViewHandle,
+    AppContext, Element, ElementBox, Entity, View, ViewContext, ViewHandle, WeakModelHandle,
+    WeakViewHandle,
 };
 use settings::Settings;
 use std::any::TypeId;
@@ -42,14 +42,14 @@ impl View for TerminalButton {
         "TerminalButton"
     }
 
-    fn render(&mut self, cx: &mut RenderContext<'_, Self>) -> ElementBox {
+    fn render(&mut self, cx: &mut ViewContext<'_, Self>) -> ElementBox {
         let workspace = self.workspace.upgrade(cx);
         let project = match workspace {
             Some(workspace) => workspace.read(cx).project().read(cx),
             None => return Empty::new().boxed(),
         };
 
-        let focused_view = cx.focused_view_id(cx.window_id());
+        let focused_view = cx.focused_view_id();
         let active = focused_view
             .map(|view_id| {
                 cx.view_type_id(cx.window_id(), view_id) == Some(TypeId::of::<TerminalView>())

crates/terminal_view/src/terminal_element.rs 🔗

@@ -10,8 +10,8 @@ use gpui::{
     platform::{CursorStyle, MouseButton},
     serde_json::json,
     text_layout::{Line, RunStyle},
-    Element, ElementBox, EventContext, FontCache, ModelContext, MouseRegion, PaintContext, Quad,
-    SizeConstraint, TextLayoutCache, WeakModelHandle, WeakViewHandle,
+    Element, ElementBox, EventContext, FontCache, ModelContext, MouseRegion, Quad, SceneBuilder,
+    SizeConstraint, TextLayoutCache, ViewContext, WeakModelHandle, WeakViewHandle,
 };
 use itertools::Itertools;
 use language::CursorShape;
@@ -45,7 +45,7 @@ pub struct LayoutState {
     size: TerminalSize,
     mode: TermMode,
     display_offset: usize,
-    hyperlink_tooltip: Option<ElementBox>,
+    hyperlink_tooltip: Option<ElementBox<TerminalView>>,
 }
 
 ///Helper struct for converting data between alacritty's cursor points, and displayed cursor points
@@ -84,10 +84,12 @@ impl LayoutCell {
 
     fn paint(
         &self,
+        scene: &mut SceneBuilder,
         origin: Vector2F,
         layout: &LayoutState,
         visible_bounds: RectF,
-        cx: &mut PaintContext,
+        view: &mut TerminalView,
+        cx: &mut ViewContext<TerminalView>,
     ) {
         let pos = {
             let point = self.point;
@@ -98,7 +100,7 @@ impl LayoutCell {
         };
 
         self.text
-            .paint(pos, visible_bounds, layout.size.line_height, cx);
+            .paint(pos, visible_bounds, layout.size.line_height, view, cx);
     }
 }
 
@@ -139,7 +141,7 @@ impl LayoutRect {
             layout.size.line_height,
         );
 
-        cx.scene.push_quad(Quad {
+        scene.push_quad(Quad {
             bounds: RectF::new(position, size),
             background: Some(self.color),
             border: Default::default(),
@@ -380,7 +382,7 @@ impl TerminalElement {
         view_id: usize,
         visible_bounds: RectF,
         mode: TermMode,
-        cx: &mut PaintContext,
+        cx: &mut ViewContext<TerminalView>,
     ) {
         let connection = self.terminal;
 
@@ -501,7 +503,7 @@ impl TerminalElement {
                 )
         }
 
-        cx.scene.push_mouse_region(region);
+        scene.push_mouse_region(region);
     }
 
     ///Configures a text style from the current settings.
@@ -553,7 +555,8 @@ impl Element for TerminalElement {
     fn layout(
         &mut self,
         constraint: gpui::SizeConstraint,
-        cx: &mut gpui::LayoutContext,
+        view: &mut TerminalView,
+        cx: &mut ViewContext<TerminalView>,
     ) -> (gpui::geometry::vector::Vector2F, Self::LayoutState) {
         let settings = cx.global::<Settings>();
         let font_cache = cx.font_cache();
@@ -717,23 +720,24 @@ impl Element for TerminalElement {
 
     fn paint(
         &mut self,
-        bounds: gpui::geometry::rect::RectF,
-        visible_bounds: gpui::geometry::rect::RectF,
+        scene: &mut SceneBuilder,
+        bounds: RectF,
+        visible_bounds: RectF,
         layout: &mut Self::LayoutState,
-        cx: &mut gpui::PaintContext,
+        cx: &mut ViewContext<TerminalView>,
     ) -> Self::PaintState {
         let visible_bounds = bounds.intersection(visible_bounds).unwrap_or_default();
 
         //Setup element stuff
         let clip_bounds = Some(visible_bounds);
 
-        cx.paint_layer(clip_bounds, |cx| {
+        scene.paint_layer(clip_bounds, |scene| {
             let origin = bounds.origin() + vec2f(layout.size.cell_width, 0.);
 
             // Elements are ephemeral, only at paint time do we know what could be clicked by a mouse
             self.attach_mouse_handlers(origin, self.view.id(), visible_bounds, layout.mode, cx);
 
-            cx.scene.push_cursor_region(gpui::CursorRegion {
+            scene.push_cursor_region(gpui::CursorRegion {
                 bounds,
                 style: if layout.hyperlink_tooltip.is_some() {
                     CursorStyle::PointingHand
@@ -742,9 +746,9 @@ impl Element for TerminalElement {
                 },
             });
 
-            cx.paint_layer(clip_bounds, |cx| {
+            scene.paint_layer(clip_bounds, |scene| {
                 //Start with a background color
-                cx.scene.push_quad(Quad {
+                scene.push_quad(Quad {
                     bounds: RectF::new(bounds.origin(), bounds.size()),
                     background: Some(layout.background_color),
                     border: Default::default(),
@@ -757,7 +761,7 @@ impl Element for TerminalElement {
             });
 
             //Draw Highlighted Backgrounds
-            cx.paint_layer(clip_bounds, |cx| {
+            scene.paint_layer(clip_bounds, |scene| {
                 for (relative_highlighted_range, color) in layout.relative_highlighted_ranges.iter()
                 {
                     if let Some((start_y, highlighted_range_lines)) =
@@ -771,29 +775,29 @@ impl Element for TerminalElement {
                             //Copied from editor. TODO: move to theme or something
                             corner_radius: 0.15 * layout.size.line_height,
                         };
-                        hr.paint(bounds, cx.scene);
+                        hr.paint(bounds, scene);
                     }
                 }
             });
 
             //Draw the text cells
-            cx.paint_layer(clip_bounds, |cx| {
+            scene.paint_layer(clip_bounds, |scene| {
                 for cell in &layout.cells {
-                    cell.paint(origin, layout, visible_bounds, cx);
+                    cell.paint(scene, origin, layout, visible_bounds, view, cx);
                 }
             });
 
             //Draw cursor
             if self.cursor_visible {
                 if let Some(cursor) = &layout.cursor {
-                    cx.paint_layer(clip_bounds, |cx| {
-                        cursor.paint(origin, cx);
+                    scene.paint_layer(clip_bounds, |scene| {
+                        cursor.paint(scene, origin, cx);
                     })
                 }
             }
 
             if let Some(element) = &mut layout.hyperlink_tooltip {
-                element.paint(origin, visible_bounds, cx)
+                Element<TerminalView>::paint(element, scene, origin, visible_bounds, view, cx)
             }
         });
     }
@@ -804,7 +808,7 @@ impl Element for TerminalElement {
 
     fn debug(
         &self,
-        _bounds: gpui::geometry::rect::RectF,
+        _bounds: RectF,
         _layout: &Self::LayoutState,
         _paint: &Self::PaintState,
         _cx: &gpui::DebugContext,

crates/terminal_view/src/terminal_view.rs 🔗

@@ -236,11 +236,7 @@ impl TerminalView {
         cx.notify();
     }
 
-    pub fn should_show_cursor(
-        &self,
-        focused: bool,
-        cx: &mut gpui::RenderContext<'_, Self>,
-    ) -> bool {
+    pub fn should_show_cursor(&self, focused: bool, cx: &mut gpui::ViewContext<'_, Self>) -> bool {
         //Don't blink the cursor when not focused, blinking is disabled, or paused
         if !focused
             || !self.blinking_on
@@ -388,12 +384,12 @@ impl View for TerminalView {
         "Terminal"
     }
 
-    fn render(&mut self, cx: &mut gpui::RenderContext<'_, Self>) -> ElementBox {
+    fn render(&mut self, cx: &mut gpui::ViewContext<'_, Self>) -> ElementBox {
         let terminal_handle = self.terminal.clone().downgrade();
 
         let self_id = cx.view_id();
         let focused = cx
-            .focused_view_id(cx.window_id())
+            .focused_view_id()
             .filter(|view_id| *view_id == self_id)
             .is_some();
 

crates/theme/src/ui.rs 🔗

@@ -11,7 +11,7 @@ use gpui::{
     platform,
     platform::MouseButton,
     scene::MouseClick,
-    Action, Element, ElementBox, EventContext, MouseState, RenderContext, View,
+    Action, Element, ElementBox, EventContext, MouseState, View, ViewContext,
 };
 use serde::Deserialize;
 
@@ -27,13 +27,13 @@ pub struct CheckboxStyle {
     pub hovered_and_checked: ContainerStyle,
 }
 
-pub fn checkbox<T: 'static, V: View>(
+pub fn checkbox<Tag: 'static, V: View>(
     label: &'static str,
     style: &CheckboxStyle,
     checked: bool,
-    cx: &mut RenderContext<V>,
-    change: fn(checked: bool, cx: &mut EventContext) -> (),
-) -> MouseEventHandler<T> {
+    cx: &mut ViewContext<V>,
+    change: fn(checked: bool, cx: &mut EventContext<V>) -> (),
+) -> MouseEventHandler<Tag, V> {
     let label = Label::new(label, style.label.text.clone())
         .contained()
         .with_style(style.label.container)
@@ -42,14 +42,14 @@ pub fn checkbox<T: 'static, V: View>(
     checkbox_with_label(label, style, checked, cx, change)
 }
 
-pub fn checkbox_with_label<T: 'static, V: View>(
-    label: ElementBox,
+pub fn checkbox_with_label<Tag: 'static, V: View>(
+    label: ElementBox<V>,
     style: &CheckboxStyle,
     checked: bool,
-    cx: &mut RenderContext<V>,
-    change: fn(checked: bool, cx: &mut EventContext) -> (),
-) -> MouseEventHandler<T> {
-    MouseEventHandler::<T>::new(0, cx, |state, _| {
+    cx: &mut ViewContext<V>,
+    change: fn(checked: bool, cx: &mut EventContext<V>) -> (),
+) -> MouseEventHandler<Tag, V> {
+    MouseEventHandler::new(0, cx, |state, _| {
         let indicator = if checked {
             svg(&style.icon)
         } else {
@@ -82,7 +82,7 @@ pub fn checkbox_with_label<T: 'static, V: View>(
             .align_children_center()
             .boxed()
     })
-    .on_click(platform::MouseButton::Left, move |_, cx| {
+    .on_click(platform::MouseButton::Left, move |_, _, cx| {
         change(!checked, cx)
     })
     .with_cursor_style(platform::CursorStyle::PointingHand)
@@ -107,7 +107,7 @@ impl Dimensions {
     }
 }
 
-pub fn svg(style: &SvgStyle) -> ConstrainedBox {
+pub fn svg<V: View>(style: &SvgStyle) -> ConstrainedBox<V> {
     Svg::new(style.asset.clone())
         .with_color(style.color)
         .constrained()
@@ -121,7 +121,7 @@ pub struct IconStyle {
     container: ContainerStyle,
 }
 
-pub fn icon(style: &IconStyle) -> Container {
+pub fn icon<V: View>(style: &IconStyle) -> Container<V> {
     svg(&style.icon).contained().with_style(style.container)
 }
 
@@ -130,8 +130,8 @@ pub fn keystroke_label<V: View>(
     label_style: &ContainedText,
     keystroke_style: &ContainedText,
     action: Box<dyn Action>,
-    cx: &mut RenderContext<V>,
-) -> Container {
+    cx: &mut ViewContext<V>,
+) -> Container<V> {
     // FIXME: Put the theme in it's own global so we can
     // query the keystroke style on our own
     keystroke_label_for(
@@ -144,14 +144,14 @@ pub fn keystroke_label<V: View>(
     )
 }
 
-pub fn keystroke_label_for(
+pub fn keystroke_label_for<V: View>(
     window_id: usize,
     view_id: usize,
     label_text: &'static str,
     label_style: &ContainedText,
     keystroke_style: &ContainedText,
     action: Box<dyn Action>,
-) -> Container {
+) -> Container<V> {
     Flex::row()
         .with_child(
             Label::new(label_text, label_style.text.clone())
@@ -175,37 +175,39 @@ pub fn keystroke_label_for(
 
 pub type ButtonStyle = Interactive<ContainedText>;
 
-pub fn cta_button<L, A, V>(
+pub fn cta_button<Tag, L, A, V>(
     label: L,
     action: A,
     max_width: f32,
     style: &ButtonStyle,
-    cx: &mut RenderContext<V>,
-) -> ElementBox
+    cx: &mut ViewContext<V>,
+) -> ElementBox<V>
 where
+    Tag: 'static,
     L: Into<Cow<'static, str>>,
     A: 'static + Action + Clone,
     V: View,
 {
-    cta_button_with_click(label, max_width, style, cx, move |_, cx| {
+    cta_button_with_click::<Tag, _, _, _>(label, max_width, style, cx, move |_, _, cx| {
         cx.dispatch_action(action.clone())
     })
     .boxed()
 }
 
-pub fn cta_button_with_click<L, V, F>(
+pub fn cta_button_with_click<Tag, L, V, F>(
     label: L,
     max_width: f32,
     style: &ButtonStyle,
-    cx: &mut RenderContext<V>,
+    cx: &mut ViewContext<V>,
     f: F,
-) -> MouseEventHandler<F>
+) -> MouseEventHandler<Tag, V>
 where
+    Tag: 'static,
     L: Into<Cow<'static, str>>,
     V: View,
-    F: Fn(MouseClick, &mut EventContext) + 'static,
+    F: Fn(MouseClick, &mut V, &mut EventContext<V>) + 'static,
 {
-    MouseEventHandler::<F>::new(0, cx, |state, _| {
+    MouseEventHandler::<Tag, V>::new(0, cx, |state, _| {
         let style = style.style_for(state, false);
         Label::new(label, style.text.to_owned())
             .aligned()
@@ -234,16 +236,17 @@ impl ModalStyle {
     }
 }
 
-pub fn modal<V, I, F>(
+pub fn modal<Tag, V, I, F>(
     title: I,
     style: &ModalStyle,
-    cx: &mut RenderContext<V>,
+    cx: &mut ViewContext<V>,
     build_modal: F,
-) -> ElementBox
+) -> ElementBox<V>
 where
+    Tag: 'static,
     V: View,
     I: Into<Cow<'static, str>>,
-    F: FnOnce(&mut gpui::RenderContext<V>) -> ElementBox,
+    F: FnOnce(&mut gpui::ViewContext<V>) -> ElementBox<V>,
 {
     const TITLEBAR_HEIGHT: f32 = 28.;
     // let active = cx.window_is_active(cx.window_id());
@@ -261,11 +264,11 @@ where
                     )
                     .boxed(),
                     // FIXME: Get a better tag type
-                    MouseEventHandler::<V>::new(999999, cx, |state, _cx| {
+                    MouseEventHandler::<Tag, V>::new(999999, cx, |state, _cx| {
                         let style = style.close_icon.style_for(state, false);
                         icon(style).boxed()
                     })
-                    .on_click(platform::MouseButton::Left, move |_, cx| {
+                    .on_click(platform::MouseButton::Left, move |_, _, cx| {
                         let window_id = cx.window_id();
                         cx.remove_window(window_id);
                     })

crates/theme_selector/src/theme_selector.rs 🔗

@@ -1,7 +1,7 @@
 use fuzzy::{match_strings, StringMatch, StringMatchCandidate};
 use gpui::{
-    actions, elements::*, AnyViewHandle, AppContext, Element, ElementBox, Entity, MouseState,
-    RenderContext, View, ViewContext, ViewHandle,
+    actions, elements::*, AnyViewHandle, AppContext, Element, ElementBox, Entity, MouseState, View,
+    ViewContext, ViewHandle,
 };
 use picker::{Picker, PickerDelegate};
 use settings::{settings_file::SettingsFile, Settings};
@@ -255,7 +255,7 @@ impl View for ThemeSelector {
         "ThemeSelector"
     }
 
-    fn render(&mut self, cx: &mut RenderContext<Self>) -> ElementBox {
+    fn render(&mut self, cx: &mut ViewContext<Self>) -> ElementBox {
         ChildView::new(&self.picker, cx).boxed()
     }
 

crates/theme_testbench/src/theme_testbench.rs 🔗

@@ -2,12 +2,12 @@ use gpui::{
     actions,
     color::Color,
     elements::{
-        Canvas, Container, ContainerStyle, Flex, Label, Margin, MouseEventHandler, Padding,
-        ParentElement, ElementBox,
+        Canvas, Container, ContainerStyle, ElementBox, Flex, Label, Margin, MouseEventHandler,
+        Padding, ParentElement,
     },
     fonts::TextStyle,
-    AppContext, Border, Element, Entity, ModelHandle, Quad, RenderContext, Task, View, ViewContext,
-    ViewHandle, WeakViewHandle,
+    AppContext, Border, Element, Entity, ModelHandle, Quad, Task, View, ViewContext, ViewHandle,
+    WeakViewHandle,
 };
 use project::Project;
 use settings::Settings;
@@ -39,7 +39,7 @@ impl ThemeTestbench {
             Flex::row()
                 .with_children(ramp.iter().cloned().map(|color| {
                     Canvas::new(move |bounds, _, cx| {
-                        cx.scene.push_quad(Quad {
+                        scene.push_quad(Quad {
                             bounds,
                             background: Some(color),
                             ..Default::default()
@@ -67,7 +67,7 @@ impl ThemeTestbench {
     fn render_layer(
         layer_index: usize,
         layer: &Layer,
-        cx: &mut RenderContext<'_, Self>,
+        cx: &mut ViewContext<'_, Self>,
     ) -> Container {
         Flex::column()
             .with_child(
@@ -123,7 +123,7 @@ impl ThemeTestbench {
         layer_index: usize,
         set_name: &'static str,
         style_set: &StyleSet,
-        cx: &mut RenderContext<'_, Self>,
+        cx: &mut ViewContext<'_, Self>,
     ) -> Flex {
         Flex::row()
             .with_child(Self::render_button(
@@ -182,7 +182,7 @@ impl ThemeTestbench {
         text: &'static str,
         style_set: &StyleSet,
         style_override: Option<fn(&StyleSet) -> &Style>,
-        cx: &mut RenderContext<'_, Self>,
+        cx: &mut ViewContext<'_, Self>,
     ) -> ElementBox {
         enum TestBenchButton {}
         MouseEventHandler::<TestBenchButton>::new(layer_index + button_index, cx, |state, cx| {
@@ -230,7 +230,7 @@ impl ThemeTestbench {
         .boxed()
     }
 
-    fn render_label(text: String, style: &Style, cx: &mut RenderContext<'_, Self>) -> Label {
+    fn render_label(text: String, style: &Style, cx: &mut ViewContext<'_, Self>) -> Label {
         let settings = cx.global::<Settings>();
         let font_cache = cx.font_cache();
         let family_id = settings.buffer_font_family;
@@ -262,7 +262,7 @@ impl View for ThemeTestbench {
         "ThemeTestbench"
     }
 
-    fn render(&mut self, cx: &mut gpui::RenderContext<'_, Self>) -> gpui::ElementBox {
+    fn render(&mut self, cx: &mut gpui::ViewContext<'_, Self>) -> gpui::ElementBox {
         let color_scheme = &cx.global::<Settings>().theme.clone().color_scheme;
 
         Flex::row()

crates/welcome/src/base_keymap_picker.rs 🔗

@@ -74,7 +74,7 @@ impl View for BaseKeymapSelector {
         "BaseKeymapSelector"
     }
 
-    fn render(&mut self, cx: &mut gpui::RenderContext<'_, Self>) -> gpui::ElementBox {
+    fn render(&mut self, cx: &mut gpui::ViewContext<'_, Self>) -> gpui::ElementBox {
         ChildView::new(&self.picker, cx).boxed()
     }
 

crates/welcome/src/welcome.rs 🔗

@@ -55,7 +55,7 @@ impl View for WelcomePage {
         "WelcomePage"
     }
 
-    fn render(&mut self, cx: &mut gpui::RenderContext<'_, Self>) -> ElementBox {
+    fn render(&mut self, cx: &mut gpui::ViewContext<'_, Self>) -> ElementBox {
         let self_handle = cx.handle();
         let settings = cx.global::<Settings>();
         let theme = settings.theme.clone();

crates/workspace/src/dock.rs 🔗

@@ -9,8 +9,7 @@ use gpui::{
     geometry::vector::Vector2F,
     impl_internal_actions,
     platform::{CursorStyle, MouseButton},
-    AppContext, Border, Element, ElementBox, RenderContext, SizeConstraint, ViewContext,
-    ViewHandle,
+    AppContext, Border, Element, ElementBox, SizeConstraint, ViewContext, ViewHandle,
 };
 use settings::{DockAnchor, Settings};
 use theme::Theme;
@@ -315,7 +314,7 @@ impl Dock {
         &self,
         theme: &Theme,
         anchor: DockAnchor,
-        cx: &mut RenderContext<Workspace>,
+        cx: &mut ViewContext<Workspace>,
     ) -> Option<ElementBox> {
         let style = &theme.workspace.dock;
 

crates/workspace/src/dock/toggle_dock_button.rs 🔗

@@ -34,7 +34,7 @@ impl View for ToggleDockButton {
         "Dock Toggle"
     }
 
-    fn render(&mut self, cx: &mut gpui::RenderContext<'_, Self>) -> ElementBox {
+    fn render(&mut self, cx: &mut gpui::ViewContext<'_, Self>) -> ElementBox {
         let workspace = self.workspace.upgrade(cx);
 
         if workspace.is_none() {

crates/workspace/src/item.rs 🔗

@@ -740,8 +740,8 @@ pub(crate) mod test {
     use super::{Item, ItemEvent};
     use crate::{sidebar::SidebarItem, ItemId, ItemNavHistory, Pane, Workspace, WorkspaceId};
     use gpui::{
-        elements::Empty, AppContext, Element, ElementBox, Entity, ModelHandle, RenderContext, Task,
-        View, ViewContext, ViewHandle, WeakViewHandle,
+        elements::Empty, AppContext, Element, ElementBox, Entity, ModelHandle, Task, View,
+        ViewContext, ViewHandle, WeakViewHandle,
     };
     use project::{Project, ProjectEntryId, ProjectPath, WorktreeId};
     use smallvec::SmallVec;
@@ -899,7 +899,7 @@ pub(crate) mod test {
             "TestItem"
         }
 
-        fn render(&mut self, _: &mut RenderContext<Self>) -> ElementBox {
+        fn render(&mut self, _: &mut ViewContext<Self>) -> ElementBox {
             Empty::new().boxed()
         }
     }

crates/workspace/src/notifications.rs 🔗

@@ -229,7 +229,7 @@ pub mod simple_message_notification {
             "MessageNotification"
         }
 
-        fn render(&mut self, cx: &mut gpui::RenderContext<'_, Self>) -> gpui::ElementBox {
+        fn render(&mut self, cx: &mut gpui::ViewContext<'_, Self>) -> gpui::ElementBox {
             let theme = cx.global::<Settings>().theme.clone();
             let theme = &theme.simple_message_notification;
 

crates/workspace/src/pane.rs 🔗

@@ -24,8 +24,7 @@ use gpui::{
     keymap_matcher::KeymapContext,
     platform::{CursorStyle, MouseButton, NavigationDirection, PromptLevel},
     Action, AnyViewHandle, AnyWeakViewHandle, AppContext, AsyncAppContext, Entity, EventContext,
-    ModelHandle, MouseRegion, Quad, RenderContext, Task, View, ViewContext, ViewHandle,
-    WeakViewHandle,
+    ModelHandle, MouseRegion, Quad, Task, View, ViewContext, ViewHandle, WeakViewHandle,
 };
 use project::{Project, ProjectEntryId, ProjectPath};
 use serde::Deserialize;
@@ -1221,7 +1220,7 @@ impl Pane {
         });
     }
 
-    fn render_tabs(&mut self, cx: &mut RenderContext<Self>) -> impl Element {
+    fn render_tabs(&mut self, cx: &mut ViewContext<Self>) -> impl Element {
         let theme = cx.global::<Settings>().theme.clone();
 
         let pane = cx.handle();
@@ -1302,7 +1301,7 @@ impl Pane {
                             let theme = cx.global::<Settings>().theme.clone();
 
                             let detail = detail.clone();
-                            move |dragged_item, cx: &mut RenderContext<Workspace>| {
+                            move |dragged_item, cx: &mut ViewContext<Workspace>| {
                                 let tab_style = &theme.workspace.tab_bar.dragged_tab;
                                 Self::render_tab(
                                     &dragged_item.item,
@@ -1384,7 +1383,7 @@ impl Pane {
         detail: Option<usize>,
         hovered: bool,
         tab_style: &theme::Tab,
-        cx: &mut RenderContext<V>,
+        cx: &mut ViewContext<V>,
     ) -> ElementBox {
         let title = item.tab_content(detail, &tab_style, cx);
         let mut container = tab_style.container.clone();
@@ -1408,7 +1407,7 @@ impl Pane {
                         Canvas::new(move |bounds, _, cx| {
                             if let Some(color) = icon_color {
                                 let square = RectF::new(bounds.origin(), vec2f(diameter, diameter));
-                                cx.scene.push_quad(Quad {
+                                scene.push_quad(Quad {
                                     bounds: square,
                                     background: Some(color),
                                     border: Default::default(),
@@ -1476,11 +1475,7 @@ impl Pane {
             .boxed()
     }
 
-    fn render_tab_bar_buttons(
-        &mut self,
-        theme: &Theme,
-        cx: &mut RenderContext<Self>,
-    ) -> ElementBox {
+    fn render_tab_bar_buttons(&mut self, theme: &Theme, cx: &mut ViewContext<Self>) -> ElementBox {
         Flex::row()
             // New menu
             .with_child(render_tab_bar_button(
@@ -1529,7 +1524,7 @@ impl Pane {
             .boxed()
     }
 
-    fn render_blank_pane(&mut self, theme: &Theme, _cx: &mut RenderContext<Self>) -> ElementBox {
+    fn render_blank_pane(&mut self, theme: &Theme, _cx: &mut ViewContext<Self>) -> ElementBox {
         let background = theme.workspace.background;
         Empty::new()
             .contained()
@@ -1547,7 +1542,7 @@ impl View for Pane {
         "Pane"
     }
 
-    fn render(&mut self, cx: &mut RenderContext<Self>) -> ElementBox {
+    fn render(&mut self, cx: &mut ViewContext<Self>) -> ElementBox {
         let this = cx.handle();
 
         enum MouseNavigationHandler {}
@@ -1705,7 +1700,7 @@ impl View for Pane {
 fn render_tab_bar_button<A: Action + Clone>(
     index: usize,
     icon: &'static str,
-    cx: &mut RenderContext<Pane>,
+    cx: &mut ViewContext<Pane>,
     action: A,
     context_menu: Option<ViewHandle<ContextMenu>>,
 ) -> ElementBox {
@@ -1853,7 +1848,7 @@ impl PaneBackdrop {
     }
 }
 
-impl Element for PaneBackdrop {
+impl Element<Pane> for PaneBackdrop {
     type LayoutState = ();
 
     type PaintState = ();
@@ -1861,31 +1856,34 @@ impl Element for PaneBackdrop {
     fn layout(
         &mut self,
         constraint: gpui::SizeConstraint,
-        cx: &mut gpui::LayoutContext,
+        view: &mut Pane,
+        cx: &mut ViewContext<Pane>,
     ) -> (Vector2F, Self::LayoutState) {
-        let size = self.child.layout(constraint, cx);
+        let size = self.child.layout(constraint, view, cx);
         (size, ())
     }
 
     fn paint(
         &mut self,
+        scene: &mut gpui::SceneBuilder,
         bounds: RectF,
         visible_bounds: RectF,
         _: &mut Self::LayoutState,
-        cx: &mut gpui::PaintContext,
+        view: &mut Pane,
+        cx: &mut ViewContext<Pane>,
     ) -> Self::PaintState {
         let background = cx.global::<Settings>().theme.editor.background;
 
         let visible_bounds = bounds.intersection(visible_bounds).unwrap_or_default();
 
-        cx.scene.push_quad(gpui::Quad {
+        scene.push_quad(gpui::Quad {
             bounds: RectF::new(bounds.origin(), bounds.size()),
             background: Some(background),
             ..Default::default()
         });
 
         let child_view_id = self.child_view;
-        cx.scene.push_mouse_region(
+        scene.push_mouse_region(
             MouseRegion::new::<Self>(child_view_id, 0, visible_bounds).on_down(
                 gpui::platform::MouseButton::Left,
                 move |_, cx| {
@@ -1895,8 +1893,9 @@ impl Element for PaneBackdrop {
             ),
         );
 
-        cx.paint_layer(Some(bounds), |cx| {
-            self.child.paint(bounds.origin(), visible_bounds, cx)
+        scene.paint_layer(Some(bounds), |scene| {
+            self.child
+                .paint(scene, bounds.origin(), visible_bounds, view, cx)
         })
     }
 
@@ -1907,9 +1906,10 @@ impl Element for PaneBackdrop {
         _visible_bounds: RectF,
         _layout: &Self::LayoutState,
         _paint: &Self::PaintState,
-        cx: &gpui::MeasurementContext,
+        view: &V,
+        cx: &gpui::ViewContext<V>,
     ) -> Option<RectF> {
-        self.child.rect_for_text_range(range_utf16, cx)
+        self.child.rect_for_text_range(range_utf16, view, cx)
     }
 
     fn debug(
@@ -1917,12 +1917,13 @@ impl Element for PaneBackdrop {
         _bounds: RectF,
         _layout: &Self::LayoutState,
         _paint: &Self::PaintState,
-        cx: &gpui::DebugContext,
+        view: &V,
+        cx: &gpui::ViewContext<V>,
     ) -> serde_json::Value {
         gpui::json::json!({
             "type": "Pane Back Drop",
             "view": self.child_view,
-            "child": self.child.debug(cx),
+            "child": self.child.debug(view, cx),
         })
     }
 }

crates/workspace/src/pane/dragged_item_receiver.rs 🔗

@@ -5,7 +5,7 @@ use gpui::{
     geometry::{rect::RectF, vector::Vector2F},
     platform::MouseButton,
     scene::MouseUp,
-    AppContext, Element, ElementBox, EventContext, MouseState, Quad, RenderContext, WeakViewHandle,
+    AppContext, Element, ElementBox, EventContext, MouseState, Quad, ViewContext, WeakViewHandle,
 };
 use project::ProjectEntryId;
 use settings::Settings;
@@ -22,14 +22,14 @@ pub fn dragged_item_receiver<Tag, F>(
     drop_index: usize,
     allow_same_pane: bool,
     split_margin: Option<f32>,
-    cx: &mut RenderContext<Pane>,
+    cx: &mut ViewContext<Pane>,
     render_child: F,
 ) -> MouseEventHandler<Tag>
 where
     Tag: 'static,
-    F: FnOnce(&mut MouseState, &mut RenderContext<Pane>) -> ElementBox,
+    F: FnOnce(&mut MouseState, &mut ViewContext<Pane>) -> ElementBox,
 {
-    MouseEventHandler::<Tag>::above(region_id, cx, |state, cx| {
+    MouseEventHandler::<Tag>::above(region_id, cx, |state, _, cx| {
         // Observing hovered will cause a render when the mouse enters regardless
         // of if mouse position was accessed before
         let drag_position = if state.hovered() {
@@ -59,7 +59,7 @@ where
                             .unwrap_or(bounds);
 
                         cx.paint_stacking_context(None, None, |cx| {
-                            cx.scene.push_quad(Quad {
+                            scene.push_quad(Quad {
                                 bounds: overlay_region,
                                 background: Some(overlay_color(cx)),
                                 border: Default::default(),
@@ -102,7 +102,7 @@ pub fn handle_dropped_item(
     index: usize,
     allow_same_pane: bool,
     split_margin: Option<f32>,
-    cx: &mut EventContext,
+    cx: &mut ViewContext<Self>,
 ) {
     enum Action {
         Move(WeakViewHandle<Pane>, usize),
@@ -110,11 +110,11 @@ pub fn handle_dropped_item(
     }
     let drag_and_drop = cx.global::<DragAndDrop<Workspace>>();
     let action = if let Some((_, dragged_item)) =
-        drag_and_drop.currently_dragged::<DraggedItem>(cx.window_id)
+        drag_and_drop.currently_dragged::<DraggedItem>(cx.window_id())
     {
         Action::Move(dragged_item.pane.clone(), dragged_item.item.id())
     } else if let Some((_, project_entry)) =
-        drag_and_drop.currently_dragged::<ProjectEntryId>(cx.window_id)
+        drag_and_drop.currently_dragged::<ProjectEntryId>(cx.window_id())
     {
         Action::Open(*project_entry)
     } else {

crates/workspace/src/pane_group.rs 🔗

@@ -5,7 +5,7 @@ use gpui::{
     elements::*,
     geometry::{rect::RectF, vector::Vector2F},
     platform::{CursorStyle, MouseButton},
-    Axis, Border, ModelHandle, RenderContext, ViewHandle,
+    Axis, Border, ModelHandle, ViewContext, ViewHandle,
 };
 use project::Project;
 use serde::Deserialize;
@@ -70,7 +70,7 @@ impl PaneGroup {
         follower_states: &FollowerStatesByLeader,
         active_call: Option<&ModelHandle<ActiveCall>>,
         active_pane: &ViewHandle<Pane>,
-        cx: &mut RenderContext<Workspace>,
+        cx: &mut ViewContext<Workspace>,
     ) -> ElementBox {
         self.root.render(
             project,
@@ -131,7 +131,7 @@ impl Member {
         follower_states: &FollowerStatesByLeader,
         active_call: Option<&ModelHandle<ActiveCall>>,
         active_pane: &ViewHandle<Pane>,
-        cx: &mut RenderContext<Workspace>,
+        cx: &mut ViewContext<Workspace>,
     ) -> ElementBox {
         enum FollowIntoExternalProject {}
 
@@ -366,7 +366,7 @@ impl PaneAxis {
         follower_state: &FollowerStatesByLeader,
         active_call: Option<&ModelHandle<ActiveCall>>,
         active_pane: &ViewHandle<Pane>,
-        cx: &mut RenderContext<Workspace>,
+        cx: &mut ViewContext<Workspace>,
     ) -> ElementBox {
         let last_member_ix = self.members.len() - 1;
         Flex::new(self.axis)

crates/workspace/src/shared_screen.rs 🔗

@@ -9,7 +9,7 @@ use gpui::{
     elements::*,
     geometry::{rect::RectF, vector::vec2f},
     platform::MouseButton,
-    AppContext, Entity, RenderContext, Task, View, ViewContext,
+    AppContext, Entity, Task, View, ViewContext,
 };
 use settings::Settings;
 use smallvec::SmallVec;
@@ -64,7 +64,7 @@ impl View for SharedScreen {
         "SharedScreen"
     }
 
-    fn render(&mut self, cx: &mut RenderContext<Self>) -> ElementBox {
+    fn render(&mut self, cx: &mut ViewContext<Self>) -> ElementBox {
         enum Focus {}
 
         let frame = self.frame.clone();
@@ -76,7 +76,7 @@ impl View for SharedScreen {
                         vec2f(frame.width() as f32, frame.height() as f32),
                     );
                     let origin = bounds.origin() + (bounds.size() / 2.) - size / 2.;
-                    cx.scene.push_surface(gpui::platform::mac::Surface {
+                    scene.push_surface(gpui::platform::mac::Surface {
                         bounds: RectF::new(origin, size),
                         image_buffer: frame.image(),
                     });

crates/workspace/src/sidebar.rs 🔗

@@ -1,7 +1,7 @@
 use crate::StatusItemView;
 use gpui::{
     elements::*, impl_actions, platform::CursorStyle, platform::MouseButton, AnyViewHandle,
-    AppContext, Entity, RenderContext, Subscription, View, ViewContext, ViewHandle,
+    AppContext, Entity, Subscription, View, ViewContext, ViewHandle,
 };
 use serde::Deserialize;
 use settings::Settings;
@@ -188,7 +188,7 @@ impl View for Sidebar {
         "Sidebar"
     }
 
-    fn render(&mut self, cx: &mut RenderContext<Self>) -> ElementBox {
+    fn render(&mut self, cx: &mut ViewContext<Self>) -> ElementBox {
         if let Some(active_item) = self.active_item() {
             enum ResizeHandleTag {}
             let style = &cx.global::<Settings>().theme.workspace.sidebar;
@@ -225,7 +225,7 @@ impl View for SidebarButtons {
         "SidebarToggleButton"
     }
 
-    fn render(&mut self, cx: &mut RenderContext<Self>) -> ElementBox {
+    fn render(&mut self, cx: &mut ViewContext<Self>) -> ElementBox {
         let theme = &cx.global::<Settings>().theme;
         let tooltip_style = theme.tooltip.clone();
         let theme = &theme.workspace.status_bar.sidebar_buttons;

crates/workspace/src/status_bar.rs 🔗

@@ -9,7 +9,7 @@ use gpui::{
     },
     json::{json, ToJson},
     AnyViewHandle, AppContext, DebugContext, ElementBox, Entity, LayoutContext, MeasurementContext,
-    PaintContext, RenderContext, SizeConstraint, Subscription, View, ViewContext, ViewHandle,
+    PaintContext, SceneBuilder, SizeConstraint, Subscription, View, ViewContext, ViewHandle,
 };
 use settings::Settings;
 
@@ -42,7 +42,7 @@ impl View for StatusBar {
         "StatusBar"
     }
 
-    fn render(&mut self, cx: &mut RenderContext<Self>) -> ElementBox {
+    fn render(&mut self, cx: &mut ViewContext<Self>) -> ElementBox {
         let theme = &cx.global::<Settings>().theme.workspace.status_bar;
 
         StatusBarElement {
@@ -143,44 +143,49 @@ struct StatusBarElement {
     right: ElementBox,
 }
 
-impl Element for StatusBarElement {
+impl<V: View> Element<V> for StatusBarElement {
     type LayoutState = ();
     type PaintState = ();
 
     fn layout(
         &mut self,
         mut constraint: SizeConstraint,
-        cx: &mut LayoutContext,
+        view: &mut V,
+        cx: &mut ViewContext<V>,
     ) -> (Vector2F, Self::LayoutState) {
         let max_width = constraint.max.x();
         constraint.min = vec2f(0., constraint.min.y());
 
-        let right_size = self.right.layout(constraint, cx);
+        let right_size = self.right.layout(constraint, view, cx);
         let constraint = SizeConstraint::new(
             vec2f(0., constraint.min.y()),
             vec2f(max_width - right_size.x(), constraint.max.y()),
         );
 
-        self.left.layout(constraint, cx);
+        self.left.layout(constraint, view, cx);
 
         (vec2f(max_width, right_size.y()), ())
     }
 
     fn paint(
         &mut self,
+        scene: &mut SceneBuilder,
         bounds: RectF,
         visible_bounds: RectF,
         _: &mut Self::LayoutState,
-        cx: &mut PaintContext,
+        view: &mut V,
+        cx: &mut ViewContext<V>,
     ) -> Self::PaintState {
         let origin_y = bounds.upper_right().y();
         let visible_bounds = bounds.intersection(visible_bounds).unwrap_or_default();
 
         let left_origin = vec2f(bounds.lower_left().x(), origin_y);
-        self.left.paint(left_origin, visible_bounds, cx);
+        self.left
+            .paint(scene, left_origin, visible_bounds, view, cx);
 
         let right_origin = vec2f(bounds.upper_right().x() - self.right.size().x(), origin_y);
-        self.right.paint(right_origin, visible_bounds, cx);
+        self.right
+            .paint(scene, right_origin, visible_bounds, view, cx);
     }
 
     fn rect_for_text_range(

crates/workspace/src/toolbar.rs 🔗

@@ -1,7 +1,7 @@
 use crate::{ItemHandle, Pane};
 use gpui::{
     elements::*, platform::CursorStyle, platform::MouseButton, Action, AnyViewHandle, AppContext,
-    Entity, RenderContext, View, ViewContext, ElementBox, ViewHandle, WeakViewHandle,
+    ElementBox, Entity, View, ViewContext, ViewHandle, WeakViewHandle,
 };
 use settings::Settings;
 
@@ -59,7 +59,7 @@ impl View for Toolbar {
         "Toolbar"
     }
 
-    fn render(&mut self, cx: &mut RenderContext<Self>) -> ElementBox {
+    fn render(&mut self, cx: &mut ViewContext<Self>) -> ElementBox {
         let theme = &cx.global::<Settings>().theme.workspace.toolbar;
 
         let mut primary_left_items = Vec::new();
@@ -168,7 +168,7 @@ fn nav_button<A: Action + Clone>(
     action: A,
     tooltip_action: A,
     action_name: &str,
-    cx: &mut RenderContext<Toolbar>,
+    cx: &mut ViewContext<Toolbar>,
 ) -> ElementBox {
     MouseEventHandler::<A>::new(0, cx, |state, _| {
         let style = if enabled {

crates/workspace/src/workspace.rs 🔗

@@ -45,8 +45,7 @@ use gpui::{
         WindowOptions,
     },
     Action, AnyModelHandle, AnyViewHandle, AppContext, AsyncAppContext, Entity, ModelContext,
-    ModelHandle, RenderContext, SizeConstraint, Subscription, Task, View, ViewContext, ViewHandle,
-    WeakViewHandle,
+    ModelHandle, SizeConstraint, Subscription, Task, View, ViewContext, ViewHandle, WeakViewHandle,
 };
 use item::{FollowableItem, FollowableItemHandle, Item, ItemHandle, ProjectItem};
 use language::LanguageRegistry;
@@ -2054,10 +2053,10 @@ impl Workspace {
         self.leader_state.followers.contains(&peer_id)
     }
 
-    fn render_titlebar(&self, theme: &Theme, cx: &mut RenderContext<Self>) -> ElementBox {
+    fn render_titlebar(&self, theme: &Theme, cx: &mut ViewContext<Self>) -> ElementBox {
         // TODO: There should be a better system in place for this
         // (https://github.com/zed-industries/zed/issues/1290)
-        let is_fullscreen = cx.window_is_fullscreen(cx.window_id());
+        let is_fullscreen = cx.window_is_fullscreen();
         let container_theme = if is_fullscreen {
             let mut container_theme = theme.workspace.titlebar.container;
             container_theme.padding.left = container_theme.padding.right;
@@ -2154,7 +2153,7 @@ impl Workspace {
         }
     }
 
-    fn render_disconnected_overlay(&self, cx: &mut RenderContext<Workspace>) -> Option<ElementBox> {
+    fn render_disconnected_overlay(&self, cx: &mut ViewContext<Workspace>) -> Option<ElementBox> {
         if self.project.read(cx).is_read_only() {
             enum DisconnectedOverlay {}
             Some(
@@ -2810,7 +2809,7 @@ impl View for Workspace {
         "Workspace"
     }
 
-    fn render(&mut self, cx: &mut RenderContext<Self>) -> ElementBox {
+    fn render(&mut self, cx: &mut ViewContext<Self>) -> ElementBox {
         let theme = cx.global::<Settings>().theme.clone();
         Stack::new()
             .with_child(