Store an AnyWindowHandle in WindowContext

Nathan Sobo created

Change summary

crates/collab_ui/src/contact_list.rs                |   4 
crates/collab_ui/src/project_shared_notification.rs |  16 
crates/command_palette/src/command_palette.rs       |   8 
crates/context_menu/src/context_menu.rs             |  12 
crates/file_finder/src/file_finder.rs               |  42 
crates/go_to_line/src/go_to_line.rs                 |  18 
crates/gpui/src/app.rs                              | 377 +++++++-------
crates/gpui/src/app/test_app_context.rs             |  32 
crates/gpui/src/app/window.rs                       | 149 ++---
crates/project_panel/src/project_panel.rs           |  28 
crates/search/src/buffer_search.rs                  |  15 
crates/search/src/project_search.rs                 |  25 
crates/vim/src/editor_events.rs                     |  10 
crates/vim/src/mode_indicator.rs                    |   4 
crates/vim/src/test/vim_test_context.rs             |   4 
crates/workspace/src/dock.rs                        |  12 
crates/workspace/src/pane.rs                        |   4 
crates/workspace/src/workspace.rs                   |  22 
crates/zed/src/zed.rs                               |  59 +-
19 files changed, 400 insertions(+), 441 deletions(-)

Detailed changes

crates/collab_ui/src/contact_list.rs 🔗

@@ -305,7 +305,7 @@ impl ContactList {
             github_login
         );
         let mut answer = cx.prompt(PromptLevel::Warning, &prompt_message, &["Remove", "Cancel"]);
