WIP

Antonio Scandurra created

Change summary

crates/gpui2/src/app.rs               |   7 
crates/gpui2/src/app/async_context.rs |  14 +-
crates/gpui2/src/app/entity_map.rs    |   4 
crates/gpui2/src/app/model_context.rs |   6 
crates/gpui2/src/app/test_context.rs  |   6 
crates/gpui2/src/gpui2.rs             |  20 ++--
crates/gpui2/src/interactive.rs       |   3 
crates/gpui2/src/view.rs              |  89 ++++++++++++-----
crates/gpui2/src/window.rs            | 142 ++++++++++++++--------------
9 files changed, 164 insertions(+), 127 deletions(-)

Detailed changes

crates/gpui2/src/app.rs 🔗

@@ -130,6 +130,7 @@ pub struct AppContext {
     pub(crate) text_style_stack: Vec<TextStyleRefinement>,
     pub(crate) globals_by_type: HashMap<TypeId, AnyBox>,
     pub(crate) unit_entity: Handle<()>,
+    pub(crate) unit_view: View<()>,
     pub(crate) entities: EntityMap,
     pub(crate) windows: SlotMap<WindowId, Option<Window>>,
     pub(crate) keymap: Arc<Mutex<Keymap>>,
@@ -653,12 +654,12 @@ impl AppContext {
 }
 
 impl Context for AppContext {
-    type EntityContext<'a, 'w, T> = ModelContext<'a, T>;
+    type EntityContext<'a, T> = ModelContext<'a, T>;
     type Result<T> = T;
 
     fn entity<T: 'static + Send>(
         &mut self,
-        build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, T>) -> T,
+        build_entity: impl FnOnce(&mut Self::EntityContext<'_, T>) -> T,
     ) -> Handle<T> {
         self.update(|cx| {
             let slot = cx.entities.reserve();
@@ -670,7 +671,7 @@ impl Context for AppContext {
     fn update_entity<T: 'static, R>(
         &mut self,
         handle: &Handle<T>,
-        update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, '_, T>) -> R,
+        update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, T>) -> R,
     ) -> R {
         self.update(|cx| {
             let mut entity = cx.entities.lease(handle);

crates/gpui2/src/app/async_context.rs 🔗

@@ -1,6 +1,6 @@
 use crate::{
     AnyWindowHandle, AppContext, Context, Executor, Handle, MainThread, ModelContext, Result, Task,
-    ViewContext, WindowContext,
+    WindowContext,
 };
 use anyhow::anyhow;
 use derive_more::{Deref, DerefMut};
@@ -14,12 +14,12 @@ pub struct AsyncAppContext {
 }
 
 impl Context for AsyncAppContext {
-    type EntityContext<'a, 'w, T> = ModelContext<'a, T>;
+    type EntityContext<'a, T> = ModelContext<'a, T>;
     type Result<T> = Result<T>;
 
     fn entity<T: 'static>(
         &mut self,
-        build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, T>) -> T,
+        build_entity: impl FnOnce(&mut Self::EntityContext<'_, T>) -> T,
     ) -> Self::Result<Handle<T>>
     where
         T: 'static + Send,
@@ -35,7 +35,7 @@ impl Context for AsyncAppContext {
     fn update_entity<T: 'static, R>(
         &mut self,
         handle: &Handle<T>,
-        update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, '_, T>) -> R,
+        update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, T>) -> R,
     ) -> Self::Result<R> {
         let app = self
             .app
@@ -216,12 +216,12 @@ impl AsyncWindowContext {
 }
 
 impl Context for AsyncWindowContext {
-    type EntityContext<'a, 'w, T> = ViewContext<'a, 'w, T>;
+    type EntityContext<'a, T> = ModelContext<'a, T>;
     type Result<T> = Result<T>;
 
     fn entity<T>(
         &mut self,
-        build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, T>) -> T,
+        build_entity: impl FnOnce(&mut Self::EntityContext<'_, T>) -> T,
     ) -> Result<Handle<T>>
     where
         T: 'static + Send,
@@ -233,7 +233,7 @@ impl Context for AsyncWindowContext {
     fn update_entity<T: 'static, R>(
         &mut self,
         handle: &Handle<T>,
-        update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, '_, T>) -> R,
+        update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, T>) -> R,
     ) -> Result<R> {
         self.app
             .update_window(self.window, |cx| cx.update_entity(handle, update))

crates/gpui2/src/app/entity_map.rs 🔗

@@ -284,7 +284,7 @@ impl<T: 'static> Handle<T> {
     pub fn update<C, R>(
         &self,
         cx: &mut C,
-        update: impl FnOnce(&mut T, &mut C::EntityContext<'_, '_, T>) -> R,
+        update: impl FnOnce(&mut T, &mut C::EntityContext<'_, T>) -> R,
     ) -> C::Result<R>
     where
         C: Context,
@@ -427,7 +427,7 @@ impl<T: 'static> WeakHandle<T> {
     pub fn update<C, R>(
         &self,
         cx: &mut C,
-        update: impl FnOnce(&mut T, &mut C::EntityContext<'_, '_, T>) -> R,
+        update: impl FnOnce(&mut T, &mut C::EntityContext<'_, T>) -> R,
     ) -> Result<R>
     where
         C: Context,

crates/gpui2/src/app/model_context.rs 🔗

@@ -224,12 +224,12 @@ where
 }
 
 impl<'a, T> Context for ModelContext<'a, T> {
-    type EntityContext<'b, 'c, U> = ModelContext<'b, U>;
+    type EntityContext<'b, U> = ModelContext<'b, U>;
     type Result<U> = U;
 
     fn entity<U>(
         &mut self,
-        build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, U>) -> U,
+        build_entity: impl FnOnce(&mut Self::EntityContext<'_, U>) -> U,
     ) -> Handle<U>
     where
         U: 'static + Send,
@@ -240,7 +240,7 @@ impl<'a, T> Context for ModelContext<'a, T> {
     fn update_entity<U: 'static, R>(
         &mut self,
         handle: &Handle<U>,
-        update: impl FnOnce(&mut U, &mut Self::EntityContext<'_, '_, U>) -> R,
+        update: impl FnOnce(&mut U, &mut Self::EntityContext<'_, U>) -> R,
     ) -> R {
         self.app.update_entity(handle, update)
     }

crates/gpui2/src/app/test_context.rs 🔗

@@ -12,12 +12,12 @@ pub struct TestAppContext {
 }
 
 impl Context for TestAppContext {
-    type EntityContext<'a, 'w, T> = ModelContext<'a, T>;
+    type EntityContext<'a, T> = ModelContext<'a, T>;
     type Result<T> = T;
 
     fn entity<T: 'static>(
         &mut self,
-        build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, T>) -> T,
+        build_entity: impl FnOnce(&mut Self::EntityContext<'_, T>) -> T,
     ) -> Self::Result<Handle<T>>
     where
         T: 'static + Send,
@@ -29,7 +29,7 @@ impl Context for TestAppContext {
     fn update_entity<T: 'static, R>(
         &mut self,
         handle: &Handle<T>,
-        update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, '_, T>) -> R,
+        update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, T>) -> R,
     ) -> Self::Result<R> {
         let mut lock = self.app.lock();
         lock.update_entity(handle, update)

crates/gpui2/src/gpui2.rs 🔗

@@ -70,12 +70,12 @@ use taffy::TaffyLayoutEngine;
 type AnyBox = Box<dyn Any + Send>;
 
 pub trait Context {
-    type EntityContext<'a, 'w, T>;
+    type EntityContext<'a, T>;
     type Result<T>;
 
     fn entity<T>(
         &mut self,
-        build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, T>) -> T,
+        build_entity: impl FnOnce(&mut Self::EntityContext<'_, T>) -> T,
     ) -> Self::Result<Handle<T>>
     where
         T: 'static + Send;
@@ -83,7 +83,7 @@ pub trait Context {
     fn update_entity<T: 'static, R>(
         &mut self,
         handle: &Handle<T>,
-        update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, '_, T>) -> R,
+        update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, T>) -> R,
     ) -> Self::Result<R>;
 }
 
@@ -111,12 +111,12 @@ impl<T> DerefMut for MainThread<T> {
 }
 
 impl<C: Context> Context for MainThread<C> {
-    type EntityContext<'a, 'w, T> = MainThread<C::EntityContext<'a, 'w, T>>;
+    type EntityContext<'a, T> = MainThread<C::EntityContext<'a, T>>;
     type Result<T> = C::Result<T>;
 
     fn entity<T>(
         &mut self,
-        build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, T>) -> T,
+        build_entity: impl FnOnce(&mut Self::EntityContext<'_, T>) -> T,
     ) -> Self::Result<Handle<T>>
     where
         T: 'static + Send,
@@ -124,8 +124,8 @@ impl<C: Context> Context for MainThread<C> {
         self.0.entity(|cx| {
             let cx = unsafe {
                 mem::transmute::<
-                    &mut C::EntityContext<'_, '_, T>,
-                    &mut MainThread<C::EntityContext<'_, '_, T>>,
+                    &mut C::EntityContext<'_, T>,
+                    &mut MainThread<C::EntityContext<'_, T>>,
                 >(cx)
             };
             build_entity(cx)
@@ -135,13 +135,13 @@ impl<C: Context> Context for MainThread<C> {
     fn update_entity<T: 'static, R>(
         &mut self,
         handle: &Handle<T>,
-        update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, '_, T>) -> R,
+        update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, T>) -> R,
     ) -> Self::Result<R> {
         self.0.update_entity(handle, |entity, cx| {
             let cx = unsafe {
                 mem::transmute::<
-                    &mut C::EntityContext<'_, '_, T>,
-                    &mut MainThread<C::EntityContext<'_, '_, T>>,
+                    &mut C::EntityContext<'_, T>,
+                    &mut MainThread<C::EntityContext<'_, T>>,
                 >(cx)
             };
             update(entity, cx)

crates/gpui2/src/interactive.rs 🔗

@@ -331,9 +331,8 @@ pub trait StatefulInteractive<V: 'static>: StatelessInteractive<V> {
         self.stateful_interaction().drag_listener =
             Some(Box::new(move |view_state, cursor_offset, cx| {
                 let drag = listener(view_state, cx);
-                let view_handle = cx.handle().upgrade().unwrap();
                 let drag_handle_view = Some(
-                    view(view_handle, move |view_state, cx| {
+                    view(cx.handle().upgrade().unwrap(), move |view_state, cx| {
                         (drag.render_drag_handle)(view_state, cx)
                     })
                     .into_any(),

crates/gpui2/src/view.rs 🔗

@@ -1,31 +1,18 @@
-use parking_lot::Mutex;
-
 use crate::{
     AnyBox, AnyElement, BorrowWindow, Bounds, Component, Element, ElementId, EntityId, Handle,
-    LayoutId, Pixels, ViewContext, WindowContext,
+    LayoutId, Pixels, ViewContext, WeakHandle, WindowContext,
+};
+use parking_lot::Mutex;
+use std::{
+    marker::PhantomData,
+    sync::{Arc, Weak},
 };
-use std::{marker::PhantomData, sync::Arc};
 
 pub struct View<V> {
-    state: Handle<V>,
+    pub(crate) state: Handle<V>,
     render: Arc<Mutex<dyn Fn(&mut V, &mut ViewContext<V>) -> AnyElement<V> + Send + 'static>>,
 }
 
-impl<V: 'static> View<V> {
-    pub fn into_any(self) -> AnyView {
-        AnyView(Arc::new(self))
-    }
-}
-
-impl<V> Clone for View<V> {
-    fn clone(&self) -> Self {
-        Self {
-            state: self.state.clone(),
-            render: self.render.clone(),
-        }
-    }
-}
-
 pub fn view<V, E>(
     state: Handle<V>,
     render: impl Fn(&mut V, &mut ViewContext<'_, '_, V>) -> E + Send + 'static,
@@ -41,6 +28,43 @@ where
     }
 }
 
+impl<V: 'static> View<V> {
+    pub fn into_any(self) -> AnyView {
+        AnyView(Arc::new(self))
+    }
+
+    pub fn downgrade(&self) -> WeakView<V> {
+        WeakView {
+            state: self.state.downgrade(),
+            render: Arc::downgrade(&self.render),
+        }
+    }
+}
+
+impl<V: 'static> View<V> {
+    pub fn update<R>(
+        &self,
+        cx: &mut WindowContext,
+        f: impl FnOnce(&mut V, &mut ViewContext<V>) -> R,
+    ) -> R {
+        let this = self.clone();
+        let mut lease = cx.app.entities.lease(&self.state);
+        let mut cx = ViewContext::mutable(&mut *cx.app, &mut *cx.window, this);
+        let result = f(&mut *lease, &mut cx);
+        cx.app.entities.end_lease(lease);
+        result
+    }
+}
+
+impl<V> Clone for View<V> {
+    fn clone(&self) -> Self {
+        Self {
+            state: self.state.clone(),
+            render: self.render.clone(),
+        }
+    }
+}
+
 impl<V: 'static, ParentViewState: 'static> Component<ParentViewState> for View<V> {
     fn render(self) -> AnyElement<ParentViewState> {
         AnyElement::new(EraseViewState {
@@ -63,7 +87,7 @@ impl<V: 'static> Element<()> for View<V> {
         _: Option<Self::ElementState>,
         cx: &mut ViewContext<()>,
     ) -> Self::ElementState {
-        self.state.update(cx, |state, cx| {
+        self.update(cx, |state, cx| {
             let mut any_element = (self.render.lock())(state, cx);
             any_element.initialize(state, cx);
             any_element
@@ -76,7 +100,7 @@ impl<V: 'static> Element<()> for View<V> {
         element: &mut Self::ElementState,
         cx: &mut ViewContext<()>,
     ) -> LayoutId {
-        self.state.update(cx, |state, cx| element.layout(state, cx))
+        self.update(cx, |state, cx| element.layout(state, cx))
     }
 
     fn paint(
@@ -86,7 +110,20 @@ impl<V: 'static> Element<()> for View<V> {
         element: &mut Self::ElementState,
         cx: &mut ViewContext<()>,
     ) {
-        self.state.update(cx, |state, cx| element.paint(state, cx))
+        self.update(cx, |state, cx| element.paint(state, cx))
+    }
+}
+
+pub struct WeakView<V> {
+    state: WeakHandle<V>,
+    render: Weak<Mutex<dyn Fn(&mut V, &mut ViewContext<V>) -> AnyElement<V> + Send + 'static>>,
+}
+
+impl<V> WeakView<V> {
+    pub fn upgrade(&self) -> Option<View<V>> {
+        let state = self.state.upgrade()?;
+        let render = self.render.upgrade()?;
+        Some(View { state, render })
     }
 }
 
@@ -153,7 +190,7 @@ impl<V: 'static> ViewObject for View<V> {
 
     fn initialize(&self, cx: &mut WindowContext) -> AnyBox {
         cx.with_element_id(self.entity_id(), |_global_id, cx| {
-            self.state.update(cx, |state, cx| {
+            self.update(cx, |state, cx| {
                 let mut any_element = Box::new((self.render.lock())(state, cx));
                 any_element.initialize(state, cx);
                 any_element as AnyBox
@@ -163,7 +200,7 @@ impl<V: 'static> ViewObject for View<V> {
 
     fn layout(&self, element: &mut AnyBox, cx: &mut WindowContext) -> LayoutId {
         cx.with_element_id(self.entity_id(), |_global_id, cx| {
-            self.state.update(cx, |state, cx| {
+            self.update(cx, |state, cx| {
                 let element = element.downcast_mut::<AnyElement<V>>().unwrap();
                 element.layout(state, cx)
             })
@@ -172,7 +209,7 @@ impl<V: 'static> ViewObject for View<V> {
 
     fn paint(&self, _: Bounds<Pixels>, element: &mut AnyBox, cx: &mut WindowContext) {
         cx.with_element_id(self.entity_id(), |_global_id, cx| {
-            self.state.update(cx, |state, cx| {
+            self.update(cx, |state, cx| {
                 let element = element.downcast_mut::<AnyElement<V>>().unwrap();
                 element.paint(state, cx);
             });

crates/gpui2/src/window.rs 🔗

@@ -3,12 +3,12 @@ use crate::{
     Bounds, BoxShadow, Context, Corners, DevicePixels, DispatchContext, DisplayId, Edges, Effect,
     Element, EntityId, EventEmitter, ExternalPaths, FileDropEvent, FocusEvent, FontId,
     GlobalElementId, GlyphId, Handle, Hsla, ImageData, InputEvent, IsZero, KeyListener, KeyMatch,
-    KeyMatcher, Keystroke, LayoutId, MainThread, MainThreadOnly, Modifiers, MonochromeSprite,
-    MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Path, Pixels, PlatformAtlas,
-    PlatformWindow, Point, PolychromeSprite, Quad, Reference, RenderGlyphParams, RenderImageParams,
-    RenderSvgParams, ScaledPixels, SceneBuilder, Shadow, SharedString, Size, Style, Subscription,
-    TaffyLayoutEngine, Task, Underline, UnderlineStyle, WeakHandle, WindowOptions,
-    SUBPIXEL_VARIANTS,
+    KeyMatcher, Keystroke, LayoutId, MainThread, MainThreadOnly, ModelContext, Modifiers,
+    MonochromeSprite, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Path, Pixels,
+    PlatformAtlas, PlatformWindow, Point, PolychromeSprite, Quad, Reference, RenderGlyphParams,
+    RenderImageParams, RenderSvgParams, ScaledPixels, SceneBuilder, Shadow, SharedString, Size,
+    Style, Subscription, TaffyLayoutEngine, Task, Underline, UnderlineStyle, View, WeakHandle,
+    WeakView, WindowOptions, SUBPIXEL_VARIANTS,
 };
 use anyhow::Result;
 use collections::HashMap;
@@ -281,7 +281,7 @@ impl ContentMask<Pixels> {
 }
 
 pub struct WindowContext<'a, 'w> {
-    app: Reference<'a, AppContext>,
+    pub(crate) app: Reference<'a, AppContext>,
     pub(crate) window: Reference<'w, Window>,
 }
 
@@ -800,42 +800,45 @@ impl<'a, 'w> WindowContext<'a, 'w> {
 
     pub(crate) fn draw(&mut self) {
         let unit_entity = self.unit_entity.clone();
-        self.update_entity(&unit_entity, |view, cx| {
-            cx.start_frame();
+        let mut root_view = self.window.root_view.take().unwrap();
+        let mut root_view_cx = ViewContext::mutable(
+            &mut self.app,
+            &mut self.window,
+            self.unit_entity.downgrade(),
+        );
 
-            let mut root_view = cx.window.root_view.take().unwrap();
+        root_view_cx.start_frame();
 
-            cx.stack(0, |cx| {
-                let available_space = cx.window.content_size.map(Into::into);
-                draw_any_view(&mut root_view, available_space, cx);
-            });
+        root_view_cx.stack(0, |cx| {
+            let available_space = cx.window.content_size.map(Into::into);
+            draw_any_view(&mut root_view, available_space, cx);
+        });
 
-            if let Some(mut active_drag) = cx.active_drag.take() {
-                cx.stack(1, |cx| {
-                    let offset = cx.mouse_position() - active_drag.cursor_offset;
-                    cx.with_element_offset(Some(offset), |cx| {
-                        let available_space =
-                            size(AvailableSpace::MinContent, AvailableSpace::MinContent);
-                        if let Some(drag_handle_view) = &mut active_drag.drag_handle_view {
-                            draw_any_view(drag_handle_view, available_space, cx);
-                        }
-                        cx.active_drag = Some(active_drag);
-                    });
+        if let Some(mut active_drag) = self.app.active_drag.take() {
+            root_view_cx.stack(1, |cx| {
+                let offset = cx.mouse_position() - active_drag.cursor_offset;
+                cx.with_element_offset(Some(offset), |cx| {
+                    let available_space =
+                        size(AvailableSpace::MinContent, AvailableSpace::MinContent);
+                    if let Some(drag_handle_view) = &mut active_drag.drag_handle_view {
+                        draw_any_view(drag_handle_view, available_space, cx);
+                    }
+                    cx.active_drag = Some(active_drag);
                 });
-            }
+            });
+        }
 
-            cx.window.root_view = Some(root_view);
-            let scene = cx.window.scene_builder.build();
+        self.window.root_view = Some(root_view);
+        let scene = self.window.scene_builder.build();
 
-            cx.run_on_main(view, |_, cx| {
-                cx.window
-                    .platform_window
-                    .borrow_on_main_thread()
-                    .draw(scene);
-                cx.window.dirty = false;
-            })
-            .detach();
-        });
+        self.run_on_main(|cx| {
+            cx.window
+                .platform_window
+                .borrow_on_main_thread()
+                .draw(scene);
+            cx.window.dirty = false;
+        })
+        .detach();
 
         fn draw_any_view(
             view: &mut AnyView,
@@ -1169,34 +1172,30 @@ impl<'a, 'w> WindowContext<'a, 'w> {
 }
 
 impl Context for WindowContext<'_, '_> {
-    type EntityContext<'a, 'w, T> = ViewContext<'a, 'w, T>;
+    type EntityContext<'a, T> = ModelContext<'a, T>;
     type Result<T> = T;
 
     fn entity<T>(
         &mut self,
-        build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, T>) -> T,
+        build_entity: impl FnOnce(&mut Self::EntityContext<'_, T>) -> T,
     ) -> Handle<T>
     where
         T: 'static + Send,
     {
         let slot = self.app.entities.reserve();
-        let entity = build_entity(&mut ViewContext::mutable(
-            &mut *self.app,
-            &mut self.window,
-            slot.downgrade(),
-        ));
+        let entity = build_entity(&mut ModelContext::mutable(&mut *self.app, slot.downgrade()));
         self.entities.insert(slot, entity)
     }
 
     fn update_entity<T: 'static, R>(
         &mut self,
         handle: &Handle<T>,
-        update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, '_, T>) -> R,
+        update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, T>) -> R,
     ) -> R {
         let mut entity = self.entities.lease(handle);
         let result = update(
             &mut *entity,
-            &mut ViewContext::mutable(&mut *self.app, &mut *self.window, handle.downgrade()),
+            &mut ModelContext::mutable(&mut *self.app, handle.downgrade()),
         );
         self.entities.end_lease(entity);
         result
@@ -1389,7 +1388,7 @@ impl<T> BorrowWindow for T where T: BorrowMut<AppContext> + BorrowMut<Window> {}
 
 pub struct ViewContext<'a, 'w, V> {
     window_cx: WindowContext<'a, 'w>,
-    view_state: WeakHandle<V>,
+    view: View<V>,
 }
 
 impl<V> Borrow<AppContext> for ViewContext<'_, '_, V> {
@@ -1417,15 +1416,19 @@ impl<V> BorrowMut<Window> for ViewContext<'_, '_, V> {
 }
 
 impl<'a, 'w, V: 'static> ViewContext<'a, 'w, V> {
-    fn mutable(app: &'a mut AppContext, window: &'w mut Window, view_state: WeakHandle<V>) -> Self {
+    pub(crate) fn mutable(app: &'a mut AppContext, window: &'w mut Window, view: View<V>) -> Self {
         Self {
             window_cx: WindowContext::mutable(app, window),
-            view_state,
+            view,
         }
     }
 
+    pub fn view(&self) -> WeakView<V> {
+        self.view.downgrade()
+    }
+
     pub fn handle(&self) -> WeakHandle<V> {
-        self.view_state.clone()
+        self.view.state.downgrade()
     }
 
     pub fn stack<R>(&mut self, order: u32, f: impl FnOnce(&mut Self) -> R) -> R {
@@ -1439,10 +1442,8 @@ impl<'a, 'w, V: 'static> ViewContext<'a, 'w, V> {
     where
         V: Any + Send,
     {
-        let entity = self.handle();
-        self.window_cx.on_next_frame(move |cx| {
-            entity.update(cx, f).ok();
-        });
+        let view = self.view();
+        self.window_cx.on_next_frame(move |cx| view.update(cx, f));
     }
 
     pub fn observe<E>(
@@ -1454,7 +1455,7 @@ impl<'a, 'w, V: 'static> ViewContext<'a, 'w, V> {
         E: 'static,
         V: Any + Send,
     {
-        let this = self.handle();
+        let view = self.view();
         let handle = handle.downgrade();
         let window_handle = self.window.handle;
         self.app.observers.insert(
@@ -1462,7 +1463,7 @@ impl<'a, 'w, V: 'static> ViewContext<'a, 'w, V> {
             Box::new(move |cx| {
                 cx.update_window(window_handle.id, |cx| {
                     if let Some(handle) = handle.upgrade() {
-                        this.update(cx, |this, cx| on_notify(this, handle, cx))
+                        view.update(cx, |this, cx| on_notify(this, handle, cx))
                             .is_ok()
                     } else {
                         false
@@ -1480,7 +1481,7 @@ impl<'a, 'w, V: 'static> ViewContext<'a, 'w, V> {
             + Send
             + 'static,
     ) -> Subscription {
-        let this = self.handle();
+        let this = self.view();
         let handle = handle.downgrade();
         let window_handle = self.window.handle;
         self.app.event_listeners.insert(
@@ -1490,7 +1491,6 @@ impl<'a, 'w, V: 'static> ViewContext<'a, 'w, V> {
                     if let Some(handle) = handle.upgrade() {
                         let event = event.downcast_ref().expect("invalid event type");
                         this.update(cx, |this, cx| on_event(this, handle, event, cx))
-                            .is_ok()
                     } else {
                         false
                     }
@@ -1506,7 +1506,7 @@ impl<'a, 'w, V: 'static> ViewContext<'a, 'w, V> {
     ) -> Subscription {
         let window_handle = self.window.handle;
         self.app.release_listeners.insert(
-            self.view_state.entity_id,
+            self.view.entity_id,
             Box::new(move |this, cx| {
                 let this = this.downcast_mut().expect("invalid entity type");
                 // todo!("are we okay with silently swallowing the error?")
@@ -1523,7 +1523,7 @@ impl<'a, 'w, V: 'static> ViewContext<'a, 'w, V> {
     where
         V: Any + Send,
     {
-        let this = self.handle();
+        let this = self.view();
         let window_handle = self.window.handle;
         self.app.release_listeners.insert(
             handle.entity_id,
@@ -1540,7 +1540,7 @@ impl<'a, 'w, V: 'static> ViewContext<'a, 'w, V> {
     pub fn notify(&mut self) {
         self.window_cx.notify();
         self.window_cx.app.push_effect(Effect::Notify {
-            emitter: self.view_state.entity_id,
+            emitter: self.view.entity_id,
         });
     }
 
@@ -1548,7 +1548,7 @@ impl<'a, 'w, V: 'static> ViewContext<'a, 'w, V> {
         &mut self,
         listener: impl Fn(&mut V, &FocusEvent, &mut ViewContext<V>) + Send + 'static,
     ) {
-        let handle = self.handle();
+        let handle = self.view();
         self.window.focus_listeners.push(Box::new(move |event, cx| {
             handle
                 .update(cx, |view, cx| listener(view, event, cx))
@@ -1564,7 +1564,7 @@ impl<'a, 'w, V: 'static> ViewContext<'a, 'w, V> {
         let old_stack_len = self.window.key_dispatch_stack.len();
         if !self.window.freeze_key_dispatch_stack {
             for (event_type, listener) in key_listeners {
-                let handle = self.handle();
+                let handle = self.view();
                 let listener = Box::new(
                     move |event: &dyn Any,
                           context_stack: &[&DispatchContext],
@@ -1654,7 +1654,7 @@ impl<'a, 'w, V: 'static> ViewContext<'a, 'w, V> {
             let cx = unsafe { mem::transmute::<&mut Self, &mut MainThread<Self>>(self) };
             Task::ready(Ok(f(view, cx)))
         } else {
-            let handle = self.handle().upgrade().unwrap();
+            let handle = self.view().upgrade().unwrap();
             self.window_cx.run_on_main(move |cx| handle.update(cx, f))
         }
     }
@@ -1667,7 +1667,7 @@ impl<'a, 'w, V: 'static> ViewContext<'a, 'w, V> {
         R: Send + 'static,
         Fut: Future<Output = R> + Send + 'static,
     {
-        let handle = self.handle();
+        let handle = self.view();
         self.window_cx.spawn(move |_, cx| {
             let result = f(handle, cx);
             async move { result.await }
@@ -1689,7 +1689,7 @@ impl<'a, 'w, V: 'static> ViewContext<'a, 'w, V> {
         f: impl Fn(&mut V, &mut ViewContext<'_, '_, V>) + Send + 'static,
     ) -> Subscription {
         let window_id = self.window.handle.id;
-        let handle = self.handle();
+        let handle = self.view();
         self.global_observers.insert(
             TypeId::of::<G>(),
             Box::new(move |cx| {
@@ -1705,7 +1705,7 @@ impl<'a, 'w, V: 'static> ViewContext<'a, 'w, V> {
         &mut self,
         handler: impl Fn(&mut V, &Event, DispatchPhase, &mut ViewContext<V>) + Send + 'static,
     ) {
-        let handle = self.handle().upgrade().unwrap();
+        let handle = self.view().upgrade().unwrap();
         self.window_cx.on_mouse_event(move |event, phase, cx| {
             handle.update(cx, |view, cx| {
                 handler(view, event, phase, cx);
@@ -1720,7 +1720,7 @@ where
     V::Event: Any + Send,
 {
     pub fn emit(&mut self, event: V::Event) {
-        let emitter = self.view_state.entity_id;
+        let emitter = self.view.entity_id;
         self.app.push_effect(Effect::Emit {
             emitter,
             event: Box::new(event),
@@ -1729,12 +1729,12 @@ where
 }
 
 impl<'a, 'w, V> Context for ViewContext<'a, 'w, V> {
-    type EntityContext<'b, 'c, U> = ViewContext<'b, 'c, U>;
+    type EntityContext<'b, U> = ModelContext<'b, U>;
     type Result<U> = U;
 
     fn entity<T>(
         &mut self,
-        build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, T>) -> T,
+        build_entity: impl FnOnce(&mut Self::EntityContext<'_, T>) -> T,
     ) -> Handle<T>
     where
         T: 'static + Send,
@@ -1745,7 +1745,7 @@ impl<'a, 'w, V> Context for ViewContext<'a, 'w, V> {
     fn update_entity<T: 'static, R>(
         &mut self,
         handle: &Handle<T>,
-        update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, '_, T>) -> R,
+        update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, T>) -> R,
     ) -> R {
         self.window_cx.update_entity(handle, update)
     }