This can block the main thread too much otherwise Release Notes: - N/A *or* Added/Fixed/Improved ...
Unified · Split
| @@ -2010,7 +2010,7 @@ impl App { · 2009 unmodified lines | |||
| 2010 | &self, | 2010 | &self, |
| 2011 | menus: Vec<MenuItem>, | 2011 | menus: Vec<MenuItem>, |
| 2012 | entries: Vec<SmallVec<[PathBuf; 2]>>, | 2012 | entries: Vec<SmallVec<[PathBuf; 2]>>, |
| 2013 | ) -> Vec<SmallVec<[PathBuf; 2]>> { | 2013 | ) -> Task<Vec<SmallVec<[PathBuf; 2]>>> { |
| 2014 | self.platform.update_jump_list(menus, entries) | 2014 | self.platform.update_jump_list(menus, entries) |
| 2015 | } | 2015 | } |
| 2016 | 2016 | ||
| @@ -254,8 +254,8 @@ pub(crate) trait Platform: 'static { · 253 unmodified lines | |||
| 254 | &self, | 254 | &self, |
| 255 | _menus: Vec<MenuItem>, | 255 | _menus: Vec<MenuItem>, |
| 256 | _entries: Vec<SmallVec<[PathBuf; 2]>>, | 256 | _entries: Vec<SmallVec<[PathBuf; 2]>>, |
| 257 | ) -> Vec<SmallVec<[PathBuf; 2]>> { | 257 | ) -> Task<Vec<SmallVec<[PathBuf; 2]>>> { |
| 258 | Vec::new() | 258 | Task::ready(Vec::new()) |
| 259 | } | 259 | } |
| 260 | fn on_app_menu_action(&self, callback: Box<dyn FnMut(&dyn Action)>); | 260 | fn on_app_menu_action(&self, callback: Box<dyn FnMut(&dyn Action)>); |
| 261 | fn on_will_open_app_menu(&self, callback: Box<dyn FnMut()>); | 261 | fn on_will_open_app_menu(&self, callback: Box<dyn FnMut()>); |
| @@ -1,4 +1,4 @@ | |||
| 1 | use std::path::PathBuf; | 1 | use std::{path::PathBuf, sync::Arc}; |
| 2 | 2 | ||
| 3 | use itertools::Itertools; | 3 | use itertools::Itertools; |
| 4 | use smallvec::SmallVec; | 4 | use smallvec::SmallVec; |
| @@ -20,25 +20,25 @@ use windows::{ · 15 unmodified lines | |||
| 20 | core::{GUID, HSTRING, Interface}, | 20 | core::{GUID, HSTRING, Interface}, |
| 21 | }; | 21 | }; |
| 22 | 22 | ||
| 23 | use crate::{Action, MenuItem}; | 23 | use crate::{Action, MenuItem, SharedString}; |
| 24 | 24 | ||
| 25 | pub(crate) struct JumpList { | 25 | pub(crate) struct JumpList { |
| 26 | pub(crate) dock_menus: Vec<DockMenuItem>, | 26 | pub(crate) dock_menus: Vec<DockMenuItem>, |
| 27 | pub(crate) recent_workspaces: Vec<SmallVec<[PathBuf; 2]>>, | 27 | pub(crate) recent_workspaces: Arc<[SmallVec<[PathBuf; 2]>]>, |
| 28 | } | 28 | } |
| 29 | 29 | ||
| 30 | impl JumpList { | 30 | impl JumpList { |
| 31 | pub(crate) fn new() -> Self { | 31 | pub(crate) fn new() -> Self { |
| 32 | Self { | 32 | Self { |
| 33 | dock_menus: Vec::new(), | 33 | dock_menus: Vec::default(), |
| 34 | recent_workspaces: Vec::new(), | 34 | recent_workspaces: Arc::default(), |
| 35 | } | 35 | } |
| 36 | } | 36 | } |
| 37 | } | 37 | } |
| 38 | 38 | ||
| 39 | pub(crate) struct DockMenuItem { | 39 | pub(crate) struct DockMenuItem { |
| 40 | pub(crate) name: String, | 40 | pub(crate) name: SharedString, |
| 41 | pub(crate) description: String, | 41 | pub(crate) description: SharedString, |
| 42 | pub(crate) action: Box<dyn Action>, | 42 | pub(crate) action: Box<dyn Action>, |
| 43 | } | 43 | } |
| 44 | 44 | ||
| @@ -46,11 +46,11 @@ impl DockMenuItem { · 1 unmodified line | |||
| 46 | pub(crate) fn new(item: MenuItem) -> anyhow::Result<Self> { | 46 | pub(crate) fn new(item: MenuItem) -> anyhow::Result<Self> { |
| 47 | match item { | 47 | match item { |
| 48 | MenuItem::Action { name, action, .. } => Ok(Self { | 48 | MenuItem::Action { name, action, .. } => Ok(Self { |
| 49 | name: name.clone().into(), | 49 | name: name.clone(), |
| 50 | description: if name == "New Window" { | 50 | description: if name == "New Window" { |
| 51 | "Opens a new window".to_string() | 51 | "Opens a new window".into() |
| 52 | } else { | 52 | } else { |
| 53 | name.into() | 53 | name |
| 54 | }, | 54 | }, |
| 55 | action, | 55 | action, |
| 56 | }), | 56 | }), |
| @@ -62,11 +62,12 @@ impl DockMenuItem { · 5 unmodified lines | |||
| 62 | // This code is based on the example from Microsoft: | 62 | // This code is based on the example from Microsoft: |
| 63 | // https://github.com/microsoft/Windows-classic-samples/blob/main/Samples/Win7Samples/winui/shell/appshellintegration/RecipePropertyHandler/RecipePropertyHandler.cpp | 63 | // https://github.com/microsoft/Windows-classic-samples/blob/main/Samples/Win7Samples/winui/shell/appshellintegration/RecipePropertyHandler/RecipePropertyHandler.cpp |
| 64 | pub(crate) fn update_jump_list( | 64 | pub(crate) fn update_jump_list( |
| 65 | jump_list: &JumpList, | 65 | recent_workspaces: &[SmallVec<[PathBuf; 2]>], |
| 66 | dock_menus: &[(SharedString, SharedString)], | ||
| 66 | ) -> anyhow::Result<Vec<SmallVec<[PathBuf; 2]>>> { | 67 | ) -> anyhow::Result<Vec<SmallVec<[PathBuf; 2]>>> { |
| 67 | let (list, removed) = create_destination_list()?; | 68 | let (list, removed) = create_destination_list()?; |
| 68 | add_recent_folders(&list, &jump_list.recent_workspaces, removed.as_ref())?; | 69 | add_recent_folders(&list, recent_workspaces, removed.as_ref())?; |
| 69 | add_dock_menu(&list, &jump_list.dock_menus)?; | 70 | add_dock_menu(&list, dock_menus)?; |
| 70 | unsafe { list.CommitList() }?; | 71 | unsafe { list.CommitList() }?; |
| 71 | Ok(removed) | 72 | Ok(removed) |
| 72 | } | 73 | } |
| @@ -110,14 +111,17 @@ fn create_destination_list() -> anyhow::Result<(ICustomDestinationList, Vec<Smal · 37 unmodified lines | |||
| 110 | Ok((list, removed)) | 111 | Ok((list, removed)) |
| 111 | } | 112 | } |
| 112 | 113 | ||
| 113 | fn add_dock_menu(list: &ICustomDestinationList, dock_menus: &[DockMenuItem]) -> anyhow::Result<()> { | 114 | fn add_dock_menu( |
| 115 | list: &ICustomDestinationList, | ||
| 116 | dock_menus: &[(SharedString, SharedString)], | ||
| 117 | ) -> anyhow::Result<()> { | ||
| 114 | unsafe { | 118 | unsafe { |
| 115 | let tasks: IObjectCollection = | 119 | let tasks: IObjectCollection = |
| 116 | CoCreateInstance(&EnumerableObjectCollection, None, CLSCTX_INPROC_SERVER)?; | 120 | CoCreateInstance(&EnumerableObjectCollection, None, CLSCTX_INPROC_SERVER)?; |
| 117 | for (idx, dock_menu) in dock_menus.iter().enumerate() { | 121 | for (idx, (name, description)) in dock_menus.iter().enumerate() { |
| 118 | let argument = HSTRING::from(format!("--dock-action {}", idx)); | 122 | let argument = HSTRING::from(format!("--dock-action {}", idx)); |
| 119 | let description = HSTRING::from(dock_menu.description.as_str()); | 123 | let description = HSTRING::from(description.as_str()); |
| 120 | let display = dock_menu.name.as_str(); | 124 | let display = name.as_str(); |
| 121 | let task = create_shell_link(argument, description, None, display)?; | 125 | let task = create_shell_link(argument, description, None, display)?; |
| 122 | tasks.AddObject(&task)?; | 126 | tasks.AddObject(&task)?; |
| 123 | } | 127 | } |
| @@ -240,14 +240,25 @@ impl WindowsPlatform { · 239 unmodified lines | |||
| 240 | } | 240 | } |
| 241 | }); | 241 | }); |
| 242 | self.inner.state.jump_list.borrow_mut().dock_menus = actions; | 242 | self.inner.state.jump_list.borrow_mut().dock_menus = actions; |
| 243 | update_jump_list(&self.inner.state.jump_list.borrow()).log_err(); | 243 | let borrow = self.inner.state.jump_list.borrow(); |
| 244 | let dock_menus = borrow | ||
| 245 | .dock_menus | ||
| 246 | .iter() | ||
| 247 | .map(|menu| (menu.name.clone(), menu.description.clone())) | ||
| 248 | .collect::<Vec<_>>(); | ||
| 249 | let recent_workspaces = borrow.recent_workspaces.clone(); | ||
| 250 | self.background_executor | ||
| 251 | .spawn(async move { | ||
| 252 | update_jump_list(&recent_workspaces, &dock_menus).log_err(); | ||
| 253 | }) | ||
| 254 | .detach(); | ||
| 244 | } | 255 | } |
| 245 | 256 | ||
| 246 | fn update_jump_list( | 257 | fn update_jump_list( |
| 247 | &self, | 258 | &self, |
| 248 | menus: Vec<MenuItem>, | 259 | menus: Vec<MenuItem>, |
| 249 | entries: Vec<SmallVec<[PathBuf; 2]>>, | 260 | entries: Vec<SmallVec<[PathBuf; 2]>>, |
| 250 | ) -> Vec<SmallVec<[PathBuf; 2]>> { | 261 | ) -> Task<Vec<SmallVec<[PathBuf; 2]>>> { |
| 251 | let mut actions = Vec::new(); | 262 | let mut actions = Vec::new(); |
| 252 | menus.into_iter().for_each(|menu| { | 263 | menus.into_iter().for_each(|menu| { |
| 253 | if let Some(dock_menu) = DockMenuItem::new(menu).log_err() { | 264 | if let Some(dock_menu) = DockMenuItem::new(menu).log_err() { |
| @@ -256,8 +267,18 @@ impl WindowsPlatform { · 2 unmodified lines | |||
| 256 | }); | 267 | }); |
| 257 | let mut jump_list = self.inner.state.jump_list.borrow_mut(); | 268 | let mut jump_list = self.inner.state.jump_list.borrow_mut(); |
| 258 | jump_list.dock_menus = actions; | 269 | jump_list.dock_menus = actions; |
| 259 | jump_list.recent_workspaces = entries; | 270 | jump_list.recent_workspaces = entries.into(); |
| 260 | update_jump_list(&jump_list).log_err().unwrap_or_default() | 271 | let dock_menus = jump_list |
| 272 | .dock_menus | ||
| 273 | .iter() | ||
| 274 | .map(|menu| (menu.name.clone(), menu.description.clone())) | ||
| 275 | .collect::<Vec<_>>(); | ||
| 276 | let recent_workspaces = jump_list.recent_workspaces.clone(); | ||
| 277 | self.background_executor.spawn(async move { | ||
| 278 | update_jump_list(&recent_workspaces, &dock_menus) | ||
| 279 | .log_err() | ||
| 280 | .unwrap_or_default() | ||
| 281 | }) | ||
| 261 | } | 282 | } |
| 262 | 283 | ||
| 263 | fn find_current_active_window(&self) -> Option<HWND> { | 284 | fn find_current_active_window(&self) -> Option<HWND> { |
| @@ -760,7 +781,7 @@ impl Platform for WindowsPlatform { · 496 unmodified lines | |||
| 760 | &self, | 781 | &self, |
| 761 | menus: Vec<MenuItem>, | 782 | menus: Vec<MenuItem>, |
| 762 | entries: Vec<SmallVec<[PathBuf; 2]>>, | 783 | entries: Vec<SmallVec<[PathBuf; 2]>>, |
| 763 | ) -> Vec<SmallVec<[PathBuf; 2]>> { | 784 | ) -> Task<Vec<SmallVec<[PathBuf; 2]>>> { |
| 764 | self.update_jump_list(menus, entries) | 785 | self.update_jump_list(menus, entries) |
| 765 | } | 786 | } |
| 766 | } | 787 | } |
| @@ -2,7 +2,7 @@ use std::path::PathBuf; · 1 unmodified line | |||
| 2 | 2 | ||
| 3 | use gpui::{AppContext, Entity, Global, MenuItem}; | 3 | use gpui::{AppContext, Entity, Global, MenuItem}; |
| 4 | use smallvec::SmallVec; | 4 | use smallvec::SmallVec; |
| 5 | use ui::App; | 5 | use ui::{App, Context}; |
| 6 | use util::{ResultExt, paths::PathExt}; | 6 | use util::{ResultExt, paths::PathExt}; |
| 7 | 7 | ||
| 8 | use crate::{ | 8 | use crate::{ |
| @@ -71,7 +71,12 @@ impl HistoryManager { · 62 unmodified lines | |||
| 71 | cx.set_global(GlobalHistoryManager(history_manager)); | 71 | cx.set_global(GlobalHistoryManager(history_manager)); |
| 72 | } | 72 | } |
| 73 | 73 | ||
| 74 | pub fn update_history(&mut self, id: WorkspaceId, entry: HistoryManagerEntry, cx: &App) { | 74 | pub fn update_history( |
| 75 | &mut self, | ||
| 76 | id: WorkspaceId, | ||
| 77 | entry: HistoryManagerEntry, | ||
| 78 | cx: &mut Context<'_, HistoryManager>, | ||
| 79 | ) { | ||
| 75 | if let Some(pos) = self.history.iter().position(|e| e.id == id) { | 80 | if let Some(pos) = self.history.iter().position(|e| e.id == id) { |
| 76 | self.history.remove(pos); | 81 | self.history.remove(pos); |
| 77 | } | 82 | } |
| @@ -79,7 +84,7 @@ impl HistoryManager { · 1 unmodified line | |||
| 79 | self.update_jump_list(cx); | 84 | self.update_jump_list(cx); |
| 80 | } | 85 | } |
| 81 | 86 | ||
| 82 | pub fn delete_history(&mut self, id: WorkspaceId, cx: &App) { | 87 | pub fn delete_history(&mut self, id: WorkspaceId, cx: &mut Context<'_, HistoryManager>) { |
| 83 | let Some(pos) = self.history.iter().position(|e| e.id == id) else { | 88 | let Some(pos) = self.history.iter().position(|e| e.id == id) else { |
| 84 | return; | 89 | return; |
| 85 | }; | 90 | }; |
| @@ -87,7 +92,7 @@ impl HistoryManager { · 1 unmodified line | |||
| 87 | self.update_jump_list(cx); | 92 | self.update_jump_list(cx); |
| 88 | } | 93 | } |
| 89 | 94 | ||
| 90 | fn update_jump_list(&mut self, cx: &App) { | 95 | fn update_jump_list(&mut self, cx: &mut Context<'_, HistoryManager>) { |
| 91 | let menus = vec![MenuItem::action("New Window", NewWindow)]; | 96 | let menus = vec![MenuItem::action("New Window", NewWindow)]; |
| 92 | let entries = self | 97 | let entries = self |
| 93 | .history | 98 | .history |
| @@ -96,29 +101,25 @@ impl HistoryManager { · 2 unmodified lines | |||
| 96 | .map(|entry| entry.path.clone()) | 101 | .map(|entry| entry.path.clone()) |
| 97 | .collect::<Vec<_>>(); | 102 | .collect::<Vec<_>>(); |
| 98 | let user_removed = cx.update_jump_list(menus, entries); | 103 | let user_removed = cx.update_jump_list(menus, entries); |
| 99 | self.remove_user_removed_workspaces(user_removed, cx); | 104 | cx.spawn(async move |this, cx| { |
| 100 | } | 105 | let user_removed = user_removed.await; |
| 101 | 106 | if user_removed.is_empty() { | |
| 102 | pub fn remove_user_removed_workspaces( | 107 | return; |
| 103 | &mut self, | ||
| 104 | user_removed: Vec<SmallVec<[PathBuf; 2]>>, | ||
| 105 | cx: &App, | ||
| 106 | ) { | ||
| 107 | if user_removed.is_empty() { | ||
| 108 | return; | ||
| 109 | } | ||
| 110 | let mut deleted_ids = Vec::new(); | ||
| 111 | for idx in (0..self.history.len()).rev() { | ||
| 112 | if let Some(entry) = self.history.get(idx) | ||
| 113 | && user_removed.contains(&entry.path) | ||
| 114 | { | ||
| 115 | deleted_ids.push(entry.id); | ||
| 116 | self.history.remove(idx); | ||
| 117 | } | 108 | } |
| 118 | } | 109 | let mut deleted_ids = Vec::new(); |
| 119 | cx.spawn(async move |_| { | 110 | if let Ok(()) = this.update(cx, |this, _| { |
| 120 | for id in deleted_ids.iter() { | 111 | for idx in (0..this.history.len()).rev() { |
| 121 | WORKSPACE_DB.delete_workspace_by_id(*id).await.log_err(); | 112 | if let Some(entry) = this.history.get(idx) |
| 113 | && user_removed.contains(&entry.path) | ||
| 114 | { | ||
| 115 | deleted_ids.push(entry.id); | ||
| 116 | this.history.remove(idx); | ||
| 117 | } | ||
| 118 | } | ||
| 119 | }) { | ||
| 120 | for id in deleted_ids.iter() { | ||
| 121 | WORKSPACE_DB.delete_workspace_by_id(*id).await.log_err(); | ||
| 122 | } | ||
| 122 | } | 123 | } |
| 123 | }) | 124 | }) |
| 124 | .detach(); | 125 | .detach(); |