-        let window_id = cx.window_id();
+        let window = cx.window();
         cx.spawn(|_, mut cx| async move {
             if answer.next().await == Some(0) {
                 if let Err(e) = user_store
@@ -313,7 +313,7 @@ impl ContactList {
                     .await
                 {
                     cx.prompt(
-                        window_id,
+                        window,
                         PromptLevel::Info,
                         &format!("Failed to remove contact: {}", e),
                         &["Ok"],

crates/collab_ui/src/project_shared_notification.rs 🔗

@@ -5,7 +5,7 @@ use gpui::{
     elements::*,
     geometry::{rect::RectF, vector::vec2f},
     platform::{CursorStyle, MouseButton, WindowBounds, WindowKind, WindowOptions},
-    AppContext, BorrowWindowContext, Entity, View, ViewContext,
+    AppContext, Entity, View, ViewContext,
 };
 use std::sync::{Arc, Weak};
 use workspace::AppState;
@@ -52,20 +52,20 @@ pub fn init(app_state: &Arc<AppState>, cx: &mut AppContext) {
                 notification_windows
                     .entry(*project_id)
                     .or_insert(Vec::new())
-                    .push(window.id());
+                    .push(window);
             }
         }
         room::Event::RemoteProjectUnshared { project_id } => {
-            if let Some(window_ids) = notification_windows.remove(&project_id) {
-                for window_id in window_ids {
-                    cx.update_window(window_id, |cx| cx.remove_window());
+            if let Some(windows) = notification_windows.remove(&project_id) {
+                for window in windows {
+                    window.remove(cx);
                 }
             }
         }
         room::Event::Left => {
-            for (_, window_ids) in notification_windows.drain() {
-                for window_id in window_ids {
-                    cx.update_window(window_id, |cx| cx.remove_window());
+            for (_, windows) in notification_windows.drain() {
+                for window in windows {
+                    window.remove(cx);
                 }
             }
         }

crates/command_palette/src/command_palette.rs 🔗

@@ -80,11 +80,11 @@ impl PickerDelegate for CommandPaletteDelegate {
         query: String,
         cx: &mut ViewContext<Picker<Self>>,
     ) -> gpui::Task<()> {
-        let window_id = cx.window_id();
         let view_id = self.focused_view_id;
+        let window = cx.window();
         cx.spawn(move |picker, mut cx| async move {
             let actions = cx
-                .available_actions(window_id, view_id)
+                .available_actions(window, view_id)
                 .into_iter()
                 .filter_map(|(name, action, bindings)| {
                     let filtered = cx.read(|cx| {
@@ -162,13 +162,13 @@ impl PickerDelegate for CommandPaletteDelegate {
 
     fn confirm(&mut self, _: bool, cx: &mut ViewContext<Picker<Self>>) {
         if !self.matches.is_empty() {
-            let window_id = cx.window_id();
+            let window = cx.window();
             let focused_view_id = self.focused_view_id;
             let action_ix = self.matches[self.selected_ix].candidate_id;
             let action = self.actions.remove(action_ix).action;
             cx.app_context()
                 .spawn(move |mut cx| async move {
-                    cx.dispatch_action(window_id, focused_view_id, action.as_ref())
+                    cx.dispatch_action(window, focused_view_id, action.as_ref())
                 })
                 .detach_and_log_err(cx);
         }

crates/context_menu/src/context_menu.rs 🔗

@@ -218,12 +218,12 @@ impl ContextMenu {
             if let Some(ContextMenuItem::Item { action, .. }) = self.items.get(ix) {
                 match action {
                     ContextMenuItemAction::Action(action) => {
-                        let window_id = cx.window_id();
+                        let window = cx.window();
                         let view_id = self.parent_view_id;
                         let action = action.boxed_clone();
                         cx.app_context()
                             .spawn(|mut cx| async move {
-                                cx.dispatch_action(window_id, view_id, action.as_ref())
+                                cx.dispatch_action(window, view_id, action.as_ref())
                             })
                             .detach_and_log_err(cx);
                     }
@@ -480,17 +480,13 @@ impl ContextMenu {
                             .on_down(MouseButton::Left, |_, _, _| {}) // Capture these events
                             .on_click(MouseButton::Left, move |_, menu, cx| {
                                 menu.cancel(&Default::default(), cx);
-                                let window_id = cx.window_id();
+                                let window = cx.window();
                                 match &action {
                                     ContextMenuItemAction::Action(action) => {
                                         let action = action.boxed_clone();
                                         cx.app_context()
                                             .spawn(|mut cx| async move {
-                                                cx.dispatch_action(
-                                                    window_id,
-                                                    view_id,
-                                                    action.as_ref(),
-                                                )
+                                                cx.dispatch_action(window, view_id, action.as_ref())
                                             })
                                             .detach_and_log_err(cx);
                                     }

crates/file_finder/src/file_finder.rs 🔗

@@ -619,7 +619,7 @@ mod tests {
         let project = Project::test(app_state.fs.clone(), ["/root".as_ref()], cx).await;
         let window = cx.add_window(|cx| Workspace::test_new(project, cx));
         let workspace = window.root(cx);
-        cx.dispatch_action(window.id(), Toggle);
+        cx.dispatch_action(window.into(), Toggle);
 
         let finder = cx.read(|cx| workspace.read(cx).modal::<FileFinder>().unwrap());
         finder
@@ -632,8 +632,8 @@ mod tests {
         });
 
         let active_pane = cx.read(|cx| workspace.read(cx).active_pane().clone());
-        cx.dispatch_action(window.id(), SelectNext);
-        cx.dispatch_action(window.id(), Confirm);
+        cx.dispatch_action(window.into(), SelectNext);
+        cx.dispatch_action(window.into(), Confirm);
         active_pane
             .condition(cx, |pane, _| pane.active_item().is_some())
             .await;
@@ -674,7 +674,7 @@ mod tests {
         let project = Project::test(app_state.fs.clone(), ["/src".as_ref()], cx).await;
         let window = cx.add_window(|cx| Workspace::test_new(project, cx));
         let workspace = window.root(cx);
-        cx.dispatch_action(window.id(), Toggle);
+        cx.dispatch_action(window.into(), Toggle);
         let finder = cx.read(|cx| workspace.read(cx).modal::<FileFinder>().unwrap());
 
         let file_query = &first_file_name[..3];
@@ -706,8 +706,8 @@ mod tests {
         });
 
         let active_pane = cx.read(|cx| workspace.read(cx).active_pane().clone());
-        cx.dispatch_action(window.id(), SelectNext);
-        cx.dispatch_action(window.id(), Confirm);
+        cx.dispatch_action(window.into(), SelectNext);
+        cx.dispatch_action(window.into(), Confirm);
         active_pane
             .condition(cx, |pane, _| pane.active_item().is_some())
             .await;
@@ -758,7 +758,7 @@ mod tests {
         let project = Project::test(app_state.fs.clone(), ["/src".as_ref()], cx).await;
         let window = cx.add_window(|cx| Workspace::test_new(project, cx));
         let workspace = window.root(cx);
-        cx.dispatch_action(window.id(), Toggle);
+        cx.dispatch_action(window.into(), Toggle);
         let finder = cx.read(|cx| workspace.read(cx).modal::<FileFinder>().unwrap());
 
         let file_query = &first_file_name[..3];
@@ -790,8 +790,8 @@ mod tests {
         });
 
         let active_pane = cx.read(|cx| workspace.read(cx).active_pane().clone());
-        cx.dispatch_action(window.id(), SelectNext);
-        cx.dispatch_action(window.id(), Confirm);
+        cx.dispatch_action(window.into(), SelectNext);
+        cx.dispatch_action(window.into(), Confirm);
         active_pane
             .condition(cx, |pane, _| pane.active_item().is_some())
             .await;
@@ -1168,7 +1168,6 @@ mod tests {
         let project = Project::test(app_state.fs.clone(), ["/src".as_ref()], cx).await;
         let window = cx.add_window(|cx| Workspace::test_new(project, cx));
         let workspace = window.root(cx);
-        let window_id = window.id();
         let worktree_id = cx.read(|cx| {
             let worktrees = workspace.read(cx).worktrees(cx).collect::<Vec<_>>();
             assert_eq!(worktrees.len(), 1);
@@ -1186,7 +1185,7 @@ mod tests {
             "fir",
             1,
             "first.rs",
-            window_id,
+            window.into(),
             &workspace,
             &deterministic,
             cx,
@@ -1201,7 +1200,7 @@ mod tests {
             "sec",
             1,
             "second.rs",
-            window_id,
+            window.into(),
             &workspace,
             &deterministic,
             cx,
@@ -1223,7 +1222,7 @@ mod tests {
             "thi",
             1,
             "third.rs",
-            window_id,
+            window.into(),
             &workspace,
             &deterministic,
             cx,
@@ -1255,7 +1254,7 @@ mod tests {
             "sec",
             1,
             "second.rs",
-            window_id,
+            window.into(),
             &workspace,
             &deterministic,
             cx,
@@ -1294,7 +1293,7 @@ mod tests {
             "thi",
             1,
             "third.rs",
-            window_id,
+            window.into(),
             &workspace,
             &deterministic,
             cx,
@@ -1376,7 +1375,6 @@ mod tests {
 
         let window = cx.add_window(|cx| Workspace::test_new(project, cx));
         let workspace = window.root(cx);
-        let window_id = window.id();
         let worktree_id = cx.read(|cx| {
             let worktrees = workspace.read(cx).worktrees(cx).collect::<Vec<_>>();
             assert_eq!(worktrees.len(), 1,);
@@ -1411,7 +1409,7 @@ mod tests {
             "sec",
             1,
             "second.rs",
-            window_id,
+            window.into(),
             &workspace,
             &deterministic,
             cx,
@@ -1433,7 +1431,7 @@ mod tests {
             "fir",
             1,
             "first.rs",
-            window_id,
+            window.into(),
             &workspace,
             &deterministic,
             cx,
@@ -1465,12 +1463,12 @@ mod tests {
         input: &str,
         expected_matches: usize,
         expected_editor_title: &str,
-        window_id: usize,
+        window: gpui::AnyWindowHandle,
         workspace: &ViewHandle<Workspace>,
         deterministic: &gpui::executor::Deterministic,
         cx: &mut gpui::TestAppContext,
     ) -> Vec<FoundPath> {
-        cx.dispatch_action(window_id, Toggle);
+        cx.dispatch_action(window, Toggle);
         let finder = cx.read(|cx| workspace.read(cx).modal::<FileFinder>().unwrap());
         finder
             .update(cx, |finder, cx| {
@@ -1487,8 +1485,8 @@ mod tests {
         });
 
         let active_pane = cx.read(|cx| workspace.read(cx).active_pane().clone());
-        cx.dispatch_action(window_id, SelectNext);
-        cx.dispatch_action(window_id, Confirm);
+        cx.dispatch_action(window, SelectNext);
+        cx.dispatch_action(window, Confirm);
         deterministic.run_until_parked();
         active_pane
             .condition(cx, |pane, _| pane.active_item().is_some())

crates/go_to_line/src/go_to_line.rs 🔗

@@ -135,16 +135,14 @@ impl Entity for GoToLine {
 
     fn release(&mut self, cx: &mut AppContext) {
         let scroll_position = self.prev_scroll_position.take();
-        if let Some(window) = self.active_editor.window(cx) {
-            window.update(cx, |cx| {
-                self.active_editor.update(cx, |editor, cx| {
-                    editor.highlight_rows(None);
-                    if let Some(scroll_position) = scroll_position {
-                        editor.set_scroll_position(scroll_position, cx);
-                    }
-                })
-            });
-        }
+        self.active_editor.window().update(cx, |cx| {
+            self.active_editor.update(cx, |editor, cx| {
+                editor.highlight_rows(None);
+                if let Some(scroll_position) = scroll_position {
+                    editor.set_scroll_position(scroll_position, cx);
+                }
+            })
+        });
     }
 }
 

crates/gpui/src/app.rs 🔗

@@ -134,16 +134,16 @@ pub trait BorrowAppContext {
 pub trait BorrowWindowContext {
     type Result<T>;
 
-    fn read_window<T, F>(&self, window_id: usize, f: F) -> Self::Result<T>
+    fn read_window<T, F>(&self, window: AnyWindowHandle, f: F) -> Self::Result<T>
     where
         F: FnOnce(&WindowContext) -> T;
-    fn read_window_optional<T, F>(&self, window_id: usize, f: F) -> Option<T>
+    fn read_window_optional<T, F>(&self, window: AnyWindowHandle, f: F) -> Option<T>
     where
         F: FnOnce(&WindowContext) -> Option<T>;
-    fn update_window<T, F>(&mut self, window_id: usize, f: F) -> Self::Result<T>
+    fn update_window<T, F>(&mut self, window: AnyWindowHandle, f: F) -> Self::Result<T>
     where
         F: FnOnce(&mut WindowContext) -> T;
-    fn update_window_optional<T, F>(&mut self, window_id: usize, f: F) -> Option<T>
+    fn update_window_optional<T, F>(&mut self, window: AnyWindowHandle, f: F) -> Option<T>
     where
         F: FnOnce(&mut WindowContext) -> Option<T>;
 }
@@ -308,12 +308,12 @@ impl App {
         result
     }
 
-    fn update_window<T, F>(&mut self, window_id: usize, callback: F) -> Option<T>
+    fn update_window<T, F>(&mut self, window: AnyWindowHandle, callback: F) -> Option<T>
     where
         F: FnOnce(&mut WindowContext) -> T,
     {
         let mut state = self.0.borrow_mut();
-        let result = state.update_window(window_id, callback);
+        let result = state.update_window(window, callback);
         state.pending_notifications.clear();
         result
     }
@@ -346,22 +346,22 @@ impl AsyncAppContext {
 
     pub fn read_window<T, F: FnOnce(&WindowContext) -> T>(
         &self,
-        window_id: usize,
+        window: AnyWindowHandle,
         callback: F,
     ) -> Option<T> {
-        self.0.borrow_mut().read_window(window_id, callback)
+        self.0.borrow_mut().read_window(window, callback)
     }
 
     pub fn update_window<T, F: FnOnce(&mut WindowContext) -> T>(
         &mut self,
-        window_id: usize,
+        window: AnyWindowHandle,
         callback: F,
     ) -> Option<T> {
-        self.0.borrow_mut().update_window(window_id, callback)
+        self.0.borrow_mut().update_window(window, callback)
     }
 
-    pub fn debug_elements(&self, window_id: usize) -> Option<json::Value> {
-        self.0.borrow().read_window(window_id, |cx| {
+    pub fn debug_elements(&self, window: AnyWindowHandle) -> Option<json::Value> {
+        self.0.borrow().read_window(window, |cx| {
             let root_view = cx.window.root_view();
             let root_element = cx.window.rendered_views.get(&root_view.id())?;
             root_element.debug(cx).log_err()
@@ -370,13 +370,13 @@ impl AsyncAppContext {
 
     pub fn dispatch_action(
         &mut self,
-        window_id: usize,
+        window: AnyWindowHandle,
         view_id: usize,
         action: &dyn Action,
     ) -> Result<()> {
         self.0
             .borrow_mut()
-            .update_window(window_id, |cx| {
+            .update_window(window, |cx| {
                 cx.dispatch_action(Some(view_id), action);
             })
             .ok_or_else(|| anyhow!("window not found"))
@@ -384,10 +384,10 @@ impl AsyncAppContext {
 
     pub fn available_actions(
         &self,
-        window_id: usize,
+        window: AnyWindowHandle,
         view_id: usize,
     ) -> Vec<(&'static str, Box<dyn Action>, SmallVec<[Binding; 1]>)> {
-        self.read_window(window_id, |cx| cx.available_actions(view_id))
+        self.read_window(window, |cx| cx.available_actions(view_id))
             .unwrap_or_default()
     }
 
@@ -411,23 +411,23 @@ impl AsyncAppContext {
         self.update(|cx| cx.add_window(window_options, build_root_view))
     }
 
-    pub fn remove_window(&mut self, window_id: usize) {
-        self.update_window(window_id, |cx| cx.remove_window());
+    pub fn remove_window(&mut self, window: AnyWindowHandle) {
+        self.update_window(window, |cx| cx.remove_window());
     }
 
-    pub fn activate_window(&mut self, window_id: usize) {
-        self.update_window(window_id, |cx| cx.activate_window());
+    pub fn activate_window(&mut self, window: AnyWindowHandle) {
+        self.update_window(window, |cx| cx.activate_window());
     }
 
     // TODO: Can we eliminate this method and move it to WindowContext then call it with update_window?s
     pub fn prompt(
         &mut self,
-        window_id: usize,
+        window: AnyWindowHandle,
         level: PromptLevel,
         msg: &str,
         answers: &[&str],
     ) -> Option<oneshot::Receiver<usize>> {
-        self.update_window(window_id, |cx| cx.prompt(level, msg, answers))
+        self.update_window(window, |cx| cx.prompt(level, msg, answers))
     }
 
     pub fn platform(&self) -> Arc<dyn Platform> {
@@ -456,38 +456,36 @@ impl BorrowAppContext for AsyncAppContext {
 impl BorrowWindowContext for AsyncAppContext {
     type Result<T> = Option<T>;
 
-    fn read_window<T, F>(&self, window_id: usize, f: F) -> Self::Result<T>
+    fn read_window<T, F>(&self, window: AnyWindowHandle, f: F) -> Self::Result<T>
     where
         F: FnOnce(&WindowContext) -> T,
     {
-        self.0.borrow().read_with(|cx| cx.read_window(window_id, f))
+        self.0.borrow().read_with(|cx| cx.read_window(window, f))
     }
 
-    fn read_window_optional<T, F>(&self, window_id: usize, f: F) -> Option<T>
+    fn read_window_optional<T, F>(&self, window: AnyWindowHandle, f: F) -> Option<T>
     where
         F: FnOnce(&WindowContext) -> Option<T>,
     {
         self.0
             .borrow_mut()
-            .update(|cx| cx.read_window_optional(window_id, f))
+            .update(|cx| cx.read_window_optional(window, f))
     }
 
-    fn update_window<T, F>(&mut self, window_id: usize, f: F) -> Self::Result<T>
+    fn update_window<T, F>(&mut self, window: AnyWindowHandle, f: F) -> Self::Result<T>
     where
         F: FnOnce(&mut WindowContext) -> T,
     {
-        self.0
-            .borrow_mut()
-            .update(|cx| cx.update_window(window_id, f))
+        self.0.borrow_mut().update(|cx| cx.update_window(window, f))
     }
 
-    fn update_window_optional<T, F>(&mut self, window_id: usize, f: F) -> Option<T>
+    fn update_window_optional<T, F>(&mut self, window: AnyWindowHandle, f: F) -> Option<T>
     where
         F: FnOnce(&mut WindowContext) -> Option<T>,
     {
         self.0
             .borrow_mut()
-            .update(|cx| cx.update_window_optional(window_id, f))
+            .update(|cx| cx.update_window_optional(window, f))
     }
 }
 
@@ -534,7 +532,7 @@ pub struct AppContext {
     global_actions: HashMap<TypeId, Box<GlobalActionCallback>>,
     keystroke_matcher: KeymapMatcher,
     next_id: usize,
-    // next_window_id: usize,
+    // next_window: AnyWindowHandle,
     next_subscription_id: usize,
     frame_count: usize,
 
@@ -794,13 +792,13 @@ impl AppContext {
         }
     }
 
-    pub fn view_ui_name(&self, window_id: usize, view_id: usize) -> Option<&'static str> {
-        Some(self.views.get(&(window_id, view_id))?.ui_name())
+    pub fn view_ui_name(&self, window: AnyWindowHandle, view_id: usize) -> Option<&'static str> {
+        Some(self.views.get(&(window.id(), view_id))?.ui_name())
     }
 
-    pub fn view_type_id(&self, window_id: usize, view_id: usize) -> Option<TypeId> {
+    pub fn view_type_id(&self, window: AnyWindowHandle, view_id: usize) -> Option<TypeId> {
         self.views_metadata
-            .get(&(window_id, view_id))
+            .get(&(window.id(), view_id))
             .map(|metadata| metadata.type_id)
     }
 
@@ -823,11 +821,11 @@ impl AppContext {
 
     fn read_window<T, F: FnOnce(&WindowContext) -> T>(
         &self,
-        window_id: usize,
+        handle: AnyWindowHandle,
         callback: F,
     ) -> Option<T> {
-        let window = self.windows.get(&window_id)?;
-        let window_context = WindowContext::immutable(self, &window, window_id);
+        let window = self.windows.get(&handle.id())?;
+        let window_context = WindowContext::immutable(self, &window, handle);
         Some(callback(&window_context))
     }
 
@@ -835,9 +833,8 @@ impl AppContext {
         &mut self,
         callback: F,
     ) -> Option<T> {
-        self.platform
-            .main_window_id()
-            .and_then(|id| self.update_window(id, callback))
+        self.main_window()
+            .and_then(|window| window.update(self, callback))
     }
 
     pub fn prompt_for_paths(
@@ -1075,10 +1072,10 @@ impl AppContext {
         }
     }
 
-    fn notify_view(&mut self, window_id: usize, view_id: usize) {
+    fn notify_view(&mut self, window: AnyWindowHandle, view_id: usize) {
         if self.pending_notifications.insert(view_id) {
             self.pending_effects
-                .push_back(Effect::ViewNotification { window_id, view_id });
+                .push_back(Effect::ViewNotification { window, view_id });
         }
     }
 
@@ -1096,13 +1093,13 @@ impl AppContext {
     pub fn is_action_available(&self, action: &dyn Action) -> bool {
         let mut available_in_window = false;
         let action_id = action.id();
-        if let Some(window_id) = self.platform.main_window_id() {
+        if let Some(window) = self.main_window() {
             available_in_window = self
-                .read_window(window_id, |cx| {
+                .read_window(window, |cx| {
                     if let Some(focused_view_id) = cx.focused_view_id() {
                         for view_id in cx.ancestors(focused_view_id) {
                             if let Some(view_metadata) =
-                                cx.views_metadata.get(&(window_id, view_id))
+                                cx.views_metadata.get(&(cx.window_handle.id(), view_id))
                             {
                                 if let Some(actions) = cx.actions.get(&view_metadata.type_id) {
                                     if actions.contains_key(&action_id) {
@@ -1367,13 +1364,12 @@ impl AppContext {
         F: FnOnce(&mut ViewContext<V>) -> V,
     {
         let handle: AnyWindowHandle = handle.into();
-        let window_id = handle.id();
 
         {
             let mut app = self.upgrade();
 
             platform_window.on_event(Box::new(move |event| {
-                app.update_window(window_id, |cx| {
+                app.update_window(handle, |cx| {
                     if let Event::KeyDown(KeyDownEvent { keystroke, .. }) = &event {
                         if cx.dispatch_keystroke(keystroke) {
                             return true;
@@ -1389,35 +1385,35 @@ impl AppContext {
         {
             let mut app = self.upgrade();
             platform_window.on_active_status_change(Box::new(move |is_active| {
-                app.update(|cx| cx.window_changed_active_status(window_id, is_active))
+                app.update(|cx| cx.window_changed_active_status(handle, is_active))
             }));
         }
 
         {
             let mut app = self.upgrade();
             platform_window.on_resize(Box::new(move || {
-                app.update(|cx| cx.window_was_resized(window_id))
+                app.update(|cx| cx.window_was_resized(handle))
             }));
         }
 
         {
             let mut app = self.upgrade();
             platform_window.on_moved(Box::new(move || {
-                app.update(|cx| cx.window_was_moved(window_id))
+                app.update(|cx| cx.window_was_moved(handle))
             }));
         }
 
         {
             let mut app = self.upgrade();
             platform_window.on_fullscreen(Box::new(move |is_fullscreen| {
-                app.update(|cx| cx.window_was_fullscreen_changed(window_id, is_fullscreen))
+                app.update(|cx| cx.window_was_fullscreen_changed(handle, is_fullscreen))
             }));
         }
 
         {
             let mut app = self.upgrade();
             platform_window.on_close(Box::new(move || {
-                app.update(|cx| cx.update_window(window_id, |cx| cx.remove_window()));
+                app.update(|cx| cx.update_window(handle, |cx| cx.remove_window()));
             }));
         }
 
@@ -1432,8 +1428,8 @@ impl AppContext {
             window: handle,
         }));
 
-        let mut window = Window::new(window_id, platform_window, self, build_root_view);
-        let mut cx = WindowContext::mutable(self, &mut window, window_id);
+        let mut window = Window::new(handle, platform_window, self, build_root_view);
+        let mut cx = WindowContext::mutable(self, &mut window, handle);
         cx.layout(false).expect("initial layout should not error");
         let scene = cx.paint().expect("initial paint should not error");
         window.platform_window.present_scene(scene);
@@ -1455,7 +1451,7 @@ impl AppContext {
     }
 
     pub fn read_view<T: View>(&self, handle: &ViewHandle<T>) -> &T {
-        if let Some(view) = self.views.get(&(handle.window_id, handle.view_id)) {
+        if let Some(view) = self.views.get(&(handle.window.id(), handle.view_id)) {
             view.as_any().downcast_ref().expect("downcast is type safe")
         } else {
             panic!("circular view reference for type {}", type_name::<T>());
@@ -1465,7 +1461,7 @@ impl AppContext {
     fn upgrade_view_handle<T: View>(&self, handle: &WeakViewHandle<T>) -> Option<ViewHandle<T>> {
         if self.ref_counts.lock().is_entity_alive(handle.view_id) {
             Some(ViewHandle::new(
-                handle.window_id,
+                handle.window,
                 handle.view_id,
                 &self.ref_counts,
             ))
@@ -1477,7 +1473,7 @@ impl AppContext {
     fn upgrade_any_view_handle(&self, handle: &AnyWeakViewHandle) -> Option<AnyViewHandle> {
         if self.ref_counts.lock().is_entity_alive(handle.view_id) {
             Some(AnyViewHandle::new(
-                handle.window_id,
+                handle.window,
                 handle.view_id,
                 handle.view_type,
                 self.ref_counts.clone(),
@@ -1585,9 +1581,10 @@ impl AppContext {
                             observations.emit(model_id, |callback| callback(self));
                         }
 
-                        Effect::ViewNotification { window_id, view_id } => {
-                            self.handle_view_notification_effect(window_id, view_id)
-                        }
+                        Effect::ViewNotification {
+                            window: window_id,
+                            view_id,
+                        } => self.handle_view_notification_effect(window_id, view_id),
 
                         Effect::GlobalNotification { type_id } => {
                             let mut subscriptions = self.global_observations.clone();
@@ -1618,13 +1615,13 @@ impl AppContext {
 
                         Effect::Focus(mut effect) => {
                             if focus_effects
-                                .get(&effect.window_id())
+                                .get(&effect.window().id())
                                 .map_or(false, |prev_effect| prev_effect.is_forced())
                             {
                                 effect.force();
                             }
 
-                            focus_effects.insert(effect.window_id(), effect);
+                            focus_effects.insert(effect.window().id(), effect);
                         }
 
                         Effect::FocusObservation {
@@ -1639,42 +1636,38 @@ impl AppContext {
                             );
                         }
 
-                        Effect::ResizeWindow { window_id } => {
-                            if let Some(window) = self.windows.get_mut(&window_id) {
+                        Effect::ResizeWindow { window } => {
+                            if let Some(window) = self.windows.get_mut(&window.id()) {
                                 window
                                     .invalidation
                                     .get_or_insert(WindowInvalidation::default());
                             }
-                            self.handle_window_moved(window_id);
+                            self.handle_window_moved(window);
                         }
 
-                        Effect::MoveWindow { window_id } => {
-                            self.handle_window_moved(window_id);
+                        Effect::MoveWindow { window } => {
+                            self.handle_window_moved(window);
                         }
 
                         Effect::WindowActivationObservation {
-                            window_id,
+                            window,
                             subscription_id,
                             callback,
                         } => self.window_activation_observations.add_callback(
-                            window_id,
+                            window.id(),
                             subscription_id,
                             callback,
                         ),
 
-                        Effect::ActivateWindow {
-                            window_id,
-                            is_active,
-                        } => {
-                            if self.handle_window_activation_effect(window_id, is_active)
-                                && is_active
+                        Effect::ActivateWindow { window, is_active } => {
+                            if self.handle_window_activation_effect(window, is_active) && is_active
                             {
                                 focus_effects
-                                    .entry(window_id)
+                                    .entry(window.id())
                                     .or_insert_with(|| FocusEffect::View {
-                                        window_id,
+                                        window,
                                         view_id: self
-                                            .read_window(window_id, |cx| cx.focused_view_id())
+                                            .read_window(window, |cx| cx.focused_view_id())
                                             .flatten(),
                                         is_forced: true,
                                     })
@@ -1683,26 +1676,26 @@ impl AppContext {
                         }
 
                         Effect::WindowFullscreenObservation {
-                            window_id,
+                            window,
                             subscription_id,
                             callback,
                         } => self.window_fullscreen_observations.add_callback(
-                            window_id,
+                            window.id(),
                             subscription_id,
                             callback,
                         ),
 
                         Effect::FullscreenWindow {
-                            window_id,
+                            window,
                             is_fullscreen,
-                        } => self.handle_fullscreen_effect(window_id, is_fullscreen),
+                        } => self.handle_fullscreen_effect(window, is_fullscreen),
 
                         Effect::WindowBoundsObservation {
-                            window_id,
+                            window,
                             subscription_id,
                             callback,
                         } => self.window_bounds_observations.add_callback(
-                            window_id,
+                            window.id(),
                             subscription_id,
                             callback,
                         ),
@@ -1714,18 +1707,15 @@ impl AppContext {
                         Effect::ActionDispatchNotification { action_id } => {
                             self.handle_action_dispatch_notification_effect(action_id)
                         }
-                        Effect::WindowShouldCloseSubscription {
-                            window_id,
-                            callback,
-                        } => {
-                            self.handle_window_should_close_subscription_effect(window_id, callback)
+                        Effect::WindowShouldCloseSubscription { window, callback } => {
+                            self.handle_window_should_close_subscription_effect(window, callback)
                         }
                         Effect::Keystroke {
-                            window_id,
+                            window,
                             keystroke,
                             handled_by,
                             result,
-                        } => self.handle_keystroke_effect(window_id, keystroke, handled_by, result),
+                        } => self.handle_keystroke_effect(window, keystroke, handled_by, result),
                         Effect::ActiveLabeledTasksChanged => {
                             self.handle_active_labeled_tasks_changed_effect()
                         }
@@ -1740,8 +1730,8 @@ impl AppContext {
                     }
                     self.pending_notifications.clear();
                 } else {
-                    for window_id in self.windows.keys().cloned().collect::<Vec<_>>() {
-                        self.update_window(window_id, |cx| {
+                    for window in self.windows().collect::<Vec<_>>() {
+                        self.update_window(window, |cx| {
                             let invalidation = if refreshing {
                                 let mut invalidation =
                                     cx.window.invalidation.take().unwrap_or_default();
@@ -1757,7 +1747,7 @@ impl AppContext {
                                 let appearance = cx.window.platform_window.appearance();
                                 cx.invalidate(invalidation, appearance);
                                 if let Some(old_parents) = cx.layout(refreshing).log_err() {
-                                    updated_windows.insert(window_id);
+                                    updated_windows.insert(window);
 
                                     if let Some(focused_view_id) = cx.focused_view_id() {
                                         let old_ancestors = std::iter::successors(
@@ -1772,7 +1762,7 @@ impl AppContext {
                                         for old_ancestor in old_ancestors.iter().copied() {
                                             if !new_ancestors.contains(&old_ancestor) {
                                                 if let Some(mut view) =
-                                                    cx.views.remove(&(window_id, old_ancestor))
+                                                    cx.views.remove(&(window.id(), old_ancestor))
                                                 {
                                                     view.focus_out(
                                                         focused_view_id,
@@ -1780,7 +1770,7 @@ impl AppContext {
                                                         old_ancestor,
                                                     );
                                                     cx.views
-                                                        .insert((window_id, old_ancestor), view);
+                                                        .insert((window.id(), old_ancestor), view);
                                                 }
                                             }
                                         }
@@ -1789,7 +1779,7 @@ impl AppContext {
                                         for new_ancestor in new_ancestors.iter().copied() {
                                             if !old_ancestors.contains(&new_ancestor) {
                                                 if let Some(mut view) =
-                                                    cx.views.remove(&(window_id, new_ancestor))
+                                                    cx.views.remove(&(window.id(), new_ancestor))
                                                 {
                                                     view.focus_in(
                                                         focused_view_id,
@@ -1797,7 +1787,7 @@ impl AppContext {
                                                         new_ancestor,
                                                     );
                                                     cx.views
-                                                        .insert((window_id, new_ancestor), view);
+                                                        .insert((window.id(), new_ancestor), view);
                                                 }
                                             }
                                         }
@@ -1806,13 +1796,15 @@ impl AppContext {
                                         // there isn't any pending focus, focus the root view.
                                         let root_view_id = cx.window.root_view().id();
                                         if focused_view_id != root_view_id
-                                            && !cx.views.contains_key(&(window_id, focused_view_id))
-                                            && !focus_effects.contains_key(&window_id)
+                                            && !cx
+                                                .views
+                                                .contains_key(&(window.id(), focused_view_id))
+                                            && !focus_effects.contains_key(&window.id())
                                         {
                                             focus_effects.insert(
-                                                window_id,
+                                                window.id(),
                                                 FocusEffect::View {
-                                                    window_id,
+                                                    window,
                                                     view_id: Some(root_view_id),
                                                     is_forced: false,
                                                 },
@@ -1833,8 +1825,8 @@ impl AppContext {
                             callback(self);
                         }
 
-                        for window_id in updated_windows.drain() {
-                            self.update_window(window_id, |cx| {
+                        for window in updated_windows.drain() {
+                            self.update_window(window, |cx| {
                                 if let Some(scene) = cx.paint().log_err() {
                                     cx.window.platform_window.present_scene(scene);
                                 }
@@ -1855,39 +1847,37 @@ impl AppContext {
         }
     }
 
-    fn window_was_resized(&mut self, window_id: usize) {
+    fn window_was_resized(&mut self, window: AnyWindowHandle) {
         self.pending_effects
-            .push_back(Effect::ResizeWindow { window_id });
+            .push_back(Effect::ResizeWindow { window });
     }
 
-    fn window_was_moved(&mut self, window_id: usize) {
+    fn window_was_moved(&mut self, window: AnyWindowHandle) {
         self.pending_effects
-            .push_back(Effect::MoveWindow { window_id });
+            .push_back(Effect::MoveWindow { window });
     }
 
-    fn window_was_fullscreen_changed(&mut self, window_id: usize, is_fullscreen: bool) {
+    fn window_was_fullscreen_changed(&mut self, window: AnyWindowHandle, is_fullscreen: bool) {
         self.pending_effects.push_back(Effect::FullscreenWindow {
-            window_id,
+            window,
             is_fullscreen,
         });
     }
 
-    fn window_changed_active_status(&mut self, window_id: usize, is_active: bool) {
-        self.pending_effects.push_back(Effect::ActivateWindow {
-            window_id,
-            is_active,
-        });
+    fn window_changed_active_status(&mut self, window: AnyWindowHandle, is_active: bool) {
+        self.pending_effects
+            .push_back(Effect::ActivateWindow { window, is_active });
     }
 
     fn keystroke(
         &mut self,
-        window_id: usize,
+        window: AnyWindowHandle,
         keystroke: Keystroke,
         handled_by: Option<Box<dyn Action>>,
         result: MatchResult,
     ) {
         self.pending_effects.push_back(Effect::Keystroke {
-            window_id,
+            window,
             keystroke,
             handled_by,
             result,
@@ -1910,16 +1900,16 @@ impl AppContext {
 
     fn handle_view_notification_effect(
         &mut self,
-        observed_window_id: usize,
+        observed_window: AnyWindowHandle,
         observed_view_id: usize,
     ) {
-        let view_key = (observed_window_id, observed_view_id);
+        let view_key = (observed_window.id(), observed_view_id);
         if let Some((view, mut view_metadata)) = self
             .views
             .remove(&view_key)
             .zip(self.views_metadata.remove(&view_key))
         {
-            if let Some(window) = self.windows.get_mut(&observed_window_id) {
+            if let Some(window) = self.windows.get_mut(&observed_window.id()) {
                 window
                     .invalidation
                     .get_or_insert_with(Default::default)
@@ -1946,17 +1936,17 @@ impl AppContext {
             })
     }
 
-    fn handle_fullscreen_effect(&mut self, window_id: usize, is_fullscreen: bool) {
-        self.update_window(window_id, |cx| {
+    fn handle_fullscreen_effect(&mut self, window: AnyWindowHandle, is_fullscreen: bool) {
+        self.update_window(window, |cx| {
             cx.window.is_fullscreen = is_fullscreen;
 
             let mut fullscreen_observations = cx.window_fullscreen_observations.clone();
-            fullscreen_observations.emit(window_id, |callback| callback(is_fullscreen, cx));
+            fullscreen_observations.emit(window.id(), |callback| callback(is_fullscreen, cx));
 
             if let Some(uuid) = cx.window_display_uuid() {
                 let bounds = cx.window_bounds();
                 let mut bounds_observations = cx.window_bounds_observations.clone();
-                bounds_observations.emit(window_id, |callback| callback(bounds, uuid, cx));
+                bounds_observations.emit(window.id(), |callback| callback(bounds, uuid, cx));
             }
 
             Some(())
@@ -1965,42 +1955,42 @@ impl AppContext {
 
     fn handle_keystroke_effect(
         &mut self,
-        window_id: usize,
+        window: AnyWindowHandle,
         keystroke: Keystroke,
         handled_by: Option<Box<dyn Action>>,
         result: MatchResult,
     ) {
-        self.update_window(window_id, |cx| {
+        self.update_window(window, |cx| {
             let mut observations = cx.keystroke_observations.clone();
-            observations.emit(window_id, move |callback| {
+            observations.emit(window.id(), move |callback| {
                 callback(&keystroke, &result, handled_by.as_ref(), cx)
             });
         });
     }
 
-    fn handle_window_activation_effect(&mut self, window_id: usize, active: bool) -> bool {
-        self.update_window(window_id, |cx| {
+    fn handle_window_activation_effect(&mut self, window: AnyWindowHandle, active: bool) -> bool {
+        self.update_window(window, |cx| {
             if cx.window.is_active == active {
                 return false;
             }
             cx.window.is_active = active;
 
             let mut observations = cx.window_activation_observations.clone();
-            observations.emit(window_id, |callback| callback(active, cx));
+            observations.emit(window.id(), |callback| callback(active, cx));
             true
         })
         .unwrap_or(false)
     }
 
     fn handle_focus_effect(&mut self, effect: FocusEffect) {
-        let window_id = effect.window_id();
-        self.update_window(window_id, |cx| {
+        let window = effect.window();
+        self.update_window(window, |cx| {
             // Ensure the newly-focused view still exists, otherwise focus
             // the root view instead.
             let focused_id = match effect {
                 FocusEffect::View { view_id, .. } => {
                     if let Some(view_id) = view_id {
-                        if cx.views.contains_key(&(window_id, view_id)) {
+                        if cx.views.contains_key(&(window.id(), view_id)) {
                             Some(view_id)
                         } else {
                             Some(cx.root_view().id())
@@ -2025,9 +2015,9 @@ impl AppContext {
             if focus_changed {
                 if let Some(blurred_id) = blurred_id {
                     for view_id in cx.ancestors(blurred_id).collect::<Vec<_>>() {
-                        if let Some(mut view) = cx.views.remove(&(window_id, view_id)) {
+                        if let Some(mut view) = cx.views.remove(&(window.id(), view_id)) {
                             view.focus_out(blurred_id, cx, view_id);
-                            cx.views.insert((window_id, view_id), view);
+                            cx.views.insert((window.id(), view_id), view);
                         }
                     }
 
@@ -2039,9 +2029,9 @@ impl AppContext {
             if focus_changed || effect.is_forced() {
                 if let Some(focused_id) = focused_id {
                     for view_id in cx.ancestors(focused_id).collect::<Vec<_>>() {
-                        if let Some(mut view) = cx.views.remove(&(window_id, view_id)) {
+                        if let Some(mut view) = cx.views.remove(&(window.id(), view_id)) {
                             view.focus_in(focused_id, cx, view_id);
-                            cx.views.insert((window_id, view_id), view);
+                            cx.views.insert((window.id(), view_id), view);
                         }
                     }
 
@@ -2063,24 +2053,24 @@ impl AppContext {
 
     fn handle_window_should_close_subscription_effect(
         &mut self,
-        window_id: usize,
+        window: AnyWindowHandle,
         mut callback: WindowShouldCloseSubscriptionCallback,
     ) {
         let mut app = self.upgrade();
-        if let Some(window) = self.windows.get_mut(&window_id) {
+        if let Some(window) = self.windows.get_mut(&window.id()) {
             window
                 .platform_window
                 .on_should_close(Box::new(move || app.update(|cx| callback(cx))))
         }
     }
 
-    fn handle_window_moved(&mut self, window_id: usize) {
-        self.update_window(window_id, |cx| {
+    fn handle_window_moved(&mut self, window: AnyWindowHandle) {
+        self.update_window(window, |cx| {
             if let Some(display) = cx.window_display_uuid() {
                 let bounds = cx.window_bounds();
                 cx.window_bounds_observations
                     .clone()
-                    .emit(window_id, move |callback| {
+                    .emit(window.id(), move |callback| {
                         callback(bounds, display, cx);
                         true
                     });
@@ -2097,10 +2087,10 @@ impl AppContext {
             });
     }
 
-    pub fn focus(&mut self, window_id: usize, view_id: Option<usize>) {
+    pub fn focus(&mut self, window: AnyWindowHandle, view_id: Option<usize>) {
         self.pending_effects
             .push_back(Effect::Focus(FocusEffect::View {
-                window_id,
+                window,
                 view_id,
                 is_forced: false,
             }));
@@ -2185,40 +2175,40 @@ impl BorrowAppContext for AppContext {
 impl BorrowWindowContext for AppContext {
     type Result<T> = Option<T>;
 
-    fn read_window<T, F>(&self, window_id: usize, f: F) -> Self::Result<T>
+    fn read_window<T, F>(&self, window: AnyWindowHandle, f: F) -> Self::Result<T>
     where
         F: FnOnce(&WindowContext) -> T,
     {
-        AppContext::read_window(self, window_id, f)
+        AppContext::read_window(self, window, f)
     }
 
-    fn read_window_optional<T, F>(&self, window_id: usize, f: F) -> Option<T>
+    fn read_window_optional<T, F>(&self, window: AnyWindowHandle, f: F) -> Option<T>
     where
         F: FnOnce(&WindowContext) -> Option<T>,
     {
-        AppContext::read_window(self, window_id, f).flatten()
+        AppContext::read_window(self, window, f).flatten()
     }
 
-    fn update_window<T, F>(&mut self, window_id: usize, f: F) -> Self::Result<T>
+    fn update_window<T, F>(&mut self, handle: AnyWindowHandle, f: F) -> Self::Result<T>
     where
         F: FnOnce(&mut WindowContext) -> T,
     {
         self.update(|app_context| {
-            let mut window = app_context.windows.remove(&window_id)?;
-            let mut window_context = WindowContext::mutable(app_context, &mut window, window_id);
+            let mut window = app_context.windows.remove(&handle.id())?;
+            let mut window_context = WindowContext::mutable(app_context, &mut window, handle);
             let result = f(&mut window_context);
             if !window_context.removed {
-                app_context.windows.insert(window_id, window);
+                app_context.windows.insert(handle.id(), window);
             }
             Some(result)
         })
     }
 
-    fn update_window_optional<T, F>(&mut self, window_id: usize, f: F) -> Option<T>
+    fn update_window_optional<T, F>(&mut self, handle: AnyWindowHandle, f: F) -> Option<T>
     where
         F: FnOnce(&mut WindowContext) -> Option<T>,
     {
-        AppContext::update_window(self, window_id, f).flatten()
+        AppContext::update_window(self, handle, f).flatten()
     }
 }
 
@@ -2242,22 +2232,22 @@ pub struct WindowInvalidation {
 #[derive(Debug)]
 pub enum FocusEffect {
     View {
-        window_id: usize,
+        window: AnyWindowHandle,
         view_id: Option<usize>,
         is_forced: bool,
     },
     ViewParent {
-        window_id: usize,
+        window: AnyWindowHandle,
         view_id: usize,
         is_forced: bool,
     },
 }
 
 impl FocusEffect {
-    fn window_id(&self) -> usize {
+    fn window(&self) -> AnyWindowHandle {
         match self {
-            FocusEffect::View { window_id, .. } => *window_id,
-            FocusEffect::ViewParent { window_id, .. } => *window_id,
+            FocusEffect::View { window, .. } => *window,
+            FocusEffect::ViewParent { window, .. } => *window,
         }
     }
 
@@ -2303,7 +2293,7 @@ pub enum Effect {
         model_id: usize,
     },
     ViewNotification {
-        window_id: usize,
+        window: AnyWindowHandle,
         view_id: usize,
     },
     Deferred {
@@ -2328,36 +2318,36 @@ pub enum Effect {
         callback: FocusObservationCallback,
     },
     ResizeWindow {
-        window_id: usize,
+        window: AnyWindowHandle,
     },
     MoveWindow {
-        window_id: usize,
+        window: AnyWindowHandle,
     },
     ActivateWindow {
-        window_id: usize,
+        window: AnyWindowHandle,
         is_active: bool,
     },
     WindowActivationObservation {
-        window_id: usize,
+        window: AnyWindowHandle,
         subscription_id: usize,
         callback: WindowActivationCallback,
     },
     FullscreenWindow {
-        window_id: usize,
+        window: AnyWindowHandle,
         is_fullscreen: bool,
     },
     WindowFullscreenObservation {
-        window_id: usize,
+        window: AnyWindowHandle,
         subscription_id: usize,
         callback: WindowFullscreenCallback,
     },
     WindowBoundsObservation {
-        window_id: usize,
+        window: AnyWindowHandle,
         subscription_id: usize,
         callback: WindowBoundsCallback,
     },
     Keystroke {
-        window_id: usize,
+        window: AnyWindowHandle,
         keystroke: Keystroke,
         handled_by: Option<Box<dyn Action>>,
         result: MatchResult,
@@ -2367,7 +2357,7 @@ pub enum Effect {
         action_id: TypeId,
     },
     WindowShouldCloseSubscription {
-        window_id: usize,
+        window: AnyWindowHandle,
         callback: WindowShouldCloseSubscriptionCallback,
     },
     ActiveLabeledTasksChanged,
@@ -2419,9 +2409,9 @@ impl Debug for Effect {
                 .debug_struct("Effect::ModelNotification")
                 .field("model_id", model_id)
                 .finish(),
-            Effect::ViewNotification { window_id, view_id } => f
+            Effect::ViewNotification { window, view_id } => f
                 .debug_struct("Effect::ViewNotification")
-                .field("window_id", window_id)
+                .field("window_id", &window.id())
                 .field("view_id", view_id)
                 .finish(),
             Effect::GlobalNotification { type_id } => f
@@ -2451,71 +2441,68 @@ impl Debug for Effect {
                 .debug_struct("Effect::ActionDispatchNotification")
                 .field("action_id", action_id)
                 .finish(),
-            Effect::ResizeWindow { window_id } => f
+            Effect::ResizeWindow { window } => f
                 .debug_struct("Effect::RefreshWindow")
-                .field("window_id", window_id)
+                .field("window_id", &window.id())
                 .finish(),
-            Effect::MoveWindow { window_id } => f
+            Effect::MoveWindow { window } => f
                 .debug_struct("Effect::MoveWindow")
-                .field("window_id", window_id)
+                .field("window_id", &window.id())
                 .finish(),
             Effect::WindowActivationObservation {
-                window_id,
+                window,
                 subscription_id,
                 ..
             } => f
                 .debug_struct("Effect::WindowActivationObservation")
-                .field("window_id", window_id)
+                .field("window_id", &window.id())
                 .field("subscription_id", subscription_id)
                 .finish(),
-            Effect::ActivateWindow {
-                window_id,
-                is_active,
-            } => f
+            Effect::ActivateWindow { window, is_active } => f
                 .debug_struct("Effect::ActivateWindow")
-                .field("window_id", window_id)
+                .field("window_id", &window.id())
                 .field("is_active", is_active)
                 .finish(),
             Effect::FullscreenWindow {
-                window_id,
+                window,
                 is_fullscreen,
             } => f
                 .debug_struct("Effect::FullscreenWindow")
-                .field("window_id", window_id)
+                .field("window_id", &window.id())
                 .field("is_fullscreen", is_fullscreen)
                 .finish(),
             Effect::WindowFullscreenObservation {
-                window_id,
+                window,
                 subscription_id,
                 callback: _,
             } => f
                 .debug_struct("Effect::WindowFullscreenObservation")
-                .field("window_id", window_id)
+                .field("window_id", &window.id())
                 .field("subscription_id", subscription_id)
                 .finish(),
 
             Effect::WindowBoundsObservation {
-                window_id,
+                window,
                 subscription_id,
                 callback: _,
             } => f
                 .debug_struct("Effect::WindowBoundsObservation")
-                .field("window_id", window_id)
+                .field("window_id", &window.id())
                 .field("subscription_id", subscription_id)
                 .finish(),
             Effect::RefreshWindows => f.debug_struct("Effect::FullViewRefresh").finish(),
-            Effect::WindowShouldCloseSubscription { window_id, .. } => f
+            Effect::WindowShouldCloseSubscription { window, .. } => f
                 .debug_struct("Effect::WindowShouldCloseSubscription")
-                .field("window_id", window_id)
+                .field("window_id", &window.id())
                 .finish(),
             Effect::Keystroke {
-                window_id,
+                window,
                 keystroke,
                 handled_by,
                 result,
             } => f
                 .debug_struct("Effect::Keystroke")
-                .field("window_id", window_id)
+                .field("window_id", &window.id())
                 .field("keystroke", keystroke)
                 .field(
                     "keystroke",

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

@@ -72,8 +72,8 @@ impl TestAppContext {
         cx
     }
 
-    pub fn dispatch_action<A: Action>(&mut self, window_id: usize, action: A) {
-        self.update_window(window_id, |window| {
+    pub fn dispatch_action<A: Action>(&mut self, window: AnyWindowHandle, action: A) {
+        self.update_window(window, |window| {
             window.dispatch_action(window.focused_view_id(), &action);
         })
         .expect("window not found");
@@ -81,10 +81,10 @@ impl TestAppContext {
 
     pub fn available_actions(
         &self,
-        window_id: usize,
+        window: AnyWindowHandle,
         view_id: usize,
     ) -> Vec<(&'static str, Box<dyn Action>, SmallVec<[Binding; 1]>)> {
-        self.read_window(window_id, |cx| cx.available_actions(view_id))
+        self.read_window(window, |cx| cx.available_actions(view_id))
             .unwrap_or_default()
     }
 
@@ -127,18 +127,18 @@ impl TestAppContext {
 
     pub fn read_window<T, F: FnOnce(&WindowContext) -> T>(
         &self,
-        window_id: usize,
+        window: AnyWindowHandle,
         callback: F,
     ) -> Option<T> {
-        self.cx.borrow().read_window(window_id, callback)
+        self.cx.borrow().read_window(window, callback)
     }
 
     pub fn update_window<T, F: FnOnce(&mut WindowContext) -> T>(
         &mut self,
-        window_id: usize,
+        window: AnyWindowHandle,
         callback: F,
     ) -> Option<T> {
-        self.cx.borrow_mut().update_window(window_id, callback)
+        self.cx.borrow_mut().update_window(window, callback)
     }
 
     pub fn add_model<T, F>(&mut self, build_model: F) -> ModelHandle<T>
@@ -317,36 +317,36 @@ impl BorrowAppContext for TestAppContext {
 impl BorrowWindowContext for TestAppContext {
     type Result<T> = T;
 
-    fn read_window<T, F: FnOnce(&WindowContext) -> T>(&self, window_id: usize, f: F) -> T {
+    fn read_window<T, F: FnOnce(&WindowContext) -> T>(&self, window: AnyWindowHandle, f: F) -> T {
         self.cx
             .borrow()
-            .read_window(window_id, f)
+            .read_window(window, f)
             .expect("window was closed")
     }
 
-    fn read_window_optional<T, F>(&self, window_id: usize, f: F) -> Option<T>
+    fn read_window_optional<T, F>(&self, window: AnyWindowHandle, f: F) -> Option<T>
     where
         F: FnOnce(&WindowContext) -> Option<T>,
     {
-        BorrowWindowContext::read_window(self, window_id, f)
+        BorrowWindowContext::read_window(self, window, f)
     }
 
     fn update_window<T, F: FnOnce(&mut WindowContext) -> T>(
         &mut self,
-        window_id: usize,
+        window: AnyWindowHandle,
         f: F,
     ) -> T {
         self.cx
             .borrow_mut()
-            .update_window(window_id, f)
+            .update_window(window, f)
             .expect("window was closed")
     }
 
-    fn update_window_optional<T, F>(&mut self, window_id: usize, f: F) -> Option<T>
+    fn update_window_optional<T, F>(&mut self, window: AnyWindowHandle, f: F) -> Option<T>
     where
         F: FnOnce(&mut WindowContext) -> Option<T>,
     {
-        BorrowWindowContext::update_window(self, window_id, f)
+        BorrowWindowContext::update_window(self, window, f)
     }
 }
 

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

@@ -13,9 +13,9 @@ use crate::{
     },
     text_layout::TextLayoutCache,
     util::post_inc,
-    Action, AnyView, AnyViewHandle, AppContext, BorrowAppContext, BorrowWindowContext, Effect,
-    Element, Entity, Handle, LayoutContext, MouseRegion, MouseRegionId, SceneBuilder, Subscription,
-    View, ViewContext, ViewHandle, WindowHandle, WindowInvalidation,
+    Action, AnyView, AnyViewHandle, AnyWindowHandle, AppContext, BorrowAppContext,
+    BorrowWindowContext, Effect, Element, Entity, Handle, LayoutContext, MouseRegion,
+    MouseRegionId, SceneBuilder, Subscription, View, ViewContext, ViewHandle, WindowInvalidation,
 };
 use anyhow::{anyhow, bail, Result};
 use collections::{HashMap, HashSet};
@@ -60,7 +60,7 @@ pub struct Window {
 
 impl Window {
     pub fn new<V, F>(
-        window_id: usize,
+        handle: AnyWindowHandle,
         platform_window: Box<dyn platform::Window>,
         cx: &mut AppContext,
         build_view: F,
@@ -92,7 +92,7 @@ impl Window {
             appearance,
         };
 
-        let mut window_context = WindowContext::mutable(cx, &mut window, window_id);
+        let mut window_context = WindowContext::mutable(cx, &mut window, handle);
         let root_view = window_context.add_view(|cx| build_view(cx));
         if let Some(invalidation) = window_context.window.invalidation.take() {
             window_context.invalidate(invalidation, appearance);
@@ -113,7 +113,7 @@ impl Window {
 pub struct WindowContext<'a> {
     pub(crate) app_context: Reference<'a, AppContext>,
     pub(crate) window: Reference<'a, Window>,
-    pub(crate) window_id: usize,
+    pub(crate) window_handle: AnyWindowHandle,
     pub(crate) removed: bool,
 }
 
@@ -144,15 +144,15 @@ impl BorrowAppContext for WindowContext<'_> {
 impl BorrowWindowContext for WindowContext<'_> {
     type Result<T> = T;
 
-    fn read_window<T, F: FnOnce(&WindowContext) -> T>(&self, window_id: usize, f: F) -> T {
-        if self.window_id == window_id {
+    fn read_window<T, F: FnOnce(&WindowContext) -> T>(&self, handle: AnyWindowHandle, f: F) -> T {
+        if self.window_handle == handle {
             f(self)
         } else {
             panic!("read_with called with id of window that does not belong to this context")
         }
     }
 
-    fn read_window_optional<T, F>(&self, window_id: usize, f: F) -> Option<T>
+    fn read_window_optional<T, F>(&self, window_id: AnyWindowHandle, f: F) -> Option<T>
     where
         F: FnOnce(&WindowContext) -> Option<T>,
     {
@@ -161,21 +161,21 @@ impl BorrowWindowContext for WindowContext<'_> {
 
     fn update_window<T, F: FnOnce(&mut WindowContext) -> T>(
         &mut self,
-        window_id: usize,
+        handle: AnyWindowHandle,
         f: F,
     ) -> T {
-        if self.window_id == window_id {
+        if self.window_handle == handle {
             f(self)
         } else {
             panic!("update called with id of window that does not belong to this context")
         }
     }
 
-    fn update_window_optional<T, F>(&mut self, window_id: usize, f: F) -> Option<T>
+    fn update_window_optional<T, F>(&mut self, handle: AnyWindowHandle, f: F) -> Option<T>
     where
         F: FnOnce(&mut WindowContext) -> Option<T>,
     {
-        BorrowWindowContext::update_window(self, window_id, f)
+        BorrowWindowContext::update_window(self, handle, f)
     }
 }
 
@@ -183,21 +183,25 @@ impl<'a> WindowContext<'a> {
     pub fn mutable(
         app_context: &'a mut AppContext,
         window: &'a mut Window,
-        window_id: usize,
+        handle: AnyWindowHandle,
     ) -> Self {
         Self {
             app_context: Reference::Mutable(app_context),
             window: Reference::Mutable(window),
-            window_id,
+            window_handle: handle,
             removed: false,
         }
     }
 
-    pub fn immutable(app_context: &'a AppContext, window: &'a Window, window_id: usize) -> Self {
+    pub fn immutable(
+        app_context: &'a AppContext,
+        window: &'a Window,
+        handle: AnyWindowHandle,
+    ) -> Self {
         Self {
             app_context: Reference::Immutable(app_context),
             window: Reference::Immutable(window),
-            window_id,
+            window_handle: handle,
             removed: false,
         }
     }
@@ -207,17 +211,11 @@ impl<'a> WindowContext<'a> {
     }
 
     pub fn window_id(&self) -> usize {
-        self.window_id
+        self.window_handle.id()
     }
 
-    pub fn window<V: View>(&self) -> Option<WindowHandle<V>> {
-        self.window.root_view.as_ref().and_then(|root_view| {
-            if root_view.is::<V>() {
-                Some(WindowHandle::new(self.window_id))
-            } else {
-                None
-            }
-        })
+    pub fn window(&self) -> AnyWindowHandle {
+        self.window_handle
     }
 
     pub fn app_context(&mut self) -> &mut AppContext {
@@ -240,10 +238,10 @@ impl<'a> WindowContext<'a> {
     where
         F: FnOnce(&mut dyn AnyView, &mut Self) -> T,
     {
-        let window_id = self.window_id;
-        let mut view = self.views.remove(&(window_id, view_id))?;
+        let handle = self.window_handle;
+        let mut view = self.views.remove(&(handle.id(), view_id))?;
         let result = f(view.as_mut(), self);
-        self.views.insert((window_id, view_id), view);
+        self.views.insert((handle.id(), view_id), view);
         Some(result)
     }
 
@@ -268,9 +266,9 @@ impl<'a> WindowContext<'a> {
     }
 
     pub fn defer(&mut self, callback: impl 'static + FnOnce(&mut WindowContext)) {
-        let window_id = self.window_id;
+        let handle = self.window_handle;
         self.app_context.defer(move |cx| {
-            cx.update_window(window_id, |cx| callback(cx));
+            cx.update_window(handle, |cx| callback(cx));
         })
     }
 
@@ -310,10 +308,10 @@ impl<'a> WindowContext<'a> {
         H: Handle<E>,
         F: 'static + FnMut(H, &E::Event, &mut WindowContext) -> bool,
     {
-        let window_id = self.window_id;
+        let window_handle = self.window_handle;
         self.app_context
             .subscribe_internal(handle, move |emitter, event, cx| {
-                cx.update_window(window_id, |cx| callback(emitter, event, cx))
+                cx.update_window(window_handle, |cx| callback(emitter, event, cx))
                     .unwrap_or(false)
             })
     }
@@ -322,17 +320,17 @@ impl<'a> WindowContext<'a> {
     where
         F: 'static + FnMut(bool, &mut WindowContext) -> bool,
     {
-        let window_id = self.window_id;
+        let handle = self.window_handle;
         let subscription_id = post_inc(&mut self.next_subscription_id);
         self.pending_effects
             .push_back(Effect::WindowActivationObservation {
-                window_id,
+                window: handle,
                 subscription_id,
                 callback: Box::new(callback),
             });
         Subscription::WindowActivationObservation(
             self.window_activation_observations
-                .subscribe(window_id, subscription_id),
+                .subscribe(handle.id(), subscription_id),
         )
     }
 
@@ -340,17 +338,17 @@ impl<'a> WindowContext<'a> {
     where
         F: 'static + FnMut(bool, &mut WindowContext) -> bool,
     {
-        let window_id = self.window_id;
+        let window = self.window_handle;
         let subscription_id = post_inc(&mut self.next_subscription_id);
         self.pending_effects
             .push_back(Effect::WindowFullscreenObservation {
-                window_id,
+                window,
                 subscription_id,
                 callback: Box::new(callback),
             });
         Subscription::WindowActivationObservation(
             self.window_activation_observations
-                .subscribe(window_id, subscription_id),
+                .subscribe(window.id(), subscription_id),
         )
     }
 
@@ -358,17 +356,17 @@ impl<'a> WindowContext<'a> {
     where
         F: 'static + FnMut(WindowBounds, Uuid, &mut WindowContext) -> bool,
     {
-        let window_id = self.window_id;
+        let window = self.window_handle;
         let subscription_id = post_inc(&mut self.next_subscription_id);
         self.pending_effects
             .push_back(Effect::WindowBoundsObservation {
-                window_id,
+                window,
                 subscription_id,
                 callback: Box::new(callback),
             });
         Subscription::WindowBoundsObservation(
             self.window_bounds_observations
-                .subscribe(window_id, subscription_id),
+                .subscribe(window.id(), subscription_id),
         )
     }
 
@@ -377,13 +375,13 @@ impl<'a> WindowContext<'a> {
         F: 'static
             + FnMut(&Keystroke, &MatchResult, Option<&Box<dyn Action>>, &mut WindowContext) -> bool,
     {
-        let window_id = self.window_id;
+        let window = self.window_handle;
         let subscription_id = post_inc(&mut self.next_subscription_id);
         self.keystroke_observations
-            .add_callback(window_id, subscription_id, Box::new(callback));
+            .add_callback(window.id(), subscription_id, Box::new(callback));
         Subscription::KeystrokeObservation(
             self.keystroke_observations
-                .subscribe(window_id, subscription_id),
+                .subscribe(window.id(), subscription_id),
         )
     }
 
@@ -391,11 +389,11 @@ impl<'a> WindowContext<'a> {
         &self,
         view_id: usize,
     ) -> Vec<(&'static str, Box<dyn Action>, SmallVec<[Binding; 1]>)> {
-        let window_id = self.window_id;
+        let handle = self.window_handle;
         let mut contexts = Vec::new();
         let mut handler_depths_by_action_id = HashMap::<TypeId, usize>::default();
         for (depth, view_id) in self.ancestors(view_id).enumerate() {
-            if let Some(view_metadata) = self.views_metadata.get(&(window_id, view_id)) {
+            if let Some(view_metadata) = self.views_metadata.get(&(handle.id(), view_id)) {
                 contexts.push(view_metadata.keymap_context.clone());
                 if let Some(actions) = self.actions.get(&view_metadata.type_id) {
                     handler_depths_by_action_id
@@ -440,13 +438,13 @@ impl<'a> WindowContext<'a> {
     }
 
     pub(crate) fn dispatch_keystroke(&mut self, keystroke: &Keystroke) -> bool {
-        let window_id = self.window_id;
+        let handle = self.window_handle;
         if let Some(focused_view_id) = self.focused_view_id() {
             let dispatch_path = self
                 .ancestors(focused_view_id)
                 .filter_map(|view_id| {
                     self.views_metadata
-                        .get(&(window_id, view_id))
+                        .get(&(handle.id(), view_id))
                         .map(|view| (view_id, view.keymap_context.clone()))
                 })
                 .collect();
@@ -471,15 +469,10 @@ impl<'a> WindowContext<'a> {
                 }
             };
 
-            self.keystroke(
-                window_id,
-                keystroke.clone(),
-                handled_by,
-                match_result.clone(),
-            );
+            self.keystroke(handle, keystroke.clone(), handled_by, match_result.clone());
             keystroke_handled
         } else {
-            self.keystroke(window_id, keystroke.clone(), None, MatchResult::None);
+            self.keystroke(handle, keystroke.clone(), None, MatchResult::None);
             false
         }
     }
@@ -487,7 +480,7 @@ impl<'a> WindowContext<'a> {
     pub(crate) fn dispatch_event(&mut self, event: Event, event_reused: bool) -> bool {
         let mut mouse_events = SmallVec::<[_; 2]>::new();
         let mut notified_views: HashSet<usize> = Default::default();
-        let window_id = self.window_id;
+        let handle = self.window_handle;
 
         // 1. Handle platform event. Keyboard events get dispatched immediately, while mouse events
         //    get mapped into the mouse-specific MouseEvent type.
@@ -851,19 +844,19 @@ impl<'a> WindowContext<'a> {
         }
 
         for view_id in notified_views {
-            self.notify_view(window_id, view_id);
+            self.notify_view(handle, view_id);
         }
 
         any_event_handled
     }
 
     pub(crate) fn dispatch_key_down(&mut self, event: &KeyDownEvent) -> bool {
-        let window_id = self.window_id;
+        let handle = self.window_handle;
         if let Some(focused_view_id) = self.window.focused_view_id {
             for view_id in self.ancestors(focused_view_id).collect::<Vec<_>>() {
-                if let Some(mut view) = self.views.remove(&(window_id, view_id)) {
+                if let Some(mut view) = self.views.remove(&(handle.id(), view_id)) {
                     let handled = view.key_down(event, self, view_id);
-                    self.views.insert((window_id, view_id), view);
+                    self.views.insert((handle.id(), view_id), view);
                     if handled {
                         return true;
                     }
@@ -877,12 +870,12 @@ impl<'a> WindowContext<'a> {
     }
 
     pub(crate) fn dispatch_key_up(&mut self, event: &KeyUpEvent) -> bool {
-        let window_id = self.window_id;
+        let handle = self.window_handle;
         if let Some(focused_view_id) = self.window.focused_view_id {
             for view_id in self.ancestors(focused_view_id).collect::<Vec<_>>() {
-                if let Some(mut view) = self.views.remove(&(window_id, view_id)) {
+                if let Some(mut view) = self.views.remove(&(handle.id(), view_id)) {
                     let handled = view.key_up(event, self, view_id);
-                    self.views.insert((window_id, view_id), view);
+                    self.views.insert((handle.id(), view_id), view);
                     if handled {
                         return true;
                     }
@@ -896,12 +889,12 @@ impl<'a> WindowContext<'a> {
     }
 
     pub(crate) fn dispatch_modifiers_changed(&mut self, event: &ModifiersChangedEvent) -> bool {
-        let window_id = self.window_id;
+        let handle = self.window_handle;
         if let Some(focused_view_id) = self.window.focused_view_id {
             for view_id in self.ancestors(focused_view_id).collect::<Vec<_>>() {
-                if let Some(mut view) = self.views.remove(&(window_id, view_id)) {
+                if let Some(mut view) = self.views.remove(&(handle.id(), view_id)) {
                     let handled = view.modifiers_changed(event, self, view_id);
-                    self.views.insert((window_id, view_id), view);
+                    self.views.insert((handle.id(), view_id), view);
                     if handled {
                         return true;
                     }
@@ -936,14 +929,14 @@ impl<'a> WindowContext<'a> {
     }
 
     pub fn render_view(&mut self, params: RenderParams) -> Result<Box<dyn AnyRootElement>> {
-        let window_id = self.window_id;
+        let handle = self.window_handle;
         let view_id = params.view_id;
         let mut view = self
             .views
-            .remove(&(window_id, view_id))
+            .remove(&(handle.id(), view_id))
             .ok_or_else(|| anyhow!("view not found"))?;
         let element = view.render(self, view_id);
-        self.views.insert((window_id, view_id), view);
+        self.views.insert((handle.id(), view_id), view);
         Ok(element)
     }
 
@@ -971,9 +964,9 @@ impl<'a> WindowContext<'a> {
                 } else if old_parent_id == new_parent_id {
                     current_view_id = *old_parent_id.unwrap();
                 } else {
-                    let window_id = self.window_id;
+                    let handle = self.window_handle;
                     for view_id_to_notify in view_ids_to_notify {
-                        self.notify_view(window_id, view_id_to_notify);
+                        self.notify_view(handle, view_id_to_notify);
                     }
                     break;
                 }
@@ -1141,7 +1134,7 @@ impl<'a> WindowContext<'a> {
     }
 
     pub fn focus(&mut self, view_id: Option<usize>) {
-        self.app_context.focus(self.window_id, view_id);
+        self.app_context.focus(self.window_handle, view_id);
     }
 
     pub fn window_bounds(&self) -> WindowBounds {
@@ -1194,26 +1187,26 @@ impl<'a> WindowContext<'a> {
         T: View,
         F: FnOnce(&mut ViewContext<T>) -> Option<T>,
     {
-        let window_id = self.window_id;
+        let handle = self.window_handle;
         let view_id = post_inc(&mut self.next_id);
         let mut cx = ViewContext::mutable(self, view_id);
         let handle = if let Some(view) = build_view(&mut cx) {
             let mut keymap_context = KeymapContext::default();
             view.update_keymap_context(&mut keymap_context, cx.app_context());
             self.views_metadata.insert(
-                (window_id, view_id),
+                (handle.id(), view_id),
                 ViewMetadata {
                     type_id: TypeId::of::<T>(),
                     keymap_context,
                 },
             );
-            self.views.insert((window_id, view_id), Box::new(view));
+            self.views.insert((handle.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))
+            Some(ViewHandle::new(handle, view_id, &self.ref_counts))
         } else {
             None
         };
@@ -1390,7 +1383,7 @@ pub struct ChildView {
 
 impl ChildView {
     pub fn new(view: &AnyViewHandle, cx: &AppContext) -> Self {
-        let view_name = cx.view_ui_name(view.window_id(), view.id()).unwrap();
+        let view_name = cx.view_ui_name(view.window, view.id()).unwrap();
         Self {
             view_id: view.id(),
             view_name,

crates/project_panel/src/project_panel.rs 🔗

@@ -1726,7 +1726,7 @@ impl ClipboardEntry {
 #[cfg(test)]
 mod tests {
     use super::*;
-    use gpui::{AnyWindowHandle, TestAppContext, ViewHandle};
+    use gpui::{AnyWindowHandle, TestAppContext, ViewHandle, WindowHandle};
     use pretty_assertions::assert_eq;
     use project::FakeFs;
     use serde_json::json;
@@ -1872,7 +1872,6 @@ mod tests {
         let project = Project::test(fs.clone(), ["/root1".as_ref(), "/root2".as_ref()], cx).await;
         let window = cx.add_window(|cx| Workspace::test_new(project.clone(), cx));
         let workspace = window.root(cx);
-        let window_id = window.id();
         let panel = workspace.update(cx, |workspace, cx| ProjectPanel::new(workspace, cx));
 
         select_path(&panel, "root1", cx);
@@ -1894,7 +1893,7 @@ mod tests {
         // Add a file with the root folder selected. The filename editor is placed
         // before the first file in the root folder.
         panel.update(cx, |panel, cx| panel.new_file(&NewFile, cx));
-        cx.read_window(window_id, |cx| {
+        window.read_with(cx, |cx| {
             let panel = panel.read(cx);
             assert!(panel.filename_editor.is_focused(cx));
         });
@@ -2225,7 +2224,6 @@ mod tests {
         let project = Project::test(fs.clone(), ["/root1".as_ref(), "/root2".as_ref()], cx).await;
         let window = cx.add_window(|cx| Workspace::test_new(project.clone(), cx));
         let workspace = window.root(cx);
-        let window_id = window.id();
         let panel = workspace.update(cx, |workspace, cx| ProjectPanel::new(workspace, cx));
 
         select_path(&panel, "root1", cx);
@@ -2247,7 +2245,7 @@ mod tests {
         // Add a file with the root folder selected. The filename editor is placed
         // before the first file in the root folder.
         panel.update(cx, |panel, cx| panel.new_file(&NewFile, cx));
-        cx.read_window(window_id, |cx| {
+        window.read_with(cx, |cx| {
             let panel = panel.read(cx);
             assert!(panel.filename_editor.is_focused(cx));
         });
@@ -2402,7 +2400,6 @@ mod tests {
         let project = Project::test(fs.clone(), ["/src".as_ref()], cx).await;
         let window = cx.add_window(|cx| Workspace::test_new(project.clone(), cx));
         let workspace = window.root(cx);
-        let window_id = window.id();
         let panel = workspace.update(cx, |workspace, cx| ProjectPanel::new(workspace, cx));
 
         toggle_expand_dir(&panel, "src/test", cx);
@@ -2419,7 +2416,7 @@ mod tests {
                 "          third.rs"
             ]
         );
-        ensure_single_file_is_opened(window_id, &workspace, "test/first.rs", cx);
+        ensure_single_file_is_opened(window, "test/first.rs", cx);
 
         submit_deletion(window.into(), &panel, cx);
         assert_eq!(
@@ -2446,9 +2443,9 @@ mod tests {
                 "          third.rs"
             ]
         );
-        ensure_single_file_is_opened(window_id, &workspace, "test/second.rs", cx);
+        ensure_single_file_is_opened(window, "test/second.rs", cx);
 
-        cx.update_window(window_id, |cx| {
+        window.update(cx, |cx| {
             let active_items = workspace
                 .read(cx)
                 .panes()
@@ -2493,7 +2490,6 @@ mod tests {
         let project = Project::test(fs.clone(), ["/src".as_ref()], cx).await;
         let window = cx.add_window(|cx| Workspace::test_new(project.clone(), cx));
         let workspace = window.root(cx);
-        let window_id = window.id();
         let panel = workspace.update(cx, |workspace, cx| ProjectPanel::new(workspace, cx));
 
         select_path(&panel, "src/", cx);
@@ -2504,7 +2500,7 @@ mod tests {
             &["v src  <== selected", "    > test"]
         );
         panel.update(cx, |panel, cx| panel.new_directory(&NewDirectory, cx));
-        cx.read_window(window_id, |cx| {
+        window.read_with(cx, |cx| {
             let panel = panel.read(cx);
             assert!(panel.filename_editor.is_focused(cx));
         });
@@ -2535,7 +2531,7 @@ mod tests {
             &["v src", "    > test  <== selected"]
         );
         panel.update(cx, |panel, cx| panel.new_file(&NewFile, cx));
-        cx.read_window(window_id, |cx| {
+        window.read_with(cx, |cx| {
             let panel = panel.read(cx);
             assert!(panel.filename_editor.is_focused(cx));
         });
@@ -2585,7 +2581,7 @@ mod tests {
             ],
         );
         panel.update(cx, |panel, cx| panel.rename(&Rename, cx));
-        cx.read_window(window_id, |cx| {
+        window.read_with(cx, |cx| {
             let panel = panel.read(cx);
             assert!(panel.filename_editor.is_focused(cx));
         });
@@ -2882,13 +2878,11 @@ mod tests {
     }
 
     fn ensure_single_file_is_opened(
-        window_id: usize,
-        workspace: &ViewHandle<Workspace>,
+        window: WindowHandle<Workspace>,
         expected_path: &str,
         cx: &mut TestAppContext,
     ) {
-        cx.read_window(window_id, |cx| {
-            let workspace = workspace.read(cx);
+        window.update_root(cx, |workspace, cx| {
             let worktrees = workspace.worktrees(cx).collect::<Vec<_>>();
             assert_eq!(worktrees.len(), 1);
             let worktree_id = WorktreeId::from_usize(worktrees[0].id());

crates/search/src/buffer_search.rs 🔗

@@ -1229,8 +1229,6 @@ mod tests {
         );
         let buffer = cx.add_model(|cx| Buffer::new(0, buffer_text, cx));
         let window = cx.add_window(|_| EmptyView);
-        let window_id = window.id();
-
         let editor = window.add_view(cx, |cx| Editor::for_buffer(buffer.clone(), None, cx));
 
         let search_bar = window.add_view(cx, |cx| {
@@ -1249,12 +1247,13 @@ mod tests {
             search_bar.activate_current_match(cx);
         });
 
-        cx.read_window(window_id, |cx| {
+        window.read_with(cx, |cx| {
             assert!(
                 !editor.is_focused(cx),
                 "Initially, the editor should not be focused"
             );
         });
+
         let initial_selections = editor.update(cx, |editor, cx| {
             let initial_selections = editor.selections.display_ranges(cx);
             assert_eq!(
@@ -1271,7 +1270,7 @@ mod tests {
             cx.focus(search_bar.query_editor.as_any());
             search_bar.select_all_matches(&SelectAllMatches, cx);
         });
-        cx.read_window(window_id, |cx| {
+        window.read_with(cx, |cx| {
             assert!(
                 editor.is_focused(cx),
                 "Should focus editor after successful SelectAllMatches"
@@ -1295,7 +1294,7 @@ mod tests {
         search_bar.update(cx, |search_bar, cx| {
             search_bar.select_next_match(&SelectNextMatch, cx);
         });
-        cx.read_window(window_id, |cx| {
+        window.read_with(cx, |cx| {
             assert!(
                 editor.is_focused(cx),
                 "Should still have editor focused after SelectNextMatch"
@@ -1324,7 +1323,7 @@ mod tests {
             cx.focus(search_bar.query_editor.as_any());
             search_bar.select_all_matches(&SelectAllMatches, cx);
         });
-        cx.read_window(window_id, |cx| {
+        window.read_with(cx, |cx| {
             assert!(
                 editor.is_focused(cx),
                 "Should focus editor after successful SelectAllMatches"
@@ -1348,7 +1347,7 @@ mod tests {
         search_bar.update(cx, |search_bar, cx| {
             search_bar.select_prev_match(&SelectPrevMatch, cx);
         });
-        cx.read_window(window_id, |cx| {
+        window.read_with(cx, |cx| {
             assert!(
                 editor.is_focused(cx),
                 "Should still have editor focused after SelectPrevMatch"
@@ -1384,7 +1383,7 @@ mod tests {
         search_bar.update(cx, |search_bar, cx| {
             search_bar.select_all_matches(&SelectAllMatches, cx);
         });
-        cx.read_window(window_id, |cx| {
+        window.read_with(cx, |cx| {
             assert!(
                 !editor.is_focused(cx),
                 "Should not switch focus to editor if SelectAllMatches does not find any matches"

crates/search/src/project_search.rs 🔗

@@ -1568,7 +1568,6 @@ pub mod tests {
         let project = Project::test(fs.clone(), ["/dir".as_ref()], cx).await;
         let window = cx.add_window(|cx| Workspace::test_new(project, cx));
         let workspace = window.root(cx);
-        let window_id = window.id();
 
         let active_item = cx.read(|cx| {
             workspace
@@ -1599,9 +1598,9 @@ pub mod tests {
         };
         let search_view_id = search_view.id();
 
-        cx.spawn(
-            |mut cx| async move { cx.dispatch_action(window_id, search_view_id, &ToggleFocus) },
-        )
+        cx.spawn(|mut cx| async move {
+            cx.dispatch_action(window.into(), search_view_id, &ToggleFocus)
+        })
         .detach();
         deterministic.run_until_parked();
         search_view.update(cx, |search_view, cx| {
@@ -1651,9 +1650,9 @@ pub mod tests {
                 "Search view should be focused after mismatching query had been used in search",
             );
         });
-        cx.spawn(
-            |mut cx| async move { cx.dispatch_action(window_id, search_view_id, &ToggleFocus) },
-        )
+        cx.spawn(|mut cx| async move {
+            cx.dispatch_action(window.into(), search_view_id, &ToggleFocus)
+        })
         .detach();
         deterministic.run_until_parked();
         search_view.update(cx, |search_view, cx| {
@@ -1683,9 +1682,9 @@ pub mod tests {
                 "Search view with mismatching query should be focused after search results are available",
             );
         });
-        cx.spawn(
-            |mut cx| async move { cx.dispatch_action(window_id, search_view_id, &ToggleFocus) },
-        )
+        cx.spawn(|mut cx| async move {
+            cx.dispatch_action(window.into(), search_view_id, &ToggleFocus)
+        })
         .detach();
         deterministic.run_until_parked();
         search_view.update(cx, |search_view, cx| {
@@ -1713,9 +1712,9 @@ pub mod tests {
             );
         });
 
-        cx.spawn(
-            |mut cx| async move { cx.dispatch_action(window_id, search_view_id, &ToggleFocus) },
-        )
+        cx.spawn(|mut cx| async move {
+            cx.dispatch_action(window.into(), search_view_id, &ToggleFocus)
+        })
         .detach();
         deterministic.run_until_parked();
         search_view.update(cx, |search_view, cx| {

crates/vim/src/editor_events.rs 🔗

@@ -1,6 +1,6 @@
 use crate::Vim;
 use editor::{EditorBlurred, EditorFocused, EditorReleased};
-use gpui::{AppContext, BorrowWindowContext};
+use gpui::AppContext;
 
 pub fn init(cx: &mut AppContext) {
     cx.subscribe_global(focused).detach();
@@ -10,7 +10,7 @@ pub fn init(cx: &mut AppContext) {
 
 fn focused(EditorFocused(editor): &EditorFocused, cx: &mut AppContext) {
     if let Some(previously_active_editor) = Vim::read(cx).active_editor.clone() {
-        cx.update_window(previously_active_editor.window_id(), |cx| {
+        previously_active_editor.window().update(cx, |cx| {
             Vim::update(cx, |vim, cx| {
                 vim.update_active_editor(cx, |previously_active_editor, cx| {
                     vim.unhook_vim_settings(previously_active_editor, cx)
@@ -19,7 +19,7 @@ fn focused(EditorFocused(editor): &EditorFocused, cx: &mut AppContext) {
         });
     }
 
-    cx.update_window(editor.window_id(), |cx| {
+    editor.window().update(cx, |cx| {
         Vim::update(cx, |vim, cx| {
             vim.set_active_editor(editor.clone(), cx);
         });
@@ -27,7 +27,7 @@ fn focused(EditorFocused(editor): &EditorFocused, cx: &mut AppContext) {
 }
 
 fn blurred(EditorBlurred(editor): &EditorBlurred, cx: &mut AppContext) {
-    cx.update_window(editor.window_id(), |cx| {
+    editor.window().update(cx, |cx| {
         Vim::update(cx, |vim, cx| {
             if let Some(previous_editor) = vim.active_editor.clone() {
                 if previous_editor == editor.clone() {
@@ -41,7 +41,7 @@ fn blurred(EditorBlurred(editor): &EditorBlurred, cx: &mut AppContext) {
 }
 
 fn released(EditorReleased(editor): &EditorReleased, cx: &mut AppContext) {
-    cx.update_window(editor.window_id(), |cx| {
+    editor.window().update(cx, |cx| {
         cx.update_default_global(|vim: &mut Vim, _| {
             if let Some(previous_editor) = vim.active_editor.clone() {
                 if previous_editor == editor.clone() {

crates/vim/src/mode_indicator.rs 🔗

@@ -1,6 +1,6 @@
 use gpui::{
     elements::{Empty, Label},
-    AnyElement, Element, Entity, Subscription, View, ViewContext, BorrowWindowContext
+    AnyElement, Element, Entity, Subscription, View, ViewContext,
 };
 use settings::SettingsStore;
 use workspace::{item::ItemHandle, StatusItemView};
@@ -20,7 +20,7 @@ impl ModeIndicator {
             if let Some(mode_indicator) = handle.upgrade(cx) {
                 match event {
                     VimEvent::ModeChanged { mode } => {
-                        cx.update_window(mode_indicator.window_id(), |cx| {
+                        mode_indicator.window().update(cx, |cx| {
                             mode_indicator.update(cx, move |mode_indicator, cx| {
                                 mode_indicator.set_mode(mode, cx);
                             })

crates/vim/src/test/vim_test_context.rs 🔗

@@ -85,8 +85,8 @@ impl<'a> VimTestContext<'a> {
     }
 
     pub fn set_state(&mut self, text: &str, mode: Mode) -> ContextHandle {
-        let window_id = self.window.id();
-        self.update_window(window_id, |cx| {
+        let window = self.window;
+        window.update(self.cx.cx.cx, |cx| {
             Vim::update(cx, |vim, cx| {
                 vim.switch_mode(mode, false, cx);
             })

crates/workspace/src/dock.rs 🔗

@@ -203,7 +203,7 @@ impl Dock {
     pub fn panel_index_for_ui_name(&self, ui_name: &str, cx: &AppContext) -> Option<usize> {
         self.panel_entries.iter().position(|entry| {
             let panel = entry.panel.as_any();
-            cx.view_ui_name(panel.window_id(), panel.id()) == Some(ui_name)
+            cx.view_ui_name(panel.window(), panel.id()) == Some(ui_name)
         })
     }
 
@@ -530,16 +530,12 @@ impl View for PanelButtons {
                                     tooltip_action.as_ref().map(|action| action.boxed_clone());
                                 move |_, this, cx| {
                                     if let Some(tooltip_action) = &tooltip_action {
-                                        let window_id = cx.window_id();
+                                        let window = cx.window();
                                         let view_id = this.workspace.id();
                                         let tooltip_action = tooltip_action.boxed_clone();
                                         cx.spawn(|_, mut cx| async move {
-                                            cx.dispatch_action(
-                                                window_id,
-                                                view_id,
-                                                &*tooltip_action,
-                                            )
-                                            .ok();
+                                            cx.dispatch_action(window, view_id, &*tooltip_action)
+                                                .ok();
                                         })
                                         .detach();
                                     }

crates/workspace/src/pane.rs 🔗

@@ -1917,8 +1917,8 @@ impl<V: View> Element<V> for PaneBackdrop<V> {
             MouseRegion::new::<Self>(child_view_id, 0, visible_bounds).on_down(
                 gpui::platform::MouseButton::Left,
                 move |_, _: &mut V, cx| {
-                    let window_id = cx.window_id();
-                    cx.app_context().focus(window_id, Some(child_view_id))
+                    let window = cx.window();
+                    cx.app_context().focus(window, Some(child_view_id))
                 },
             ),
         );

crates/workspace/src/workspace.rs 🔗

@@ -1250,11 +1250,11 @@ impl Workspace {
         _: &CloseWindow,
         cx: &mut ViewContext<Self>,
     ) -> Option<Task<Result<()>>> {
-        let window_id = cx.window_id();
+        let window = cx.window();
         let prepare = self.prepare_to_close(false, cx);
         Some(cx.spawn(|_, mut cx| async move {
             if prepare.await? {
-                cx.remove_window(window_id);
+                cx.remove_window(window);
             }
             Ok(())
         }))
@@ -1266,7 +1266,7 @@ impl Workspace {
         cx: &mut ViewContext<Self>,
     ) -> Task<Result<bool>> {
         let active_call = self.active_call().cloned();
-        let window_id = cx.window_id();
+        let window = cx.window();
 
         cx.spawn(|this, mut cx| async move {
             let workspace_count = cx
@@ -1281,7 +1281,7 @@ impl Workspace {
                     && active_call.read_with(&cx, |call, _| call.room().is_some())
                 {
                     let answer = cx.prompt(
-                        window_id,
+                        window,
                         PromptLevel::Warning,
                         "Do you want to leave the current call?",
                         &["Close window and hang up", "Cancel"],
@@ -1390,7 +1390,7 @@ impl Workspace {
         paths: Vec<PathBuf>,
         cx: &mut ViewContext<Self>,
     ) -> Task<Result<()>> {
-        let window = cx.window::<Self>();
+        let window = cx.window().downcast::<Self>();
         let is_remote = self.project.read(cx).is_remote();
         let has_worktree = self.project.read(cx).worktrees(cx).next().is_some();
         let has_dirty_items = self.items(cx).any(|item| item.is_dirty(cx));
@@ -3181,7 +3181,7 @@ impl Workspace {
             let left_visible = left_dock.is_open();
             let left_active_panel = left_dock.visible_panel().and_then(|panel| {
                 Some(
-                    cx.view_ui_name(panel.as_any().window_id(), panel.id())?
+                    cx.view_ui_name(panel.as_any().window(), panel.id())?
                         .to_string(),
                 )
             });
@@ -3194,7 +3194,7 @@ impl Workspace {
             let right_visible = right_dock.is_open();
             let right_active_panel = right_dock.visible_panel().and_then(|panel| {
                 Some(
-                    cx.view_ui_name(panel.as_any().window_id(), panel.id())?
+                    cx.view_ui_name(panel.as_any().window(), panel.id())?
                         .to_string(),
                 )
             });
@@ -3207,7 +3207,7 @@ impl Workspace {
             let bottom_visible = bottom_dock.is_open();
             let bottom_active_panel = bottom_dock.visible_panel().and_then(|panel| {
                 Some(
-                    cx.view_ui_name(panel.as_any().window_id(), panel.id())?
+                    cx.view_ui_name(panel.as_any().window(), panel.id())?
                         .to_string(),
                 )
             });
@@ -4000,7 +4000,7 @@ pub fn join_remote_project(
             workspace.downgrade()
         };
 
-        cx.activate_window(workspace.window_id());
+        cx.activate_window(workspace.window());
         cx.platform().activate(true);
 
         workspace.update(&mut cx, |workspace, cx| {
@@ -4049,9 +4049,9 @@ pub fn restart(_: &Restart, cx: &mut AppContext) {
         // prompt in the active window before switching to a different window.
         workspace_windows.sort_by_key(|window| window.is_active(&cx) == Some(false));
 
-        if let (true, Some(window)) = (should_confirm, workspace_windows.first()) {
+        if let (true, Some(window)) = (should_confirm, workspace_windows.first().copied()) {
             let answer = cx.prompt(
-                window.id(),
+                window.into(),
                 PromptLevel::Info,
                 "Are you sure you want to restart?",
                 &["Restart", "Cancel"],

crates/zed/src/zed.rs 🔗

@@ -179,13 +179,12 @@ pub fn init(app_state: &Arc<AppState>, cx: &mut gpui::AppContext) {
         move |workspace: &mut Workspace, _: &DebugElements, cx: &mut ViewContext<Workspace>| {
             let app_state = workspace.app_state().clone();
             let markdown = app_state.languages.language_for_name("JSON");
-            let window_id = cx.window_id();
+            let window = cx.window();
             cx.spawn(|workspace, mut cx| async move {
                 let markdown = markdown.await.log_err();
-                let content = to_string_pretty(
-                    &cx.debug_elements(window_id)
-                        .ok_or_else(|| anyhow!("could not debug elements for {window_id}"))?,
-                )
+                let content = to_string_pretty(&cx.debug_elements(window).ok_or_else(|| {
+                    anyhow!("could not debug elements for window {}", window.id())
+                })?)
                 .unwrap();
                 workspace
                     .update(&mut cx, |workspace, cx| {
@@ -416,9 +415,9 @@ fn quit(_: &Quit, cx: &mut gpui::AppContext) {
         // prompt in the active window before switching to a different window.
         workspace_windows.sort_by_key(|window| window.is_active(&cx) == Some(false));
 
-        if let (true, Some(window)) = (should_confirm, workspace_windows.first()) {
+        if let (true, Some(window)) = (should_confirm, workspace_windows.first().copied()) {
             let answer = cx.prompt(
-                window.id(),
+                window.into(),
                 PromptLevel::Info,
                 "Are you sure you want to quit?",
                 &["Quit", "Cancel"],
@@ -716,8 +715,8 @@ mod tests {
     use editor::{scroll::autoscroll::Autoscroll, DisplayPoint, Editor};
     use fs::{FakeFs, Fs};
     use gpui::{
-        actions, elements::Empty, executor::Deterministic, Action, AnyElement, AppContext,
-        AssetSource, Element, Entity, TestAppContext, View, ViewHandle,
+        actions, elements::Empty, executor::Deterministic, Action, AnyElement, AnyWindowHandle,
+        AppContext, AssetSource, Element, Entity, TestAppContext, View, ViewHandle,
     };
     use language::LanguageRegistry;
     use node_runtime::NodeRuntime;
@@ -1317,11 +1316,10 @@ mod tests {
         project.update(cx, |project, _| project.languages().add(rust_lang()));
         let window = cx.add_window(|cx| Workspace::test_new(project, cx));
         let workspace = window.root(cx);
-        let window_id = window.id();
         let worktree = cx.read(|cx| workspace.read(cx).worktrees(cx).next().unwrap());
 
         // Create a new untitled buffer
-        cx.dispatch_action(window_id, NewFile);
+        cx.dispatch_action(window.into(), NewFile);
         let editor = workspace.read_with(cx, |workspace, cx| {
             workspace
                 .active_item(cx)
@@ -1376,7 +1374,7 @@ mod tests {
 
         // Open the same newly-created file in another pane item. The new editor should reuse
         // the same buffer.
-        cx.dispatch_action(window_id, NewFile);
+        cx.dispatch_action(window.into(), NewFile);
         workspace
             .update(cx, |workspace, cx| {
                 workspace.split_and_clone(
@@ -1412,10 +1410,9 @@ mod tests {
         project.update(cx, |project, _| project.languages().add(rust_lang()));
         let window = cx.add_window(|cx| Workspace::test_new(project, cx));
         let workspace = window.root(cx);
-        let window_id = window.id();
 
         // Create a new untitled buffer
-        cx.dispatch_action(window_id, NewFile);
+        cx.dispatch_action(window.into(), NewFile);
         let editor = workspace.read_with(cx, |workspace, cx| {
             workspace
                 .active_item(cx)
@@ -1465,7 +1462,6 @@ mod tests {
         let project = Project::test(app_state.fs.clone(), ["/root".as_ref()], cx).await;
         let window = cx.add_window(|cx| Workspace::test_new(project, cx));
         let workspace = window.root(cx);
-        let window_id = window.id();
 
         let entries = cx.read(|cx| workspace.file_project_paths(cx));
         let file1 = entries[0].clone();
@@ -1487,7 +1483,7 @@ mod tests {
             (editor.downgrade(), buffer)
         });
 
-        cx.dispatch_action(window_id, pane::SplitRight);
+        cx.dispatch_action(window.into(), pane::SplitRight);
         let editor_2 = cx.update(|cx| {
             let pane_2 = workspace.read(cx).active_pane().clone();
             assert_ne!(pane_1, pane_2);
@@ -1497,7 +1493,7 @@ mod tests {
 
             pane2_item.downcast::<Editor>().unwrap().downgrade()
         });
-        cx.dispatch_action(window_id, workspace::CloseActiveItem);
+        cx.dispatch_action(window.into(), workspace::CloseActiveItem);
 
         cx.foreground().run_until_parked();
         workspace.read_with(cx, |workspace, _| {
@@ -1505,7 +1501,7 @@ mod tests {
             assert_eq!(workspace.active_pane(), &pane_1);
         });
 
-        cx.dispatch_action(window_id, workspace::CloseActiveItem);
+        cx.dispatch_action(window.into(), workspace::CloseActiveItem);
         cx.foreground().run_until_parked();
         window.simulate_prompt_answer(1, cx);
         cx.foreground().run_until_parked();
@@ -2063,11 +2059,10 @@ mod tests {
         cx.foreground().run_until_parked();
 
         let window = cx.add_window(|_| TestView);
-        let window_id = window.id();
 
         // Test loading the keymap base at all
         assert_key_bindings_for(
-            window_id,
+            window.into(),
             cx,
             vec![("backspace", &A), ("k", &ActivatePreviousPane)],
             line!(),
@@ -2094,7 +2089,7 @@ mod tests {
         cx.foreground().run_until_parked();
 
         assert_key_bindings_for(
-            window_id,
+            window.into(),
             cx,
             vec![("backspace", &B), ("k", &ActivatePreviousPane)],
             line!(),
@@ -2117,7 +2112,7 @@ mod tests {
         cx.foreground().run_until_parked();
 
         assert_key_bindings_for(
-            window_id,
+            window.into(),
             cx,
             vec![("backspace", &B), ("[", &ActivatePrevItem)],
             line!(),
@@ -2125,7 +2120,7 @@ mod tests {
 
         #[track_caller]
         fn assert_key_bindings_for<'a>(
-            window_id: usize,
+            window: AnyWindowHandle,
             cx: &TestAppContext,
             actions: Vec<(&'static str, &'a dyn Action)>,
             line: u32,
@@ -2133,7 +2128,7 @@ mod tests {
             for (key, action) in actions {
                 // assert that...
                 assert!(
-                    cx.available_actions(window_id, 0)
+                    cx.available_actions(window, 0)
                         .into_iter()
                         .any(|(_, bound_action, b)| {
                             // action names match...
@@ -2234,11 +2229,10 @@ mod tests {
         cx.foreground().run_until_parked();
 
         let window = cx.add_window(|_| TestView);
-        let window_id = window.id();
 
         // Test loading the keymap base at all
         assert_key_bindings_for(
-            window_id,
+            window.into(),
             cx,
             vec![("backspace", &A), ("k", &ActivatePreviousPane)],
             line!(),
@@ -2264,7 +2258,12 @@ mod tests {
 
         cx.foreground().run_until_parked();
 
-        assert_key_bindings_for(window_id, cx, vec![("k", &ActivatePreviousPane)], line!());
+        assert_key_bindings_for(
+            window.into(),
+            cx,
+            vec![("k", &ActivatePreviousPane)],
+            line!(),
+        );
 
         // Test modifying the base, while retaining the users keymap
         fs.save(
@@ -2282,11 +2281,11 @@ mod tests {
 
         cx.foreground().run_until_parked();
 
-        assert_key_bindings_for(window_id, cx, vec![("[", &ActivatePrevItem)], line!());
+        assert_key_bindings_for(window.into(), cx, vec![("[", &ActivatePrevItem)], line!());
 
         #[track_caller]
         fn assert_key_bindings_for<'a>(
-            window_id: usize,
+            window: AnyWindowHandle,
             cx: &TestAppContext,
             actions: Vec<(&'static str, &'a dyn Action)>,
             line: u32,
@@ -2294,7 +2293,7 @@ mod tests {
             for (key, action) in actions {
                 // assert that...
                 assert!(
-                    cx.available_actions(window_id, 0)
+                    cx.available_actions(window, 0)
                         .into_iter()
                         .any(|(_, bound_action, b)| {
                             // action names match...