diff --git a/crates/gpui/src/app.rs b/crates/gpui/src/app.rs index 9cd626746838ee579bfa9ce5405986afc07eefcb..5dc0f0c49d1353a21520cd641b2415d88a532bf2 100644 --- a/crates/gpui/src/app.rs +++ b/crates/gpui/src/app.rs @@ -192,6 +192,13 @@ impl App { cx.borrow_mut().quit(); } })); + foreground_platform.on_validate_menu_command(Box::new({ + let cx = app.0.clone(); + move |action| { + let cx = cx.borrow_mut(); + cx.is_action_available(action) + } + })); foreground_platform.on_menu_command(Box::new({ let cx = app.0.clone(); move |action| { @@ -1364,6 +1371,26 @@ impl MutableAppContext { }) } + pub fn is_action_available(&self, action: &dyn Action) -> bool { + let action_type = action.as_any().type_id(); + if let Some(window_id) = self.cx.platform.key_window_id() { + if let Some((presenter, _)) = self.presenters_and_platform_windows.get(&window_id) { + let dispatch_path = presenter.borrow().dispatch_path(&self.cx); + for view_id in dispatch_path { + if let Some(view) = self.views.get(&(window_id, view_id)) { + let view_type = view.as_any().type_id(); + if let Some(actions) = self.actions.get(&view_type) { + if actions.contains_key(&action_type) { + return true; + } + } + } + } + } + } + self.global_actions.contains_key(&action_type) + } + pub fn dispatch_action_at(&mut self, window_id: usize, view_id: usize, action: &dyn Action) { let presenter = self .presenters_and_platform_windows diff --git a/crates/gpui/src/platform.rs b/crates/gpui/src/platform.rs index 8b813025540385a1efb0738147c6654204fe24ae..68eefeca67ec19466aac030454f18838f354892a 100644 --- a/crates/gpui/src/platform.rs +++ b/crates/gpui/src/platform.rs @@ -73,6 +73,7 @@ pub(crate) trait ForegroundPlatform { fn run(&self, on_finish_launching: Box ()>); fn on_menu_command(&self, callback: Box); + fn on_validate_menu_command(&self, callback: Box bool>); fn set_menus(&self, menus: Vec, matcher: &keymap::Matcher); fn prompt_for_paths( &self, diff --git a/crates/gpui/src/platform/mac/platform.rs b/crates/gpui/src/platform/mac/platform.rs index 89b3389bbeba7a5c40a0cc3d2990793b2f4de44f..54ed421e50ad51eb4aed5ec50f9030fc6b767177 100644 --- a/crates/gpui/src/platform/mac/platform.rs +++ b/crates/gpui/src/platform/mac/platform.rs @@ -89,6 +89,10 @@ unsafe fn build_classes() { sel!(handleGPUIMenuItem:), handle_menu_item as extern "C" fn(&mut Object, Sel, id), ); + decl.add_method( + sel!(validateMenuItem:), + validate_menu_item as extern "C" fn(&mut Object, Sel, id) -> bool, + ); decl.add_method( sel!(application:openURLs:), open_urls as extern "C" fn(&mut Object, Sel, id, id), @@ -107,6 +111,7 @@ pub struct MacForegroundPlatformState { quit: Option>, event: Option bool>>, menu_command: Option>, + validate_menu_command: Option bool>>, open_urls: Option)>>, finish_launching: Option ()>>, menu_actions: Vec>, @@ -237,6 +242,10 @@ impl platform::ForegroundPlatform for MacForegroundPlatform { self.0.borrow_mut().menu_command = Some(callback); } + fn on_validate_menu_command(&self, callback: Box bool>) { + self.0.borrow_mut().validate_menu_command = Some(callback); + } + fn set_menus(&self, menus: Vec, keystroke_matcher: &keymap::Matcher) { unsafe { let app: id = msg_send![APP_CLASS, sharedApplication]; @@ -738,6 +747,23 @@ extern "C" fn handle_menu_item(this: &mut Object, _: Sel, item: id) { } } +extern "C" fn validate_menu_item(this: &mut Object, _: Sel, item: id) -> bool { + unsafe { + let mut result = false; + let platform = get_foreground_platform(this); + let mut platform = platform.0.borrow_mut(); + if let Some(mut callback) = platform.validate_menu_command.take() { + let tag: NSInteger = msg_send![item, tag]; + let index = tag as usize; + if let Some(action) = platform.menu_actions.get(index) { + result = callback(action.as_ref()); + } + platform.validate_menu_command = Some(callback); + } + result + } +} + unsafe fn ns_string(string: &str) -> id { NSString::alloc(nil).init_str(string).autorelease() } diff --git a/crates/gpui/src/platform/test.rs b/crates/gpui/src/platform/test.rs index 7c808d0fbb98a80952d876046de3dab3a15a9e66..ce64fdf01a828ee077d34840869eb651292ed638 100644 --- a/crates/gpui/src/platform/test.rs +++ b/crates/gpui/src/platform/test.rs @@ -74,6 +74,8 @@ impl super::ForegroundPlatform for ForegroundPlatform { fn on_menu_command(&self, _: Box) {} + fn on_validate_menu_command(&self, _: Box bool>) {} + fn set_menus(&self, _: Vec, _: &keymap::Matcher) {} fn prompt_for_paths(